@fireproof/core 0.18.0 → 0.19.0-dev-publish

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