@fireproof/core 0.18.0 → 0.19.5-dev

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. package/README.md +29 -15
  2. package/chunk-7OGPZSGT.js +39 -0
  3. package/chunk-7OGPZSGT.js.map +1 -0
  4. package/chunk-H3A2HMMM.js +164 -0
  5. package/chunk-H3A2HMMM.js.map +1 -0
  6. package/chunk-HCXR2M5B.js +202 -0
  7. package/chunk-HCXR2M5B.js.map +1 -0
  8. package/chunk-QHSXUST7.js +208 -0
  9. package/chunk-QHSXUST7.js.map +1 -0
  10. package/chunk-VZGT7ZYP.js +22 -0
  11. package/chunk-VZGT7ZYP.js.map +1 -0
  12. package/index.cjs +4649 -0
  13. package/index.cjs.map +1 -0
  14. package/index.d.cts +911 -0
  15. package/index.d.ts +911 -0
  16. package/index.js +2923 -0
  17. package/index.js.map +1 -0
  18. package/metafile-cjs.json +1 -0
  19. package/metafile-esm.json +1 -0
  20. package/node-sys-container-E7LADX2Z.js +29 -0
  21. package/node-sys-container-E7LADX2Z.js.map +1 -0
  22. package/package.json +23 -109
  23. package/sqlite-data-store-YS4U7AQ4.js +120 -0
  24. package/sqlite-data-store-YS4U7AQ4.js.map +1 -0
  25. package/sqlite-meta-store-FJZSZG4R.js +137 -0
  26. package/sqlite-meta-store-FJZSZG4R.js.map +1 -0
  27. package/sqlite-wal-store-6JZ4URNS.js +123 -0
  28. package/sqlite-wal-store-6JZ4URNS.js.map +1 -0
  29. package/store-file-HMHPQTUV.js +193 -0
  30. package/store-file-HMHPQTUV.js.map +1 -0
  31. package/store-indexdb-MRVZG4OG.js +20 -0
  32. package/store-indexdb-MRVZG4OG.js.map +1 -0
  33. package/store-sql-5XMJ5OWJ.js +406 -0
  34. package/store-sql-5XMJ5OWJ.js.map +1 -0
  35. package/dist/browser/fireproof.cjs +0 -1172
  36. package/dist/browser/fireproof.cjs.map +0 -1
  37. package/dist/browser/fireproof.d.cts +0 -268
  38. package/dist/browser/fireproof.d.ts +0 -268
  39. package/dist/browser/fireproof.global.js +0 -24178
  40. package/dist/browser/fireproof.global.js.map +0 -1
  41. package/dist/browser/fireproof.js +0 -1147
  42. package/dist/browser/fireproof.js.map +0 -1
  43. package/dist/browser/metafile-cjs.json +0 -1
  44. package/dist/browser/metafile-esm.json +0 -1
  45. package/dist/browser/metafile-iife.json +0 -1
  46. package/dist/memory/fireproof.cjs +0 -1172
  47. package/dist/memory/fireproof.cjs.map +0 -1
  48. package/dist/memory/fireproof.d.cts +0 -268
  49. package/dist/memory/fireproof.d.ts +0 -268
  50. package/dist/memory/fireproof.global.js +0 -24178
  51. package/dist/memory/fireproof.global.js.map +0 -1
  52. package/dist/memory/fireproof.js +0 -1147
  53. package/dist/memory/fireproof.js.map +0 -1
  54. package/dist/memory/metafile-cjs.json +0 -1
  55. package/dist/memory/metafile-esm.json +0 -1
  56. package/dist/memory/metafile-iife.json +0 -1
  57. package/dist/node/fireproof.cjs +0 -1172
  58. package/dist/node/fireproof.cjs.map +0 -1
  59. package/dist/node/fireproof.d.cts +0 -268
  60. package/dist/node/fireproof.d.ts +0 -268
  61. package/dist/node/fireproof.global.js +0 -38540
  62. package/dist/node/fireproof.global.js.map +0 -1
  63. package/dist/node/fireproof.js +0 -1138
  64. package/dist/node/fireproof.js.map +0 -1
  65. package/dist/node/metafile-cjs.json +0 -1
  66. package/dist/node/metafile-esm.json +0 -1
  67. package/dist/node/metafile-iife.json +0 -1
package/index.cjs ADDED
@@ -0,0 +1,4649 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+ var __copyProps = (to, from, except, desc) => {
16
+ if (from && typeof from === "object" || typeof from === "function") {
17
+ for (let key of __getOwnPropNames(from))
18
+ if (!__hasOwnProp.call(to, key) && key !== except)
19
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
31
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
+
33
+ // src/types.ts
34
+ function isFalsy(value) {
35
+ return value === false && value === null && value === void 0;
36
+ }
37
+ function throwFalsy(value) {
38
+ if (isFalsy(value)) {
39
+ throw new Error("value is Falsy");
40
+ }
41
+ return value;
42
+ }
43
+ function falsyToUndef(value) {
44
+ if (isFalsy(value)) {
45
+ return void 0;
46
+ }
47
+ return value;
48
+ }
49
+ var init_types = __esm({
50
+ "src/types.ts"() {
51
+ "use strict";
52
+ }
53
+ });
54
+
55
+ // src/runtime/node-sys-container.ts
56
+ var node_sys_container_exports = {};
57
+ __export(node_sys_container_exports, {
58
+ createNodeSysContainer: () => createNodeSysContainer
59
+ });
60
+ async function createNodeSysContainer() {
61
+ const nodePath = "node:path";
62
+ const nodeOS = "node:os";
63
+ const nodeURL = "node:url";
64
+ const nodeFS = "node:fs";
65
+ const fs = (await import(nodeFS)).promises;
66
+ const path = await import(nodePath);
67
+ return {
68
+ state: "node",
69
+ ...path,
70
+ ...await import(nodeOS),
71
+ ...await import(nodeURL),
72
+ ...fs,
73
+ join,
74
+ stat: fs.stat,
75
+ readdir: fs.readdir,
76
+ readfile: fs.readFile,
77
+ writefile: fs.writeFile
78
+ };
79
+ }
80
+ var init_node_sys_container = __esm({
81
+ "src/runtime/node-sys-container.ts"() {
82
+ "use strict";
83
+ init_sys_container();
84
+ }
85
+ });
86
+
87
+ // src/runtime/sys-container.ts
88
+ function join(...paths) {
89
+ return paths.map((i) => i.replace(/\/+$/, "")).join("/");
90
+ }
91
+ var stdEnv, import_uuidv7, import_cement, onceStart, envImpl, sysContainer, SysContainer;
92
+ var init_sys_container = __esm({
93
+ "src/runtime/sys-container.ts"() {
94
+ "use strict";
95
+ stdEnv = __toESM(require("std-env"), 1);
96
+ import_uuidv7 = require("uuidv7");
97
+ import_cement = require("@adviser/cement");
98
+ init_types();
99
+ onceStart = new import_cement.ResolveOnce();
100
+ envImpl = new import_cement.EnvImpl({
101
+ symbol: "FP_ENV",
102
+ presetEnv: /* @__PURE__ */ new Map([
103
+ // ["FP_DEBUG", "xxx"],
104
+ // ["FP_ENV", "development"],
105
+ ])
106
+ });
107
+ sysContainer = class {
108
+ constructor() {
109
+ this.freight = {
110
+ state: "seeded",
111
+ join,
112
+ dirname: (path) => path.split("/").slice(0, -1).join("/"),
113
+ homedir: () => {
114
+ throw new Error("SysContainer:homedir is not available in seeded state");
115
+ },
116
+ fileURLToPath: (strurl) => {
117
+ let url;
118
+ if (typeof strurl === "string") {
119
+ url = new URL(strurl);
120
+ } else {
121
+ url = strurl;
122
+ }
123
+ return url.pathname;
124
+ },
125
+ // assert: (condition: unknown, message?: string | Error) => {
126
+ // if (!condition) {
127
+ // if (message instanceof Error) {
128
+ // throw message;
129
+ // } else {
130
+ // throw new Error(message);
131
+ // }
132
+ // }
133
+ // },
134
+ mkdir: () => Promise.reject(new Error("SysContainer:mkdir is not available in seeded state")),
135
+ readdir: () => Promise.reject(new Error("SysContainer:readdir is not available in seeded state")),
136
+ rm: () => Promise.reject(new Error("SysContainer:rm is not available in seeded state")),
137
+ copyFile: () => Promise.reject(new Error("SysContainer:copyFile is not available in seeded state")),
138
+ readfile: () => Promise.reject(new Error("SysContainer:readfile is not available in seeded state")),
139
+ unlink: () => Promise.reject(new Error("SysContainer:unlink is not available in seeded state")),
140
+ writefile: () => Promise.reject(new Error("SysContainer:writefile is not available in seeded state")),
141
+ stat: () => Promise.reject(new Error("SysContainer:stat is not available in seeded state"))
142
+ };
143
+ this.id = (0, import_uuidv7.uuidv4)();
144
+ this.homedir = () => {
145
+ this.logSeeded("homedir");
146
+ return throwFalsy(this.freight).homedir();
147
+ };
148
+ this.env = envImpl;
149
+ }
150
+ async start() {
151
+ await onceStart.once(async () => {
152
+ switch (this.freight.state) {
153
+ case "seeded":
154
+ if (stdEnv.isNode) {
155
+ const { createNodeSysContainer: createNodeSysContainer2 } = await Promise.resolve().then(() => (init_node_sys_container(), node_sys_container_exports));
156
+ this.freight = await createNodeSysContainer2();
157
+ } else {
158
+ this.freight.state = "browser";
159
+ }
160
+ return;
161
+ case "browser":
162
+ case "node":
163
+ return;
164
+ }
165
+ });
166
+ }
167
+ async readdir(path, options) {
168
+ this.logSeeded("readdir");
169
+ return throwFalsy(this.freight).readdir(path, options) || [];
170
+ }
171
+ async readdirent(path, options) {
172
+ this.logSeeded("readdirent");
173
+ return throwFalsy(this.freight).readdir(path, { ...options, withFileTypes: true }) || [];
174
+ }
175
+ async readfile(path, options) {
176
+ this.logSeeded("readfile");
177
+ return throwFalsy(this.freight).readfile(path, options);
178
+ }
179
+ async mkdir(path, options) {
180
+ this.logSeeded("mkdir");
181
+ return throwFalsy(this.freight).mkdir(path, options);
182
+ }
183
+ async rm(path, options) {
184
+ this.logSeeded("rm");
185
+ return throwFalsy(this.freight).rm(path, options);
186
+ }
187
+ async unlink(path) {
188
+ this.logSeeded("unlink");
189
+ return throwFalsy(this.freight).unlink(path);
190
+ }
191
+ async writefile(path, data) {
192
+ this.logSeeded("writefile");
193
+ return throwFalsy(this.freight).writefile(path, data);
194
+ }
195
+ async copyFile(source, destination) {
196
+ this.logSeeded("copyFile");
197
+ return throwFalsy(this.freight).copyFile(source, destination);
198
+ }
199
+ async stat(path) {
200
+ this.logSeeded("stat");
201
+ return throwFalsy(this.freight).stat(path);
202
+ }
203
+ fileURLToPath(url) {
204
+ this.logSeeded("fileURLToPath");
205
+ return throwFalsy(this.freight).fileURLToPath(url);
206
+ }
207
+ dirname(path) {
208
+ this.logSeeded("dirname");
209
+ return throwFalsy(this.freight).dirname(path);
210
+ }
211
+ join(...args) {
212
+ this.logSeeded("join");
213
+ return throwFalsy(this.freight).join(...args);
214
+ }
215
+ logSeeded(method) {
216
+ if (this.freight.state === "seeded") {
217
+ const err = new Error();
218
+ console.warn(`SysContainer.${method} is not available in seeded state:`, err.stack);
219
+ }
220
+ }
221
+ };
222
+ SysContainer = new sysContainer();
223
+ }
224
+ });
225
+
226
+ // src/runtime/data-dir.ts
227
+ function dataDir(name, base) {
228
+ const dataDir2 = _dataDir(name, base);
229
+ return dataDir2;
230
+ }
231
+ function _dataDir(name, base) {
232
+ if (!base) {
233
+ if (import_std_env.isNode || import_std_env.isDeno) {
234
+ base = SysContainer.env.get("FP_STORAGE_URL") || `file://${SysContainer.join(SysContainer.homedir(), ".fireproof")}`;
235
+ } else {
236
+ base = `indexdb://fp`;
237
+ }
238
+ }
239
+ let url;
240
+ if (typeof base === "string") {
241
+ try {
242
+ url = new URL(base.toString());
243
+ } catch (e) {
244
+ try {
245
+ base = `file://${base}`;
246
+ url = new URL(base);
247
+ } catch (e2) {
248
+ throw new Error(`invalid base url: ${base}`);
249
+ }
250
+ }
251
+ } else {
252
+ url = base;
253
+ }
254
+ url.searchParams.set("name", name || "");
255
+ return url.toString();
256
+ }
257
+ var import_std_env;
258
+ var init_data_dir = __esm({
259
+ "src/runtime/data-dir.ts"() {
260
+ "use strict";
261
+ init_sys_container();
262
+ import_std_env = require("std-env");
263
+ }
264
+ });
265
+
266
+ // src/runtime/store-file-utils.ts
267
+ async function getPath(url, logger) {
268
+ const basePath = url.toString().replace(new RegExp(`^${url.protocol}//`), "").replace(/\?.*$/, "");
269
+ const name = url.searchParams.get("name");
270
+ if (name) {
271
+ const version = url.searchParams.get("version");
272
+ if (!version) throw logger.Error().Str("url", url.toString()).Msg(`version not found`).AsError();
273
+ return SysContainer.join(basePath, version, name);
274
+ }
275
+ return SysContainer.join(basePath);
276
+ }
277
+ function getFileName(url, key, logger) {
278
+ switch (getStore(url, logger, (...a) => a.join("/"))) {
279
+ case "data":
280
+ return key + ".car";
281
+ case "meta":
282
+ return key + ".json";
283
+ default:
284
+ throw logger.Error().Str("url", url.toString()).Msg(`unsupported store type`).AsError();
285
+ }
286
+ }
287
+ function ensureIndexName(url, name) {
288
+ if (url.searchParams.has("index")) {
289
+ name = (url.searchParams.get("index")?.replace(/[^a-zA-Z0-9]/g, "") || "idx") + "-" + name;
290
+ }
291
+ return name;
292
+ }
293
+ var init_store_file_utils = __esm({
294
+ "src/runtime/store-file-utils.ts"() {
295
+ "use strict";
296
+ init_utils();
297
+ init_sys_container();
298
+ }
299
+ });
300
+
301
+ // src/runtime/store-file-version.ts
302
+ var FILESTORE_VERSION;
303
+ var init_store_file_version = __esm({
304
+ "src/runtime/store-file-version.ts"() {
305
+ "use strict";
306
+ FILESTORE_VERSION = "v0.19-file";
307
+ }
308
+ });
309
+
310
+ // src/runtime/store-indexdb-version.ts
311
+ var INDEXDB_VERSION;
312
+ var init_store_indexdb_version = __esm({
313
+ "src/runtime/store-indexdb-version.ts"() {
314
+ "use strict";
315
+ INDEXDB_VERSION = "v0.19-indexdb";
316
+ }
317
+ });
318
+
319
+ // src/runtime/store-sql/v0.19-sqlite/version.ts
320
+ var SQLITE_VERSION;
321
+ var init_version = __esm({
322
+ "src/runtime/store-sql/v0.19-sqlite/version.ts"() {
323
+ "use strict";
324
+ SQLITE_VERSION = "v0.19-sqlite";
325
+ }
326
+ });
327
+
328
+ // src/runtime/index.ts
329
+ var runtime_exports = {};
330
+ __export(runtime_exports, {
331
+ FILESTORE_VERSION: () => FILESTORE_VERSION,
332
+ INDEXDB_VERSION: () => INDEXDB_VERSION,
333
+ SQLITE_VERSION: () => SQLITE_VERSION,
334
+ SysContainer: () => SysContainer,
335
+ dataDir: () => dataDir,
336
+ ensureIndexName: () => ensureIndexName,
337
+ getFileName: () => getFileName,
338
+ getPath: () => getPath,
339
+ join: () => join
340
+ });
341
+ var init_runtime = __esm({
342
+ "src/runtime/index.ts"() {
343
+ "use strict";
344
+ init_sys_container();
345
+ init_data_dir();
346
+ init_store_file_utils();
347
+ init_store_file_version();
348
+ init_store_indexdb_version();
349
+ init_version();
350
+ }
351
+ });
352
+
353
+ // src/utils.ts
354
+ function ensureLogger(optsOrLogger, componentName, ctx) {
355
+ let logger = globalLogger;
356
+ if ((0, import_cement2.IsLogger)(optsOrLogger)) {
357
+ logger = optsOrLogger;
358
+ } else if (optsOrLogger && (0, import_cement2.IsLogger)(optsOrLogger.logger)) {
359
+ logger = optsOrLogger.logger;
360
+ }
361
+ const cLogger = logger.With().Module(componentName);
362
+ const debug = [];
363
+ if (ctx) {
364
+ if ("debug" in ctx) {
365
+ if (typeof ctx.debug === "string" && ctx.debug.length > 0) {
366
+ debug.push(ctx.debug);
367
+ } else {
368
+ debug.push(componentName);
369
+ }
370
+ delete ctx.debug;
371
+ }
372
+ if ("this" in ctx) {
373
+ cLogger.Str("this", (0, import_uuidv72.uuidv7)());
374
+ delete ctx.this;
375
+ }
376
+ for (const [key, value] of Object.entries(ctx)) {
377
+ switch (typeof value) {
378
+ case "string":
379
+ cLogger.Str(key, value);
380
+ break;
381
+ case "number":
382
+ cLogger.Uint64(key, value);
383
+ break;
384
+ default:
385
+ if (value instanceof Date) {
386
+ cLogger.Str(key, value.toISOString());
387
+ } else if (value instanceof URL) {
388
+ cLogger.Str(key, value.toString());
389
+ } else if (typeof value === "function") {
390
+ cLogger.Ref(key, value);
391
+ } else {
392
+ cLogger.Any(key, value);
393
+ }
394
+ break;
395
+ }
396
+ }
397
+ }
398
+ registerFP_DEBUG.once(async () => {
399
+ SysContainer.env.onSet((key, value) => {
400
+ if (value) {
401
+ logger.SetDebug(value);
402
+ }
403
+ }, "FP_DEBUG");
404
+ }).finally(() => {
405
+ });
406
+ if (debug.length > 0) {
407
+ logger.SetDebug(debug);
408
+ }
409
+ const out = cLogger.Logger();
410
+ return out;
411
+ }
412
+ function getStore(url, logger, joiner) {
413
+ let result = url.searchParams.get("store");
414
+ if (!result) throw logger.Error().Str("url", url.toString()).Msg(`store not found`).AsError();
415
+ if (url.searchParams.has("index")) {
416
+ result = joiner(url.searchParams.get("index") || "idx", result);
417
+ }
418
+ return result;
419
+ }
420
+ function getKey(url, logger) {
421
+ const result = url.searchParams.get("key");
422
+ if (!result) throw logger.Error().Str("url", url.toString()).Msg(`key not found`).AsError();
423
+ return result;
424
+ }
425
+ function getName(url, logger) {
426
+ let result = url.searchParams.get("name");
427
+ if (!result) {
428
+ result = SysContainer.dirname(url.pathname);
429
+ if (result.length === 0) {
430
+ throw logger.Error().Str("url", url.toString()).Msg(`name not found`).AsError();
431
+ }
432
+ }
433
+ return result;
434
+ }
435
+ function exception2Result(fn) {
436
+ return fn().then((value) => import_cement2.Result.Ok(value)).catch((e) => import_cement2.Result.Err(e));
437
+ }
438
+ async function exceptionWrapper(fn) {
439
+ return fn().catch((e) => import_cement2.Result.Err(e));
440
+ }
441
+ var import_cement2, import_uuidv72, globalLogger, registerFP_DEBUG;
442
+ var init_utils = __esm({
443
+ "src/utils.ts"() {
444
+ "use strict";
445
+ import_cement2 = require("@adviser/cement");
446
+ init_runtime();
447
+ import_uuidv72 = require("uuidv7");
448
+ globalLogger = new import_cement2.LoggerImpl();
449
+ registerFP_DEBUG = new import_cement2.ResolveOnce();
450
+ }
451
+ });
452
+
453
+ // src/blockstore/gateway.ts
454
+ function isNotFoundError(e) {
455
+ if (import_cement3.Result.Is(e)) {
456
+ if (e.isOk()) return false;
457
+ e = e.Err();
458
+ }
459
+ if (e.code === "ENOENT") return true;
460
+ return false;
461
+ }
462
+ var import_cement3, NotFoundError;
463
+ var init_gateway = __esm({
464
+ "src/blockstore/gateway.ts"() {
465
+ "use strict";
466
+ import_cement3 = require("@adviser/cement");
467
+ NotFoundError = class extends Error {
468
+ constructor() {
469
+ super(...arguments);
470
+ this.code = "ENOENT";
471
+ }
472
+ };
473
+ }
474
+ });
475
+
476
+ // src/runtime/store-indexdb.ts
477
+ var store_indexdb_exports = {};
478
+ __export(store_indexdb_exports, {
479
+ IndexDBDataGateway: () => IndexDBDataGateway,
480
+ IndexDBMetaGateway: () => IndexDBMetaGateway,
481
+ IndexDBTestStore: () => IndexDBTestStore,
482
+ IndexDBWalGateway: () => IndexDBWalGateway,
483
+ getIndexDBName: () => getIndexDBName,
484
+ guardVersion: () => guardVersion
485
+ });
486
+ function ensureVersion(url) {
487
+ const ret = new URL(url.toString());
488
+ ret.searchParams.set("version", url.searchParams.get("version") || INDEXDB_VERSION);
489
+ return ret;
490
+ }
491
+ function guardVersion(url) {
492
+ if (!url.searchParams.has("version")) {
493
+ return import_cement4.Result.Err(`missing version: ${url.toString()}`);
494
+ }
495
+ return import_cement4.Result.Ok(url);
496
+ }
497
+ function sanitzeKey(key) {
498
+ if (key.length === 1) {
499
+ key = key[0];
500
+ }
501
+ return key;
502
+ }
503
+ async function connectIdb(url, logger) {
504
+ const dbName = getIndexDBName(url, logger);
505
+ const once2 = await onceIndexDB.get(dbName.fullDb).once(async () => {
506
+ const db = await (0, import_idb.openDB)(dbName.fullDb, 1, {
507
+ upgrade(db2) {
508
+ ["version", "data", "wal", "meta", "idx.data", "idx.wal", "idx.meta"].map((store) => {
509
+ db2.createObjectStore(store, {
510
+ autoIncrement: false
511
+ });
512
+ });
513
+ }
514
+ });
515
+ const found = await db.get("version", "version");
516
+ const version = url.searchParams.get("version") || INDEXDB_VERSION;
517
+ if (!found) {
518
+ await db.put("version", { version }, "version");
519
+ } else if (found.version !== version) {
520
+ logger.Warn().Str("url", url.toString()).Str("version", version).Str("found", found.version).Msg("version mismatch");
521
+ }
522
+ return { db, dbName, version };
523
+ });
524
+ url.searchParams.set("version", once2.version);
525
+ return once2.db;
526
+ }
527
+ function joinDBName(...names) {
528
+ return names.map((i) => i.replace(/^[^a-zA-Z0-9]+/g, "").replace(/[^a-zA-Z0-9]+/g, "_")).filter((i) => i.length).join(".");
529
+ }
530
+ function getIndexDBName(iurl, logger) {
531
+ const url = ensureVersion(iurl);
532
+ const fullDb = url.pathname.replace(/^\/+/, "").replace(/\?.*$/, "");
533
+ const dbName = url.searchParams.get("name");
534
+ if (!dbName) throw logger.Error().Str("url", url.toString()).Msg(`name not found`).AsError();
535
+ const result = joinDBName(fullDb, dbName);
536
+ const objStore = getStore(url, logger, joinDBName);
537
+ const connectionKey = [result, objStore].join(":");
538
+ return {
539
+ fullDb: result,
540
+ objStore,
541
+ connectionKey,
542
+ dbName
543
+ };
544
+ }
545
+ var import_idb, import_cement4, onceIndexDB, IndexDBGateway, IndexDBDataGateway, IndexDBWalGateway, IndexDBMetaGateway, txtEncoder, IndexDBTestStore;
546
+ var init_store_indexdb = __esm({
547
+ "src/runtime/store-indexdb.ts"() {
548
+ "use strict";
549
+ import_idb = require("idb");
550
+ import_cement4 = require("@adviser/cement");
551
+ init_store_indexdb_version();
552
+ init_utils();
553
+ init_gateway();
554
+ init_sys_container();
555
+ onceIndexDB = new import_cement4.KeyedResolvOnce();
556
+ IndexDBGateway = class {
557
+ constructor(logger) {
558
+ this.db = {};
559
+ this.logger = logger;
560
+ }
561
+ idb() {
562
+ this.db;
563
+ }
564
+ async start(baseURL) {
565
+ return exception2Result(async () => {
566
+ this.logger.Debug().Url(baseURL).Msg("starting");
567
+ await SysContainer.start();
568
+ this.db = await connectIdb(baseURL, this.logger);
569
+ this.logger.Debug().Url(baseURL).Msg("started");
570
+ });
571
+ }
572
+ async close() {
573
+ return import_cement4.Result.Ok(void 0);
574
+ }
575
+ async destroy(baseUrl) {
576
+ return exception2Result(async () => {
577
+ const type = getStore(baseUrl, this.logger, joinDBName);
578
+ const idb = this.db;
579
+ const trans = idb.transaction(type, "readwrite");
580
+ const object_store = trans.objectStore(type);
581
+ const toDelete = [];
582
+ for (let cursor = await object_store.openCursor(); cursor; cursor = await cursor.continue()) {
583
+ toDelete.push(cursor.primaryKey);
584
+ }
585
+ for (const key of toDelete) {
586
+ await trans.db.delete(type, key);
587
+ }
588
+ await trans.done;
589
+ });
590
+ }
591
+ async get(url) {
592
+ return exceptionWrapper(async () => {
593
+ const key = getKey(url, this.logger);
594
+ const store = getStore(url, this.logger, joinDBName);
595
+ this.logger.Debug().Url(url).Str("key", key).Str("store", store).Msg("getting");
596
+ const tx = this.db.transaction([store], "readonly");
597
+ const bytes = await tx.objectStore(store).get(sanitzeKey(key));
598
+ await tx.done;
599
+ if (!bytes) {
600
+ return import_cement4.Result.Err(new NotFoundError(`missing ${key}`));
601
+ }
602
+ return import_cement4.Result.Ok(bytes);
603
+ });
604
+ }
605
+ async put(url, value) {
606
+ return exception2Result(async () => {
607
+ const key = getKey(url, this.logger);
608
+ const store = getStore(url, this.logger, joinDBName);
609
+ this.logger.Debug().Url(url).Str("key", key).Str("store", store).Msg("putting");
610
+ const tx = this.db.transaction([store], "readwrite");
611
+ await tx.objectStore(store).put(value, sanitzeKey(key));
612
+ await tx.done;
613
+ });
614
+ }
615
+ async delete(url) {
616
+ return exception2Result(async () => {
617
+ const key = getKey(url, this.logger);
618
+ const store = getStore(url, this.logger, joinDBName);
619
+ this.logger.Debug().Url(url).Str("key", key).Str("store", store).Msg("deleting");
620
+ const tx = this.db.transaction([store], "readwrite");
621
+ await tx.objectStore(store).delete(sanitzeKey(key));
622
+ await tx.done;
623
+ return import_cement4.Result.Ok(void 0);
624
+ });
625
+ }
626
+ };
627
+ IndexDBDataGateway = class extends IndexDBGateway {
628
+ constructor(logger) {
629
+ super(ensureLogger(logger, "IndexDBDataGateway", {}));
630
+ }
631
+ buildUrl(baseUrl, key) {
632
+ const url = new URL(baseUrl.toString());
633
+ url.searchParams.set("key", key);
634
+ return Promise.resolve(import_cement4.Result.Ok(url));
635
+ }
636
+ };
637
+ IndexDBWalGateway = class extends IndexDBGateway {
638
+ constructor(logger) {
639
+ super(ensureLogger(logger, "IndexDBWalGateway", {}));
640
+ }
641
+ buildUrl(baseUrl, key) {
642
+ const url = new URL(baseUrl.toString());
643
+ url.searchParams.set("key", key);
644
+ return Promise.resolve(import_cement4.Result.Ok(url));
645
+ }
646
+ };
647
+ IndexDBMetaGateway = class extends IndexDBGateway {
648
+ constructor(logger) {
649
+ super(ensureLogger(logger, "IndexDBDataGateway", {}));
650
+ this.branches = /* @__PURE__ */ new Set();
651
+ }
652
+ async buildUrl(baseUrl, key) {
653
+ const url = new URL(baseUrl.toString());
654
+ this.branches.add(key);
655
+ url.searchParams.set("key", key);
656
+ return import_cement4.Result.Ok(url);
657
+ }
658
+ };
659
+ txtEncoder = new TextEncoder();
660
+ IndexDBTestStore = class {
661
+ constructor(logger) {
662
+ this.logger = ensureLogger(logger, "IndexDBTestStore", {});
663
+ }
664
+ async get(url, key) {
665
+ const db = await connectIdb(url, this.logger);
666
+ const store = getStore(url, this.logger, joinDBName);
667
+ this.logger.Debug().Str("key", key).Str("store", store).Msg("getting");
668
+ let bytes = await db.get(store, sanitzeKey(key));
669
+ this.logger.Debug().Str("key", key).Str("store", store).Int("len", bytes.length).Msg("got");
670
+ if (typeof bytes === "string") {
671
+ bytes = txtEncoder.encode(bytes);
672
+ }
673
+ return bytes;
674
+ }
675
+ };
676
+ }
677
+ });
678
+
679
+ // src/runtime/store-file.ts
680
+ var store_file_exports = {};
681
+ __export(store_file_exports, {
682
+ FileDataGateway: () => FileDataGateway,
683
+ FileMetaGateway: () => FileMetaGateway,
684
+ FileTestStore: () => FileTestStore,
685
+ FileWALGateway: () => FileWALGateway
686
+ });
687
+ async function ensureVersionFile(path, logger) {
688
+ let once2 = versionFiles.get(path);
689
+ if (!once2) {
690
+ once2 = new import_cement7.ResolveOnce();
691
+ versionFiles.set(path, once2);
692
+ }
693
+ await once2.once(async () => {
694
+ await SysContainer.mkdir(path, { recursive: true });
695
+ const vFile = SysContainer.join(path, "version");
696
+ const vFileStat = await SysContainer.stat(vFile).catch(() => void 0);
697
+ if (!vFileStat) {
698
+ await SysContainer.writefile(SysContainer.join(path, "version"), FILESTORE_VERSION);
699
+ return;
700
+ } else if (!vFileStat.isFile()) {
701
+ throw logger.Error().Str("file", vFile).Msg(`version file is a directory`).AsError();
702
+ }
703
+ const v = await SysContainer.readfile(vFile);
704
+ if (v.toString() !== FILESTORE_VERSION) {
705
+ console.warn(`version mismatch:${vFile}: ${v.toString()}!=${FILESTORE_VERSION}`);
706
+ }
707
+ });
708
+ return path;
709
+ }
710
+ function toArrayBuffer(buffer) {
711
+ const ab = new ArrayBuffer(buffer.length);
712
+ const view = new Uint8Array(ab);
713
+ for (let i = 0; i < buffer.length; ++i) {
714
+ view[i] = buffer[i];
715
+ }
716
+ return view;
717
+ }
718
+ var import_cement7, versionFiles, FileGateway, FileWALGateway, FileMetaGateway, FileDataGateway, FileTestStore;
719
+ var init_store_file = __esm({
720
+ "src/runtime/store-file.ts"() {
721
+ "use strict";
722
+ init_sys_container();
723
+ init_store_file_version();
724
+ import_cement7 = require("@adviser/cement");
725
+ init_utils();
726
+ init_gateway();
727
+ init_store_file_utils();
728
+ versionFiles = /* @__PURE__ */ new Map();
729
+ FileGateway = class {
730
+ constructor(logger) {
731
+ this.logger = logger;
732
+ }
733
+ start(baseURL) {
734
+ return exception2Result(async () => {
735
+ await SysContainer.start();
736
+ baseURL.searchParams.set("version", baseURL.searchParams.get("version") || FILESTORE_VERSION);
737
+ const url = await this.buildUrl(baseURL, "dummy");
738
+ if (url.isErr()) return url;
739
+ const dbdir = this.getFilePath(url.Ok());
740
+ await SysContainer.mkdir(SysContainer.dirname(dbdir), { recursive: true });
741
+ const dbroot = SysContainer.dirname(dbdir);
742
+ this.logger.Debug().Str("url", url.Ok().toString()).Str("dbroot", SysContainer.dirname(dbroot)).Msg("start");
743
+ await ensureVersionFile(dbroot, this.logger);
744
+ });
745
+ }
746
+ async close() {
747
+ return import_cement7.Result.Ok(void 0);
748
+ }
749
+ getFilePath(url) {
750
+ const path = url.toString().replace(/^file:\/\//, "").replace(/\?.*$/, "");
751
+ this.logger.Debug().Str("url", url.toString()).Str("path", path).Msg("getFilePath");
752
+ return path;
753
+ }
754
+ async put(url, body) {
755
+ return exception2Result(async () => {
756
+ const file = this.getFilePath(url);
757
+ this.logger.Debug().Str("url", url.toString()).Str("file", file).Msg("put");
758
+ await SysContainer.writefile(file, body);
759
+ });
760
+ }
761
+ async get(url) {
762
+ return exceptionWrapper(async () => {
763
+ const file = this.getFilePath(url);
764
+ try {
765
+ const res = await SysContainer.readfile(file);
766
+ this.logger.Debug().Url(url).Str("file", file).Msg("get");
767
+ return import_cement7.Result.Ok(new Uint8Array(res));
768
+ } catch (e) {
769
+ if (isNotFoundError(e)) {
770
+ return import_cement7.Result.Err(new NotFoundError(`file not found: ${file}`));
771
+ }
772
+ return import_cement7.Result.Err(e);
773
+ }
774
+ });
775
+ }
776
+ async delete(url) {
777
+ return exception2Result(async () => {
778
+ await SysContainer.unlink(this.getFilePath(url));
779
+ });
780
+ }
781
+ async destroyDir(baseURL) {
782
+ const url = await this.buildUrl(baseURL, "x");
783
+ if (url.isErr()) return url;
784
+ const filepath = SysContainer.dirname(this.getFilePath(url.Ok()));
785
+ let dir = [];
786
+ try {
787
+ dir = await SysContainer.readdir(filepath);
788
+ } catch (e) {
789
+ if (!isNotFoundError(e)) {
790
+ throw this.logger.Error().Err(e).Str("dir", filepath).Msg("destroy:readdir").AsError();
791
+ }
792
+ }
793
+ for (const file of dir) {
794
+ const pathed = SysContainer.join(filepath, file);
795
+ try {
796
+ await SysContainer.unlink(pathed);
797
+ } catch (e) {
798
+ if (!isNotFoundError(e)) {
799
+ throw this.logger.Error().Err(e).Str("file", pathed).Msg("destroy:unlink").AsError();
800
+ }
801
+ }
802
+ }
803
+ return import_cement7.Result.Ok(void 0);
804
+ }
805
+ };
806
+ FileWALGateway = class extends FileGateway {
807
+ constructor(logger) {
808
+ super(ensureLogger(logger, "FileWALGateway"));
809
+ }
810
+ async destroy(baseURL) {
811
+ return this.destroyDir(baseURL);
812
+ }
813
+ async buildUrl(baseUrl, key) {
814
+ const url = new URL(baseUrl.toString());
815
+ url.pathname = SysContainer.join(await getPath(baseUrl, this.logger), ensureIndexName(baseUrl, "wal"), key + ".json");
816
+ return import_cement7.Result.Ok(url);
817
+ }
818
+ };
819
+ FileMetaGateway = class extends FileGateway {
820
+ constructor(logger) {
821
+ super(ensureLogger(logger, "FileMetaGateway"));
822
+ }
823
+ async destroy(baseURL) {
824
+ return this.destroyDir(baseURL);
825
+ }
826
+ async buildUrl(baseUrl, key) {
827
+ const url = new URL(baseUrl.toString());
828
+ url.pathname = SysContainer.join(await getPath(baseUrl, this.logger), ensureIndexName(baseUrl, "meta"), key + ".json");
829
+ return import_cement7.Result.Ok(url);
830
+ }
831
+ };
832
+ FileDataGateway = class extends FileGateway {
833
+ constructor(logger) {
834
+ super(ensureLogger(logger, "FileDataGateway"));
835
+ this.branches = /* @__PURE__ */ new Set();
836
+ }
837
+ async destroy(baseURL) {
838
+ return this.destroyDir(baseURL);
839
+ }
840
+ async buildUrl(baseUrl, key) {
841
+ const url = new URL(baseUrl.toString());
842
+ url.pathname = SysContainer.join(await getPath(baseUrl, this.logger), ensureIndexName(baseUrl, "data"), key + ".car");
843
+ return import_cement7.Result.Ok(url);
844
+ }
845
+ };
846
+ FileTestStore = class {
847
+ constructor(logger) {
848
+ this.logger = ensureLogger(logger, "FileTestStore");
849
+ }
850
+ async get(url, key) {
851
+ const logger = ensureLogger(this.logger, "get", { url: url.toString(), key });
852
+ const dbFile = SysContainer.join(
853
+ await getPath(url, this.logger),
854
+ getStore(url, this.logger, SysContainer.join),
855
+ getFileName(url, key, this.logger)
856
+ );
857
+ logger.Debug().Str("dbFile", dbFile).Msg("get");
858
+ const buffer = await SysContainer.readfile(dbFile);
859
+ logger.Debug().Str("dbFile", dbFile).Len(buffer).Msg("got");
860
+ return toArrayBuffer(buffer);
861
+ }
862
+ };
863
+ }
864
+ });
865
+
866
+ // src/runtime/store-sql/types.ts
867
+ var DefaultSQLTableNames;
868
+ var init_types2 = __esm({
869
+ "src/runtime/store-sql/types.ts"() {
870
+ "use strict";
871
+ DefaultSQLTableNames = {
872
+ data: "Datas",
873
+ meta: "Metas",
874
+ wal: "Wals"
875
+ };
876
+ }
877
+ });
878
+
879
+ // src/runtime/store-sql/ensurer.ts
880
+ function sqlTableName(...names) {
881
+ return names.map((name) => name.replace(/^[^a-zA-Z0-9]+/, "").replace(/[^a-zA-Z0-9]+/g, "_")).filter((i) => i.length).join("_");
882
+ }
883
+ function ensureTableNames(url, opts) {
884
+ let isIndex = "";
885
+ if (url.searchParams.has("index")) {
886
+ isIndex = url.searchParams.get("index") || ".idx";
887
+ }
888
+ const ret = opts?.tableNames || DefaultSQLTableNames;
889
+ if (isIndex.length) {
890
+ return {
891
+ data: sqlTableName(isIndex, ret.data),
892
+ meta: sqlTableName(isIndex, ret.meta),
893
+ wal: sqlTableName(isIndex, ret.wal)
894
+ };
895
+ }
896
+ return {
897
+ data: sqlTableName(ret.data),
898
+ meta: sqlTableName(ret.meta),
899
+ wal: sqlTableName(ret.wal)
900
+ };
901
+ }
902
+ function ensureTextEncoder(opts) {
903
+ return opts?.textEncoder || textEncoder2;
904
+ }
905
+ function ensureTextDecoder(opts) {
906
+ return opts?.textDecoder || textDecoder2;
907
+ }
908
+ function url2sqlFlavor(url, logger) {
909
+ const flavor = url.protocol.replace(/:.*$/, "");
910
+ switch (flavor) {
911
+ case "sqlite":
912
+ case "mysql":
913
+ case "postgres":
914
+ return flavor;
915
+ default:
916
+ throw logger.Error().Str("flavor", flavor).Msg("unsupported protocol").AsError();
917
+ }
918
+ }
919
+ function ensureSQLOpts(url, opts, componentName, ctx) {
920
+ const logger = ensureLogger(opts, componentName, ctx);
921
+ return {
922
+ url,
923
+ sqlFlavor: url2sqlFlavor(url, logger),
924
+ tableNames: ensureTableNames(url, opts),
925
+ logger,
926
+ textEncoder: ensureTextEncoder(opts),
927
+ textDecoder: ensureTextDecoder(opts)
928
+ };
929
+ }
930
+ var textEncoder2, textDecoder2;
931
+ var init_ensurer = __esm({
932
+ "src/runtime/store-sql/ensurer.ts"() {
933
+ "use strict";
934
+ init_utils();
935
+ init_types2();
936
+ textEncoder2 = new TextEncoder();
937
+ textDecoder2 = new TextDecoder();
938
+ }
939
+ });
940
+
941
+ // src/runtime/store-sql/sqlite-adapter-better-sqlite3.ts
942
+ var import_cement8, onceSQLiteConnections, SQLiteConnection;
943
+ var init_sqlite_adapter_better_sqlite3 = __esm({
944
+ "src/runtime/store-sql/sqlite-adapter-better-sqlite3.ts"() {
945
+ "use strict";
946
+ import_cement8 = require("@adviser/cement");
947
+ init_sys_container();
948
+ init_ensurer();
949
+ onceSQLiteConnections = new import_cement8.KeyedResolvOnce();
950
+ SQLiteConnection = class _SQLiteConnection {
951
+ static fromURL(url, opts = {}) {
952
+ return new _SQLiteConnection(url, opts);
953
+ }
954
+ get client() {
955
+ if (!this._client) {
956
+ throw this.logger.Error().Msg("client not connected").AsError();
957
+ }
958
+ return this._client;
959
+ }
960
+ constructor(url, opts) {
961
+ this.opts = ensureSQLOpts(url, opts, "SQLiteConnection", { url });
962
+ this.logger = this.opts.logger;
963
+ this.url = url;
964
+ this.logger.Debug().Msg("constructor");
965
+ }
966
+ async connect() {
967
+ let fName = this.url.toString().replace("sqlite://", "").replace(/\?.*$/, "");
968
+ if (!fName) {
969
+ throw this.logger.Error().Str("url", this.url.toString()).Msg("filename is empty").AsError();
970
+ }
971
+ const hasName = this.url.searchParams.get("name");
972
+ if (hasName) {
973
+ fName = SysContainer.join(fName, hasName);
974
+ if (!fName.endsWith(".sqlite")) {
975
+ fName += ".sqlite";
976
+ }
977
+ }
978
+ this._client = await onceSQLiteConnections.get(fName).once(async () => {
979
+ this.logger.Debug().Str("filename", fName).Msg("connect");
980
+ const Sqlite3Database = (await import("better-sqlite3")).default;
981
+ if (hasName) {
982
+ await SysContainer.mkdir(SysContainer.dirname(fName), { recursive: true });
983
+ }
984
+ const db = new Sqlite3Database(fName, {
985
+ // verbose: console.log,
986
+ nativeBinding: "./node_modules/better-sqlite3/build/Release/better_sqlite3.node"
987
+ });
988
+ if (!db) {
989
+ throw this.logger.Error().Msg("connect failed").AsError();
990
+ }
991
+ return db;
992
+ });
993
+ }
994
+ async close() {
995
+ this.logger.Debug().Msg("close");
996
+ await this.client.close();
997
+ }
998
+ };
999
+ }
1000
+ });
1001
+
1002
+ // src/runtime/store-sql/sql-connection-factory.ts
1003
+ function SQLConnectionFactory(databaseURL, opts = {}) {
1004
+ const logger = ensureLogger(opts, "SQLFactory");
1005
+ switch (databaseURL.protocol) {
1006
+ case "sqlite:":
1007
+ logger.Debug().Str("databaseURL", databaseURL.toString()).Msg("connecting to sqlite");
1008
+ return SQLiteConnection.fromURL(databaseURL, {
1009
+ ...opts,
1010
+ logger
1011
+ });
1012
+ default:
1013
+ throw logger.Error().Msg("unsupported protocol " + databaseURL.protocol).AsError();
1014
+ }
1015
+ }
1016
+ var init_sql_connection_factory = __esm({
1017
+ "src/runtime/store-sql/sql-connection-factory.ts"() {
1018
+ "use strict";
1019
+ init_utils();
1020
+ init_sqlite_adapter_better_sqlite3();
1021
+ }
1022
+ });
1023
+
1024
+ // src/runtime/store-sql/v0.19-sqlite/sqlite-ensure-version.ts
1025
+ async function ensureSQLiteVersion(url, dbConn) {
1026
+ const version = await once.once(async () => {
1027
+ const logger = ensureLogger(dbConn.opts, "ensureSQLiteVersion", {
1028
+ version: SQLITE_VERSION,
1029
+ url: dbConn.url.toString()
1030
+ });
1031
+ await dbConn.client.prepare(
1032
+ `CREATE TABLE IF NOT EXISTS version (
1033
+ version TEXT NOT NULL,
1034
+ updated_at TEXT NOT NULL)`
1035
+ ).run();
1036
+ const rows = await dbConn.client.prepare(`select version from version`).all();
1037
+ if (rows.length > 1) {
1038
+ throw logger.Error().Msg(`more than one version row found`).AsError();
1039
+ }
1040
+ if (rows.length === 0) {
1041
+ await dbConn.client.prepare(`insert into version (version, updated_at) values (?, ?)`).run(SQLITE_VERSION, (/* @__PURE__ */ new Date()).toISOString());
1042
+ return SQLITE_VERSION;
1043
+ }
1044
+ if (rows[0].version !== SQLITE_VERSION) {
1045
+ logger.Warn().Any("row", rows[0]).Msg(`version mismatch`);
1046
+ }
1047
+ return rows[0].version;
1048
+ });
1049
+ url.searchParams.set("version", version);
1050
+ }
1051
+ var import_cement9, once;
1052
+ var init_sqlite_ensure_version = __esm({
1053
+ "src/runtime/store-sql/v0.19-sqlite/sqlite-ensure-version.ts"() {
1054
+ "use strict";
1055
+ init_version();
1056
+ import_cement9 = require("@adviser/cement");
1057
+ init_utils();
1058
+ once = new import_cement9.ResolveOnce();
1059
+ }
1060
+ });
1061
+
1062
+ // src/runtime/store-sql/v0.19-sqlite/sqlite-wal-store.ts
1063
+ var sqlite_wal_store_exports = {};
1064
+ __export(sqlite_wal_store_exports, {
1065
+ V0_18_0SQLiteWalStore: () => V0_18_0SQLiteWalStore,
1066
+ WalSQLRecordBuilder: () => WalSQLRecordBuilder
1067
+ });
1068
+ var import_cement10, WalSQLRecordBuilder, V0_18_0SQLiteWalStore;
1069
+ var init_sqlite_wal_store = __esm({
1070
+ "src/runtime/store-sql/v0.19-sqlite/sqlite-wal-store.ts"() {
1071
+ "use strict";
1072
+ import_cement10 = require("@adviser/cement");
1073
+ init_sqlite_ensure_version();
1074
+ init_utils();
1075
+ WalSQLRecordBuilder = class _WalSQLRecordBuilder {
1076
+ #record;
1077
+ constructor(record) {
1078
+ this.#record = record;
1079
+ }
1080
+ static fromRecord(record) {
1081
+ return new _WalSQLRecordBuilder(record);
1082
+ }
1083
+ build() {
1084
+ return this.#record;
1085
+ }
1086
+ };
1087
+ V0_18_0SQLiteWalStore = class {
1088
+ constructor(dbConn) {
1089
+ this.dbConn = dbConn;
1090
+ this.textEncoder = dbConn.opts.textEncoder;
1091
+ this.logger = ensureLogger(dbConn.opts, "SQLiteWalStore");
1092
+ this.logger.Debug().Msg("constructor");
1093
+ }
1094
+ async start(url) {
1095
+ this.logger.Debug().Msg("start");
1096
+ await this.dbConn.connect();
1097
+ await ensureSQLiteVersion(url, this.dbConn);
1098
+ }
1099
+ table(url) {
1100
+ return getStore(url, this.logger, (...x) => x.join("_"));
1101
+ }
1102
+ #createTable = new import_cement10.KeyedResolvOnce();
1103
+ async createTable(url) {
1104
+ return this.#createTable.get(this.table(url)).once(async (table) => {
1105
+ await this.dbConn.client.prepare(
1106
+ `CREATE TABLE IF NOT EXISTS ${table} (
1107
+ name TEXT not null,
1108
+ branch TEXT not null,
1109
+ state BLOB NOT NULL,
1110
+ updated_at TEXT NOT NULL,
1111
+ PRIMARY KEY (name, branch)
1112
+ )`
1113
+ ).run();
1114
+ });
1115
+ }
1116
+ #insertStmt = new import_cement10.KeyedResolvOnce();
1117
+ async insertStmt(url) {
1118
+ return this.#insertStmt.get(this.table(url)).once(async (table) => {
1119
+ await this.createTable(url);
1120
+ return this.dbConn.client.prepare(`insert into ${table}
1121
+ (name, branch, state, updated_at)
1122
+ values (?, ?, ?, ?)
1123
+ ON CONFLICT(name, branch) DO UPDATE SET state=?, updated_at=?
1124
+ `);
1125
+ });
1126
+ }
1127
+ #selectStmt = new import_cement10.KeyedResolvOnce();
1128
+ async selectStmt(url) {
1129
+ return this.#selectStmt.get(this.table(url)).once(async (table) => {
1130
+ await this.createTable(url);
1131
+ return this.dbConn.client.prepare(
1132
+ `select name, branch, state, updated_at from ${table}
1133
+ where name = ? and branch = ?`
1134
+ );
1135
+ });
1136
+ }
1137
+ #deleteStmt = new import_cement10.KeyedResolvOnce();
1138
+ async deleteStmt(url) {
1139
+ return this.#deleteStmt.get(this.table(url)).once(async (table) => {
1140
+ await this.createTable(url);
1141
+ return this.dbConn.client.prepare(`delete from ${table} where name = ? and branch = ?`);
1142
+ });
1143
+ }
1144
+ async insert(url, ose) {
1145
+ const wal = WalSQLRecordBuilder.fromRecord(ose).build();
1146
+ const bufState = Buffer.from(this.textEncoder.encode(JSON.stringify(wal.state)));
1147
+ return this.insertStmt(url).then(
1148
+ (i) => i.run(ose.name, ose.branch, bufState, wal.updated_at.toISOString(), bufState, wal.updated_at.toISOString())
1149
+ );
1150
+ }
1151
+ async select(url, key) {
1152
+ const res = (await this.selectStmt(url).then((i) => i.all(key.name, key.branch))).map((irow) => {
1153
+ const row = irow;
1154
+ return {
1155
+ name: row.name,
1156
+ branch: row.branch,
1157
+ state: Uint8Array.from(row.state),
1158
+ updated_at: new Date(row.updated_at)
1159
+ };
1160
+ });
1161
+ this.logger.Debug().Str("name", key.name).Str("branch", key.branch).Uint64("res", res.length).Msg("select");
1162
+ return res;
1163
+ }
1164
+ async delete(url, key) {
1165
+ this.logger.Debug().Str("name", key.name).Str("branch", key.branch).Msg("delete");
1166
+ return this.deleteStmt(url).then((i) => i.run(key.name, key.branch));
1167
+ }
1168
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1169
+ async close(url) {
1170
+ this.logger.Debug().Msg("close");
1171
+ return import_cement10.Result.Ok(void 0);
1172
+ }
1173
+ async destroy(url) {
1174
+ return exception2Result(async () => {
1175
+ this.logger.Debug().Msg("destroy");
1176
+ await this.createTable(url);
1177
+ await this.dbConn.client.prepare(`delete from ${this.table(url)}`).run();
1178
+ });
1179
+ }
1180
+ };
1181
+ }
1182
+ });
1183
+
1184
+ // src/runtime/store-sql/v0.19-sqlite/sqlite-data-store.ts
1185
+ var sqlite_data_store_exports = {};
1186
+ __export(sqlite_data_store_exports, {
1187
+ DataSQLRecordBuilder: () => DataSQLRecordBuilder,
1188
+ V0_18_0SQLiteDataStore: () => V0_18_0SQLiteDataStore
1189
+ });
1190
+ var import_cement11, DataSQLRecordBuilder, V0_18_0SQLiteDataStore;
1191
+ var init_sqlite_data_store = __esm({
1192
+ "src/runtime/store-sql/v0.19-sqlite/sqlite-data-store.ts"() {
1193
+ "use strict";
1194
+ import_cement11 = require("@adviser/cement");
1195
+ init_sqlite_ensure_version();
1196
+ init_utils();
1197
+ DataSQLRecordBuilder = class _DataSQLRecordBuilder {
1198
+ constructor(dataRecord) {
1199
+ this.dataRecord = dataRecord;
1200
+ }
1201
+ static fromUploadParams(data, params) {
1202
+ return new _DataSQLRecordBuilder({
1203
+ name: params.name,
1204
+ car: params.car,
1205
+ data,
1206
+ updated_at: /* @__PURE__ */ new Date()
1207
+ });
1208
+ }
1209
+ build() {
1210
+ return this.dataRecord;
1211
+ }
1212
+ };
1213
+ V0_18_0SQLiteDataStore = class {
1214
+ constructor(dbConn) {
1215
+ this.dbConn = dbConn;
1216
+ this.logger = ensureLogger(dbConn.opts, "SQLiteDataStore");
1217
+ this.logger.Debug().Msg("constructor");
1218
+ }
1219
+ table(url) {
1220
+ return getStore(url, this.logger, (...x) => x.join("_"));
1221
+ }
1222
+ #createTable = new import_cement11.KeyedResolvOnce();
1223
+ async createTable(url) {
1224
+ return this.#createTable.get(this.table(url)).once(async (table) => {
1225
+ await this.dbConn.client.prepare(
1226
+ `CREATE TABLE IF NOT EXISTS ${table} (
1227
+ name TEXT NOT NULL,
1228
+ car TEXT PRIMARY KEY,
1229
+ data BLOB NOT NULL,
1230
+ updated_at TEXT NOT NULL)`
1231
+ ).run();
1232
+ });
1233
+ }
1234
+ #insertStmt = new import_cement11.KeyedResolvOnce();
1235
+ async insertStmt(url) {
1236
+ return this.#insertStmt.get(this.table(url)).once(async (table) => {
1237
+ await this.createTable(url);
1238
+ return this.dbConn.client.prepare(`
1239
+ insert into ${table}
1240
+ (name, car, data, updated_at) values (?, ?, ?, ?)
1241
+ ON CONFLICT(car) DO UPDATE SET updated_at=?`);
1242
+ });
1243
+ }
1244
+ #selectStmt = new import_cement11.KeyedResolvOnce();
1245
+ async selectStmt(url) {
1246
+ return this.#selectStmt.get(this.table(url)).once(async (table) => {
1247
+ await this.createTable(url);
1248
+ return this.dbConn.client.prepare(`select name, car, data, updated_at from ${table} where car = ?`);
1249
+ });
1250
+ }
1251
+ #deleteStmt = new import_cement11.KeyedResolvOnce();
1252
+ async deleteStmt(url) {
1253
+ return this.#deleteStmt.get(this.table(url)).once(async (table) => {
1254
+ await this.createTable(url);
1255
+ return this.dbConn.client.prepare(`delete from ${table} where car = ?`);
1256
+ });
1257
+ }
1258
+ async start(url) {
1259
+ this.logger.Debug().Msg("start-connect");
1260
+ await this.dbConn.connect();
1261
+ this.logger.Debug().Msg("start-connected");
1262
+ await ensureSQLiteVersion(url, this.dbConn);
1263
+ this.logger.Debug().Msg("start-set-version");
1264
+ }
1265
+ async insert(url, ose) {
1266
+ this.logger.Debug().Str("name", ose.name).Str("car", ose.car).Uint64("data-len", ose.data.length).Msg("insert");
1267
+ const updated_at = ose.updated_at.toISOString();
1268
+ return this.insertStmt(url).then((i) => i.run(ose.name, ose.car, Buffer.from(ose.data), updated_at, updated_at));
1269
+ }
1270
+ async select(url, car) {
1271
+ this.logger.Debug().Str("car", car).Msg("select");
1272
+ return (await this.selectStmt(url).then((i) => i.all(car))).map((irow) => {
1273
+ const row = irow;
1274
+ return {
1275
+ name: row.name,
1276
+ car: row.car,
1277
+ data: Uint8Array.from(row.data),
1278
+ updated_at: new Date(row.updated_at)
1279
+ };
1280
+ });
1281
+ }
1282
+ async delete(url, car) {
1283
+ this.logger.Debug().Str("car", car).Msg("delete");
1284
+ const ret = await this.deleteStmt(url).then((i) => i.run(car));
1285
+ return ret;
1286
+ }
1287
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1288
+ async close(url) {
1289
+ this.logger.Debug().Msg("close");
1290
+ return import_cement11.Result.Ok(void 0);
1291
+ }
1292
+ async destroy(url) {
1293
+ return exception2Result(async () => {
1294
+ this.logger.Debug().Msg("destroy");
1295
+ await this.createTable(url);
1296
+ await this.dbConn.client.prepare(`delete from ${this.table(url)}`).run();
1297
+ });
1298
+ }
1299
+ };
1300
+ }
1301
+ });
1302
+
1303
+ // src/runtime/store-sql/v0.19-sqlite/sqlite-meta-store.ts
1304
+ var sqlite_meta_store_exports = {};
1305
+ __export(sqlite_meta_store_exports, {
1306
+ MetaSQLRecordBuilder: () => MetaSQLRecordBuilder,
1307
+ V0_18_0SQLiteMetaStore: () => V0_18_0SQLiteMetaStore
1308
+ });
1309
+ var import_cement12, MetaSQLRecordBuilder, V0_18_0SQLiteMetaStore;
1310
+ var init_sqlite_meta_store = __esm({
1311
+ "src/runtime/store-sql/v0.19-sqlite/sqlite-meta-store.ts"() {
1312
+ "use strict";
1313
+ import_cement12 = require("@adviser/cement");
1314
+ init_sqlite_ensure_version();
1315
+ init_utils();
1316
+ MetaSQLRecordBuilder = class _MetaSQLRecordBuilder {
1317
+ constructor(record, textEncoder3) {
1318
+ this.record = record;
1319
+ this.textEncoder = textEncoder3;
1320
+ }
1321
+ static fromUploadMetaFnParams(data, params, textEncoder3) {
1322
+ return new _MetaSQLRecordBuilder(
1323
+ {
1324
+ name: params.name,
1325
+ branch: params.branch,
1326
+ meta: data,
1327
+ updated_at: /* @__PURE__ */ new Date()
1328
+ },
1329
+ textEncoder3
1330
+ );
1331
+ }
1332
+ static fromBytes(str, name, branch, textEncoder3) {
1333
+ return new _MetaSQLRecordBuilder(
1334
+ {
1335
+ name,
1336
+ branch,
1337
+ meta: textEncoder3.encode(str),
1338
+ updated_at: /* @__PURE__ */ new Date()
1339
+ },
1340
+ textEncoder3
1341
+ );
1342
+ }
1343
+ build() {
1344
+ return this.record;
1345
+ }
1346
+ };
1347
+ V0_18_0SQLiteMetaStore = class {
1348
+ constructor(dbConn) {
1349
+ this.dbConn = dbConn;
1350
+ this.logger = ensureLogger(dbConn.opts, "SQLiteMetaStore");
1351
+ this.logger.Debug().Msg("constructor");
1352
+ }
1353
+ async start(url) {
1354
+ this.logger.Debug().Url(url).Msg("starting");
1355
+ await this.dbConn.connect();
1356
+ await ensureSQLiteVersion(url, this.dbConn);
1357
+ this.logger.Debug().Url(url).Msg("started");
1358
+ }
1359
+ table(url) {
1360
+ return getStore(url, this.logger, (...x) => x.join("_"));
1361
+ }
1362
+ #createTable = new import_cement12.KeyedResolvOnce();
1363
+ async createTable(url) {
1364
+ return this.#createTable.get(this.table(url)).once(async (table) => {
1365
+ await this.dbConn.client.prepare(
1366
+ `CREATE TABLE IF NOT EXISTS ${table} (
1367
+ name TEXT not null,
1368
+ branch TEXT not null,
1369
+ meta BLOB NOT NULL,
1370
+ updated_at TEXT NOT NULL,
1371
+ PRIMARY KEY (name, branch)
1372
+ )`
1373
+ ).run();
1374
+ });
1375
+ }
1376
+ #insertStmt = new import_cement12.KeyedResolvOnce();
1377
+ async insertStmt(url) {
1378
+ return this.#insertStmt.get(this.table(url)).once(async (table) => {
1379
+ await this.createTable(url);
1380
+ return this.dbConn.client.prepare(`insert into ${table}
1381
+ (name, branch, meta, updated_at)
1382
+ values (?, ?, ?, ?)
1383
+ ON CONFLICT(name, branch) DO UPDATE SET meta=?, updated_at=?
1384
+ `);
1385
+ });
1386
+ }
1387
+ #selectStmt = new import_cement12.KeyedResolvOnce();
1388
+ async selectStmt(url) {
1389
+ return this.#selectStmt.get(this.table(url)).once(async (table) => {
1390
+ await this.createTable(url);
1391
+ return this.dbConn.client.prepare(`select name, branch, meta, updated_at from ${table} where name = ? and branch = ?`);
1392
+ });
1393
+ }
1394
+ #deleteStmt = new import_cement12.KeyedResolvOnce();
1395
+ async deleteStmt(url) {
1396
+ return this.#deleteStmt.get(this.table(url)).once(async (table) => {
1397
+ await this.createTable(url);
1398
+ return this.dbConn.client.prepare(`delete from ${table} where name = ? and branch = ?`);
1399
+ });
1400
+ }
1401
+ async insert(url, ose) {
1402
+ this.logger.Debug().Str("name", ose.name).Str("branch", ose.branch).Uint64("data-len", ose.meta.length).Msg("insert");
1403
+ const bufMeta = Buffer.from(ose.meta);
1404
+ return this.insertStmt(url).then(
1405
+ (i) => i.run(ose.name, ose.branch, bufMeta, ose.updated_at.toISOString(), bufMeta, ose.updated_at.toISOString())
1406
+ );
1407
+ }
1408
+ async select(url, key) {
1409
+ this.logger.Debug().Str("name", key.name).Str("branch", key.branch).Msg("select");
1410
+ return (await this.selectStmt(url).then((i) => i.all(key.name, key.branch))).map((irow) => {
1411
+ const row = irow;
1412
+ return {
1413
+ name: row.name,
1414
+ branch: row.branch,
1415
+ meta: Uint8Array.from(row.meta),
1416
+ updated_at: new Date(row.updated_at)
1417
+ };
1418
+ });
1419
+ }
1420
+ async delete(url, key) {
1421
+ this.logger.Debug().Str("name", key.name).Str("branch", key.branch).Msg("delete");
1422
+ return this.deleteStmt(url).then((i) => i.run(key.name, key.branch));
1423
+ }
1424
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1425
+ async close(url) {
1426
+ this.logger.Debug().Msg("close");
1427
+ return import_cement12.Result.Ok(void 0);
1428
+ }
1429
+ async destroy(url) {
1430
+ return exception2Result(async () => {
1431
+ this.logger.Debug().Msg("destroy");
1432
+ await this.dbConn.client.prepare(`delete from ${this.table(url)}`).run();
1433
+ });
1434
+ }
1435
+ };
1436
+ }
1437
+ });
1438
+
1439
+ // src/runtime/store-sql/store-version-factory.ts
1440
+ async function WalStoreFactory(db) {
1441
+ switch (db.opts.sqlFlavor) {
1442
+ case "sqlite": {
1443
+ const { V0_18_0SQLiteWalStore: V0_18_0SQLiteWalStore2 } = await Promise.resolve().then(() => (init_sqlite_wal_store(), sqlite_wal_store_exports));
1444
+ const store = new V0_18_0SQLiteWalStore2(db);
1445
+ return store;
1446
+ }
1447
+ default:
1448
+ throw ensureLogger(db.opts, "WalStoreFactory").Error().Msg("unsupported db connection").AsError();
1449
+ }
1450
+ }
1451
+ async function DataStoreFactory(db) {
1452
+ switch (db.opts.sqlFlavor) {
1453
+ case "sqlite": {
1454
+ const { V0_18_0SQLiteDataStore: V0_18_0SQLiteDataStore2 } = await Promise.resolve().then(() => (init_sqlite_data_store(), sqlite_data_store_exports));
1455
+ const store = new V0_18_0SQLiteDataStore2(db);
1456
+ return store;
1457
+ }
1458
+ default:
1459
+ throw ensureLogger(db.opts, "DataStoreFactory").Error().Msg("unsupported db connection").AsError();
1460
+ }
1461
+ }
1462
+ async function MetaStoreFactory(db) {
1463
+ switch (db.opts.sqlFlavor) {
1464
+ case "sqlite": {
1465
+ const { V0_18_0SQLiteMetaStore: V0_18_0SQLiteMetaStore2 } = await Promise.resolve().then(() => (init_sqlite_meta_store(), sqlite_meta_store_exports));
1466
+ const store = new V0_18_0SQLiteMetaStore2(db);
1467
+ return store;
1468
+ }
1469
+ default:
1470
+ throw ensureLogger(db.opts, "MetaStoreFactory").Error().Msg("unsupported db connection").AsError();
1471
+ }
1472
+ }
1473
+ var init_store_version_factory = __esm({
1474
+ "src/runtime/store-sql/store-version-factory.ts"() {
1475
+ "use strict";
1476
+ init_utils();
1477
+ init_version();
1478
+ }
1479
+ });
1480
+
1481
+ // src/runtime/store-sql/store-sql.ts
1482
+ var store_sql_exports = {};
1483
+ __export(store_sql_exports, {
1484
+ SQLDataGateway: () => SQLDataGateway,
1485
+ SQLMetaGateway: () => SQLMetaGateway,
1486
+ SQLTestStore: () => SQLTestStore,
1487
+ SQLWalGateway: () => SQLWalGateway
1488
+ });
1489
+ var import_cement13, SQLWalGateway, SQLMetaGateway, SQLDataGateway, SQLTestStore;
1490
+ var init_store_sql = __esm({
1491
+ "src/runtime/store-sql/store-sql.ts"() {
1492
+ "use strict";
1493
+ import_cement13 = require("@adviser/cement");
1494
+ init_sql_connection_factory();
1495
+ init_store_version_factory();
1496
+ init_utils();
1497
+ init_gateway();
1498
+ SQLWalGateway = class {
1499
+ constructor(logger) {
1500
+ this.walSQLStore = {};
1501
+ this.logger = ensureLogger(logger, "SQLWalGateway");
1502
+ }
1503
+ buildUrl(baseUrl, key) {
1504
+ const url = new URL(baseUrl.toString());
1505
+ url.searchParams.set("key", key);
1506
+ return Promise.resolve(import_cement13.Result.Ok(url));
1507
+ }
1508
+ async start(baseUrl) {
1509
+ return exception2Result(async () => {
1510
+ this.logger.Debug().Url(baseUrl).Msg("start");
1511
+ const conn = SQLConnectionFactory(baseUrl);
1512
+ const ws = await WalStoreFactory(conn);
1513
+ await ws.start(baseUrl);
1514
+ this.walSQLStore = ws;
1515
+ });
1516
+ }
1517
+ close(baseUrl) {
1518
+ return this.walSQLStore.close(baseUrl);
1519
+ }
1520
+ destroy(baseUrl) {
1521
+ return this.walSQLStore.destroy(baseUrl);
1522
+ }
1523
+ async put(url, body) {
1524
+ return exception2Result(async () => {
1525
+ const branch = getKey(url, this.logger);
1526
+ const name = getName(url, this.logger);
1527
+ await this.walSQLStore.insert(url, {
1528
+ state: body,
1529
+ updated_at: /* @__PURE__ */ new Date(),
1530
+ name,
1531
+ branch
1532
+ });
1533
+ });
1534
+ }
1535
+ async get(url) {
1536
+ return exceptionWrapper(async () => {
1537
+ const branch = getKey(url, this.logger);
1538
+ const name = getName(url, this.logger);
1539
+ const record = await this.walSQLStore.select(url, { name, branch });
1540
+ if (record.length === 0) {
1541
+ return import_cement13.Result.Err(new NotFoundError(`not found ${name} ${branch}`));
1542
+ }
1543
+ return import_cement13.Result.Ok(record[0].state);
1544
+ });
1545
+ }
1546
+ async delete(url) {
1547
+ return exception2Result(async () => {
1548
+ const branch = getKey(url, this.logger);
1549
+ const name = getName(url, this.logger);
1550
+ await this.walSQLStore.delete(url, { name, branch });
1551
+ });
1552
+ }
1553
+ };
1554
+ SQLMetaGateway = class {
1555
+ constructor(logger) {
1556
+ this.metaSQLStore = {};
1557
+ this.logger = ensureLogger(logger, "SQLMetaGateway");
1558
+ }
1559
+ buildUrl(baseUrl, key) {
1560
+ const url = new URL(baseUrl.toString());
1561
+ url.searchParams.set("key", key);
1562
+ return Promise.resolve(import_cement13.Result.Ok(url));
1563
+ }
1564
+ async start(baseUrl) {
1565
+ return exception2Result(async () => {
1566
+ this.logger.Debug().Url(baseUrl).Msg("start");
1567
+ const conn = SQLConnectionFactory(baseUrl);
1568
+ const ws = await MetaStoreFactory(conn);
1569
+ await ws.start(baseUrl);
1570
+ this.metaSQLStore = ws;
1571
+ this.logger.Debug().Url(baseUrl).Msg("started");
1572
+ });
1573
+ }
1574
+ close(baseUrl) {
1575
+ return this.metaSQLStore.close(baseUrl);
1576
+ }
1577
+ destroy(baseUrl) {
1578
+ return this.metaSQLStore.destroy(baseUrl);
1579
+ }
1580
+ async put(url, body) {
1581
+ return exception2Result(async () => {
1582
+ const branch = getKey(url, this.logger);
1583
+ const name = getName(url, this.logger);
1584
+ await this.metaSQLStore.insert(url, {
1585
+ meta: body,
1586
+ updated_at: /* @__PURE__ */ new Date(),
1587
+ name,
1588
+ branch
1589
+ });
1590
+ });
1591
+ }
1592
+ async get(url) {
1593
+ return exceptionWrapper(async () => {
1594
+ const branch = getKey(url, this.logger);
1595
+ const name = getName(url, this.logger);
1596
+ const record = await this.metaSQLStore.select(url, {
1597
+ name,
1598
+ branch
1599
+ });
1600
+ if (record.length === 0) {
1601
+ return import_cement13.Result.Err(new NotFoundError(`not found ${name} ${branch}`));
1602
+ }
1603
+ return import_cement13.Result.Ok(record[0].meta);
1604
+ });
1605
+ }
1606
+ async delete(url) {
1607
+ return exception2Result(async () => {
1608
+ const branch = getKey(url, this.logger);
1609
+ const name = getName(url, this.logger);
1610
+ await this.metaSQLStore.delete(url, {
1611
+ name,
1612
+ branch
1613
+ });
1614
+ });
1615
+ }
1616
+ };
1617
+ SQLDataGateway = class {
1618
+ constructor(logger) {
1619
+ this.dataSQLStore = {};
1620
+ this.logger = ensureLogger(logger, "SQLDataGateway");
1621
+ }
1622
+ buildUrl(baseUrl, key) {
1623
+ const url = new URL(baseUrl.toString());
1624
+ url.searchParams.set("key", key);
1625
+ return Promise.resolve(import_cement13.Result.Ok(url));
1626
+ }
1627
+ async start(baseUrl) {
1628
+ return exception2Result(async () => {
1629
+ this.logger.Debug().Url(baseUrl).Msg("pre-sql-connection");
1630
+ const conn = SQLConnectionFactory(baseUrl);
1631
+ this.logger.Debug().Url(baseUrl).Msg("post-sql-connection");
1632
+ const ws = await DataStoreFactory(conn);
1633
+ this.logger.Debug().Url(baseUrl).Msg("post-data-store-factory");
1634
+ await ws.start(baseUrl);
1635
+ this.dataSQLStore = ws;
1636
+ this.logger.Debug().Url(baseUrl).Msg("started");
1637
+ });
1638
+ }
1639
+ close(baseUrl) {
1640
+ return this.dataSQLStore.close(baseUrl);
1641
+ }
1642
+ destroy(baseUrl) {
1643
+ return this.dataSQLStore.destroy(baseUrl);
1644
+ }
1645
+ async put(url, body) {
1646
+ return exception2Result(async () => {
1647
+ const cid = getKey(url, this.logger);
1648
+ const name = getName(url, this.logger);
1649
+ await this.dataSQLStore.insert(url, {
1650
+ data: body,
1651
+ updated_at: /* @__PURE__ */ new Date(),
1652
+ name,
1653
+ car: cid
1654
+ });
1655
+ });
1656
+ }
1657
+ async get(url) {
1658
+ return exceptionWrapper(async () => {
1659
+ const branch = getKey(url, this.logger);
1660
+ const record = await this.dataSQLStore.select(url, branch);
1661
+ if (record.length === 0) {
1662
+ return import_cement13.Result.Err(new NotFoundError(`not found ${branch}`));
1663
+ }
1664
+ return import_cement13.Result.Ok(record[0].data);
1665
+ });
1666
+ }
1667
+ async delete(url) {
1668
+ return exception2Result(async () => {
1669
+ const branch = getKey(url, this.logger);
1670
+ await this.dataSQLStore.delete(url, branch);
1671
+ return import_cement13.Result.Ok(void 0);
1672
+ });
1673
+ }
1674
+ };
1675
+ SQLTestStore = class {
1676
+ constructor(ilogger) {
1677
+ const logger = ensureLogger(ilogger, "SQLTestStore");
1678
+ this.logger = logger;
1679
+ }
1680
+ async get(url, key) {
1681
+ const conn = SQLConnectionFactory(url);
1682
+ const name = getName(url, this.logger);
1683
+ switch (url.searchParams.get("store")) {
1684
+ case "wal": {
1685
+ const sqlStore = await WalStoreFactory(conn);
1686
+ await sqlStore.start(url);
1687
+ const records = await sqlStore.select(url, {
1688
+ name,
1689
+ branch: key
1690
+ });
1691
+ return records[0].state;
1692
+ }
1693
+ case "meta": {
1694
+ const sqlStore = await MetaStoreFactory(conn);
1695
+ await sqlStore.start(url);
1696
+ const records = await sqlStore.select(url, {
1697
+ name,
1698
+ branch: key
1699
+ });
1700
+ return records[0].meta;
1701
+ }
1702
+ case "data": {
1703
+ const sqlStore = await DataStoreFactory(conn);
1704
+ await sqlStore.start(url);
1705
+ const records = await sqlStore.select(url, key);
1706
+ return records[0].data;
1707
+ }
1708
+ default:
1709
+ throw this.logger.Error().Str("key", key).Msg(`Method not implemented`);
1710
+ }
1711
+ }
1712
+ };
1713
+ }
1714
+ });
1715
+
1716
+ // src/index.ts
1717
+ var src_exports = {};
1718
+ __export(src_exports, {
1719
+ CRDT: () => CRDT,
1720
+ Database: () => Database,
1721
+ Index: () => Index,
1722
+ PACKAGE_VERSION: () => PACKAGE_VERSION,
1723
+ blockstore: () => blockstore_exports,
1724
+ bs: () => blockstore_exports,
1725
+ ensureLogger: () => ensureLogger,
1726
+ exception2Result: () => exception2Result,
1727
+ exceptionWrapper: () => exceptionWrapper,
1728
+ falsyToUndef: () => falsyToUndef,
1729
+ fireproof: () => fireproof,
1730
+ getKey: () => getKey,
1731
+ getName: () => getName,
1732
+ getStore: () => getStore,
1733
+ index: () => index,
1734
+ isFalsy: () => isFalsy,
1735
+ rt: () => runtime_exports,
1736
+ throwFalsy: () => throwFalsy
1737
+ });
1738
+ module.exports = __toCommonJS(src_exports);
1739
+
1740
+ // src/database.ts
1741
+ var import_uuidv73 = require("uuidv7");
1742
+ var import_cement17 = require("@adviser/cement");
1743
+
1744
+ // src/write-queue.ts
1745
+ function writeQueue(worker, payload = Infinity, unbounded = false) {
1746
+ const queue = [];
1747
+ let isProcessing = false;
1748
+ async function process() {
1749
+ if (isProcessing || queue.length === 0) return;
1750
+ isProcessing = true;
1751
+ const tasksToProcess = queue.splice(0, payload);
1752
+ const updates = tasksToProcess.map((item) => item.task);
1753
+ if (unbounded) {
1754
+ const promises = updates.map(async (update, index2) => {
1755
+ try {
1756
+ const result = await worker([update]);
1757
+ tasksToProcess[index2].resolve(result);
1758
+ } catch (error) {
1759
+ tasksToProcess[index2].reject(error);
1760
+ }
1761
+ });
1762
+ await Promise.all(promises);
1763
+ } else {
1764
+ try {
1765
+ const result = await worker(updates);
1766
+ tasksToProcess.forEach((task) => task.resolve(result));
1767
+ } catch (error) {
1768
+ tasksToProcess.forEach((task) => task.reject(error));
1769
+ }
1770
+ }
1771
+ isProcessing = false;
1772
+ void process();
1773
+ }
1774
+ return {
1775
+ push(task) {
1776
+ return new Promise((resolve, reject) => {
1777
+ queue.push({ task, resolve, reject });
1778
+ void process();
1779
+ });
1780
+ }
1781
+ };
1782
+ }
1783
+
1784
+ // src/crdt.ts
1785
+ var import_cement16 = require("@adviser/cement");
1786
+
1787
+ // src/crdt-helpers.ts
1788
+ var import_block6 = require("multiformats/block");
1789
+ var import_link = require("multiformats/link");
1790
+ var import_sha23 = require("multiformats/hashes/sha2");
1791
+ var codec2 = __toESM(require("@ipld/dag-cbor"), 1);
1792
+ var import_crdt = require("@web3-storage/pail/crdt");
1793
+ var import_clock2 = require("@web3-storage/pail/clock");
1794
+ var Batch = __toESM(require("@web3-storage/pail/crdt/batch"), 1);
1795
+
1796
+ // src/blockstore/index.ts
1797
+ var blockstore_exports = {};
1798
+ __export(blockstore_exports, {
1799
+ BaseBlockstore: () => BaseBlockstore,
1800
+ CarTransaction: () => CarTransaction,
1801
+ CompactionFetcher: () => CompactionFetcher,
1802
+ ConnectREST: () => ConnectREST,
1803
+ ConnectionBase: () => ConnectionBase,
1804
+ DataStore: () => DataStore,
1805
+ EncryptedBlockstore: () => EncryptedBlockstore,
1806
+ Loadable: () => Loadable,
1807
+ Loader: () => Loader,
1808
+ MetaStore: () => MetaStore,
1809
+ NotFoundError: () => NotFoundError,
1810
+ RemoteWAL: () => RemoteWAL,
1811
+ isNotFoundError: () => isNotFoundError,
1812
+ parseCarFile: () => parseCarFile,
1813
+ registerStoreProtocol: () => registerStoreProtocol,
1814
+ testStoreFactory: () => testStoreFactory,
1815
+ toStoreRuntime: () => toStoreRuntime,
1816
+ toURL: () => toURL
1817
+ });
1818
+
1819
+ // src/blockstore/connection-base.ts
1820
+ var import_clock = require("@web3-storage/pail/clock");
1821
+ var import_block = require("@web3-storage/pail/block");
1822
+ init_types();
1823
+
1824
+ // src/blockstore/task-manager.ts
1825
+ init_utils();
1826
+ var TaskManager = class {
1827
+ constructor(loader) {
1828
+ this.eventsWeHandled = /* @__PURE__ */ new Set();
1829
+ this.queue = [];
1830
+ this.isProcessing = false;
1831
+ this.loader = loader;
1832
+ this.logger = ensureLogger(loader.logger, "TaskManager");
1833
+ }
1834
+ async handleEvent(eventBlock) {
1835
+ const cid = eventBlock.cid.toString();
1836
+ const parents = eventBlock.value.parents.map((cid2) => cid2.toString());
1837
+ for (const parent of parents) {
1838
+ this.eventsWeHandled.add(parent);
1839
+ }
1840
+ this.queue.push({ cid, eventBlock, retries: 0 });
1841
+ this.queue = this.queue.filter(({ cid: cid2 }) => !this.eventsWeHandled.has(cid2));
1842
+ void this.processQueue();
1843
+ }
1844
+ async processQueue() {
1845
+ if (this.isProcessing) return;
1846
+ this.isProcessing = true;
1847
+ const filteredQueue = this.queue.filter(({ cid }) => !this.eventsWeHandled.has(cid));
1848
+ const first = filteredQueue[0];
1849
+ if (!first) {
1850
+ return;
1851
+ }
1852
+ try {
1853
+ this.loader?.remoteMetaStore?.handleByteHeads([first.eventBlock.value.data.dbMeta]);
1854
+ this.eventsWeHandled.add(first.cid);
1855
+ this.queue = this.queue.filter(({ cid }) => !this.eventsWeHandled.has(cid));
1856
+ } catch (err) {
1857
+ if (first.retries++ > 3) {
1858
+ this.logger.Error().Str("cid", first.cid).Msg("failed to process event block after 3 retries");
1859
+ this.queue = this.queue.filter(({ cid }) => cid !== first.cid);
1860
+ }
1861
+ await new Promise((resolve) => setTimeout(resolve, 50));
1862
+ throw this.logger.Error().Err(err).Msg("failed to process event block").AsError();
1863
+ } finally {
1864
+ this.isProcessing = false;
1865
+ if (this.queue.length > 0) {
1866
+ void this.processQueue();
1867
+ }
1868
+ }
1869
+ }
1870
+ };
1871
+
1872
+ // src/blockstore/connection-base.ts
1873
+ init_utils();
1874
+ var ConnectionBase = class {
1875
+ constructor(logger) {
1876
+ // readonly ready: Promise<unknown>;
1877
+ // todo move to LRU blockstore https://github.com/web3-storage/w3clock/blob/main/src/worker/block.js
1878
+ this.eventBlocks = new import_block.MemoryBlockstore();
1879
+ this.parents = [];
1880
+ this.loaded = Promise.resolve();
1881
+ this.logger = ensureLogger(logger, "ConnectionBase");
1882
+ }
1883
+ async refresh() {
1884
+ await throwFalsy(throwFalsy(this.loader).remoteMetaStore).load("main");
1885
+ await (await throwFalsy(this.loader).remoteWAL())._process();
1886
+ }
1887
+ connect({ loader }) {
1888
+ if (!loader) throw this.logger.Error().Msg("loader is required").AsError();
1889
+ this.connectMeta({ loader });
1890
+ this.connectStorage({ loader });
1891
+ }
1892
+ connectMeta({ loader }) {
1893
+ if (!loader) throw this.logger.Error().Msg("loader is required").AsError();
1894
+ this.loader = loader;
1895
+ this.taskManager = new TaskManager(loader);
1896
+ this.onConnect();
1897
+ this.logger.Warn().Msg("connectMeta: connecting to remote meta store is disabled");
1898
+ }
1899
+ async onConnect() {
1900
+ return;
1901
+ }
1902
+ connectStorage({ loader }) {
1903
+ if (!loader) throw this.logger.Error().Msg("loader is required").AsError();
1904
+ this.loader = loader;
1905
+ this.logger.Warn().Msg("connectStorage: connecting to remote meta store is disabled");
1906
+ }
1907
+ async createEventBlock(bytes) {
1908
+ const data = {
1909
+ dbMeta: bytes
1910
+ };
1911
+ const event = await import_clock.EventBlock.create(
1912
+ data,
1913
+ this.parents
1914
+ );
1915
+ await this.eventBlocks.put(event.cid, event.bytes);
1916
+ return event;
1917
+ }
1918
+ async decodeEventBlock(bytes) {
1919
+ const event = await (0, import_clock.decodeEventBlock)(bytes);
1920
+ return event;
1921
+ }
1922
+ // move this stuff to connect
1923
+ // async getDashboardURL(compact = true) {
1924
+ // const baseUrl = 'https://dashboard.fireproof.storage/'
1925
+ // if (!this.loader?.remoteCarStore) return new URL('/howto', baseUrl)
1926
+ // // if (compact) {
1927
+ // // await this.compact()
1928
+ // // }
1929
+ // const currents = await this.loader?.metaStore?.load()
1930
+ // if (!currents) throw new Error("Can't sync empty database: save data first")
1931
+ // if (currents.length > 1)
1932
+ // throw new Error("Can't sync database with split heads: make an update first")
1933
+ // const current = currents[0]
1934
+ // const params = {
1935
+ // car: current.car.toString()
1936
+ // }
1937
+ // if (current.key) {
1938
+ // // @ts-ignore
1939
+ // params.key = current.key.toString()
1940
+ // }
1941
+ // // @ts-ignore
1942
+ // if (this.name) {
1943
+ // // @ts-ignore
1944
+ // params.name = this.name
1945
+ // }
1946
+ // const url = new URL('/import#' + new URLSearchParams(params).toString(), baseUrl)
1947
+ // console.log('Import to dashboard: ' + url.toString())
1948
+ // return url
1949
+ // }
1950
+ // openDashboard() {
1951
+ // void this.getDashboardURL().then(url => {
1952
+ // if (url) window.open(url.toString(), '_blank')
1953
+ // })
1954
+ // }
1955
+ };
1956
+
1957
+ // src/blockstore/connect-rest.ts
1958
+ init_utils();
1959
+ var ConnectREST = class extends ConnectionBase {
1960
+ constructor(base, logger) {
1961
+ super(ensureLogger(logger, "ConnectREST"));
1962
+ this.baseUrl = new URL(base);
1963
+ }
1964
+ async dataUpload(bytes, params) {
1965
+ const carCid = params.car.toString();
1966
+ const uploadURL = new URL(`/cars/${carCid}.car`, this.baseUrl);
1967
+ const done = await fetch(uploadURL, { method: "PUT", body: bytes });
1968
+ if (!done.ok) {
1969
+ throw this.logger.Error().Msg("failed to upload data " + done.statusText);
1970
+ }
1971
+ }
1972
+ async dataDownload(params) {
1973
+ const { car } = params;
1974
+ const fetchFromUrl = new URL(`/cars/${car.toString()}.car`, this.baseUrl);
1975
+ const response = await fetch(fetchFromUrl);
1976
+ if (!response.ok) {
1977
+ return void 0;
1978
+ }
1979
+ const bytes = new Uint8Array(await response.arrayBuffer());
1980
+ return bytes;
1981
+ }
1982
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1983
+ async metaUpload(bytes, params) {
1984
+ return void 0;
1985
+ }
1986
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1987
+ async metaDownload(params) {
1988
+ return [];
1989
+ }
1990
+ };
1991
+
1992
+ // src/blockstore/store-factory.ts
1993
+ var import_cement14 = require("@adviser/cement");
1994
+ init_data_dir();
1995
+
1996
+ // src/runtime/files.ts
1997
+ var UnixFS = __toESM(require("@ipld/unixfs"), 1);
1998
+ var raw = __toESM(require("multiformats/codecs/raw"), 1);
1999
+ var import_fixed = require("@ipld/unixfs/file/chunker/fixed");
2000
+ var import_balanced = require("@ipld/unixfs/file/layout/balanced");
2001
+ var import_ipfs_unixfs_exporter = require("ipfs-unixfs-exporter");
2002
+ var queuingStrategy = UnixFS.withCapacity();
2003
+ var settings = UnixFS.configure({
2004
+ fileChunkEncoder: raw,
2005
+ smallFileEncoder: raw,
2006
+ chunker: (0, import_fixed.withMaxChunkSize)(1024 * 1024),
2007
+ fileLayout: (0, import_balanced.withWidth)(1024)
2008
+ });
2009
+ async function collect(collectable) {
2010
+ const chunks = [];
2011
+ await collectable.pipeTo(
2012
+ new WritableStream({
2013
+ write(chunk) {
2014
+ chunks.push(chunk);
2015
+ }
2016
+ })
2017
+ );
2018
+ return chunks;
2019
+ }
2020
+ async function encodeFile(blob) {
2021
+ const readable = createFileEncoderStream(blob);
2022
+ const blocks = await collect(readable);
2023
+ return { cid: blocks.at(-1).cid, blocks };
2024
+ }
2025
+ async function decodeFile(blocks, cid, meta) {
2026
+ const entry = await (0, import_ipfs_unixfs_exporter.exporter)(cid.toString(), blocks, { length: meta.size });
2027
+ const chunks = [];
2028
+ for await (const chunk of entry.content()) {
2029
+ chunks.push(chunk);
2030
+ }
2031
+ return new File(chunks, entry.name, { type: meta.type, lastModified: 0 });
2032
+ }
2033
+ function createFileEncoderStream(blob) {
2034
+ const { readable, writable } = new TransformStream({}, queuingStrategy);
2035
+ const unixfsWriter = UnixFS.createWriter({ writable, settings });
2036
+ const fileBuilder = new UnixFSFileBuilder("", blob);
2037
+ void (async () => {
2038
+ await fileBuilder.finalize(unixfsWriter);
2039
+ await unixfsWriter.close();
2040
+ })();
2041
+ return readable;
2042
+ }
2043
+ var UnixFSFileBuilder = class {
2044
+ #file;
2045
+ constructor(name, file) {
2046
+ this.name = name;
2047
+ this.#file = file;
2048
+ }
2049
+ async finalize(writer) {
2050
+ const unixfsFileWriter = UnixFS.createFileWriter(writer);
2051
+ await this.#file.stream().pipeTo(
2052
+ new WritableStream({
2053
+ async write(chunk) {
2054
+ await unixfsFileWriter.write(chunk);
2055
+ }
2056
+ })
2057
+ );
2058
+ return await unixfsFileWriter.close();
2059
+ }
2060
+ };
2061
+
2062
+ // src/blockstore/store.ts
2063
+ var import_p_limit2 = __toESM(require("p-limit"), 1);
2064
+ var import_dag_json = require("@ipld/dag-json");
2065
+ var import_cement6 = require("@adviser/cement");
2066
+ init_types();
2067
+ init_gateway();
2068
+ init_utils();
2069
+ init_store_indexdb();
2070
+
2071
+ // src/blockstore/loader.ts
2072
+ var import_p_limit = __toESM(require("p-limit"), 1);
2073
+ var import_car = require("@ipld/car");
2074
+ var import_cement5 = require("@adviser/cement");
2075
+
2076
+ // src/blockstore/types.ts
2077
+ function toCIDBlock(block) {
2078
+ return block;
2079
+ }
2080
+
2081
+ // src/blockstore/loader-helpers.ts
2082
+ var import_block2 = require("multiformats/block");
2083
+ var import_sha2 = require("multiformats/hashes/sha2");
2084
+ var raw2 = __toESM(require("multiformats/codecs/raw"), 1);
2085
+ var CBW = __toESM(require("@ipld/car/buffer-writer"), 1);
2086
+ var codec = __toESM(require("@ipld/dag-cbor"), 1);
2087
+ async function encodeCarFile(roots, t) {
2088
+ let size = 0;
2089
+ const headerSize = CBW.headerLength({ roots });
2090
+ size += headerSize;
2091
+ for (const { cid, bytes } of t.entries()) {
2092
+ size += CBW.blockLength({ cid, bytes });
2093
+ }
2094
+ const buffer = new Uint8Array(size);
2095
+ const writer = CBW.createWriter(buffer, { headerSize });
2096
+ for (const r of roots) {
2097
+ writer.addRoot(r);
2098
+ }
2099
+ for (const { cid, bytes } of t.entries()) {
2100
+ writer.write({ cid, bytes });
2101
+ }
2102
+ writer.close();
2103
+ return await (0, import_block2.encode)({ value: writer.bytes, hasher: import_sha2.sha256, codec: raw2 });
2104
+ }
2105
+ async function encodeCarHeader(fp) {
2106
+ return await (0, import_block2.encode)({
2107
+ value: { fp },
2108
+ hasher: import_sha2.sha256,
2109
+ codec
2110
+ });
2111
+ }
2112
+ async function parseCarFile(reader, logger) {
2113
+ const roots = await reader.getRoots();
2114
+ const header = await reader.get(roots[0]);
2115
+ if (!header) throw logger.Error().Msg("missing header block").AsError();
2116
+ const { value } = await (0, import_block2.decode)({ bytes: header.bytes, hasher: import_sha2.sha256, codec });
2117
+ const fpvalue = value;
2118
+ if (fpvalue && !fpvalue.fp) {
2119
+ throw logger.Error().Msg("missing fp").AsError();
2120
+ }
2121
+ return fpvalue.fp;
2122
+ }
2123
+
2124
+ // src/blockstore/encrypt-helpers.ts
2125
+ var import_sha22 = require("multiformats/hashes/sha2");
2126
+ var import_multiformats2 = require("multiformats");
2127
+ var import_block3 = require("multiformats/block");
2128
+ var dagcbor = __toESM(require("@ipld/dag-cbor"), 1);
2129
+ var import_block4 = require("@web3-storage/pail/block");
2130
+ var import_utils7 = require("prolly-trees/utils");
2131
+ var import_cache = require("prolly-trees/cache");
2132
+ var import_cid_set = require("prolly-trees/cid-set");
2133
+
2134
+ // src/blockstore/encrypt-codec.ts
2135
+ var import_multiformats = require("multiformats");
2136
+ init_utils();
2137
+ function makeCodec(ilogger, crypto2, randomBytes2) {
2138
+ const logger = ensureLogger(ilogger, "makeCodec");
2139
+ const enc32 = (value) => {
2140
+ value = +value;
2141
+ const buff = new Uint8Array(4);
2142
+ buff[3] = value >>> 24;
2143
+ buff[2] = value >>> 16;
2144
+ buff[1] = value >>> 8;
2145
+ buff[0] = value & 255;
2146
+ return buff;
2147
+ };
2148
+ const readUInt32LE = (buffer) => {
2149
+ const offset = buffer.byteLength - 4;
2150
+ return (buffer[offset] | buffer[offset + 1] << 8 | buffer[offset + 2] << 16) + buffer[offset + 3] * 16777216;
2151
+ };
2152
+ const concat = (buffers) => {
2153
+ const uint8Arrays = buffers.map((b) => b instanceof ArrayBuffer ? new Uint8Array(b) : b);
2154
+ const totalLength = uint8Arrays.reduce((sum, arr) => sum + arr.length, 0);
2155
+ const result = new Uint8Array(totalLength);
2156
+ let offset = 0;
2157
+ for (const arr of uint8Arrays) {
2158
+ result.set(arr, offset);
2159
+ offset += arr.length;
2160
+ }
2161
+ return result;
2162
+ };
2163
+ const encode4 = ({ iv, bytes }) => concat([iv, bytes]);
2164
+ const decode4 = (bytes) => {
2165
+ const iv = bytes.subarray(0, 12);
2166
+ bytes = bytes.slice(12);
2167
+ return { iv, bytes };
2168
+ };
2169
+ const code = 3145728 + 1337;
2170
+ async function subtleKey(key) {
2171
+ return await crypto2.importKey(
2172
+ "raw",
2173
+ // raw or jwk
2174
+ key,
2175
+ // raw data
2176
+ "AES-GCM",
2177
+ false,
2178
+ // extractable
2179
+ ["encrypt", "decrypt"]
2180
+ );
2181
+ }
2182
+ const decrypt = async ({ key, value }) => {
2183
+ const { bytes: inBytes, iv } = value;
2184
+ const cryKey = await subtleKey(key);
2185
+ const deBytes = await crypto2.decrypt(
2186
+ {
2187
+ name: "AES-GCM",
2188
+ iv,
2189
+ tagLength: 128
2190
+ },
2191
+ cryKey,
2192
+ inBytes
2193
+ );
2194
+ const bytes = new Uint8Array(deBytes);
2195
+ const len = readUInt32LE(bytes.subarray(0, 4));
2196
+ const cid = import_multiformats.CID.decode(bytes.subarray(4, 4 + len));
2197
+ return { cid, bytes: bytes.subarray(4 + len) };
2198
+ };
2199
+ const encrypt = async ({ key, cid, bytes }) => {
2200
+ const len = enc32(cid.bytes.byteLength);
2201
+ const iv = randomBytes2(12);
2202
+ const msg = concat([len, cid.bytes, bytes]);
2203
+ try {
2204
+ const cryKey = await subtleKey(key);
2205
+ const deBytes = await crypto2.encrypt(
2206
+ {
2207
+ name: "AES-GCM",
2208
+ iv,
2209
+ tagLength: 128
2210
+ },
2211
+ cryKey,
2212
+ msg
2213
+ );
2214
+ bytes = new Uint8Array(deBytes);
2215
+ } catch (e) {
2216
+ throw logger.Error().Err(e).Msg("encrypt failed").AsError();
2217
+ }
2218
+ return { value: { bytes, iv } };
2219
+ };
2220
+ const cryptoFn = (key) => {
2221
+ return { encrypt: (opts) => encrypt({ ...opts, key }), decrypt: (opts) => decrypt({ ...opts, key }) };
2222
+ };
2223
+ const name = "jchris@encrypted-block:aes-gcm";
2224
+ return { encode: encode4, decode: decode4, code, name, encrypt, decrypt, crypto: cryptoFn };
2225
+ }
2226
+
2227
+ // src/blockstore/encrypt-helpers.ts
2228
+ function carLogIncludesGroup(list, cidMatch) {
2229
+ return list.some((cid) => {
2230
+ return cid.toString() === cidMatch.toString();
2231
+ });
2232
+ }
2233
+ function makeEncDec(logger, crypto2, randomBytes2) {
2234
+ const codec4 = makeCodec(logger, crypto2, randomBytes2);
2235
+ const encrypt = async function* ({
2236
+ get: get2,
2237
+ cids,
2238
+ hasher: hasher4,
2239
+ key,
2240
+ cache: cache3,
2241
+ chunker: chunker2,
2242
+ root: root3
2243
+ }) {
2244
+ const set = /* @__PURE__ */ new Set();
2245
+ let eroot;
2246
+ if (!carLogIncludesGroup(cids, root3)) cids.push(root3);
2247
+ for (const cid of cids) {
2248
+ const unencrypted = await get2(cid);
2249
+ if (!unencrypted) throw logger.Error().Ref("cid", cid).Msg("missing cid block").AsError();
2250
+ const encrypted = await codec4.encrypt({ ...unencrypted, key });
2251
+ const block2 = await (0, import_block3.encode)({ ...encrypted, codec: codec4, hasher: hasher4 });
2252
+ yield block2;
2253
+ set.add(block2.cid.toString());
2254
+ if (unencrypted.cid.equals(root3)) eroot = block2.cid;
2255
+ }
2256
+ if (!eroot) throw logger.Error().Msg("cids does not include root").AsError();
2257
+ const list = [...set].map((s) => import_multiformats2.CID.parse(s));
2258
+ let last;
2259
+ for await (const node of (0, import_cid_set.create)({ list, get: get2, cache: cache3, chunker: chunker2, hasher: hasher4, codec: dagcbor })) {
2260
+ const block2 = await node.block;
2261
+ yield block2;
2262
+ last = block2;
2263
+ }
2264
+ if (!last) throw logger.Error().Msg("missing last block").AsError();
2265
+ const head = [eroot, last.cid];
2266
+ const block = await (0, import_block3.encode)({ value: head, codec: dagcbor, hasher: hasher4 });
2267
+ yield block;
2268
+ };
2269
+ const decrypt = async function* ({
2270
+ root: root3,
2271
+ get: get2,
2272
+ key,
2273
+ cache: cache3,
2274
+ chunker: chunker2,
2275
+ hasher: hasher4
2276
+ }) {
2277
+ const getWithDecode = async (cid) => get2(cid).then(async (block) => {
2278
+ if (!block) return;
2279
+ const decoded = await (0, import_block3.decode)({ ...block, codec: dagcbor, hasher: hasher4 });
2280
+ return decoded;
2281
+ });
2282
+ const getWithDecrypt = async (cid) => get2(cid).then(async (block) => {
2283
+ if (!block) return;
2284
+ const decoded = await (0, import_block3.decode)({ ...block, codec: codec4, hasher: hasher4 });
2285
+ return decoded;
2286
+ });
2287
+ const decodedRoot = await getWithDecode(root3);
2288
+ if (!decodedRoot) throw logger.Error().Msg("missing root").AsError();
2289
+ if (!decodedRoot.bytes) throw logger.Error().Msg("missing bytes").AsError();
2290
+ const {
2291
+ value: [eroot, tree]
2292
+ } = decodedRoot;
2293
+ const rootBlock = await get2(eroot);
2294
+ if (!rootBlock) throw logger.Error().Msg("missing root block").AsError();
2295
+ const cidset = await (0, import_cid_set.load)({ cid: tree, get: getWithDecode, cache: cache3, chunker: chunker2, codec: codec4, hasher: hasher4 });
2296
+ const { result: nodes } = await cidset.getAllEntries();
2297
+ const unwrap = async (eblock) => {
2298
+ if (!eblock) throw logger.Error().Msg("missing block").AsError();
2299
+ if (!eblock.value) {
2300
+ eblock = await (0, import_block3.decode)({ ...eblock, codec: codec4, hasher: hasher4 });
2301
+ if (!eblock.value) throw logger.Error().Msg("missing value").AsError();
2302
+ }
2303
+ const { bytes, cid } = await codec4.decrypt({ ...eblock, key }).catch((e) => {
2304
+ throw e;
2305
+ });
2306
+ const block = await (0, import_block3.create)({ cid, bytes, hasher: hasher4, codec: codec4 });
2307
+ return block;
2308
+ };
2309
+ const promises = [];
2310
+ for (const { cid } of nodes) {
2311
+ if (!rootBlock.cid.equals(cid)) promises.push(getWithDecrypt(cid).then(unwrap));
2312
+ }
2313
+ yield* promises;
2314
+ yield unwrap(rootBlock);
2315
+ };
2316
+ return { encrypt, decrypt };
2317
+ }
2318
+ var chunker = (0, import_utils7.bf)(30);
2319
+ function hexStringToUint8Array(hexString) {
2320
+ const length = hexString.length;
2321
+ const uint8Array = new Uint8Array(length / 2);
2322
+ for (let i = 0; i < length; i += 2) {
2323
+ uint8Array[i / 2] = parseInt(hexString.substring(i, i + 2), 16);
2324
+ }
2325
+ return uint8Array;
2326
+ }
2327
+ async function encryptedEncodeCarFile(logger, crypto2, key, rootCid, t) {
2328
+ const encryptionKey = hexStringToUint8Array(key);
2329
+ const encryptedBlocks = new import_block4.MemoryBlockstore();
2330
+ const cidsToEncrypt = [];
2331
+ for (const { cid, bytes } of t.entries()) {
2332
+ cidsToEncrypt.push(cid);
2333
+ const g = await t.get(cid);
2334
+ if (!g) throw logger.Error().Ref("cid", cid).Int("bytes", bytes.length).Msg("missing cid block").AsError();
2335
+ }
2336
+ let last = null;
2337
+ const { encrypt } = makeEncDec(logger, crypto2, crypto2.randomBytes);
2338
+ for await (const block of encrypt({
2339
+ cids: cidsToEncrypt,
2340
+ get: t.get.bind(t),
2341
+ key: encryptionKey,
2342
+ hasher: import_sha22.sha256,
2343
+ chunker,
2344
+ cache: import_cache.nocache,
2345
+ root: rootCid
2346
+ })) {
2347
+ await encryptedBlocks.put(block.cid, block.bytes);
2348
+ last = block;
2349
+ }
2350
+ if (!last) throw logger.Error().Msg("no blocks encrypted").AsError();
2351
+ const encryptedCar = await encodeCarFile([last.cid], encryptedBlocks);
2352
+ return encryptedCar;
2353
+ }
2354
+ async function decodeEncryptedCar(logger, crypto2, key, reader) {
2355
+ const roots = await reader.getRoots();
2356
+ const root3 = roots[0];
2357
+ return await decodeCarBlocks(logger, crypto2, root3, reader.get.bind(reader), key);
2358
+ }
2359
+ async function decodeCarBlocks(logger, crypto2, root3, get2, keyMaterial) {
2360
+ const decryptionKeyUint8 = hexStringToUint8Array(keyMaterial);
2361
+ const decryptionKey = decryptionKeyUint8.buffer.slice(0, decryptionKeyUint8.byteLength);
2362
+ const decryptedBlocks = new import_block4.MemoryBlockstore();
2363
+ let last = null;
2364
+ const { decrypt } = makeEncDec(logger, crypto2, crypto2.randomBytes);
2365
+ for await (const block of decrypt({
2366
+ root: root3,
2367
+ get: get2,
2368
+ key: decryptionKey,
2369
+ hasher: import_sha22.sha256,
2370
+ chunker,
2371
+ cache: import_cache.nocache
2372
+ })) {
2373
+ await decryptedBlocks.put(block.cid, block.bytes);
2374
+ last = block;
2375
+ }
2376
+ if (!last) throw logger.Error().Msg("no blocks decrypted").AsError();
2377
+ return { blocks: decryptedBlocks, root: last.cid };
2378
+ }
2379
+
2380
+ // src/blockstore/transaction.ts
2381
+ var import_block5 = require("@web3-storage/pail/block");
2382
+ init_types();
2383
+
2384
+ // src/runtime/crypto.ts
2385
+ function randomBytes(size) {
2386
+ const bytes = new Uint8Array(size);
2387
+ if (size > 0) {
2388
+ crypto.getRandomValues(bytes);
2389
+ }
2390
+ return bytes;
2391
+ }
2392
+ function digestSHA256(data) {
2393
+ return Promise.resolve(crypto.subtle.digest("SHA-256", data));
2394
+ }
2395
+ function toCryptoOpts(cryptoOpts = {}) {
2396
+ const opts = {
2397
+ importKey: cryptoOpts.importKey || crypto.subtle.importKey.bind(crypto.subtle),
2398
+ encrypt: cryptoOpts.encrypt || crypto.subtle.encrypt.bind(crypto.subtle),
2399
+ decrypt: cryptoOpts.decrypt || crypto.subtle.decrypt.bind(crypto.subtle),
2400
+ randomBytes: cryptoOpts.randomBytes || randomBytes,
2401
+ digestSHA256: cryptoOpts.digestSHA256 || digestSHA256
2402
+ };
2403
+ return opts;
2404
+ }
2405
+
2406
+ // src/blockstore/transaction.ts
2407
+ init_utils();
2408
+ var CarTransaction = class extends import_block5.MemoryBlockstore {
2409
+ constructor(parent, opts = { add: true }) {
2410
+ super();
2411
+ if (opts.add) {
2412
+ parent.transactions.add(this);
2413
+ }
2414
+ this.parent = parent;
2415
+ }
2416
+ async get(cid) {
2417
+ return await this.superGet(cid) || falsyToUndef(await this.parent.get(cid));
2418
+ }
2419
+ async superGet(cid) {
2420
+ return super.get(cid);
2421
+ }
2422
+ };
2423
+ function defaultedBlockstoreRuntime(opts, component, ctx) {
2424
+ const logger = ensureLogger(opts, component, ctx);
2425
+ const store = opts.store || {};
2426
+ return {
2427
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2428
+ applyMeta: (meta, snap) => {
2429
+ return Promise.resolve();
2430
+ },
2431
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2432
+ compact: async (blocks) => {
2433
+ return {};
2434
+ },
2435
+ autoCompact: 100,
2436
+ public: false,
2437
+ name: void 0,
2438
+ threshold: 1e3 * 1e3,
2439
+ ...opts,
2440
+ logger,
2441
+ crypto: toCryptoOpts(opts.crypto),
2442
+ store,
2443
+ storeRuntime: toStoreRuntime(store, logger)
2444
+ };
2445
+ }
2446
+ var blockstoreFactory = function(opts) {
2447
+ if (opts.name) {
2448
+ return new EncryptedBlockstore(opts);
2449
+ } else {
2450
+ return new BaseBlockstore(opts);
2451
+ }
2452
+ };
2453
+ var BaseBlockstore = class {
2454
+ constructor(ebOpts = {}) {
2455
+ this.transactions = /* @__PURE__ */ new Set();
2456
+ this.ebOpts = defaultedBlockstoreRuntime(ebOpts, "BaseBlockstore");
2457
+ this.logger = this.ebOpts.logger;
2458
+ }
2459
+ // ready: Promise<void>;
2460
+ ready() {
2461
+ return Promise.resolve();
2462
+ }
2463
+ async close() {
2464
+ }
2465
+ async destroy() {
2466
+ }
2467
+ async get(cid) {
2468
+ if (!cid) throw this.logger.Error().Msg("required cid").AsError();
2469
+ for (const f of this.transactions) {
2470
+ const v = await f.superGet(cid);
2471
+ if (v) return v;
2472
+ }
2473
+ }
2474
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2475
+ async put(cid, block) {
2476
+ throw this.logger.Error().Msg("use a transaction to put").AsError();
2477
+ }
2478
+ // TransactionMeta
2479
+ async transaction(fn, _opts = {}) {
2480
+ const t = new CarTransaction(this);
2481
+ const done = await fn(t);
2482
+ this.lastTxMeta = done;
2483
+ return { t, meta: done };
2484
+ }
2485
+ async *entries() {
2486
+ const seen = /* @__PURE__ */ new Set();
2487
+ for (const t of this.transactions) {
2488
+ for await (const blk of t.entries()) {
2489
+ if (seen.has(blk.cid.toString())) continue;
2490
+ seen.add(blk.cid.toString());
2491
+ yield blk;
2492
+ }
2493
+ }
2494
+ }
2495
+ };
2496
+ var EncryptedBlockstore = class extends BaseBlockstore {
2497
+ constructor(ebOpts) {
2498
+ super(ebOpts);
2499
+ this.compacting = false;
2500
+ this.logger = ensureLogger(ebOpts, "EncryptedBlockstore");
2501
+ const { name } = ebOpts;
2502
+ if (!name) {
2503
+ throw this.logger.Error().Msg("name required").AsError();
2504
+ }
2505
+ this.name = name;
2506
+ this.loader = new Loader(this.name, ebOpts);
2507
+ }
2508
+ ready() {
2509
+ return this.loader.ready();
2510
+ }
2511
+ close() {
2512
+ return this.loader.close();
2513
+ }
2514
+ destroy() {
2515
+ return this.loader.destroy();
2516
+ }
2517
+ async get(cid) {
2518
+ const got = await super.get(cid);
2519
+ if (got) return got;
2520
+ if (!this.loader) {
2521
+ return;
2522
+ }
2523
+ return falsyToUndef(await this.loader.getBlock(cid));
2524
+ }
2525
+ async transaction(fn, opts = { noLoader: false }) {
2526
+ const { t, meta: done } = await super.transaction(fn);
2527
+ const cars = await this.loader.commit(t, done, opts);
2528
+ if (this.ebOpts.autoCompact && this.loader.carLog.length > this.ebOpts.autoCompact) {
2529
+ setTimeout(() => void this.compact(), 10);
2530
+ }
2531
+ if (cars) {
2532
+ this.transactions.delete(t);
2533
+ return { meta: done, cars, t };
2534
+ }
2535
+ throw this.logger.Error().Msg("failed to commit car files").AsError();
2536
+ }
2537
+ async getFile(car, cid, isPublic = false) {
2538
+ await this.ready();
2539
+ if (!this.loader) throw this.logger.Error().Msg("loader required to get file, database must be named").AsError();
2540
+ const reader = await this.loader.loadFileCar(car, isPublic);
2541
+ const block = await reader.get(cid);
2542
+ if (!block) throw this.logger.Error().Str("cid", cid.toString()).Msg(`Missing block`).AsError();
2543
+ return block.bytes;
2544
+ }
2545
+ async compact() {
2546
+ await this.ready();
2547
+ if (!this.loader) throw this.logger.Error().Msg("loader required to compact").AsError();
2548
+ if (this.loader.carLog.length < 2) return;
2549
+ const compactFn = this.ebOpts.compact || ((blocks) => this.defaultCompact(blocks, this.logger));
2550
+ if (!compactFn || this.compacting) return;
2551
+ const blockLog = new CompactionFetcher(this);
2552
+ this.compacting = true;
2553
+ const meta = await compactFn(blockLog);
2554
+ await this.loader?.commit(blockLog.loggedBlocks, meta, {
2555
+ compact: true,
2556
+ noLoader: true
2557
+ });
2558
+ this.compacting = false;
2559
+ }
2560
+ async defaultCompact(blocks, logger) {
2561
+ if (!this.loader) {
2562
+ throw logger.Error().Msg("no loader").AsError();
2563
+ }
2564
+ if (!this.lastTxMeta) {
2565
+ throw logger.Error().Msg("no lastTxMeta").AsError();
2566
+ }
2567
+ for await (const blk of this.loader.entries(false)) {
2568
+ blocks.loggedBlocks.putSync(blk.cid, blk.bytes);
2569
+ }
2570
+ for (const t of this.transactions) {
2571
+ for await (const blk of t.entries()) {
2572
+ blocks.loggedBlocks.putSync(blk.cid, blk.bytes);
2573
+ }
2574
+ }
2575
+ return this.lastTxMeta;
2576
+ }
2577
+ async *entries() {
2578
+ for await (const blk of this.loader.entries()) {
2579
+ yield blk;
2580
+ }
2581
+ }
2582
+ };
2583
+ var CompactionFetcher = class {
2584
+ constructor(blocks) {
2585
+ this.blockstore = blocks;
2586
+ this.loggedBlocks = new CarTransaction(blocks);
2587
+ }
2588
+ async get(cid) {
2589
+ const block = await this.blockstore.get(cid);
2590
+ if (block) this.loggedBlocks.putSync(cid, block.bytes);
2591
+ return falsyToUndef(block);
2592
+ }
2593
+ };
2594
+
2595
+ // src/blockstore/commit-queue.ts
2596
+ var CommitQueue = class {
2597
+ constructor() {
2598
+ this.queue = [];
2599
+ this.processing = false;
2600
+ }
2601
+ async enqueue(fn) {
2602
+ return new Promise((resolve, reject) => {
2603
+ const queueFn = async () => {
2604
+ try {
2605
+ resolve(await fn());
2606
+ } catch (e) {
2607
+ reject(e);
2608
+ } finally {
2609
+ this.processing = false;
2610
+ this.processNext();
2611
+ }
2612
+ };
2613
+ this.queue.push(queueFn);
2614
+ if (!this.processing) {
2615
+ this.processNext();
2616
+ }
2617
+ });
2618
+ }
2619
+ processNext() {
2620
+ if (this.queue.length > 0 && !this.processing) {
2621
+ this.processing = true;
2622
+ const queueFn = this.queue.shift();
2623
+ if (queueFn) {
2624
+ queueFn();
2625
+ }
2626
+ }
2627
+ }
2628
+ };
2629
+
2630
+ // src/blockstore/loader.ts
2631
+ var CBW2 = __toESM(require("@ipld/car/buffer-writer"), 1);
2632
+ function carLogIncludesGroup2(list, cids) {
2633
+ return list.some((arr) => {
2634
+ return arr.toString() === cids.toString();
2635
+ });
2636
+ }
2637
+ function uniqueCids(list, remove = /* @__PURE__ */ new Set()) {
2638
+ const byString = /* @__PURE__ */ new Map();
2639
+ for (const cid of list) {
2640
+ if (remove.has(cid.toString())) continue;
2641
+ byString.set(cid.toString(), cid);
2642
+ }
2643
+ return [...byString.values()];
2644
+ }
2645
+ function toHexString(byteArray) {
2646
+ return Array.from(byteArray).map((byte) => byte.toString(16).padStart(2, "0")).join("");
2647
+ }
2648
+ var Loadable = class {
2649
+ constructor() {
2650
+ this.name = "";
2651
+ this.carLog = new Array();
2652
+ }
2653
+ };
2654
+ var Loader = class {
2655
+ constructor(name, ebOpts) {
2656
+ this.commitQueue = new CommitQueue();
2657
+ this.isCompacting = false;
2658
+ this.carReaders = /* @__PURE__ */ new Map();
2659
+ this.seenCompacted = /* @__PURE__ */ new Set();
2660
+ this.processedCars = /* @__PURE__ */ new Set();
2661
+ this.carLog = [];
2662
+ this.getBlockCache = /* @__PURE__ */ new Map();
2663
+ this.seenMeta = /* @__PURE__ */ new Set();
2664
+ this.writeLimit = (0, import_p_limit.default)(1);
2665
+ this.onceReady = new import_cement5.ResolveOnce();
2666
+ this.name = name;
2667
+ this.ebOpts = defaultedBlockstoreRuntime(
2668
+ {
2669
+ ...ebOpts,
2670
+ name
2671
+ },
2672
+ "Loader"
2673
+ );
2674
+ this.logger = this.ebOpts.logger;
2675
+ }
2676
+ // readonly id = uuidv4();
2677
+ async carStore() {
2678
+ return this.ebOpts.storeRuntime.makeDataStore(this);
2679
+ }
2680
+ async fileStore() {
2681
+ return this.ebOpts.storeRuntime.makeDataStore(this);
2682
+ }
2683
+ async remoteWAL() {
2684
+ return this.ebOpts.storeRuntime.makeRemoteWAL(this);
2685
+ }
2686
+ async metaStore() {
2687
+ return this.ebOpts.storeRuntime.makeMetaStore(this);
2688
+ }
2689
+ async ready() {
2690
+ return this.onceReady.once(async () => {
2691
+ const metas = this.ebOpts.meta ? [this.ebOpts.meta] : await (await this.metaStore()).load("main");
2692
+ if (metas) {
2693
+ await this.handleDbMetasFromStore(metas);
2694
+ }
2695
+ });
2696
+ }
2697
+ async close() {
2698
+ const toClose = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.remoteWAL()]);
2699
+ await Promise.all(toClose.map((store) => store.close()));
2700
+ }
2701
+ async destroy() {
2702
+ const toDestroy = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.remoteWAL()]);
2703
+ await Promise.all(toDestroy.map((store) => store.destroy()));
2704
+ }
2705
+ // async snapToCar(carCid: AnyLink | string) {
2706
+ // await this.ready
2707
+ // if (typeof carCid === 'string') {
2708
+ // carCid = CID.parse(carCid)
2709
+ // }
2710
+ // const carHeader = await this.loadCarHeaderFromMeta({ car: carCid, key: this.key || null })
2711
+ // this.carLog = [carCid, ...carHeader.cars]
2712
+ // await this.getMoreReaders(carHeader.cars)
2713
+ // await this._applyCarHeader(carHeader, true)
2714
+ // }
2715
+ async handleDbMetasFromStore(metas) {
2716
+ for (const meta of metas) {
2717
+ await this.writeLimit(async () => {
2718
+ await this.mergeDbMetaIntoClock(meta);
2719
+ });
2720
+ }
2721
+ }
2722
+ async mergeDbMetaIntoClock(meta) {
2723
+ if (this.isCompacting) {
2724
+ throw this.logger.Error().Msg("cannot merge while compacting").AsError();
2725
+ }
2726
+ if (this.seenMeta.has(meta.cars.toString())) return;
2727
+ this.seenMeta.add(meta.cars.toString());
2728
+ if (meta.key) {
2729
+ await this.setKey(meta.key);
2730
+ }
2731
+ if (carLogIncludesGroup2(this.carLog, meta.cars)) {
2732
+ return;
2733
+ }
2734
+ const carHeader = await this.loadCarHeaderFromMeta(meta);
2735
+ carHeader.compact.map((c) => c.toString()).forEach(this.seenCompacted.add, this.seenCompacted);
2736
+ await this.getMoreReaders(carHeader.cars.flat());
2737
+ this.carLog = [...uniqueCids([meta.cars, ...this.carLog, ...carHeader.cars], this.seenCompacted)];
2738
+ await this.ebOpts.applyMeta?.(carHeader.meta);
2739
+ }
2740
+ async ingestKeyFromMeta(meta) {
2741
+ const { key } = meta;
2742
+ if (key) {
2743
+ await this.setKey(key);
2744
+ }
2745
+ }
2746
+ async loadCarHeaderFromMeta({ cars: cids }) {
2747
+ const reader = await this.loadCar(cids[0]);
2748
+ return await parseCarFile(reader, this.logger);
2749
+ }
2750
+ async _getKey() {
2751
+ if (this.key) return this.key;
2752
+ if (!this.ebOpts.public) {
2753
+ await this.setKey(toHexString(this.ebOpts.crypto.randomBytes(32)));
2754
+ }
2755
+ return this.key || void 0;
2756
+ }
2757
+ async commitFiles(t, done, opts = { noLoader: false, compact: false }) {
2758
+ return this.commitQueue.enqueue(() => this._commitInternalFiles(t, done, opts));
2759
+ }
2760
+ // can these skip the queue? or have a file queue?
2761
+ async _commitInternalFiles(t, done, opts = { noLoader: false, compact: false }) {
2762
+ await this.ready();
2763
+ const { files: roots } = this.makeFileCarHeader(done);
2764
+ const cids = [];
2765
+ const cars = await this.prepareCarFilesFiles(roots, t, !!opts.public);
2766
+ for (const car of cars) {
2767
+ const { cid, bytes } = car;
2768
+ await (await this.fileStore()).save({ cid, bytes });
2769
+ await (await this.remoteWAL()).enqueueFile(cid, !!opts.public);
2770
+ cids.push(cid);
2771
+ }
2772
+ return cids;
2773
+ }
2774
+ async loadFileCar(cid, isPublic = false) {
2775
+ return await this.storesLoadCar(cid, await this.fileStore(), this.remoteFileStore, isPublic);
2776
+ }
2777
+ async commit(t, done, opts = { noLoader: false, compact: false }) {
2778
+ return this.commitQueue.enqueue(() => this._commitInternal(t, done, opts));
2779
+ }
2780
+ async cacheTransaction(t) {
2781
+ for await (const block of t.entries()) {
2782
+ const sBlock = block.cid.toString();
2783
+ if (!this.getBlockCache.has(sBlock)) {
2784
+ this.getBlockCache.set(sBlock, block);
2785
+ }
2786
+ }
2787
+ }
2788
+ async cacheCarReader(carCidStr, reader) {
2789
+ if (this.processedCars.has(carCidStr)) return;
2790
+ this.processedCars.add(carCidStr);
2791
+ for await (const block of reader.blocks()) {
2792
+ const sBlock = block.cid.toString();
2793
+ if (!this.getBlockCache.has(sBlock)) {
2794
+ this.getBlockCache.set(sBlock, block);
2795
+ }
2796
+ }
2797
+ }
2798
+ async _commitInternal(t, done, opts = { noLoader: false, compact: false }) {
2799
+ await this.ready();
2800
+ const fp = this.makeCarHeader(done, this.carLog, !!opts.compact);
2801
+ const rootBlock = await encodeCarHeader(fp);
2802
+ const cars = await this.prepareCarFiles(rootBlock, t, !!opts.public);
2803
+ const cids = [];
2804
+ for (const car of cars) {
2805
+ const { cid, bytes } = car;
2806
+ await (await this.carStore()).save({ cid, bytes });
2807
+ cids.push(cid);
2808
+ }
2809
+ await this.cacheTransaction(t);
2810
+ const newDbMeta = { cars: cids, key: this.key || null };
2811
+ await (await this.remoteWAL()).enqueue(newDbMeta, opts);
2812
+ await (await this.metaStore()).save(newDbMeta);
2813
+ await this.updateCarLog(cids, fp, !!opts.compact);
2814
+ return cids;
2815
+ }
2816
+ async prepareCarFilesFiles(roots, t, isPublic) {
2817
+ const theKey = isPublic ? null : await this._getKey();
2818
+ const car = theKey && this.ebOpts.crypto ? await encryptedEncodeCarFile(this.logger, this.ebOpts.crypto, theKey, roots[0], t) : await encodeCarFile(roots, t);
2819
+ return [car];
2820
+ }
2821
+ async prepareCarFiles(rootBlock, t, isPublic) {
2822
+ const theKey = isPublic ? void 0 : await this._getKey();
2823
+ const carFiles = [];
2824
+ const threshold = this.ebOpts.threshold || 1e3 * 1e3;
2825
+ let clonedt = new CarTransaction(t.parent, { add: false });
2826
+ clonedt.putSync(rootBlock.cid, rootBlock.bytes);
2827
+ let newsize = CBW2.blockLength(toCIDBlock(rootBlock));
2828
+ let cidRootBlock = rootBlock;
2829
+ for (const { cid, bytes } of t.entries()) {
2830
+ newsize += CBW2.blockLength(toCIDBlock({ cid, bytes }));
2831
+ if (newsize >= threshold) {
2832
+ carFiles.push(await this.createCarFile(theKey, cidRootBlock.cid, clonedt));
2833
+ clonedt = new CarTransaction(t.parent, { add: false });
2834
+ clonedt.putSync(cid, bytes);
2835
+ cidRootBlock = { cid, bytes };
2836
+ newsize = CBW2.blockLength(toCIDBlock({ cid, bytes }));
2837
+ } else {
2838
+ clonedt.putSync(cid, bytes);
2839
+ }
2840
+ }
2841
+ carFiles.push(await this.createCarFile(theKey, cidRootBlock.cid, clonedt));
2842
+ return carFiles;
2843
+ }
2844
+ async createCarFile(theKey, cid, t) {
2845
+ try {
2846
+ return theKey && this.ebOpts.crypto ? await encryptedEncodeCarFile(this.logger, this.ebOpts.crypto, theKey, cid, t) : await encodeCarFile([cid], t);
2847
+ } catch (e) {
2848
+ console.error("error creating car file", e);
2849
+ throw e;
2850
+ }
2851
+ }
2852
+ makeFileCarHeader(result) {
2853
+ const files = [];
2854
+ for (const [, meta] of Object.entries(result.files || {})) {
2855
+ if (meta && typeof meta === "object" && "cid" in meta && meta !== null) {
2856
+ files.push(meta.cid);
2857
+ }
2858
+ }
2859
+ return { ...result, files };
2860
+ }
2861
+ async updateCarLog(cids, fp, compact) {
2862
+ if (compact) {
2863
+ const previousCompactCid = fp.compact[fp.compact.length - 1];
2864
+ fp.compact.map((c) => c.toString()).forEach(this.seenCompacted.add, this.seenCompacted);
2865
+ this.carLog = [...uniqueCids([...this.carLog, ...fp.cars, cids], this.seenCompacted)];
2866
+ await this.removeCidsForCompact(previousCompactCid[0]);
2867
+ } else {
2868
+ this.carLog.unshift(cids);
2869
+ }
2870
+ }
2871
+ async removeCidsForCompact(cid) {
2872
+ const carHeader = await this.loadCarHeaderFromMeta({
2873
+ cars: [cid]
2874
+ });
2875
+ for (const cids of carHeader.compact) {
2876
+ for (const cid2 of cids) {
2877
+ await (await this.carStore()).remove(cid2);
2878
+ }
2879
+ }
2880
+ }
2881
+ // async flushCars() {
2882
+ // await this.ready
2883
+ // // for each cid in car log, make a dbMeta
2884
+ // for (const cid of this.carLog) {
2885
+ // const dbMeta = { car: cid, key: this.key || null } as DbMeta
2886
+ // await this.remoteWAL!.enqueue(dbMeta, { public: false })
2887
+ // }
2888
+ // }
2889
+ async *entries(cache3 = true) {
2890
+ await this.ready();
2891
+ if (cache3) {
2892
+ for (const [, block] of this.getBlockCache) {
2893
+ yield block;
2894
+ }
2895
+ } else {
2896
+ for (const [, block] of this.getBlockCache) {
2897
+ yield block;
2898
+ }
2899
+ for (const cids of this.carLog) {
2900
+ for (const cid of cids) {
2901
+ const reader = await this.loadCar(cid);
2902
+ if (!reader) throw this.logger.Error().Ref("cid", cid).Msg("missing car reader").AsError();
2903
+ for await (const block of reader.blocks()) {
2904
+ const sCid = block.cid.toString();
2905
+ if (!this.getBlockCache.has(sCid)) {
2906
+ yield block;
2907
+ }
2908
+ }
2909
+ }
2910
+ }
2911
+ }
2912
+ }
2913
+ async getBlock(cid) {
2914
+ await this.ready();
2915
+ const sCid = cid.toString();
2916
+ if (this.getBlockCache.has(sCid)) return this.getBlockCache.get(sCid);
2917
+ const getCarCid = async (carCid) => {
2918
+ if (this.getBlockCache.has(sCid)) return this.getBlockCache.get(sCid);
2919
+ const reader = await this.loadCar(carCid);
2920
+ if (!reader) {
2921
+ throw this.logger.Error().Ref("cid", carCid).Msg("missing car reader").AsError();
2922
+ }
2923
+ await this.cacheCarReader(carCid.toString(), reader).catch(() => {
2924
+ return;
2925
+ });
2926
+ if (this.getBlockCache.has(sCid)) return this.getBlockCache.get(sCid);
2927
+ throw this.logger.Error().Str("cid", sCid).Msg("block not in reader").AsError();
2928
+ };
2929
+ const getCompactCarCids = async (carCid) => {
2930
+ const reader = await this.loadCar(carCid);
2931
+ if (!reader) {
2932
+ throw this.logger.Error().Str("cid", carCid.toString()).Msg("missing car reader").AsError();
2933
+ }
2934
+ const header = await parseCarFile(reader, this.logger);
2935
+ const compacts = header.compact;
2936
+ let got2;
2937
+ const batchSize2 = 5;
2938
+ for (let i = 0; i < compacts.length; i += batchSize2) {
2939
+ const promises = [];
2940
+ for (let j = i; j < Math.min(i + batchSize2, compacts.length); j++) {
2941
+ for (const cid2 of compacts[j]) {
2942
+ promises.push(getCarCid(cid2));
2943
+ }
2944
+ }
2945
+ try {
2946
+ got2 = await Promise.any(promises);
2947
+ } catch {
2948
+ }
2949
+ if (got2) break;
2950
+ }
2951
+ if (this.getBlockCache.has(sCid)) return this.getBlockCache.get(sCid);
2952
+ throw this.logger.Error().Str("cid", sCid).Msg("block not in compact reader").AsError();
2953
+ };
2954
+ let got;
2955
+ const batchSize = 5;
2956
+ for (let i = 0; i < this.carLog.length; i += batchSize) {
2957
+ const batch = this.carLog.slice(i, i + batchSize);
2958
+ const promises = batch.flatMap((slice) => slice.map(getCarCid));
2959
+ try {
2960
+ got = await Promise.any(promises);
2961
+ } catch {
2962
+ }
2963
+ if (got) break;
2964
+ }
2965
+ if (!got) {
2966
+ try {
2967
+ got = await getCompactCarCids(this.carLog[this.carLog.length - 1][0]);
2968
+ } catch {
2969
+ }
2970
+ }
2971
+ return got;
2972
+ }
2973
+ makeCarHeader(meta, cars, compact = false) {
2974
+ const coreHeader = compact ? { cars: [], compact: cars } : { cars, compact: [] };
2975
+ return { ...coreHeader, meta };
2976
+ }
2977
+ async loadCar(cid) {
2978
+ if (!this.carStore) {
2979
+ throw this.logger.Error().Msg("car store not initialized").AsError();
2980
+ }
2981
+ const loaded = await this.storesLoadCar(cid, await this.carStore(), this.remoteCarStore);
2982
+ return loaded;
2983
+ }
2984
+ //What if instead it returns an Array of CarHeader
2985
+ async storesLoadCar(cid, local, remote, publicFiles) {
2986
+ const cidsString = cid.toString();
2987
+ if (!this.carReaders.has(cidsString)) {
2988
+ this.carReaders.set(
2989
+ cidsString,
2990
+ (async () => {
2991
+ let loadedCar = void 0;
2992
+ try {
2993
+ this.logger.Debug().Str("cid", cidsString).Msg("loading car");
2994
+ loadedCar = await local.load(cid);
2995
+ this.logger.Debug().Bool("loadedCar", loadedCar).Msg("loaded");
2996
+ } catch (e) {
2997
+ if (remote) {
2998
+ const remoteCar = await remote.load(cid);
2999
+ if (remoteCar) {
3000
+ this.logger.Debug().Ref("cid", remoteCar.cid).Msg("saving remote car locally");
3001
+ await local.save(remoteCar);
3002
+ loadedCar = remoteCar;
3003
+ }
3004
+ } else {
3005
+ this.logger.Error().Str("cid", cidsString).Err(e).Msg("loading car");
3006
+ }
3007
+ }
3008
+ if (!loadedCar) {
3009
+ throw this.logger.Error().Url(local.url).Str("cid", cidsString).Msg("missing car files").AsError();
3010
+ }
3011
+ const rawReader = await import_car.CarReader.fromBytes(loadedCar.bytes);
3012
+ const readerP = publicFiles ? Promise.resolve(rawReader) : this.ensureDecryptedReader(rawReader);
3013
+ const cachedReaderP = readerP.then(async (reader) => {
3014
+ await this.cacheCarReader(cidsString, reader).catch(() => {
3015
+ return;
3016
+ });
3017
+ return reader;
3018
+ });
3019
+ this.carReaders.set(cidsString, cachedReaderP);
3020
+ return readerP;
3021
+ })().catch((e) => {
3022
+ this.carReaders.delete(cidsString);
3023
+ throw e;
3024
+ })
3025
+ );
3026
+ }
3027
+ return this.carReaders.get(cidsString);
3028
+ }
3029
+ async ensureDecryptedReader(reader) {
3030
+ const theKey = await this._getKey();
3031
+ if (this.ebOpts.public || !(theKey && this.ebOpts.crypto)) {
3032
+ return reader;
3033
+ }
3034
+ const { blocks, root: root3 } = await decodeEncryptedCar(this.logger, this.ebOpts.crypto, theKey, reader);
3035
+ return {
3036
+ getRoots: () => [root3],
3037
+ get: blocks.get.bind(blocks),
3038
+ blocks: blocks.entries.bind(blocks)
3039
+ };
3040
+ }
3041
+ async setKey(key) {
3042
+ if (this.key && this.key !== key)
3043
+ throw this.logger.Error().Str("this.key", this.key).Str("key", key).Msg("setting key").AsError();
3044
+ this.key = key;
3045
+ const encoder = new TextEncoder();
3046
+ const data = encoder.encode(key);
3047
+ const hashBuffer = await this.ebOpts.crypto.digestSHA256(data);
3048
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
3049
+ this.keyId = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
3050
+ }
3051
+ async getMoreReaders(cids) {
3052
+ const limit = (0, import_p_limit.default)(5);
3053
+ const missing = cids.filter((cid) => !this.carReaders.has(cid.toString()));
3054
+ await Promise.all(missing.map((cid) => limit(() => this.loadCar(cid))));
3055
+ }
3056
+ };
3057
+
3058
+ // src/blockstore/store.ts
3059
+ var VersionedStore = class {
3060
+ constructor(name, url, logger) {
3061
+ this._onStarted = [];
3062
+ this._onClosed = [];
3063
+ this.name = name;
3064
+ this.url = url;
3065
+ this.logger = logger;
3066
+ }
3067
+ onStarted(fn) {
3068
+ this._onStarted.push(fn);
3069
+ }
3070
+ onClosed(fn) {
3071
+ this._onClosed.push(fn);
3072
+ }
3073
+ };
3074
+ var textEncoder = new TextEncoder();
3075
+ var textDecoder = new TextDecoder();
3076
+ var MetaStore = class extends VersionedStore {
3077
+ constructor(name, url, logger, gateway) {
3078
+ super(name, url, ensureLogger(logger, "MetaStore", {}));
3079
+ this.tag = "header-base";
3080
+ this.gateway = gateway;
3081
+ }
3082
+ makeHeader({ cars, key }) {
3083
+ const toEncode = { cars };
3084
+ if (key) toEncode.key = key;
3085
+ return (0, import_dag_json.format)(toEncode);
3086
+ }
3087
+ parseHeader(headerData) {
3088
+ const got = (0, import_dag_json.parse)(headerData);
3089
+ return got;
3090
+ }
3091
+ async start() {
3092
+ this.logger.Debug().Msg("starting");
3093
+ const res = await this.gateway.start(this.url);
3094
+ if (res.isErr()) {
3095
+ return res;
3096
+ }
3097
+ this._onStarted.forEach((fn) => fn());
3098
+ return guardVersion(this.url);
3099
+ }
3100
+ async load(branch) {
3101
+ this.logger.Debug().Str("branch", branch || "").Msg("loading");
3102
+ const url = await this.gateway.buildUrl(this.url, branch || "main");
3103
+ if (url.isErr()) {
3104
+ throw this.logger.Error().Err(url.Err()).Str("branch", branch || "").Str("url", this.url.toString()).Msg("got error from gateway.buildUrl").AsError();
3105
+ }
3106
+ const bytes = await this.gateway.get(url.Ok());
3107
+ if (bytes.isErr()) {
3108
+ if (isNotFoundError(bytes)) {
3109
+ return void 0;
3110
+ }
3111
+ throw this.logger.Error().Err(bytes.Err()).Msg("gateway get").AsError();
3112
+ }
3113
+ try {
3114
+ return [this.parseHeader(textDecoder.decode(bytes.Ok()))];
3115
+ } catch (e) {
3116
+ throw this.logger.Error().Err(e).Msg("parseHeader").AsError();
3117
+ }
3118
+ }
3119
+ async save(meta, branch = "main") {
3120
+ this.logger.Debug().Str("branch", branch).Any("meta", meta).Msg("saving meta");
3121
+ const bytes = this.makeHeader(meta);
3122
+ const url = await this.gateway.buildUrl(this.url, branch);
3123
+ if (url.isErr()) {
3124
+ throw this.logger.Error().Err(url.Err()).Str("branch", branch).Url(this.url).Msg("got error from gateway.buildUrl").AsError();
3125
+ }
3126
+ const res = await this.gateway.put(url.Ok(), textEncoder.encode(bytes));
3127
+ if (res.isErr()) {
3128
+ throw this.logger.Error().Err(res.Err()).Msg("got error from gateway.put").AsError();
3129
+ }
3130
+ return res.Ok();
3131
+ }
3132
+ async close() {
3133
+ await this.gateway.close(this.url);
3134
+ this._onClosed.forEach((fn) => fn());
3135
+ return import_cement6.Result.Ok(void 0);
3136
+ }
3137
+ async destroy() {
3138
+ return this.gateway.destroy(this.url);
3139
+ }
3140
+ };
3141
+ var DataStore = class extends VersionedStore {
3142
+ constructor(name, url, logger, gateway) {
3143
+ super(
3144
+ name,
3145
+ url,
3146
+ ensureLogger(logger, "DataStore", {
3147
+ url: () => url.toString()
3148
+ })
3149
+ );
3150
+ this.tag = "car-base";
3151
+ this.gateway = gateway;
3152
+ }
3153
+ async start() {
3154
+ this.logger.Debug().Msg("starting-gateway");
3155
+ const res = await this.gateway.start(this.url);
3156
+ if (res.isErr()) {
3157
+ this.logger.Error().Err(res.Err()).Msg("started-gateway");
3158
+ return res;
3159
+ }
3160
+ this._onStarted.forEach((fn) => fn());
3161
+ const version = guardVersion(this.url);
3162
+ if (version.isErr()) {
3163
+ this.logger.Error().Err(res.Err()).Msg("guardVersion");
3164
+ await this.close();
3165
+ return version;
3166
+ }
3167
+ this.logger.Debug().Msg("started");
3168
+ return version;
3169
+ }
3170
+ async load(cid) {
3171
+ this.logger.Debug().Any("cid", cid).Msg("loading");
3172
+ const url = await this.gateway.buildUrl(this.url, cid.toString());
3173
+ if (url.isErr()) {
3174
+ throw this.logger.Error().Err(url.Err()).Str("cid", cid.toString()).Msg("got error from gateway.buildUrl").AsError();
3175
+ }
3176
+ const res = await this.gateway.get(url.Ok());
3177
+ if (res.isErr()) {
3178
+ throw res.Err();
3179
+ }
3180
+ return { cid, bytes: res.Ok() };
3181
+ }
3182
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
3183
+ async save(car, opts) {
3184
+ this.logger.Debug().Any("cid", car.cid.toString()).Msg("saving");
3185
+ const url = await this.gateway.buildUrl(this.url, car.cid.toString());
3186
+ if (url.isErr()) {
3187
+ throw this.logger.Error().Err(url.Err()).Ref("cid", car.cid).Msg("got error from gateway.buildUrl").AsError();
3188
+ }
3189
+ const res = await this.gateway.put(url.Ok(), car.bytes);
3190
+ if (res.isErr()) {
3191
+ throw this.logger.Error().Err(res.Err()).Msg("got error from gateway.put").AsError();
3192
+ }
3193
+ return res.Ok();
3194
+ }
3195
+ async remove(cid) {
3196
+ const url = await this.gateway.buildUrl(this.url, cid.toString());
3197
+ if (url.isErr()) {
3198
+ return url;
3199
+ }
3200
+ return this.gateway.delete(url.Ok());
3201
+ }
3202
+ async close() {
3203
+ await this.gateway.close(this.url);
3204
+ this._onClosed.forEach((fn) => fn());
3205
+ return import_cement6.Result.Ok(void 0);
3206
+ }
3207
+ destroy() {
3208
+ return this.gateway.destroy(this.url);
3209
+ }
3210
+ };
3211
+ var RemoteWAL = class extends VersionedStore {
3212
+ constructor(loader, url, logger, gateway) {
3213
+ super(loader.name, url, ensureLogger(logger, "RemoteWAL"));
3214
+ this.tag = "rwal-base";
3215
+ this._ready = new import_cement6.ResolveOnce();
3216
+ this.walState = { operations: [], noLoaderOps: [], fileOperations: [] };
3217
+ this.processing = void 0;
3218
+ this.processQueue = new CommitQueue();
3219
+ this.loader = loader;
3220
+ this.gateway = gateway;
3221
+ }
3222
+ async ready() {
3223
+ return this._ready.once(async () => {
3224
+ const walState = await this.load().catch((e) => {
3225
+ this.logger.Error().Any("error", e).Msg("error loading wal");
3226
+ return void 0;
3227
+ });
3228
+ if (!walState) {
3229
+ this.walState.operations = [];
3230
+ this.walState.fileOperations = [];
3231
+ } else {
3232
+ this.walState.operations = walState.operations || [];
3233
+ this.walState.fileOperations = walState.fileOperations || [];
3234
+ }
3235
+ });
3236
+ }
3237
+ async enqueue(dbMeta, opts) {
3238
+ await this.ready();
3239
+ if (opts.noLoader) {
3240
+ this.walState.noLoaderOps.push(dbMeta);
3241
+ } else {
3242
+ this.walState.operations.push(dbMeta);
3243
+ }
3244
+ await this.save(this.walState);
3245
+ void this._process();
3246
+ }
3247
+ async enqueueFile(fileCid, publicFile = false) {
3248
+ await this.ready();
3249
+ this.walState.fileOperations.push({ cid: fileCid, public: publicFile });
3250
+ }
3251
+ async _process() {
3252
+ await this.ready();
3253
+ if (!this.loader.remoteCarStore) return;
3254
+ await this.processQueue.enqueue(async () => {
3255
+ await this._doProcess();
3256
+ if (this.walState.operations.length || this.walState.fileOperations.length || this.walState.noLoaderOps.length) {
3257
+ setTimeout(() => void this._process(), 0);
3258
+ }
3259
+ });
3260
+ }
3261
+ async _doProcess() {
3262
+ if (!this.loader.remoteCarStore) return;
3263
+ const rmlp = (async () => {
3264
+ const operations = [...this.walState.operations];
3265
+ const fileOperations = [...this.walState.fileOperations];
3266
+ const uploads = [];
3267
+ const noLoaderOps = [...this.walState.noLoaderOps];
3268
+ const limit = (0, import_p_limit2.default)(5);
3269
+ if (operations.length + fileOperations.length + noLoaderOps.length === 0) return;
3270
+ for (const dbMeta of noLoaderOps) {
3271
+ const uploadP = limit(async () => {
3272
+ for (const cid of dbMeta.cars) {
3273
+ const car = await (await this.loader.carStore()).load(cid);
3274
+ if (!car) {
3275
+ if (carLogIncludesGroup2(this.loader.carLog, dbMeta.cars))
3276
+ throw this.logger.Error().Ref("cid", cid).Msg("missing local car").AsError();
3277
+ } else {
3278
+ await throwFalsy(this.loader.remoteCarStore).save(car);
3279
+ }
3280
+ this.walState.noLoaderOps = this.walState.noLoaderOps.filter((op) => op !== dbMeta);
3281
+ }
3282
+ });
3283
+ uploads.push(uploadP);
3284
+ }
3285
+ for (const dbMeta of operations) {
3286
+ const uploadP = limit(async () => {
3287
+ for (const cid of dbMeta.cars) {
3288
+ const car = await (await this.loader.carStore()).load(cid).catch(() => null);
3289
+ if (!car) {
3290
+ if (carLogIncludesGroup2(this.loader.carLog, dbMeta.cars))
3291
+ throw this.logger.Error().Ref("cid", cid).Msg(`missing local car`).AsError();
3292
+ } else {
3293
+ await throwFalsy(this.loader.remoteCarStore).save(car);
3294
+ }
3295
+ }
3296
+ this.walState.operations = this.walState.operations.filter((op) => op !== dbMeta);
3297
+ });
3298
+ uploads.push(uploadP);
3299
+ }
3300
+ if (fileOperations.length) {
3301
+ const dbLoader = this.loader;
3302
+ for (const { cid: fileCid, public: publicFile } of fileOperations) {
3303
+ const uploadP = limit(async () => {
3304
+ const fileBlock = await (await dbLoader.fileStore()).load(fileCid);
3305
+ await dbLoader.remoteFileStore?.save(fileBlock, { public: publicFile });
3306
+ this.walState.fileOperations = this.walState.fileOperations.filter((op) => op.cid !== fileCid);
3307
+ });
3308
+ uploads.push(uploadP);
3309
+ }
3310
+ }
3311
+ try {
3312
+ const res = await Promise.allSettled(uploads);
3313
+ const errors = res.filter((r) => r.status === "rejected");
3314
+ if (errors.length) {
3315
+ throw this.logger.Error().Any(
3316
+ "errors",
3317
+ errors.map((e) => e.reason)
3318
+ ).Msg("error uploading").AsError();
3319
+ errors[0].reason;
3320
+ }
3321
+ if (operations.length) {
3322
+ const lastOp = operations[operations.length - 1];
3323
+ await this.loader.remoteMetaStore?.save(lastOp).catch((e) => {
3324
+ this.walState.operations.push(lastOp);
3325
+ throw this.logger.Error().Any("error", e).Msg("error saving remote meta").AsError();
3326
+ });
3327
+ }
3328
+ } finally {
3329
+ await this.save(this.walState);
3330
+ }
3331
+ })();
3332
+ await rmlp;
3333
+ }
3334
+ async start() {
3335
+ const res = await this.gateway.start(this.url);
3336
+ if (res.isErr()) {
3337
+ return res;
3338
+ }
3339
+ const ver = guardVersion(this.url);
3340
+ if (ver.isErr()) {
3341
+ await this.close();
3342
+ return ver;
3343
+ }
3344
+ const ready = await exception2Result(() => this.ready());
3345
+ this._onStarted.forEach((fn) => fn());
3346
+ if (ready.isErr()) {
3347
+ await this.close();
3348
+ return ready;
3349
+ }
3350
+ return ready;
3351
+ }
3352
+ async load() {
3353
+ this.logger.Debug().Msg("loading");
3354
+ const filepath = await this.gateway.buildUrl(this.url, "main");
3355
+ if (filepath.isErr()) {
3356
+ throw this.logger.Error().Err(filepath.Err()).Str("url", this.url.toString()).Msg("error building url").AsError();
3357
+ }
3358
+ const bytes = await this.gateway.get(filepath.Ok());
3359
+ if (bytes.isErr()) {
3360
+ if (isNotFoundError(bytes)) {
3361
+ return void 0;
3362
+ }
3363
+ throw this.logger.Error().Err(bytes.Err()).Msg("error get").AsError();
3364
+ }
3365
+ try {
3366
+ return bytes && (0, import_dag_json.parse)(textDecoder.decode(bytes.Ok()));
3367
+ } catch (e) {
3368
+ throw this.logger.Error().Err(e).Msg("error parse").AsError();
3369
+ }
3370
+ }
3371
+ async save(state) {
3372
+ const filepath = await this.gateway.buildUrl(this.url, "main");
3373
+ if (filepath.isErr()) {
3374
+ throw this.logger.Error().Err(filepath.Err()).Str("url", this.url.toString()).Msg("error building url").AsError();
3375
+ }
3376
+ let encoded;
3377
+ try {
3378
+ encoded = (0, import_dag_json.format)(state);
3379
+ } catch (e) {
3380
+ throw this.logger.Error().Err(e).Any("state", state).Msg("error format").AsError();
3381
+ }
3382
+ const res = await this.gateway.put(filepath.Ok(), textEncoder.encode(encoded));
3383
+ if (res.isErr()) {
3384
+ throw this.logger.Error().Err(res.Err()).Str("filePath", filepath.Ok().toString()).Msg("error saving").AsError();
3385
+ }
3386
+ }
3387
+ async close() {
3388
+ await this.gateway.close(this.url);
3389
+ this._onClosed.forEach((fn) => fn());
3390
+ return import_cement6.Result.Ok(void 0);
3391
+ }
3392
+ destroy() {
3393
+ return this.gateway.destroy(this.url);
3394
+ }
3395
+ };
3396
+
3397
+ // src/blockstore/store-factory.ts
3398
+ init_utils();
3399
+ function ensureIsIndex(url, isIndex) {
3400
+ if (isIndex) {
3401
+ url.searchParams.set("index", isIndex);
3402
+ return url;
3403
+ } else {
3404
+ url.searchParams.delete("index");
3405
+ return url;
3406
+ }
3407
+ }
3408
+ function toURL(pathOrUrl, isIndex) {
3409
+ if (pathOrUrl instanceof URL) return ensureIsIndex(pathOrUrl, isIndex);
3410
+ try {
3411
+ const url = new URL(pathOrUrl);
3412
+ return ensureIsIndex(url, isIndex);
3413
+ } catch (e) {
3414
+ const url = new URL(`file://${pathOrUrl}`);
3415
+ return ensureIsIndex(url, isIndex);
3416
+ }
3417
+ }
3418
+ function buildURL(optURL, loader) {
3419
+ const storeOpts = loader.ebOpts.store;
3420
+ return toURL(optURL || dataDir(loader.name, storeOpts.stores?.base), storeOpts.isIndex);
3421
+ }
3422
+ var storeFactory = /* @__PURE__ */ new Map();
3423
+ function registerStoreProtocol(item) {
3424
+ if (storeFactory.has(item.protocol)) {
3425
+ throw new Error(`protocol ${item.protocol} already registered`);
3426
+ }
3427
+ storeFactory.set(item.protocol, item);
3428
+ }
3429
+ function runStoreFactory(url, logger, run) {
3430
+ const item = storeFactory.get(url.protocol);
3431
+ if (!item) {
3432
+ throw logger.Error().Url(url).Str("protocol", url.protocol).Any("keys", Array(storeFactory.keys())).Msg(`unsupported protocol`).AsError();
3433
+ }
3434
+ logger.Debug().Str("protocol", url.protocol).Msg("run");
3435
+ return run(item);
3436
+ }
3437
+ var onceLoadDataGateway = new import_cement14.KeyedResolvOnce();
3438
+ function loadDataGateway(url, logger) {
3439
+ return onceLoadDataGateway.get(url.protocol).once(async () => {
3440
+ return runStoreFactory(url, logger, async (item) => item.data(logger));
3441
+ });
3442
+ }
3443
+ var onceDataStoreFactory = new import_cement14.KeyedResolvOnce();
3444
+ async function dataStoreFactory(loader) {
3445
+ const url = buildURL(loader.ebOpts.store.stores?.data, loader);
3446
+ const logger = ensureLogger(loader.logger, "dataStoreFactory", { url: url.toString() });
3447
+ url.searchParams.set("store", "data");
3448
+ return onceDataStoreFactory.get(url.toString()).once(async () => {
3449
+ const gateway = await loadDataGateway(url, logger);
3450
+ const store = new DataStore(loader.name, url, loader.logger, gateway);
3451
+ await store.start();
3452
+ logger.Debug().Str("prepared", store.url.toString()).Msg("produced");
3453
+ return store;
3454
+ });
3455
+ }
3456
+ var onceLoadMetaGateway = new import_cement14.KeyedResolvOnce();
3457
+ function loadMetaGateway(url, logger) {
3458
+ return onceLoadMetaGateway.get(url.protocol).once(async () => {
3459
+ return runStoreFactory(url, logger, async (item) => item.meta(logger));
3460
+ });
3461
+ }
3462
+ var onceMetaStoreFactory = new import_cement14.KeyedResolvOnce();
3463
+ async function metaStoreFactory(loader) {
3464
+ const url = buildURL(loader.ebOpts.store.stores?.meta, loader);
3465
+ const logger = ensureLogger(loader.logger, "metaStoreFactory", { url: () => url.toString() });
3466
+ url.searchParams.set("store", "meta");
3467
+ return onceMetaStoreFactory.get(url.toString()).once(async () => {
3468
+ logger.Debug().Str("protocol", url.protocol).Msg("pre-protocol switch");
3469
+ const gateway = await loadMetaGateway(url, logger);
3470
+ const store = new MetaStore(loader.name, url, loader.logger, gateway);
3471
+ logger.Debug().Msg("pre-start");
3472
+ await store.start();
3473
+ logger.Debug().Msg("post-start");
3474
+ return store;
3475
+ });
3476
+ }
3477
+ var onceWalGateway = new import_cement14.KeyedResolvOnce();
3478
+ function loadWalGateway(url, logger) {
3479
+ return onceWalGateway.get(url.protocol).once(async () => {
3480
+ return runStoreFactory(url, logger, async (item) => item.wal(logger));
3481
+ });
3482
+ }
3483
+ var onceRemoteWalFactory = new import_cement14.KeyedResolvOnce();
3484
+ async function remoteWalFactory(loader) {
3485
+ const url = buildURL(loader.ebOpts.store.stores?.meta, loader);
3486
+ const logger = ensureLogger(loader.logger, "remoteWalFactory", { url: url.toString() });
3487
+ url.searchParams.set("store", "wal");
3488
+ return onceRemoteWalFactory.get(url.toString()).once(async () => {
3489
+ const gateway = await loadWalGateway(url, logger);
3490
+ logger.Debug().Str("prepared", url.toString()).Msg("produced");
3491
+ const store = new RemoteWAL(loader, url, loader.logger, gateway);
3492
+ await store.start();
3493
+ return store;
3494
+ });
3495
+ }
3496
+ async function testStoreFactory(url, ilogger) {
3497
+ const logger = ensureLogger(
3498
+ {
3499
+ logger: ilogger
3500
+ },
3501
+ "testStoreFactory"
3502
+ );
3503
+ return runStoreFactory(url, logger, async (item) => item.test(logger));
3504
+ }
3505
+ function toStoreRuntime(opts, ilogger) {
3506
+ const logger = ensureLogger(ilogger, "toStoreRuntime", {});
3507
+ return {
3508
+ makeMetaStore: (loader) => {
3509
+ logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.makeMetaStore).Msg("makeMetaStore");
3510
+ return (loader.ebOpts.store.makeMetaStore || metaStoreFactory)(loader);
3511
+ },
3512
+ makeDataStore: (loader) => {
3513
+ logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.makeDataStore).Msg("makeDataStore");
3514
+ return (loader.ebOpts.store.makeDataStore || dataStoreFactory)(loader);
3515
+ },
3516
+ makeRemoteWAL: (loader) => {
3517
+ logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.makeRemoteWAL).Msg("makeRemoteWAL");
3518
+ return (loader.ebOpts.store.makeRemoteWAL || remoteWalFactory)(loader);
3519
+ },
3520
+ encodeFile: opts.encodeFile || encodeFile,
3521
+ decodeFile: opts.decodeFile || decodeFile
3522
+ };
3523
+ }
3524
+ registerStoreProtocol({
3525
+ protocol: "file:",
3526
+ data: async (logger) => {
3527
+ const { FileDataGateway: FileDataGateway2 } = await Promise.resolve().then(() => (init_store_file(), store_file_exports));
3528
+ return new FileDataGateway2(logger);
3529
+ },
3530
+ meta: async (logger) => {
3531
+ const { FileMetaGateway: FileMetaGateway2 } = await Promise.resolve().then(() => (init_store_file(), store_file_exports));
3532
+ return new FileMetaGateway2(logger);
3533
+ },
3534
+ wal: async (logger) => {
3535
+ const { FileWALGateway: FileWALGateway2 } = await Promise.resolve().then(() => (init_store_file(), store_file_exports));
3536
+ return new FileWALGateway2(logger);
3537
+ },
3538
+ test: async (logger) => {
3539
+ const { FileTestStore: FileTestStore2 } = await Promise.resolve().then(() => (init_store_file(), store_file_exports));
3540
+ return new FileTestStore2(logger);
3541
+ }
3542
+ });
3543
+ registerStoreProtocol({
3544
+ protocol: "indexdb:",
3545
+ data: async (logger) => {
3546
+ const { IndexDBDataGateway: IndexDBDataGateway2 } = await Promise.resolve().then(() => (init_store_indexdb(), store_indexdb_exports));
3547
+ return new IndexDBDataGateway2(logger);
3548
+ },
3549
+ meta: async (logger) => {
3550
+ const { IndexDBMetaGateway: IndexDBMetaGateway2 } = await Promise.resolve().then(() => (init_store_indexdb(), store_indexdb_exports));
3551
+ return new IndexDBMetaGateway2(logger);
3552
+ },
3553
+ wal: async (logger) => {
3554
+ const { IndexDBMetaGateway: IndexDBMetaGateway2 } = await Promise.resolve().then(() => (init_store_indexdb(), store_indexdb_exports));
3555
+ return new IndexDBMetaGateway2(logger);
3556
+ },
3557
+ test: async (logger) => {
3558
+ const { IndexDBTestStore: IndexDBTestStore2 } = await Promise.resolve().then(() => (init_store_indexdb(), store_indexdb_exports));
3559
+ return new IndexDBTestStore2(logger);
3560
+ }
3561
+ });
3562
+ registerStoreProtocol({
3563
+ protocol: "sqlite:",
3564
+ data: async (logger) => {
3565
+ const { SQLDataGateway: SQLDataGateway2 } = await Promise.resolve().then(() => (init_store_sql(), store_sql_exports));
3566
+ return new SQLDataGateway2(logger);
3567
+ },
3568
+ meta: async (logger) => {
3569
+ const { SQLMetaGateway: SQLMetaGateway2 } = await Promise.resolve().then(() => (init_store_sql(), store_sql_exports));
3570
+ return new SQLMetaGateway2(logger);
3571
+ },
3572
+ wal: async (logger) => {
3573
+ const { SQLWalGateway: SQLWalGateway2 } = await Promise.resolve().then(() => (init_store_sql(), store_sql_exports));
3574
+ return new SQLWalGateway2(logger);
3575
+ },
3576
+ test: async (logger) => {
3577
+ const { SQLTestStore: SQLTestStore2 } = await Promise.resolve().then(() => (init_store_sql(), store_sql_exports));
3578
+ return new SQLTestStore2(logger);
3579
+ }
3580
+ });
3581
+
3582
+ // src/blockstore/index.ts
3583
+ init_gateway();
3584
+
3585
+ // src/crdt-helpers.ts
3586
+ init_types();
3587
+ function time(tag) {
3588
+ }
3589
+ function timeEnd(tag) {
3590
+ }
3591
+ function toString(key, logger) {
3592
+ switch (typeof key) {
3593
+ case "string":
3594
+ case "number":
3595
+ return key.toString();
3596
+ default:
3597
+ throw logger.Error().Msg("Invalid key type").AsError();
3598
+ }
3599
+ }
3600
+ async function applyBulkUpdateToCrdt(store, tblocks, head, updates, logger) {
3601
+ let result = null;
3602
+ if (updates.length > 1) {
3603
+ const batch = await Batch.create(tblocks, head);
3604
+ for (const update of updates) {
3605
+ const link = await writeDocContent(store, tblocks, update, logger);
3606
+ await batch.put(toString(update.id, logger), link);
3607
+ }
3608
+ result = await batch.commit();
3609
+ } else if (updates.length === 1) {
3610
+ const link = await writeDocContent(store, tblocks, updates[0], logger);
3611
+ result = await (0, import_crdt.put)(tblocks, head, toString(updates[0].id, logger), link);
3612
+ }
3613
+ if (!result) throw logger.Error().Uint64("updates.len", updates.length).Msg("Missing result").AsError();
3614
+ if (result.event) {
3615
+ for (const { cid, bytes } of [
3616
+ ...result.additions,
3617
+ // ...result.removals,
3618
+ result.event
3619
+ ]) {
3620
+ tblocks.putSync(cid, bytes);
3621
+ }
3622
+ }
3623
+ return { head: result.head };
3624
+ }
3625
+ async function writeDocContent(store, blocks, update, logger) {
3626
+ let value;
3627
+ if (update.del) {
3628
+ value = { del: true };
3629
+ } else {
3630
+ if (!update.value) throw logger.Error().Msg("Missing value").AsError();
3631
+ await processFiles(store, blocks, update.value, logger);
3632
+ value = { doc: update.value };
3633
+ }
3634
+ const block = await (0, import_block6.encode)({ value, hasher: import_sha23.sha256, codec: codec2 });
3635
+ blocks.putSync(block.cid, block.bytes);
3636
+ return block.cid;
3637
+ }
3638
+ async function processFiles(store, blocks, doc, logger) {
3639
+ if (doc._files) {
3640
+ await processFileset(logger, store, blocks, doc._files);
3641
+ }
3642
+ if (doc._publicFiles) {
3643
+ await processFileset(logger, store, blocks, doc._publicFiles, true);
3644
+ }
3645
+ }
3646
+ async function processFileset(logger, store, blocks, files, publicFiles = false) {
3647
+ const dbBlockstore = blocks.parent;
3648
+ if (!dbBlockstore.loader) throw logger.Error().Msg("Missing loader, database name is required").AsError();
3649
+ const t = new CarTransaction(dbBlockstore);
3650
+ const didPut = [];
3651
+ for (const filename in files) {
3652
+ if (File === files[filename].constructor) {
3653
+ const file = files[filename];
3654
+ const { cid, blocks: fileBlocks } = await store.encodeFile(file);
3655
+ didPut.push(filename);
3656
+ for (const block of fileBlocks) {
3657
+ t.putSync(block.cid, block.bytes);
3658
+ }
3659
+ files[filename] = { cid, type: file.type, size: file.size };
3660
+ } else {
3661
+ const { cid, type, size, car } = files[filename];
3662
+ if (cid && type && size && car) {
3663
+ files[filename] = { cid, type, size, car };
3664
+ }
3665
+ }
3666
+ }
3667
+ if (didPut.length) {
3668
+ const car = await dbBlockstore.loader.commitFiles(t, { files }, {
3669
+ public: publicFiles
3670
+ });
3671
+ if (car) {
3672
+ for (const name of didPut) {
3673
+ files[name] = { car, ...files[name] };
3674
+ }
3675
+ }
3676
+ }
3677
+ }
3678
+ async function getValueFromCrdt(blocks, head, key, logger) {
3679
+ if (!head.length) throw logger.Debug().Msg("Getting from an empty database").AsError();
3680
+ const link = await (0, import_crdt.get)(blocks, head, key);
3681
+ if (!link) throw logger.Error().Str("key", key).Msg(`Missing key`).AsError();
3682
+ return await getValueFromLink(blocks, link, logger);
3683
+ }
3684
+ function readFiles(blocks, { doc }) {
3685
+ if (!doc) return;
3686
+ if (doc._files) {
3687
+ readFileset(blocks, doc._files);
3688
+ }
3689
+ if (doc._publicFiles) {
3690
+ readFileset(blocks, doc._publicFiles, true);
3691
+ }
3692
+ }
3693
+ function readFileset(blocks, files, isPublic = false) {
3694
+ for (const filename in files) {
3695
+ const fileMeta = files[filename];
3696
+ if (fileMeta.cid) {
3697
+ if (isPublic) {
3698
+ fileMeta.url = `https://${fileMeta.cid.toString()}.ipfs.w3s.link/`;
3699
+ }
3700
+ if (fileMeta.car) {
3701
+ fileMeta.file = async () => await blocks.ebOpts.storeRuntime.decodeFile(
3702
+ {
3703
+ get: async (cid) => {
3704
+ return await blocks.getFile(throwFalsy(fileMeta.car), cid, isPublic);
3705
+ }
3706
+ },
3707
+ fileMeta.cid,
3708
+ fileMeta
3709
+ );
3710
+ }
3711
+ }
3712
+ files[filename] = fileMeta;
3713
+ }
3714
+ }
3715
+ async function getValueFromLink(blocks, link, logger) {
3716
+ const block = await blocks.get(link);
3717
+ if (!block) throw logger.Error().Str("link", link.toString()).Msg(`Missing linked block`).AsError();
3718
+ const { value } = await (0, import_block6.decode)({ bytes: block.bytes, hasher: import_sha23.sha256, codec: codec2 });
3719
+ const cvalue = {
3720
+ ...value,
3721
+ cid: link
3722
+ };
3723
+ readFiles(blocks, cvalue);
3724
+ return cvalue;
3725
+ }
3726
+ var DirtyEventFetcher = class extends import_clock2.EventFetcher {
3727
+ async get(link) {
3728
+ try {
3729
+ return super.get(link);
3730
+ } catch (e) {
3731
+ console.error("missing event", link.toString(), e);
3732
+ return { value: void 0 };
3733
+ }
3734
+ }
3735
+ };
3736
+ async function clockChangesSince(blocks, head, since, opts, logger) {
3737
+ const eventsFetcher = opts.dirty ? new DirtyEventFetcher(blocks) : new import_clock2.EventFetcher(blocks);
3738
+ const keys = /* @__PURE__ */ new Set();
3739
+ const updates = await gatherUpdates(
3740
+ blocks,
3741
+ eventsFetcher,
3742
+ head,
3743
+ since,
3744
+ [],
3745
+ keys,
3746
+ /* @__PURE__ */ new Set(),
3747
+ opts.limit || Infinity,
3748
+ logger
3749
+ );
3750
+ return { result: updates.reverse(), head };
3751
+ }
3752
+ async function gatherUpdates(blocks, eventsFetcher, head, since, updates = [], keys, didLinks, limit, logger) {
3753
+ if (limit <= 0) return updates;
3754
+ const sHead = head.map((l) => l.toString());
3755
+ for (const link of since) {
3756
+ if (sHead.includes(link.toString())) {
3757
+ return updates;
3758
+ }
3759
+ }
3760
+ for (const link of head) {
3761
+ if (didLinks.has(link.toString())) continue;
3762
+ didLinks.add(link.toString());
3763
+ const { value: event } = await eventsFetcher.get(link);
3764
+ if (!event) continue;
3765
+ const { type } = event.data;
3766
+ let ops = [];
3767
+ if (type === "batch") {
3768
+ ops = event.data.ops;
3769
+ } else if (type === "put") {
3770
+ ops = [event.data];
3771
+ }
3772
+ for (let i = ops.length - 1; i >= 0; i--) {
3773
+ const { key, value } = ops[i];
3774
+ if (!keys.has(key)) {
3775
+ const docValue = await getValueFromLink(blocks, value, logger);
3776
+ updates.push({ id: key, value: docValue.doc, del: docValue.del, clock: link });
3777
+ limit--;
3778
+ keys.add(key);
3779
+ }
3780
+ }
3781
+ if (event.parents) {
3782
+ updates = await gatherUpdates(blocks, eventsFetcher, event.parents, since, updates, keys, didLinks, limit, logger);
3783
+ }
3784
+ }
3785
+ return updates;
3786
+ }
3787
+ async function* getAllEntries(blocks, head, logger) {
3788
+ for await (const [key, link] of (0, import_crdt.entries)(blocks, head)) {
3789
+ const docValue = await getValueFromLink(blocks, link, logger);
3790
+ yield { id: key, value: docValue.doc, del: docValue.del };
3791
+ }
3792
+ }
3793
+ async function* clockVis(blocks, head) {
3794
+ for await (const line of (0, import_clock2.vis)(blocks, head)) {
3795
+ yield line;
3796
+ }
3797
+ }
3798
+ var isCompacting = false;
3799
+ async function doCompact(blockLog, head, logger) {
3800
+ if (isCompacting) {
3801
+ return;
3802
+ }
3803
+ isCompacting = true;
3804
+ time("compact head");
3805
+ for (const cid of head) {
3806
+ const bl = await blockLog.get(cid);
3807
+ if (!bl) throw logger.Error().Ref("cid", cid).Msg("Missing head block").AsError();
3808
+ }
3809
+ timeEnd("compact head");
3810
+ time("compact all entries");
3811
+ for await (const _entry of getAllEntries(blockLog, head, logger)) {
3812
+ continue;
3813
+ }
3814
+ timeEnd("compact all entries");
3815
+ time("compact clock vis");
3816
+ for await (const _line of (0, import_clock2.vis)(blockLog, head)) {
3817
+ }
3818
+ timeEnd("compact clock vis");
3819
+ time("compact root");
3820
+ const result = await (0, import_crdt.root)(blockLog, head);
3821
+ timeEnd("compact root");
3822
+ time("compact root blocks");
3823
+ for (const { cid, bytes } of [...result.additions, ...result.removals]) {
3824
+ blockLog.loggedBlocks.putSync(cid, bytes);
3825
+ }
3826
+ timeEnd("compact root blocks");
3827
+ time("compact changes");
3828
+ await clockChangesSince(blockLog, head, [], {}, logger);
3829
+ timeEnd("compact changes");
3830
+ isCompacting = false;
3831
+ }
3832
+ async function getBlock(blocks, cidString) {
3833
+ const block = await blocks.get((0, import_link.parse)(cidString));
3834
+ if (!block) throw new Error(`Missing block ${cidString}`);
3835
+ const { cid, value } = await (0, import_block6.decode)({ bytes: block.bytes, codec: codec2, hasher: import_sha23.sha256 });
3836
+ return new import_block6.Block({ cid, value, bytes: block.bytes });
3837
+ }
3838
+
3839
+ // src/indexer.ts
3840
+ init_types();
3841
+
3842
+ // src/indexer-helpers.ts
3843
+ var import_block7 = require("multiformats/block");
3844
+ var import_sha24 = require("multiformats/hashes/sha2");
3845
+ var codec3 = __toESM(require("@ipld/dag-cbor"), 1);
3846
+ var import_charwise = __toESM(require("charwise"), 1);
3847
+ var DbIndex = __toESM(require("prolly-trees/db-index"), 1);
3848
+ var import_utils20 = require("prolly-trees/utils");
3849
+ var import_cache2 = require("prolly-trees/cache");
3850
+ var IndexTree = class {
3851
+ };
3852
+ function refCompare(aRef, bRef) {
3853
+ if (Number.isNaN(aRef)) return -1;
3854
+ if (Number.isNaN(bRef)) throw new Error("ref may not be Infinity or NaN");
3855
+ if (aRef === Infinity) return 1;
3856
+ return (0, import_utils20.simpleCompare)(aRef, bRef);
3857
+ }
3858
+ function compare(a, b) {
3859
+ const [aKey, aRef] = a;
3860
+ const [bKey, bRef] = b;
3861
+ const comp = (0, import_utils20.simpleCompare)(aKey, bKey);
3862
+ if (comp !== 0) return comp;
3863
+ return refCompare(aRef, bRef);
3864
+ }
3865
+ var byKeyOpts = { cache: import_cache2.nocache, chunker: (0, import_utils20.bf)(30), codec: codec3, hasher: import_sha24.sha256, compare };
3866
+ var byIdOpts = { cache: import_cache2.nocache, chunker: (0, import_utils20.bf)(30), codec: codec3, hasher: import_sha24.sha256, compare: import_utils20.simpleCompare };
3867
+ function indexEntriesForChanges(changes, mapFn) {
3868
+ const indexEntries = [];
3869
+ changes.forEach(({ id: key, value, del }) => {
3870
+ if (del || !value) return;
3871
+ let mapCalled = false;
3872
+ const mapReturn = mapFn({ ...value, _id: key }, (k, v) => {
3873
+ mapCalled = true;
3874
+ if (typeof k === "undefined") return;
3875
+ indexEntries.push({
3876
+ key: [import_charwise.default.encode(k), key],
3877
+ value: v || null
3878
+ });
3879
+ });
3880
+ if (!mapCalled && mapReturn) {
3881
+ indexEntries.push({
3882
+ key: [import_charwise.default.encode(mapReturn), key],
3883
+ value: null
3884
+ });
3885
+ }
3886
+ });
3887
+ return indexEntries;
3888
+ }
3889
+ function makeProllyGetBlock(blocks) {
3890
+ return async (address) => {
3891
+ const block = await blocks.get(address);
3892
+ if (!block) throw new Error(`Missing block ${address.toString()}`);
3893
+ const { cid, bytes } = block;
3894
+ return (0, import_block7.create)({ cid, bytes, hasher: import_sha24.sha256, codec: codec3 });
3895
+ };
3896
+ }
3897
+ async function bulkIndex(tblocks, inIndex, indexEntries, opts) {
3898
+ if (!indexEntries.length) return inIndex;
3899
+ if (!inIndex.root) {
3900
+ if (!inIndex.cid) {
3901
+ let returnRootBlock = void 0;
3902
+ let returnNode = void 0;
3903
+ for await (const node of await DbIndex.create({
3904
+ get: makeProllyGetBlock(tblocks),
3905
+ list: indexEntries,
3906
+ ...opts
3907
+ })) {
3908
+ const block = await node.block;
3909
+ await tblocks.put(block.cid, block.bytes);
3910
+ returnRootBlock = block;
3911
+ returnNode = node;
3912
+ }
3913
+ if (!returnNode || !returnRootBlock) throw new Error("failed to create index");
3914
+ return { root: returnNode, cid: returnRootBlock.cid };
3915
+ } else {
3916
+ inIndex.root = await DbIndex.load({ cid: inIndex.cid, get: makeProllyGetBlock(tblocks), ...opts });
3917
+ }
3918
+ }
3919
+ const { root: root3, blocks: newBlocks } = await inIndex.root.bulk(indexEntries);
3920
+ if (root3) {
3921
+ for await (const block of newBlocks) {
3922
+ await tblocks.put(block.cid, block.bytes);
3923
+ }
3924
+ return { root: root3, cid: (await root3.block).cid };
3925
+ } else {
3926
+ return { root: void 0, cid: void 0 };
3927
+ }
3928
+ }
3929
+ async function loadIndex(tblocks, cid, opts) {
3930
+ return await DbIndex.load({ cid, get: makeProllyGetBlock(tblocks), ...opts });
3931
+ }
3932
+ async function applyQuery(crdt, resp, query) {
3933
+ if (query.descending) {
3934
+ resp.result = resp.result.reverse();
3935
+ }
3936
+ if (query.limit) {
3937
+ resp.result = resp.result.slice(0, query.limit);
3938
+ }
3939
+ if (query.includeDocs) {
3940
+ resp.result = await Promise.all(
3941
+ resp.result.map(async (row) => {
3942
+ const val = await crdt.get(row.id);
3943
+ const doc = val ? { ...val.doc, _id: row.id } : void 0;
3944
+ return { ...row, doc };
3945
+ })
3946
+ );
3947
+ }
3948
+ return {
3949
+ rows: resp.result.map(({ key, ...row }) => {
3950
+ return {
3951
+ key: import_charwise.default.decode(key),
3952
+ ...row
3953
+ };
3954
+ })
3955
+ };
3956
+ }
3957
+ function encodeRange(range) {
3958
+ return [import_charwise.default.encode(range[0]), import_charwise.default.encode(range[1])];
3959
+ }
3960
+ function encodeKey(key) {
3961
+ return import_charwise.default.encode(key);
3962
+ }
3963
+
3964
+ // src/indexer.ts
3965
+ init_utils();
3966
+ function index({ _crdt }, name, mapFn, meta) {
3967
+ if (mapFn && meta) throw _crdt.logger.Error().Msg("cannot provide both mapFn and meta").AsError();
3968
+ if (mapFn && mapFn.constructor.name !== "Function") throw _crdt.logger.Error().Msg("mapFn must be a function").AsError();
3969
+ if (_crdt.indexers.has(name)) {
3970
+ const idx = _crdt.indexers.get(name);
3971
+ idx.applyMapFn(name, mapFn, meta);
3972
+ } else {
3973
+ const idx = new Index(_crdt, name, mapFn, meta);
3974
+ _crdt.indexers.set(name, idx);
3975
+ }
3976
+ return _crdt.indexers.get(name);
3977
+ }
3978
+ var Index = class {
3979
+ constructor(crdt, name, mapFn, meta) {
3980
+ this.mapFnString = "";
3981
+ this.byKey = new IndexTree();
3982
+ this.byId = new IndexTree();
3983
+ this.includeDocsDefault = false;
3984
+ this.logger = ensureLogger(crdt.logger, "Index");
3985
+ this.blockstore = crdt.indexBlockstore;
3986
+ this.crdt = crdt;
3987
+ this.applyMapFn(name, mapFn, meta);
3988
+ this.name = name;
3989
+ if (!(this.mapFnString || this.initError)) throw this.logger.Error().Msg("missing mapFnString").AsError();
3990
+ }
3991
+ ready() {
3992
+ return Promise.all([this.blockstore.ready(), this.crdt.ready()]).then(() => {
3993
+ });
3994
+ }
3995
+ close() {
3996
+ return Promise.all([this.blockstore.close(), this.crdt.close()]).then(() => {
3997
+ });
3998
+ }
3999
+ destroy() {
4000
+ return Promise.all([this.blockstore.destroy(), this.crdt.destroy()]).then(() => {
4001
+ });
4002
+ }
4003
+ applyMapFn(name, mapFn, meta) {
4004
+ if (mapFn && meta) throw this.logger.Error().Msg("cannot provide both mapFn and meta").AsError();
4005
+ if (this.name && this.name !== name) throw this.logger.Error().Msg("cannot change name").AsError();
4006
+ this.name = name;
4007
+ try {
4008
+ if (meta) {
4009
+ if (this.indexHead && this.indexHead.map((c) => c.toString()).join() !== meta.head.map((c) => c.toString()).join()) {
4010
+ throw this.logger.Error().Msg("cannot apply different head meta").AsError();
4011
+ }
4012
+ if (this.mapFnString) {
4013
+ if (this.mapFnString !== meta.map) {
4014
+ this.logger.Warn().Msg(`cannot apply different mapFn meta: old mapFnString ${this.mapFnString} new mapFnString ${meta.map}`);
4015
+ } else {
4016
+ this.byId.cid = meta.byId;
4017
+ this.byKey.cid = meta.byKey;
4018
+ this.indexHead = meta.head;
4019
+ }
4020
+ } else {
4021
+ this.mapFnString = meta.map;
4022
+ this.byId.cid = meta.byId;
4023
+ this.byKey.cid = meta.byKey;
4024
+ this.indexHead = meta.head;
4025
+ }
4026
+ } else {
4027
+ if (this.mapFn) {
4028
+ if (mapFn) {
4029
+ if (this.mapFn.toString() !== mapFn.toString()) {
4030
+ throw this.logger.Error().Msg("cannot apply different mapFn app2").AsError();
4031
+ }
4032
+ }
4033
+ } else {
4034
+ if (!mapFn) {
4035
+ mapFn = (doc) => doc[name] ?? void 0;
4036
+ }
4037
+ if (this.mapFnString) {
4038
+ if (this.mapFnString !== mapFn.toString()) {
4039
+ throw this.logger.Error().Msg("cannot apply different mapFn app").AsError();
4040
+ }
4041
+ } else {
4042
+ this.mapFnString = mapFn.toString();
4043
+ }
4044
+ this.mapFn = mapFn;
4045
+ }
4046
+ }
4047
+ const matches = /=>\s*(.*)/.test(this.mapFnString);
4048
+ this.includeDocsDefault = matches;
4049
+ } catch (e) {
4050
+ this.initError = e;
4051
+ }
4052
+ }
4053
+ async query(opts = {}) {
4054
+ await this.ready();
4055
+ await this._updateIndex();
4056
+ await this._hydrateIndex();
4057
+ if (!this.byKey.root) {
4058
+ return await applyQuery(this.crdt, { result: [] }, opts);
4059
+ }
4060
+ if (this.includeDocsDefault && opts.includeDocs === void 0) opts.includeDocs = true;
4061
+ if (opts.range) {
4062
+ const eRange = encodeRange(opts.range);
4063
+ return await applyQuery(this.crdt, await throwFalsy(this.byKey.root).range(eRange[0], eRange[1]), opts);
4064
+ }
4065
+ if (opts.key) {
4066
+ const encodedKey = encodeKey(opts.key);
4067
+ return await applyQuery(this.crdt, await throwFalsy(this.byKey.root).get(encodedKey), opts);
4068
+ }
4069
+ if (Array.isArray(opts.keys)) {
4070
+ const results = await Promise.all(
4071
+ opts.keys.map(async (key) => {
4072
+ const encodedKey = encodeKey(key);
4073
+ return (await applyQuery(this.crdt, await throwFalsy(this.byKey.root).get(encodedKey), opts)).rows;
4074
+ })
4075
+ );
4076
+ return { rows: results.flat() };
4077
+ }
4078
+ if (opts.prefix) {
4079
+ if (!Array.isArray(opts.prefix)) opts.prefix = [opts.prefix];
4080
+ const start = [...opts.prefix, NaN];
4081
+ const end = [...opts.prefix, Infinity];
4082
+ const encodedR = encodeRange([start, end]);
4083
+ return await applyQuery(this.crdt, await this.byKey.root.range(...encodedR), opts);
4084
+ }
4085
+ const all = await this.byKey.root.getAllEntries();
4086
+ return await applyQuery(
4087
+ this.crdt,
4088
+ {
4089
+ // @ts-expect-error getAllEntries returns a different type than range
4090
+ result: all.result.map(({ key: [k, id], value }) => ({
4091
+ key: k,
4092
+ id,
4093
+ value
4094
+ }))
4095
+ },
4096
+ opts
4097
+ );
4098
+ }
4099
+ _resetIndex() {
4100
+ this.byId = new IndexTree();
4101
+ this.byKey = new IndexTree();
4102
+ this.indexHead = void 0;
4103
+ }
4104
+ async _hydrateIndex() {
4105
+ if (this.byId.root && this.byKey.root) return;
4106
+ if (!this.byId.cid || !this.byKey.cid) return;
4107
+ this.byId.root = await loadIndex(this.blockstore, this.byId.cid, byIdOpts);
4108
+ this.byKey.root = await loadIndex(this.blockstore, this.byKey.cid, byKeyOpts);
4109
+ }
4110
+ async _updateIndex() {
4111
+ await this.ready();
4112
+ if (this.initError) throw this.initError;
4113
+ if (!this.mapFn) throw this.logger.Error().Msg("No map function defined").AsError();
4114
+ let result, head;
4115
+ if (!this.indexHead || this.indexHead.length === 0) {
4116
+ ({ result, head } = await this.crdt.allDocs());
4117
+ } else {
4118
+ ({ result, head } = await this.crdt.changes(this.indexHead));
4119
+ }
4120
+ if (result.length === 0) {
4121
+ this.indexHead = head;
4122
+ }
4123
+ let staleKeyIndexEntries = [];
4124
+ let removeIdIndexEntries = [];
4125
+ if (this.byId.root) {
4126
+ const removeIds = result.map(({ id: key }) => key);
4127
+ const { result: oldChangeEntries } = await this.byId.root.getMany(removeIds);
4128
+ staleKeyIndexEntries = oldChangeEntries.map((key) => ({ key, del: true }));
4129
+ removeIdIndexEntries = oldChangeEntries.map((key) => ({ key: key[1], del: true }));
4130
+ }
4131
+ const indexEntries = indexEntriesForChanges(result, this.mapFn);
4132
+ const byIdIndexEntries = indexEntries.map(({ key }) => ({
4133
+ key: key[1],
4134
+ value: key
4135
+ }));
4136
+ const indexerMeta = { indexes: /* @__PURE__ */ new Map() };
4137
+ for (const [name, indexer] of this.crdt.indexers) {
4138
+ if (indexer.indexHead) {
4139
+ indexerMeta.indexes?.set(name, {
4140
+ byId: indexer.byId.cid,
4141
+ byKey: indexer.byKey.cid,
4142
+ head: indexer.indexHead,
4143
+ map: indexer.mapFnString,
4144
+ name: indexer.name
4145
+ });
4146
+ }
4147
+ }
4148
+ if (result.length === 0) {
4149
+ return indexerMeta;
4150
+ }
4151
+ const { meta } = await this.blockstore.transaction(async (tblocks) => {
4152
+ this.byId = await bulkIndex(tblocks, this.byId, removeIdIndexEntries.concat(byIdIndexEntries), byIdOpts);
4153
+ this.byKey = await bulkIndex(tblocks, this.byKey, staleKeyIndexEntries.concat(indexEntries), byKeyOpts);
4154
+ this.indexHead = head;
4155
+ if (this.byId.cid && this.byKey.cid) {
4156
+ const idxMeta = {
4157
+ byId: this.byId.cid,
4158
+ byKey: this.byKey.cid,
4159
+ head,
4160
+ map: this.mapFnString,
4161
+ name: this.name
4162
+ };
4163
+ indexerMeta.indexes?.set(this.name, idxMeta);
4164
+ }
4165
+ return indexerMeta;
4166
+ });
4167
+ return meta;
4168
+ }
4169
+ };
4170
+
4171
+ // src/crdt-clock.ts
4172
+ var import_clock3 = require("@web3-storage/pail/clock");
4173
+ var import_crdt2 = require("@web3-storage/pail/crdt");
4174
+ var import_cement15 = require("@adviser/cement");
4175
+ init_types();
4176
+
4177
+ // src/apply-head-queue.ts
4178
+ function applyHeadQueue(worker, logger) {
4179
+ const queue = [];
4180
+ let isProcessing = false;
4181
+ async function* process() {
4182
+ if (isProcessing || queue.length === 0) return;
4183
+ isProcessing = true;
4184
+ const allUpdates = [];
4185
+ try {
4186
+ while (queue.length > 0) {
4187
+ queue.sort((a, b) => b.updates ? 1 : -1);
4188
+ const task = queue.shift();
4189
+ if (!task) continue;
4190
+ await worker(task.newHead, task.prevHead, task.updates !== null).catch((e) => {
4191
+ throw logger.Error().Err(e).Msg("int_applyHead worker error").AsError();
4192
+ });
4193
+ if (task.updates) {
4194
+ allUpdates.push(...task.updates);
4195
+ }
4196
+ if (!queue.some((t) => t.updates) || task.updates) {
4197
+ const allTasksHaveUpdates = queue.every((task2) => task2.updates !== null);
4198
+ yield { updates: allUpdates, all: allTasksHaveUpdates };
4199
+ allUpdates.length = 0;
4200
+ }
4201
+ }
4202
+ } finally {
4203
+ isProcessing = false;
4204
+ const generator = process();
4205
+ let result = await generator.next();
4206
+ while (!result.done) {
4207
+ result = await generator.next();
4208
+ }
4209
+ }
4210
+ }
4211
+ return {
4212
+ push(task) {
4213
+ queue.push(task);
4214
+ return process();
4215
+ },
4216
+ size() {
4217
+ return queue.length;
4218
+ }
4219
+ };
4220
+ }
4221
+
4222
+ // src/crdt-clock.ts
4223
+ init_utils();
4224
+ var CRDTClock = class {
4225
+ constructor(blockstore) {
4226
+ // todo: track local and remote clocks independently, merge on read
4227
+ // that way we can drop the whole remote if we need to
4228
+ // should go with making sure the local clock only references locally available blockstore on write
4229
+ this.head = [];
4230
+ this.zoomers = /* @__PURE__ */ new Set();
4231
+ this.watchers = /* @__PURE__ */ new Set();
4232
+ this.emptyWatchers = /* @__PURE__ */ new Set();
4233
+ this._ready = new import_cement15.ResolveOnce();
4234
+ this.blockstore = blockstore;
4235
+ this.logger = ensureLogger(blockstore.logger, "CRDTClock");
4236
+ this.applyHeadQueue = applyHeadQueue(this.int_applyHead.bind(this), this.logger);
4237
+ }
4238
+ async ready() {
4239
+ return this._ready.once(async () => {
4240
+ await this.blockstore.ready();
4241
+ });
4242
+ }
4243
+ async close() {
4244
+ await this.blockstore.close();
4245
+ }
4246
+ setHead(head) {
4247
+ this.head = head;
4248
+ }
4249
+ async applyHead(newHead, prevHead, updates) {
4250
+ for await (const { updates: updatesAcc, all } of this.applyHeadQueue.push({
4251
+ newHead,
4252
+ prevHead,
4253
+ updates
4254
+ })) {
4255
+ return this.processUpdates(updatesAcc, all, prevHead);
4256
+ }
4257
+ }
4258
+ async processUpdates(updatesAcc, all, prevHead) {
4259
+ let internalUpdates = updatesAcc;
4260
+ if (this.watchers.size && !all) {
4261
+ const changes = await clockChangesSince(throwFalsy(this.blockstore), this.head, prevHead, {}, this.logger);
4262
+ internalUpdates = changes.result;
4263
+ }
4264
+ this.zoomers.forEach((fn) => fn());
4265
+ this.notifyWatchers(internalUpdates || []);
4266
+ }
4267
+ notifyWatchers(updates) {
4268
+ this.emptyWatchers.forEach((fn) => fn());
4269
+ this.watchers.forEach((fn) => fn(updates || []));
4270
+ }
4271
+ onTick(fn) {
4272
+ this.watchers.add(fn);
4273
+ }
4274
+ onTock(fn) {
4275
+ this.emptyWatchers.add(fn);
4276
+ }
4277
+ onZoom(fn) {
4278
+ this.zoomers.add(fn);
4279
+ }
4280
+ async int_applyHead(newHead, prevHead, localUpdates) {
4281
+ const ogHead = sortClockHead(this.head);
4282
+ newHead = sortClockHead(newHead);
4283
+ if (compareClockHeads(ogHead, newHead)) {
4284
+ return;
4285
+ }
4286
+ const ogPrev = sortClockHead(prevHead);
4287
+ if (compareClockHeads(ogHead, ogPrev)) {
4288
+ this.setHead(newHead);
4289
+ return;
4290
+ }
4291
+ const noLoader = !localUpdates;
4292
+ if (!this.blockstore) {
4293
+ throw this.logger.Error().Msg("missing blockstore").AsError();
4294
+ }
4295
+ await validateBlocks(this.logger, newHead, this.blockstore);
4296
+ const { meta } = await this.blockstore.transaction(
4297
+ async (tblocks) => {
4298
+ const advancedHead = await advanceBlocks(this.logger, newHead, tblocks, this.head);
4299
+ const result = await (0, import_crdt2.root)(tblocks, advancedHead);
4300
+ for (const { cid, bytes } of [
4301
+ ...result.additions
4302
+ // ...result.removals
4303
+ ]) {
4304
+ tblocks.putSync(cid, bytes);
4305
+ }
4306
+ return { head: advancedHead };
4307
+ },
4308
+ { noLoader }
4309
+ );
4310
+ this.setHead(meta.head);
4311
+ }
4312
+ };
4313
+ function sortClockHead(clockHead) {
4314
+ return clockHead.sort((a, b) => a.toString().localeCompare(b.toString()));
4315
+ }
4316
+ async function validateBlocks(logger, newHead, blockstore) {
4317
+ if (!blockstore) throw logger.Error().Msg("missing blockstore");
4318
+ newHead.map(async (cid) => {
4319
+ const got = await blockstore.get(cid);
4320
+ if (!got) {
4321
+ throw logger.Error().Str("cid", cid.toString()).Msg("int_applyHead missing block").AsError();
4322
+ }
4323
+ });
4324
+ }
4325
+ function compareClockHeads(head1, head2) {
4326
+ return head1.toString() === head2.toString();
4327
+ }
4328
+ async function advanceBlocks(logger, newHead, tblocks, head) {
4329
+ for (const cid of newHead) {
4330
+ try {
4331
+ head = await (0, import_clock3.advance)(tblocks, head, cid);
4332
+ } catch (e) {
4333
+ logger.Debug().Err(e).Msg("failed to advance head");
4334
+ continue;
4335
+ }
4336
+ }
4337
+ return head;
4338
+ }
4339
+
4340
+ // src/crdt.ts
4341
+ init_utils();
4342
+ var CRDT = class {
4343
+ constructor(name, opts = {}) {
4344
+ this.onceReady = new import_cement16.ResolveOnce();
4345
+ this.indexers = /* @__PURE__ */ new Map();
4346
+ this.name = name;
4347
+ this.logger = ensureLogger(opts, "CRDT");
4348
+ this.opts = opts;
4349
+ this.blockstore = blockstoreFactory({
4350
+ name,
4351
+ applyMeta: async (meta) => {
4352
+ const crdtMeta = meta;
4353
+ if (!crdtMeta.head) throw this.logger.Error().Msg("missing head").AsError();
4354
+ await this.clock.applyHead(crdtMeta.head, []);
4355
+ },
4356
+ compact: async (blocks) => {
4357
+ await doCompact(blocks, this.clock.head, this.logger);
4358
+ return { head: this.clock.head };
4359
+ },
4360
+ autoCompact: this.opts.autoCompact || 100,
4361
+ crypto: this.opts.crypto,
4362
+ store: { ...this.opts.store, isIndex: void 0 },
4363
+ public: this.opts.public,
4364
+ meta: this.opts.meta,
4365
+ threshold: this.opts.threshold
4366
+ });
4367
+ this.indexBlockstore = blockstoreFactory({
4368
+ name,
4369
+ applyMeta: async (meta) => {
4370
+ const idxCarMeta = meta;
4371
+ if (!idxCarMeta.indexes) throw this.logger.Error().Msg("missing indexes").AsError();
4372
+ for (const [name2, idx] of Object.entries(idxCarMeta.indexes)) {
4373
+ index({ _crdt: this }, name2, void 0, idx);
4374
+ }
4375
+ },
4376
+ crypto: this.opts.crypto,
4377
+ store: { ...this.opts.store, isIndex: this.opts.store?.isIndex || "idx" },
4378
+ public: this.opts.public
4379
+ });
4380
+ this.clock = new CRDTClock(this.blockstore);
4381
+ this.clock.onZoom(() => {
4382
+ for (const idx of this.indexers.values()) {
4383
+ idx._resetIndex();
4384
+ }
4385
+ });
4386
+ }
4387
+ async ready() {
4388
+ return this.onceReady.once(async () => {
4389
+ await Promise.all([this.blockstore.ready(), this.indexBlockstore.ready(), this.clock.ready()]);
4390
+ });
4391
+ }
4392
+ async close() {
4393
+ await Promise.all([this.blockstore.close(), this.indexBlockstore.close(), this.clock.close()]);
4394
+ }
4395
+ async destroy() {
4396
+ await Promise.all([this.blockstore.destroy(), this.indexBlockstore.destroy()]);
4397
+ }
4398
+ async bulk(updates) {
4399
+ await this.ready();
4400
+ const prevHead = [...this.clock.head];
4401
+ const done = await this.blockstore.transaction(async (blocks) => {
4402
+ const { head } = await applyBulkUpdateToCrdt(
4403
+ this.blockstore.ebOpts.storeRuntime,
4404
+ blocks,
4405
+ this.clock.head,
4406
+ updates,
4407
+ this.logger
4408
+ );
4409
+ updates = updates.map((dupdate) => {
4410
+ readFiles(this.blockstore, { doc: dupdate.value });
4411
+ return dupdate;
4412
+ });
4413
+ return { head };
4414
+ });
4415
+ await this.clock.applyHead(done.meta.head, prevHead, updates);
4416
+ return done.meta;
4417
+ }
4418
+ // if (snap) await this.clock.applyHead(crdtMeta.head, this.clock.head)
4419
+ async allDocs() {
4420
+ await this.ready();
4421
+ const result = [];
4422
+ for await (const entry of getAllEntries(this.blockstore, this.clock.head, this.logger)) {
4423
+ result.push(entry);
4424
+ }
4425
+ return { result, head: this.clock.head };
4426
+ }
4427
+ async vis() {
4428
+ await this.ready();
4429
+ const txt = [];
4430
+ for await (const line of clockVis(this.blockstore, this.clock.head)) {
4431
+ txt.push(line);
4432
+ }
4433
+ return txt.join("\n");
4434
+ }
4435
+ async getBlock(cidString) {
4436
+ await this.ready();
4437
+ return await getBlock(this.blockstore, cidString);
4438
+ }
4439
+ async get(key) {
4440
+ await this.ready();
4441
+ const result = await getValueFromCrdt(this.blockstore, this.clock.head, key, this.logger);
4442
+ if (result.del) return void 0;
4443
+ return result;
4444
+ }
4445
+ async changes(since = [], opts = {}) {
4446
+ await this.ready();
4447
+ return await clockChangesSince(this.blockstore, this.clock.head, since, opts, this.logger);
4448
+ }
4449
+ async compact() {
4450
+ const blocks = this.blockstore;
4451
+ return await blocks.compact();
4452
+ }
4453
+ };
4454
+
4455
+ // src/database.ts
4456
+ init_sys_container();
4457
+ init_utils();
4458
+ init_gateway();
4459
+ var Database = class {
4460
+ constructor(name, opts) {
4461
+ this.opts = {};
4462
+ this._listening = false;
4463
+ this._listeners = /* @__PURE__ */ new Set();
4464
+ this._noupdate_listeners = /* @__PURE__ */ new Set();
4465
+ this._ready = new import_cement17.ResolveOnce();
4466
+ this.name = name;
4467
+ this.opts = opts || this.opts;
4468
+ this.logger = ensureLogger(this.opts, "Database");
4469
+ this._crdt = new CRDT(name, this.opts);
4470
+ this.blockstore = this._crdt.blockstore;
4471
+ this._writeQueue = writeQueue(async (updates) => {
4472
+ return await this._crdt.bulk(updates);
4473
+ });
4474
+ this._crdt.clock.onTock(() => {
4475
+ this._no_update_notify();
4476
+ });
4477
+ }
4478
+ static {
4479
+ this.databases = /* @__PURE__ */ new Map();
4480
+ }
4481
+ async close() {
4482
+ await this.ready();
4483
+ await this._crdt.close();
4484
+ await this.blockstore.close();
4485
+ }
4486
+ async destroy() {
4487
+ await this.ready();
4488
+ await this._crdt.destroy();
4489
+ await this.blockstore.destroy();
4490
+ }
4491
+ async ready() {
4492
+ return this._ready.once(async () => {
4493
+ await SysContainer.start();
4494
+ await this._crdt.ready();
4495
+ await this.blockstore.ready();
4496
+ });
4497
+ }
4498
+ async get(id) {
4499
+ this.logger.Debug().Str("id", id).Msg("get-pre-ready");
4500
+ await this.ready();
4501
+ this.logger.Debug().Str("id", id).Msg("get-post-ready");
4502
+ const got = await this._crdt.get(id).catch((e) => {
4503
+ throw new NotFoundError(`Not found: ${id} - ${e.message}`);
4504
+ });
4505
+ if (!got) throw new NotFoundError(`Not found: ${id}`);
4506
+ const { doc } = got;
4507
+ return { ...doc, _id: id };
4508
+ }
4509
+ async put(doc) {
4510
+ this.logger.Debug().Str("id", doc._id).Msg("put-pre-ready");
4511
+ await this.ready();
4512
+ this.logger.Debug().Str("id", doc._id).Msg("put-post-ready");
4513
+ const { _id, ...value } = doc;
4514
+ const docId = _id || (0, import_uuidv73.uuidv7)();
4515
+ const result = await this._writeQueue.push({
4516
+ id: docId,
4517
+ value: {
4518
+ ...value,
4519
+ _id: docId
4520
+ }
4521
+ });
4522
+ return { id: docId, clock: result?.head };
4523
+ }
4524
+ async del(id) {
4525
+ await this.ready();
4526
+ const result = await this._writeQueue.push({ id, del: true });
4527
+ return { id, clock: result?.head };
4528
+ }
4529
+ async changes(since = [], opts = {}) {
4530
+ await this.ready();
4531
+ const { result, head } = await this._crdt.changes(since, opts);
4532
+ const rows = result.map(({ id: key, value, del, clock }) => ({
4533
+ key,
4534
+ value: del ? { _id: key, _deleted: true } : { _id: key, ...value },
4535
+ clock
4536
+ }));
4537
+ return { rows, clock: head };
4538
+ }
4539
+ async allDocs() {
4540
+ await this.ready();
4541
+ const { result, head } = await this._crdt.allDocs();
4542
+ const rows = result.map(({ id: key, value, del }) => ({
4543
+ key,
4544
+ value: del ? { _id: key, _deleted: true } : { _id: key, ...value }
4545
+ }));
4546
+ return { rows, clock: head };
4547
+ }
4548
+ async allDocuments() {
4549
+ return this.allDocs();
4550
+ }
4551
+ subscribe(listener, updates) {
4552
+ if (updates) {
4553
+ if (!this._listening) {
4554
+ this._listening = true;
4555
+ this._crdt.clock.onTick((updates2) => {
4556
+ void this._notify(updates2);
4557
+ });
4558
+ }
4559
+ this._listeners.add(listener);
4560
+ return () => {
4561
+ this._listeners.delete(listener);
4562
+ };
4563
+ } else {
4564
+ this._noupdate_listeners.add(listener);
4565
+ return () => {
4566
+ this._noupdate_listeners.delete(listener);
4567
+ };
4568
+ }
4569
+ }
4570
+ // todo if we add this onto dbs in fireproof.ts then we can make index.ts a separate package
4571
+ async query(field, opts = {}) {
4572
+ await this.ready();
4573
+ const _crdt = this._crdt;
4574
+ const idx = typeof field === "string" ? index({ _crdt }, field) : index({ _crdt }, makeName(field.toString()), field);
4575
+ return await idx.query(opts);
4576
+ }
4577
+ async compact() {
4578
+ await this.ready();
4579
+ await this._crdt.compact();
4580
+ }
4581
+ async _notify(updates) {
4582
+ await this.ready();
4583
+ if (this._listeners.size) {
4584
+ const docs = updates.map(({ id, value }) => ({ ...value, _id: id }));
4585
+ for (const listener of this._listeners) {
4586
+ await (async () => await listener(docs))().catch((e) => {
4587
+ this.logger.Error().Err(e).Msg("subscriber error");
4588
+ });
4589
+ }
4590
+ }
4591
+ }
4592
+ async _no_update_notify() {
4593
+ await this.ready();
4594
+ if (this._noupdate_listeners.size) {
4595
+ for (const listener of this._noupdate_listeners) {
4596
+ await (async () => await listener([]))().catch((e) => {
4597
+ this.logger.Error().Err(e).Msg("subscriber error");
4598
+ });
4599
+ }
4600
+ }
4601
+ }
4602
+ };
4603
+ function toSortedArray(set) {
4604
+ if (!set) return [];
4605
+ return Object.entries(set).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => ({ [k]: v }));
4606
+ }
4607
+ function fireproof(name, opts) {
4608
+ const key = JSON.stringify(
4609
+ toSortedArray({
4610
+ name,
4611
+ stores: toSortedArray(opts?.store?.stores),
4612
+ makeMetaStore: !!opts?.store?.makeMetaStore,
4613
+ makeDataStore: !!opts?.store?.makeDataStore,
4614
+ makeRemoteWAL: !!opts?.store?.makeRemoteWAL,
4615
+ encodeFile: !!opts?.store?.encodeFile,
4616
+ decodeFile: !!opts?.store?.decodeFile
4617
+ })
4618
+ );
4619
+ let db = Database.databases.get(key);
4620
+ if (!db) {
4621
+ db = new Database(name, opts);
4622
+ Database.databases.set(key, db);
4623
+ }
4624
+ return db;
4625
+ }
4626
+ function makeName(fnString) {
4627
+ const regex = /\(([^,()]+,\s*[^,()]+|\[[^\]]+\],\s*[^,()]+)\)/g;
4628
+ let found = null;
4629
+ const matches = Array.from(fnString.matchAll(regex), (match) => match[1].trim());
4630
+ if (matches.length === 0) {
4631
+ found = /=>\s*(.*)/.exec(fnString);
4632
+ }
4633
+ if (!found) {
4634
+ return fnString;
4635
+ } else {
4636
+ return found[1];
4637
+ }
4638
+ }
4639
+
4640
+ // src/index.ts
4641
+ init_types();
4642
+ init_runtime();
4643
+ init_utils();
4644
+
4645
+ // src/version.ts
4646
+ var PACKAGE_VERSION = Object.keys({
4647
+ "0.19.5-dev": "xxxx"
4648
+ })[0];
4649
+ //# sourceMappingURL=index.cjs.map