@fireproof/core 0.20.0-dev-preview-40 → 0.20.0-dev-preview-50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/deno/index.js +2 -2
- package/deno/index.js.map +1 -1
- package/deno.json +3 -2
- package/index.cjs +955 -599
- package/index.cjs.map +1 -1
- package/index.d.cts +334 -127
- package/index.d.ts +334 -127
- package/index.js +939 -582
- package/index.js.map +1 -1
- package/indexeddb/index.cjs.map +1 -1
- package/indexeddb/index.js.map +1 -1
- package/indexeddb/metafile-cjs.json +1 -1
- package/indexeddb/metafile-esm.json +1 -1
- package/metafile-cjs.json +1 -1
- package/metafile-esm.json +1 -1
- package/package.json +7 -5
- package/react/index.cjs +17 -9
- package/react/index.cjs.map +1 -1
- package/react/index.d.cts +5 -4
- package/react/index.d.ts +5 -4
- package/react/index.js +17 -9
- package/react/index.js.map +1 -1
- package/react/metafile-cjs.json +1 -1
- package/react/metafile-esm.json +1 -1
- package/tests/blockstore/interceptor-gateway.test.ts +15 -1
- package/tests/blockstore/keyed-crypto-indexeddb-file.test.ts +8 -18
- package/tests/blockstore/keyed-crypto.test.ts +31 -53
- package/tests/blockstore/loader.test.ts +21 -19
- package/tests/blockstore/store.test.ts +52 -56
- package/tests/blockstore/transaction.test.ts +13 -11
- package/tests/fireproof/all-gateway.test.ts +53 -50
- package/tests/fireproof/attachable.test.ts +356 -0
- package/tests/fireproof/crdt.test.ts +100 -60
- package/tests/fireproof/database.test.ts +95 -54
- package/tests/fireproof/fireproof.test.ts +58 -55
- package/tests/fireproof/hello.test.ts +4 -4
- package/tests/fireproof/indexer.test.ts +44 -44
- package/tests/fireproof/stable-cid.test.ts +69 -0
- package/tests/fireproof/utils.test.ts +21 -10
- package/tests/gateway/file/loader-config.test.ts +25 -25
- package/tests/gateway/fp-envelope-serialize.test.ts +8 -8
- package/tests/gateway/indexeddb/loader-config.test.ts +6 -6
- package/tests/helpers.ts +81 -2
- package/tests/react/useFireproof.test.tsx +59 -17
package/index.cjs
CHANGED
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
31
31
|
var index_exports = {};
|
32
32
|
__export(index_exports, {
|
33
33
|
CRDTImpl: () => CRDTImpl,
|
34
|
+
DataAndMetaAndWalAndBaseStore: () => DataAndMetaAndWalAndBaseStore,
|
34
35
|
DatabaseImpl: () => DatabaseImpl,
|
35
36
|
Index: () => Index,
|
36
37
|
LedgerFactory: () => LedgerFactory,
|
@@ -47,6 +48,7 @@ __export(index_exports, {
|
|
47
48
|
ensureLogger: () => ensureLogger,
|
48
49
|
ensureSuperLog: () => ensureSuperLog,
|
49
50
|
ensureSuperThis: () => ensureSuperThis,
|
51
|
+
ensureURIDefaults: () => ensureURIDefaults,
|
50
52
|
exceptionWrapper: () => exceptionWrapper,
|
51
53
|
falsyToUndef: () => falsyToUndef,
|
52
54
|
fireproof: () => fireproof,
|
@@ -64,6 +66,7 @@ __export(index_exports, {
|
|
64
66
|
onSuperThis: () => onSuperThis,
|
65
67
|
rt: () => runtime_exports,
|
66
68
|
runtime: () => runtime_exports,
|
69
|
+
storeType2DataMetaWal: () => storeType2DataMetaWal,
|
67
70
|
throwFalsy: () => throwFalsy,
|
68
71
|
toSortedArray: () => toSortedArray,
|
69
72
|
toStoreURIRuntime: () => toStoreURIRuntime
|
@@ -100,8 +103,13 @@ var PARAM = {
|
|
100
103
|
FRAG_LEN: "len",
|
101
104
|
FRAG_HEAD: "headerSize",
|
102
105
|
EXTRACTKEY: "extractKey",
|
103
|
-
SELF_REFLECT: "selfReflect"
|
106
|
+
SELF_REFLECT: "selfReflect",
|
104
107
|
// if no subscribe in Gateway see your own META updates
|
108
|
+
CAR_PARALLEL: "parallel",
|
109
|
+
CAR_CACHE_SIZE: "carCacheSize",
|
110
|
+
CAR_COMPACT_CACHE_SIZE: "carCompactCacheSize",
|
111
|
+
CAR_META_CACHE_SIZE: "carMetaCacheSize",
|
112
|
+
GENESIS_CID: "baembeiarootfireproofgenesisblockaaaafireproofgenesisblocka"
|
105
113
|
// FS = "fs",
|
106
114
|
};
|
107
115
|
function throwFalsy(value) {
|
@@ -116,6 +124,18 @@ function falsyToUndef(value) {
|
|
116
124
|
}
|
117
125
|
return value;
|
118
126
|
}
|
127
|
+
var DataAndMetaAndWalAndBaseStore = class {
|
128
|
+
constructor(dam) {
|
129
|
+
this.wal = dam.wal;
|
130
|
+
this.file = dam.file;
|
131
|
+
this.car = dam.car;
|
132
|
+
this.meta = dam.meta;
|
133
|
+
this.baseStores = [this.file, this.car, this.meta];
|
134
|
+
if (this.wal) {
|
135
|
+
this.baseStores.push(this.wal);
|
136
|
+
}
|
137
|
+
}
|
138
|
+
};
|
119
139
|
|
120
140
|
// src/utils.ts
|
121
141
|
var import_base58 = require("multiformats/bases/base58");
|
@@ -326,21 +346,25 @@ function ensureLogger(sthis, componentName, ctx) {
|
|
326
346
|
return out;
|
327
347
|
}
|
328
348
|
function getStore(url, sthis, joiner) {
|
329
|
-
const
|
330
|
-
|
331
|
-
|
349
|
+
const fromUrl = url.getParam(PARAM.STORE);
|
350
|
+
let pathPart;
|
351
|
+
switch (fromUrl) {
|
352
|
+
case "car":
|
353
|
+
case "file":
|
354
|
+
pathPart = "data";
|
355
|
+
break;
|
332
356
|
case "wal":
|
333
357
|
case "meta":
|
358
|
+
pathPart = fromUrl;
|
334
359
|
break;
|
335
360
|
default:
|
336
361
|
throw sthis.logger.Error().Url(url).Msg(`store not found`).AsError();
|
337
|
-
throw sthis.logger.Error().Url(url).Msg(`store not found`).AsError();
|
338
362
|
}
|
339
|
-
let name =
|
363
|
+
let name = pathPart;
|
340
364
|
if (url.hasParam("index")) {
|
341
365
|
name = joiner(url.getParam(PARAM.INDEX) || "idx", name);
|
342
366
|
}
|
343
|
-
return {
|
367
|
+
return { pathPart, fromUrl, name };
|
344
368
|
}
|
345
369
|
function getKey(url, logger) {
|
346
370
|
const result = url.getParam(PARAM.KEY);
|
@@ -442,6 +466,35 @@ function makeName(fnString) {
|
|
442
466
|
return found[1];
|
443
467
|
}
|
444
468
|
}
|
469
|
+
function storeType2DataMetaWal(store) {
|
470
|
+
switch (store) {
|
471
|
+
case "car":
|
472
|
+
case "file":
|
473
|
+
return "data";
|
474
|
+
case "meta":
|
475
|
+
case "wal":
|
476
|
+
return store;
|
477
|
+
default:
|
478
|
+
throw new Error(`unknown store ${store}`);
|
479
|
+
}
|
480
|
+
}
|
481
|
+
function ensureURIDefaults(sthis, name, curi, uri, store, ctx) {
|
482
|
+
ctx = ctx || {};
|
483
|
+
const ret = (curi ? import_cement.URI.from(curi) : uri).build().setParam(PARAM.STORE, store).defParam(PARAM.NAME, name);
|
484
|
+
if (!ret.hasParam(PARAM.NAME)) {
|
485
|
+
throw sthis.logger.Error().Url(ret).Any("ctx", ctx).Msg("Ledger name is required").AsError();
|
486
|
+
}
|
487
|
+
if (ctx.idx) {
|
488
|
+
ret.defParam(PARAM.INDEX, "idx");
|
489
|
+
ret.defParam(PARAM.STORE_KEY, `@${ret.getParam(PARAM.NAME)}-${storeType2DataMetaWal(store)}-idx@`);
|
490
|
+
} else {
|
491
|
+
ret.defParam(PARAM.STORE_KEY, `@${ret.getParam(PARAM.NAME)}-${storeType2DataMetaWal(store)}@`);
|
492
|
+
}
|
493
|
+
if (store === "car") {
|
494
|
+
ret.defParam(PARAM.SUFFIX, ".car");
|
495
|
+
}
|
496
|
+
return ret.URI();
|
497
|
+
}
|
445
498
|
|
446
499
|
// src/write-queue.ts
|
447
500
|
var import_cement2 = require("@adviser/cement");
|
@@ -1123,8 +1176,10 @@ function getFileName(url, sthis) {
|
|
1123
1176
|
const key = url.getParam("key");
|
1124
1177
|
if (!key) throw sthis.logger.Error().Url(url).Msg(`key not found`).AsError();
|
1125
1178
|
const res = (0, import_core.getStore)(url, sthis, (...a) => a.join("-"));
|
1126
|
-
switch (res.
|
1127
|
-
case "
|
1179
|
+
switch (res.fromUrl) {
|
1180
|
+
case "file":
|
1181
|
+
return sthis.pathOps.join(res.name, key);
|
1182
|
+
case "car":
|
1128
1183
|
return sthis.pathOps.join(res.name, key + ".car");
|
1129
1184
|
case "wal":
|
1130
1185
|
case "meta":
|
@@ -1272,8 +1327,13 @@ var MemoryGateway = class {
|
|
1272
1327
|
close(baseUrl) {
|
1273
1328
|
return Promise.resolve(import_cement6.Result.Ok(void 0));
|
1274
1329
|
}
|
1275
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
1276
1330
|
destroy(baseUrl) {
|
1331
|
+
const keyUrl = baseUrl.toString();
|
1332
|
+
for (const key of this.memorys.keys()) {
|
1333
|
+
if (key.startsWith(keyUrl)) {
|
1334
|
+
this.memorys.delete(key);
|
1335
|
+
}
|
1336
|
+
}
|
1277
1337
|
this.memorys.clear();
|
1278
1338
|
return Promise.resolve(import_cement6.Result.Ok(void 0));
|
1279
1339
|
}
|
@@ -1285,7 +1345,7 @@ var MemoryGateway = class {
|
|
1285
1345
|
get(url) {
|
1286
1346
|
const x = this.memorys.get(url.toString());
|
1287
1347
|
if (!x) {
|
1288
|
-
return Promise.resolve(import_cement6.Result.Err(new NotFoundError(
|
1348
|
+
return Promise.resolve(import_cement6.Result.Err(new NotFoundError(`not found: ${url.toString()}`)));
|
1289
1349
|
}
|
1290
1350
|
return Promise.resolve(import_cement6.Result.Ok(x));
|
1291
1351
|
}
|
@@ -1391,9 +1451,6 @@ async function decode2DbMetaEvents(sthis, rserializedMeta) {
|
|
1391
1451
|
if (!Array.isArray(serializedMeta)) {
|
1392
1452
|
return sthis.logger.Debug().Any("metaEntries", serializedMeta).Msg("No data in MetaEntries").ResultError();
|
1393
1453
|
}
|
1394
|
-
if (!serializedMeta.length) {
|
1395
|
-
return sthis.logger.Debug().Msg("No MetaEntries found").ResultError();
|
1396
|
-
}
|
1397
1454
|
return import_cement8.Result.Ok(
|
1398
1455
|
await Promise.all(
|
1399
1456
|
serializedMeta.map(async (metaEntry) => {
|
@@ -1458,10 +1515,9 @@ async function fpDeserialize(sthis, url, intoRaw, pdecoder) {
|
|
1458
1515
|
...pdecoder
|
1459
1516
|
};
|
1460
1517
|
switch (url.getParam(PARAM.STORE)) {
|
1461
|
-
case "
|
1462
|
-
|
1463
|
-
|
1464
|
-
}
|
1518
|
+
case "car":
|
1519
|
+
return makeFPEnvelope(FPEnvelopeTypes.CAR, await decoder.car(sthis, raw2));
|
1520
|
+
case "file":
|
1465
1521
|
return makeFPEnvelope(FPEnvelopeTypes.FILE, await decoder.file(sthis, raw2));
|
1466
1522
|
case "wal":
|
1467
1523
|
return makeFPEnvelope(FPEnvelopeTypes.WAL, await decode2WalState(sthis, await decoder.wal(sthis, raw2)));
|
@@ -1523,7 +1579,7 @@ var DefSerdeGateway = class {
|
|
1523
1579
|
const urlWithoutKey = url.build().delParam(PARAM.KEY).delParam(PARAM.SELF_REFLECT).toString();
|
1524
1580
|
this.subscribeFn.set(urlWithoutKey, rawCallback);
|
1525
1581
|
return import_cement9.Result.Ok(() => {
|
1526
|
-
this.subscribeFn.delete(
|
1582
|
+
this.subscribeFn.delete(urlWithoutKey);
|
1527
1583
|
});
|
1528
1584
|
}
|
1529
1585
|
const unreg = await this.gw.subscribe(url, rawCallback, sthis);
|
@@ -1652,37 +1708,49 @@ var Block = import_block.Block;
|
|
1652
1708
|
async function decode({
|
1653
1709
|
bytes,
|
1654
1710
|
codec: codec3,
|
1655
|
-
hasher:
|
1711
|
+
hasher: hasher6
|
1656
1712
|
}) {
|
1657
1713
|
if (bytes == null) throw new Error('Missing required argument "bytes"');
|
1658
|
-
if (codec3 == null ||
|
1714
|
+
if (codec3 == null || hasher6 == null) throw new Error("Missing required argument: codec or hasher");
|
1659
1715
|
const value = await Promise.resolve(codec3.decode(bytes));
|
1660
|
-
|
1716
|
+
let toHash = bytes;
|
1717
|
+
if (codec3.valueToHashBytes) {
|
1718
|
+
toHash = await Promise.resolve(codec3.valueToHashBytes(value));
|
1719
|
+
}
|
1720
|
+
const hash = await hasher6.digest(toHash);
|
1661
1721
|
const cid = import_multiformats2.CID.create(1, codec3.code, hash);
|
1662
|
-
return new import_block.Block({ value, bytes, cid });
|
1722
|
+
return new import_block.Block({ value, bytes: toHash, cid });
|
1663
1723
|
}
|
1664
1724
|
async function encode({
|
1665
1725
|
value,
|
1666
1726
|
codec: codec3,
|
1667
|
-
hasher:
|
1727
|
+
hasher: hasher6
|
1668
1728
|
}) {
|
1669
1729
|
if (typeof value === "undefined") throw new Error('Missing required argument "value"');
|
1670
|
-
if (codec3 == null ||
|
1671
|
-
|
1672
|
-
|
1730
|
+
if (codec3 == null || hasher6 == null) throw new Error("Missing required argument: codec or hasher");
|
1731
|
+
let bytes;
|
1732
|
+
let hash;
|
1733
|
+
if (codec3.bytesToHash) {
|
1734
|
+
const hashable = await Promise.resolve(codec3.bytesToHash(value));
|
1735
|
+
hash = await hasher6.digest(hashable);
|
1736
|
+
bytes = await Promise.resolve(codec3.encode(value));
|
1737
|
+
} else {
|
1738
|
+
bytes = await Promise.resolve(codec3.encode(value));
|
1739
|
+
hash = await hasher6.digest(bytes);
|
1740
|
+
}
|
1673
1741
|
const cid = import_multiformats2.CID.create(1, codec3.code, hash);
|
1674
|
-
return new
|
1742
|
+
return new Block({ value, bytes, cid });
|
1675
1743
|
}
|
1676
1744
|
async function create({
|
1677
1745
|
bytes,
|
1678
1746
|
cid,
|
1679
|
-
hasher:
|
1747
|
+
hasher: hasher6,
|
1680
1748
|
codec: codec3
|
1681
1749
|
}) {
|
1682
1750
|
if (bytes == null) throw new Error('Missing required argument "bytes"');
|
1683
|
-
if (
|
1751
|
+
if (hasher6 == null) throw new Error('Missing required argument "hasher"');
|
1684
1752
|
const value = await Promise.resolve(codec3.decode(bytes));
|
1685
|
-
const hash = await
|
1753
|
+
const hash = await hasher6.digest(bytes);
|
1686
1754
|
if (!import_multiformats2.bytes.equals(cid.multihash.bytes, hash.bytes)) {
|
1687
1755
|
throw new Error("CID hash does not match bytes");
|
1688
1756
|
}
|
@@ -2080,6 +2148,9 @@ var DatabaseImpl = class {
|
|
2080
2148
|
this.id = ledger.id;
|
2081
2149
|
this.logger = ensureLogger(this.sthis, "Database");
|
2082
2150
|
}
|
2151
|
+
attach(a) {
|
2152
|
+
return this.ledger.attach(a);
|
2153
|
+
}
|
2083
2154
|
get name() {
|
2084
2155
|
return this.ledger.name;
|
2085
2156
|
}
|
@@ -2175,19 +2246,27 @@ var import_cement19 = require("@adviser/cement");
|
|
2175
2246
|
// src/blockstore/index.ts
|
2176
2247
|
var blockstore_exports = {};
|
2177
2248
|
__export(blockstore_exports, {
|
2249
|
+
AttachedRemotesImpl: () => AttachedRemotesImpl,
|
2250
|
+
BaseActiveStore: () => BaseActiveStore,
|
2178
2251
|
BaseBlockstoreImpl: () => BaseBlockstoreImpl,
|
2179
2252
|
Car2FPMsg: () => Car2FPMsg,
|
2253
|
+
CarActiveStore: () => CarActiveStore,
|
2254
|
+
CarLog: () => CarLog,
|
2180
2255
|
CarTransactionImpl: () => CarTransactionImpl,
|
2181
2256
|
CompactionFetcher: () => CompactionFetcher,
|
2182
|
-
ConnectionBase: () => ConnectionBase,
|
2183
2257
|
DbMetaEventEqual: () => DbMetaEventEqual,
|
2184
2258
|
DbMetaEventsEqual: () => DbMetaEventsEqual,
|
2185
2259
|
EncryptedBlockstore: () => EncryptedBlockstore,
|
2186
2260
|
FPEnvelopeTypes: () => FPEnvelopeTypes,
|
2187
2261
|
File2FPMsg: () => File2FPMsg,
|
2262
|
+
FileActiveStore: () => FileActiveStore,
|
2188
2263
|
InterceptorGateway: () => InterceptorGateway,
|
2189
2264
|
Loader: () => Loader,
|
2265
|
+
MetaActiveStore: () => MetaActiveStore,
|
2190
2266
|
PassThroughGateway: () => PassThroughGateway,
|
2267
|
+
TaskManager: () => TaskManager,
|
2268
|
+
WALActiveStore: () => WALActiveStore,
|
2269
|
+
createAttachedStores: () => createAttachedStores,
|
2191
2270
|
createDbMetaEvent: () => createDbMetaEvent,
|
2192
2271
|
defaultGatewayFactoryItem: () => defaultGatewayFactoryItem,
|
2193
2272
|
ensureStoreEnDeFile: () => ensureStoreEnDeFile,
|
@@ -2201,6 +2280,37 @@ __export(blockstore_exports, {
|
|
2201
2280
|
});
|
2202
2281
|
|
2203
2282
|
// src/blockstore/types.ts
|
2283
|
+
var CarLog = class {
|
2284
|
+
constructor() {
|
2285
|
+
this._logs = [];
|
2286
|
+
}
|
2287
|
+
get length() {
|
2288
|
+
return this._logs.length;
|
2289
|
+
}
|
2290
|
+
last() {
|
2291
|
+
const x = [...this._logs[this._logs.length - 1]];
|
2292
|
+
Object.freeze(x);
|
2293
|
+
return x;
|
2294
|
+
}
|
2295
|
+
xunshift(logs) {
|
2296
|
+
this._logs.unshift(logs);
|
2297
|
+
}
|
2298
|
+
update(logs) {
|
2299
|
+
this._logs.length = 0;
|
2300
|
+
this._logs.push(...logs);
|
2301
|
+
}
|
2302
|
+
asArray() {
|
2303
|
+
const a = [
|
2304
|
+
...this._logs.map((l) => {
|
2305
|
+
const x = [...l];
|
2306
|
+
Object.freeze(x);
|
2307
|
+
return x;
|
2308
|
+
})
|
2309
|
+
];
|
2310
|
+
Object.freeze(a);
|
2311
|
+
return a;
|
2312
|
+
}
|
2313
|
+
};
|
2204
2314
|
function toCIDBlock(block) {
|
2205
2315
|
return block;
|
2206
2316
|
}
|
@@ -2210,24 +2320,34 @@ function DbMetaEventEqual(a, b) {
|
|
2210
2320
|
function DbMetaEventsEqual(a, b) {
|
2211
2321
|
return a.length === b.length && a.every((e, i) => DbMetaEventEqual(e, b[i]));
|
2212
2322
|
}
|
2323
|
+
var BaseActiveStore = class {
|
2324
|
+
};
|
2325
|
+
var CarActiveStore = class extends BaseActiveStore {
|
2326
|
+
};
|
2327
|
+
var FileActiveStore = class extends BaseActiveStore {
|
2328
|
+
};
|
2329
|
+
var MetaActiveStore = class extends BaseActiveStore {
|
2330
|
+
};
|
2331
|
+
var WALActiveStore = class extends BaseActiveStore {
|
2332
|
+
};
|
2213
2333
|
|
2214
2334
|
// src/blockstore/store-factory.ts
|
2215
|
-
var
|
2335
|
+
var import_cement17 = require("@adviser/cement");
|
2216
2336
|
|
2217
2337
|
// src/blockstore/store.ts
|
2218
|
-
var
|
2338
|
+
var import_cement16 = require("@adviser/cement");
|
2219
2339
|
|
2220
2340
|
// src/blockstore/loader.ts
|
2221
2341
|
var import_p_limit = __toESM(require("p-limit"), 1);
|
2222
2342
|
var import_reader = require("@ipld/car/reader");
|
2223
|
-
var
|
2343
|
+
var import_cement14 = require("@adviser/cement");
|
2224
2344
|
|
2225
2345
|
// src/blockstore/loader-helpers.ts
|
2226
2346
|
var import_sha22 = require("multiformats/hashes/sha2");
|
2227
2347
|
var dagCodec = __toESM(require("@ipld/dag-cbor"), 1);
|
2228
2348
|
async function parseCarFile(reader, logger) {
|
2229
|
-
const roots = await reader.
|
2230
|
-
const header =
|
2349
|
+
const roots = await reader.roots;
|
2350
|
+
const header = reader.blocks.find((i) => i.cid.equals(roots[0]));
|
2231
2351
|
if (!header) throw logger.Error().Msg("missing header block").AsError();
|
2232
2352
|
const dec = await decode({ bytes: header.bytes, hasher: import_sha22.sha256, codec: dagCodec });
|
2233
2353
|
const fpvalue = dec.value;
|
@@ -2242,6 +2362,7 @@ var import_block4 = require("@fireproof/vendor/@web3-storage/pail/block");
|
|
2242
2362
|
var import_cement11 = require("@adviser/cement");
|
2243
2363
|
var CarTransactionImpl = class {
|
2244
2364
|
#memblock = new import_block4.MemoryBlockstore();
|
2365
|
+
#hackUnshift;
|
2245
2366
|
constructor(parent, opts = { add: true, noLoader: false }) {
|
2246
2367
|
if (opts.add) {
|
2247
2368
|
parent.transactions.add(this);
|
@@ -2249,7 +2370,7 @@ var CarTransactionImpl = class {
|
|
2249
2370
|
this.parent = parent;
|
2250
2371
|
}
|
2251
2372
|
async get(cid) {
|
2252
|
-
return await this.superGet(cid)
|
2373
|
+
return await this.superGet(cid) ?? falsyToUndef(await this.parent.get(cid));
|
2253
2374
|
}
|
2254
2375
|
async superGet(cid) {
|
2255
2376
|
return this.#memblock.get(cid);
|
@@ -2260,7 +2381,16 @@ var CarTransactionImpl = class {
|
|
2260
2381
|
putSync(cid, bytes) {
|
2261
2382
|
this.#memblock.putSync(cid, bytes);
|
2262
2383
|
}
|
2384
|
+
unshift(cid, bytes) {
|
2385
|
+
if (this.#hackUnshift) {
|
2386
|
+
throw new Error("unshift already called");
|
2387
|
+
}
|
2388
|
+
this.#hackUnshift = { cid, bytes };
|
2389
|
+
}
|
2263
2390
|
async *entries() {
|
2391
|
+
if (this.#hackUnshift) {
|
2392
|
+
yield this.#hackUnshift;
|
2393
|
+
}
|
2264
2394
|
for await (const blk of this.#memblock.entries()) {
|
2265
2395
|
yield blk;
|
2266
2396
|
}
|
@@ -2286,6 +2416,11 @@ function defaultedBlockstoreRuntime(sthis, opts, component, ctx) {
|
|
2286
2416
|
keyBag: opts.keyBag || {},
|
2287
2417
|
crypto: (0, import_cement11.toCryptoRuntime)(opts.crypto),
|
2288
2418
|
storeUrls: opts.storeUrls,
|
2419
|
+
taskManager: {
|
2420
|
+
removeAfter: 3,
|
2421
|
+
retryTimeout: 50,
|
2422
|
+
...opts.taskManager
|
2423
|
+
},
|
2289
2424
|
// storeEnDeFile: ensureStoreEnDeFile(opts.storeEnDeFile),
|
2290
2425
|
// store,
|
2291
2426
|
storeRuntime: toStoreRuntime(sthis, ensureStoreEnDeFile(opts.storeEnDeFile))
|
@@ -2378,10 +2513,8 @@ var EncryptedBlockstore = class extends BaseBlockstoreImpl {
|
|
2378
2513
|
async get(cid) {
|
2379
2514
|
const got = await super.get(cid);
|
2380
2515
|
if (got) return got;
|
2381
|
-
|
2382
|
-
|
2383
|
-
}
|
2384
|
-
return falsyToUndef(await this.loader.getBlock(cid));
|
2516
|
+
const ret = falsyToUndef(await this.loader.getBlock(cid, this.loader.attachedStores.local()));
|
2517
|
+
return ret;
|
2385
2518
|
}
|
2386
2519
|
async transaction(fn, opts = { noLoader: false }) {
|
2387
2520
|
this.logger.Debug().Msg("enter transaction");
|
@@ -2401,11 +2534,8 @@ var EncryptedBlockstore = class extends BaseBlockstoreImpl {
|
|
2401
2534
|
async getFile(car, cid) {
|
2402
2535
|
await this.ready();
|
2403
2536
|
if (!this.loader) throw this.logger.Error().Msg("loader required to get file, ledger must be named").AsError();
|
2404
|
-
const reader = await this.loader.loadFileCar(
|
2405
|
-
|
2406
|
-
/*, isPublic */
|
2407
|
-
);
|
2408
|
-
const block = await reader.get(cid);
|
2537
|
+
const reader = await this.loader.loadFileCar(car, this.loader.attachedStores.local());
|
2538
|
+
const block = await reader.blocks.find((i) => i.cid.equals(cid));
|
2409
2539
|
if (!block) throw this.logger.Error().Str("cid", cid.toString()).Msg(`Missing block`).AsError();
|
2410
2540
|
return block.bytes;
|
2411
2541
|
}
|
@@ -2512,8 +2642,8 @@ var CommitQueue = class {
|
|
2512
2642
|
|
2513
2643
|
// src/blockstore/commitor.ts
|
2514
2644
|
var CBW = __toESM(require("@ipld/car/buffer-writer"), 1);
|
2515
|
-
var import_sha23 = require("multiformats/hashes/sha2");
|
2516
2645
|
var dagCodec2 = __toESM(require("@ipld/dag-cbor"), 1);
|
2646
|
+
var import_sha23 = require("multiformats/hashes/sha2");
|
2517
2647
|
async function encodeCarFile(roots, t, codec3) {
|
2518
2648
|
let size = 0;
|
2519
2649
|
const headerSize = CBW.headerLength({ roots });
|
@@ -2538,7 +2668,7 @@ async function createCarFile(encoder, cid, t) {
|
|
2538
2668
|
async function commitFiles(fileStore, walStore, t, done) {
|
2539
2669
|
const { files: roots } = makeFileCarHeader(done);
|
2540
2670
|
const cids = [];
|
2541
|
-
const codec3 =
|
2671
|
+
const codec3 = await fileStore.keyedCrypto().then((i) => i.codec());
|
2542
2672
|
const cars = await prepareCarFilesFiles(codec3, roots, t);
|
2543
2673
|
for (const car of cars) {
|
2544
2674
|
const { cid, bytes } = car;
|
@@ -2564,7 +2694,7 @@ async function prepareCarFilesFiles(encoder, roots, t) {
|
|
2564
2694
|
return [await encodeCarFile(roots, t, encoder)];
|
2565
2695
|
}
|
2566
2696
|
function makeCarHeader(meta, cars, compact = false) {
|
2567
|
-
const coreHeader = compact ? { cars: [], compact: cars } : { cars, compact: [] };
|
2697
|
+
const coreHeader = compact ? { cars: [], compact: cars.asArray() } : { cars: cars.asArray(), compact: [] };
|
2568
2698
|
return { ...coreHeader, meta };
|
2569
2699
|
}
|
2570
2700
|
async function encodeCarHeader(fp) {
|
@@ -2591,7 +2721,7 @@ async function commit(params, t, done, opts = { noLoader: false, compact: false
|
|
2591
2721
|
}
|
2592
2722
|
async function prepareCarFiles(encoder, threshold, rootBlock, t) {
|
2593
2723
|
const carFiles = [];
|
2594
|
-
threshold = threshold ||
|
2724
|
+
threshold = threshold || 16 * 65536;
|
2595
2725
|
let clonedt = new CarTransactionImpl(t.parent, { add: false, noLoader: false });
|
2596
2726
|
clonedt.putSync(rootBlock.cid, rootBlock.bytes);
|
2597
2727
|
let newsize = CBW.blockLength(toCIDBlock(rootBlock));
|
@@ -2617,19 +2747,20 @@ var import_sha24 = require("multiformats/hashes/sha2");
|
|
2617
2747
|
|
2618
2748
|
// src/blockstore/task-manager.ts
|
2619
2749
|
var TaskManager = class {
|
2620
|
-
constructor(sthis, callback) {
|
2750
|
+
constructor(sthis, callback, params) {
|
2621
2751
|
// we need to remove the events after some time
|
2622
2752
|
this.eventsWeHandled = /* @__PURE__ */ new Set();
|
2623
2753
|
this.queue = [];
|
2624
2754
|
this.isProcessing = false;
|
2625
2755
|
this.logger = ensureLogger(sthis, "TaskManager");
|
2626
2756
|
this.callback = callback;
|
2757
|
+
this.params = params;
|
2627
2758
|
}
|
2628
|
-
async handleEvent(cid, parents, dbMeta) {
|
2759
|
+
async handleEvent(cid, parents, dbMeta, store) {
|
2629
2760
|
for (const parent of parents) {
|
2630
2761
|
this.eventsWeHandled.add(parent.toString());
|
2631
2762
|
}
|
2632
|
-
this.queue.push({ cid: cid.toString(), dbMeta, retries: 0 });
|
2763
|
+
this.queue.push({ cid: cid.toString(), dbMeta, retries: 0, store });
|
2633
2764
|
this.queue = this.queue.filter(({ cid: cid2 }) => !this.eventsWeHandled.has(cid2));
|
2634
2765
|
void this.processQueue();
|
2635
2766
|
}
|
@@ -2643,7 +2774,7 @@ var TaskManager = class {
|
|
2643
2774
|
return;
|
2644
2775
|
}
|
2645
2776
|
try {
|
2646
|
-
await this.callback(first.dbMeta);
|
2777
|
+
await this.callback(first.dbMeta, first.store);
|
2647
2778
|
this.eventsWeHandled.add(first.cid);
|
2648
2779
|
this.queue = this.queue.filter(({ cid }) => !this.eventsWeHandled.has(cid));
|
2649
2780
|
} catch (err) {
|
@@ -2652,7 +2783,7 @@ var TaskManager = class {
|
|
2652
2783
|
this.queue = this.queue.filter(({ cid }) => cid !== first.cid);
|
2653
2784
|
}
|
2654
2785
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
2655
|
-
|
2786
|
+
this.logger.Warn().Err(err).Msg("retry to process event block");
|
2656
2787
|
} finally {
|
2657
2788
|
this.isProcessing = false;
|
2658
2789
|
if (this.queue.length > 0) {
|
@@ -2662,13 +2793,299 @@ var TaskManager = class {
|
|
2662
2793
|
}
|
2663
2794
|
};
|
2664
2795
|
|
2796
|
+
// src/blockstore/attachable-store.ts
|
2797
|
+
var import_cement13 = require("@adviser/cement");
|
2798
|
+
var AttachedImpl = class {
|
2799
|
+
constructor(gws, stores, unreg) {
|
2800
|
+
this.gatewayUrls = gws;
|
2801
|
+
this.stores = new DataAndMetaAndWalAndBaseStore(stores);
|
2802
|
+
this.unreg = unreg;
|
2803
|
+
}
|
2804
|
+
async detach() {
|
2805
|
+
const toClose = [this.stores.car.close(), this.stores.file.close(), this.stores.meta.close()];
|
2806
|
+
if (this.stores.wal) {
|
2807
|
+
toClose.push(this.stores.wal.close());
|
2808
|
+
}
|
2809
|
+
await Promise.all(toClose);
|
2810
|
+
this.unreg();
|
2811
|
+
}
|
2812
|
+
status() {
|
2813
|
+
return "attached";
|
2814
|
+
}
|
2815
|
+
};
|
2816
|
+
var FileActiveStoreImpl = class extends FileActiveStore {
|
2817
|
+
constructor(ref, active, attached) {
|
2818
|
+
super();
|
2819
|
+
this.ref = ref;
|
2820
|
+
this.active = active;
|
2821
|
+
this.xattached = attached;
|
2822
|
+
}
|
2823
|
+
local() {
|
2824
|
+
return this.xattached.local();
|
2825
|
+
}
|
2826
|
+
remotes() {
|
2827
|
+
return this.xattached.remotes();
|
2828
|
+
}
|
2829
|
+
};
|
2830
|
+
var CarActiveStoreImpl = class extends CarActiveStore {
|
2831
|
+
constructor(ref, active, attached) {
|
2832
|
+
super();
|
2833
|
+
this.ref = ref;
|
2834
|
+
this.active = active;
|
2835
|
+
this.xattached = attached;
|
2836
|
+
}
|
2837
|
+
local() {
|
2838
|
+
return this.xattached.local();
|
2839
|
+
}
|
2840
|
+
remotes() {
|
2841
|
+
return [this.active, ...this.xattached.remotes().filter((i) => i !== this.active)];
|
2842
|
+
}
|
2843
|
+
};
|
2844
|
+
var CarAttachedStoresImpl = class {
|
2845
|
+
constructor(attached) {
|
2846
|
+
this.attached = attached;
|
2847
|
+
}
|
2848
|
+
local() {
|
2849
|
+
return this.attached.local().active.car;
|
2850
|
+
}
|
2851
|
+
remotes() {
|
2852
|
+
return this.attached.remotes().map(({ active }) => active.car);
|
2853
|
+
}
|
2854
|
+
};
|
2855
|
+
var FileAttachedStoresImpl = class {
|
2856
|
+
constructor(attached) {
|
2857
|
+
this.attached = attached;
|
2858
|
+
}
|
2859
|
+
local() {
|
2860
|
+
return this.attached.local().active.file;
|
2861
|
+
}
|
2862
|
+
remotes() {
|
2863
|
+
return this.attached.remotes().map(({ active }) => active.file);
|
2864
|
+
}
|
2865
|
+
};
|
2866
|
+
var MetaActiveStoreImpl = class extends MetaActiveStore {
|
2867
|
+
constructor(ref, active, attached) {
|
2868
|
+
super();
|
2869
|
+
this.ref = ref;
|
2870
|
+
this.active = active;
|
2871
|
+
this.xattached = attached;
|
2872
|
+
}
|
2873
|
+
local() {
|
2874
|
+
return this.xattached.local();
|
2875
|
+
}
|
2876
|
+
remotes() {
|
2877
|
+
return [this.active, ...this.xattached.remotes().filter((i) => i !== this.active)];
|
2878
|
+
}
|
2879
|
+
};
|
2880
|
+
var MetaAttachedStoresImpl = class {
|
2881
|
+
constructor(attached) {
|
2882
|
+
this.attached = attached;
|
2883
|
+
}
|
2884
|
+
local() {
|
2885
|
+
return this.attached.local().active.meta;
|
2886
|
+
}
|
2887
|
+
remotes() {
|
2888
|
+
return this.attached.remotes().map(({ active }) => active.meta);
|
2889
|
+
}
|
2890
|
+
};
|
2891
|
+
var WALActiveStoreImpl = class extends WALActiveStore {
|
2892
|
+
constructor(ref, active, attached) {
|
2893
|
+
super();
|
2894
|
+
this.ref = ref;
|
2895
|
+
this.active = active;
|
2896
|
+
this.xattached = attached;
|
2897
|
+
}
|
2898
|
+
local() {
|
2899
|
+
return this.xattached.local();
|
2900
|
+
}
|
2901
|
+
remotes() {
|
2902
|
+
return this.xattached.remotes();
|
2903
|
+
}
|
2904
|
+
};
|
2905
|
+
var WALAttachedStoresImpl = class {
|
2906
|
+
constructor(attached) {
|
2907
|
+
this.attached = attached;
|
2908
|
+
}
|
2909
|
+
local() {
|
2910
|
+
return this.attached.local().active.wal;
|
2911
|
+
}
|
2912
|
+
remotes() {
|
2913
|
+
return this.attached.remotes().filter(({ active }) => active.wal).map(({ active }) => active.wal);
|
2914
|
+
}
|
2915
|
+
};
|
2916
|
+
var ActiveStoreImpl = class {
|
2917
|
+
constructor(active, attached) {
|
2918
|
+
this.active = active;
|
2919
|
+
this.xattached = attached;
|
2920
|
+
}
|
2921
|
+
local() {
|
2922
|
+
return this.xattached.local();
|
2923
|
+
}
|
2924
|
+
remotes() {
|
2925
|
+
return this.xattached.remotes();
|
2926
|
+
}
|
2927
|
+
baseStores() {
|
2928
|
+
const bs = [this.active.car, this.active.file, this.active.meta];
|
2929
|
+
if (this.active.wal) {
|
2930
|
+
bs.push(this.active.wal);
|
2931
|
+
}
|
2932
|
+
return bs;
|
2933
|
+
}
|
2934
|
+
carStore() {
|
2935
|
+
return new CarActiveStoreImpl(this, this.active.car, new CarAttachedStoresImpl(this.xattached));
|
2936
|
+
}
|
2937
|
+
fileStore() {
|
2938
|
+
return new FileActiveStoreImpl(this, this.active.file, new FileAttachedStoresImpl(this.xattached));
|
2939
|
+
}
|
2940
|
+
metaStore() {
|
2941
|
+
return new MetaActiveStoreImpl(this, this.active.meta, new MetaAttachedStoresImpl(this.xattached));
|
2942
|
+
}
|
2943
|
+
walStore() {
|
2944
|
+
if (!this.active.wal) {
|
2945
|
+
throw this.xattached.loadable.sthis.logger.Error().Msg("wal store not set").AsError();
|
2946
|
+
}
|
2947
|
+
return new WALActiveStoreImpl(this, this.active.wal, new WALAttachedStoresImpl(this.xattached));
|
2948
|
+
}
|
2949
|
+
};
|
2950
|
+
function isLoadable(unknown) {
|
2951
|
+
return !!unknown.sthis && !!unknown.attachedStores;
|
2952
|
+
}
|
2953
|
+
async function createAttachedStores(urlOrGup, arOrLoadable, name = "local") {
|
2954
|
+
let ar;
|
2955
|
+
if (!isLoadable(arOrLoadable)) {
|
2956
|
+
ar = arOrLoadable;
|
2957
|
+
} else {
|
2958
|
+
ar = arOrLoadable.attachedStores;
|
2959
|
+
}
|
2960
|
+
let gup;
|
2961
|
+
if (!urlOrGup) {
|
2962
|
+
throw new Error("urlOrGup is required");
|
2963
|
+
}
|
2964
|
+
if ((0, import_cement13.isCoerceURI)(urlOrGup)) {
|
2965
|
+
const url = urlOrGup;
|
2966
|
+
gup = {
|
2967
|
+
car: { url },
|
2968
|
+
file: { url },
|
2969
|
+
meta: { url },
|
2970
|
+
wal: { url }
|
2971
|
+
};
|
2972
|
+
} else {
|
2973
|
+
gup = urlOrGup;
|
2974
|
+
}
|
2975
|
+
return await ar.attach({
|
2976
|
+
name,
|
2977
|
+
prepare: async () => gup
|
2978
|
+
});
|
2979
|
+
}
|
2980
|
+
var AttachedRemotesImpl = class {
|
2981
|
+
constructor(loadable) {
|
2982
|
+
this._remotes = new import_cement13.KeyedResolvOnce();
|
2983
|
+
this.loadable = loadable;
|
2984
|
+
}
|
2985
|
+
forRemotes(action) {
|
2986
|
+
return Promise.all(this.remotes().map((i) => action(i))).then(() => void 0);
|
2987
|
+
}
|
2988
|
+
remotes() {
|
2989
|
+
return this._remotes.values().filter(({ value }) => value.isOk() && !value.Ok().stores.wal).map(({ value }) => value.Ok().stores).map((i) => this.activate(i));
|
2990
|
+
}
|
2991
|
+
local() {
|
2992
|
+
if (!this._local) {
|
2993
|
+
throw this.loadable.sthis.logger.Error().Msg("local store not set").AsError();
|
2994
|
+
}
|
2995
|
+
return new ActiveStoreImpl(this._local.stores, this);
|
2996
|
+
}
|
2997
|
+
activate(store) {
|
2998
|
+
if ((0, import_cement13.isCoerceURI)(store)) {
|
2999
|
+
const activateUrl = import_cement13.URI.from(store);
|
3000
|
+
let maxScore = 0;
|
3001
|
+
let maxStore;
|
3002
|
+
for (const { value } of this._remotes.values()) {
|
3003
|
+
if (value.isErr()) {
|
3004
|
+
continue;
|
3005
|
+
}
|
3006
|
+
for (const url of value.Ok().stores.baseStores.map((i) => i.url())) {
|
3007
|
+
const mr = url.match(activateUrl);
|
3008
|
+
if (mr.score > maxScore) {
|
3009
|
+
maxScore = mr.score;
|
3010
|
+
maxStore = value.Ok().stores;
|
3011
|
+
}
|
3012
|
+
}
|
3013
|
+
}
|
3014
|
+
if (!maxStore) {
|
3015
|
+
throw this.loadable.sthis.logger.Error().Url(activateUrl).Msg("no store found").AsError();
|
3016
|
+
}
|
3017
|
+
store = maxStore;
|
3018
|
+
}
|
3019
|
+
return new ActiveStoreImpl(store, this);
|
3020
|
+
}
|
3021
|
+
async detach() {
|
3022
|
+
await Promise.all(
|
3023
|
+
this._remotes.values().map(async ({ value: rvalue }) => {
|
3024
|
+
if (rvalue.isOk()) {
|
3025
|
+
await rvalue.Ok().detach();
|
3026
|
+
}
|
3027
|
+
})
|
3028
|
+
);
|
3029
|
+
}
|
3030
|
+
async attach(attached) {
|
3031
|
+
const gwp = await attached.prepare();
|
3032
|
+
const gws = {
|
3033
|
+
car: {
|
3034
|
+
...gwp.car,
|
3035
|
+
url: ensureURIDefaults(this.loadable.sthis, attached.name, gwp.car.url, import_cement13.URI.from(gwp.car.url), "car")
|
3036
|
+
},
|
3037
|
+
file: {
|
3038
|
+
...gwp.file,
|
3039
|
+
url: ensureURIDefaults(this.loadable.sthis, attached.name, void 0, import_cement13.URI.from(gwp.file.url), "file", { file: true })
|
3040
|
+
},
|
3041
|
+
meta: {
|
3042
|
+
...gwp.meta,
|
3043
|
+
url: ensureURIDefaults(this.loadable.sthis, attached.name, void 0, import_cement13.URI.from(gwp.meta.url), "meta")
|
3044
|
+
},
|
3045
|
+
wal: gwp.wal ? {
|
3046
|
+
...gwp.wal,
|
3047
|
+
url: ensureURIDefaults(this.loadable.sthis, attached.name, void 0, import_cement13.URI.from(gwp.wal.url), "wal")
|
3048
|
+
} : void 0
|
3049
|
+
};
|
3050
|
+
const key = JSON.stringify(
|
3051
|
+
toSortedArray({
|
3052
|
+
carUrl: gws.car.url.toString(),
|
3053
|
+
filesUrl: gws.file.url.toString(),
|
3054
|
+
metaUrl: gws.meta.url.toString(),
|
3055
|
+
walUrl: gws.wal?.url.toString()
|
3056
|
+
})
|
3057
|
+
);
|
3058
|
+
return this._remotes.get(key).once(async () => {
|
3059
|
+
const rt = toStoreRuntime(this.loadable.sthis);
|
3060
|
+
const result = new AttachedImpl(
|
3061
|
+
gws,
|
3062
|
+
await rt.makeStores({
|
3063
|
+
byStore: gws,
|
3064
|
+
loader: this.loadable
|
3065
|
+
}),
|
3066
|
+
() => {
|
3067
|
+
this._remotes.unget(key);
|
3068
|
+
}
|
3069
|
+
);
|
3070
|
+
if (result.stores.wal) {
|
3071
|
+
if (this._local) {
|
3072
|
+
throw this.loadable.sthis.logger.Error().Msg("local store could only set once").AsError();
|
3073
|
+
}
|
3074
|
+
this._local = result;
|
3075
|
+
}
|
3076
|
+
return result;
|
3077
|
+
});
|
3078
|
+
}
|
3079
|
+
};
|
3080
|
+
|
2665
3081
|
// src/blockstore/loader.ts
|
2666
3082
|
function carLogIncludesGroup(list, cids) {
|
2667
|
-
|
2668
|
-
|
2669
|
-
|
3083
|
+
const cidSet = cids.map((cid) => cid.toString()).sort().join(",");
|
3084
|
+
return list.some(
|
3085
|
+
(arr) => cidSet === arr.map((cid) => cid.toString()).sort().join(",")
|
3086
|
+
);
|
2670
3087
|
}
|
2671
|
-
function uniqueCids(list, remove =
|
3088
|
+
function uniqueCids(list, remove = new import_cement14.LRUSet()) {
|
2672
3089
|
const byString = /* @__PURE__ */ new Map();
|
2673
3090
|
for (const cid of list) {
|
2674
3091
|
if (remove.has(cid.toString())) continue;
|
@@ -2680,18 +3097,9 @@ var Loader = class {
|
|
2680
3097
|
constructor(sthis, ebOpts) {
|
2681
3098
|
this.commitQueue = new CommitQueue();
|
2682
3099
|
this.isCompacting = false;
|
2683
|
-
this.
|
2684
|
-
this.
|
2685
|
-
this.
|
2686
|
-
this.carLog = [];
|
2687
|
-
this.getBlockCache = /* @__PURE__ */ new Map();
|
2688
|
-
this.seenMeta = /* @__PURE__ */ new Set();
|
2689
|
-
this.writeLimit = (0, import_p_limit.default)(1);
|
2690
|
-
this._carStore = new import_cement13.ResolveOnce();
|
2691
|
-
this._fileStore = new import_cement13.ResolveOnce();
|
2692
|
-
this._WALStore = new import_cement13.ResolveOnce();
|
2693
|
-
this._metaStore = new import_cement13.ResolveOnce();
|
2694
|
-
this.onceReady = new import_cement13.ResolveOnce();
|
3100
|
+
this.maxConcurrentWrite = (0, import_p_limit.default)(1);
|
3101
|
+
this.carLog = new CarLog();
|
3102
|
+
this.onceReady = new import_cement14.ResolveOnce();
|
2695
3103
|
this.sthis = sthis;
|
2696
3104
|
this.ebOpts = defaultedBlockstoreRuntime(
|
2697
3105
|
sthis,
|
@@ -2701,76 +3109,75 @@ var Loader = class {
|
|
2701
3109
|
},
|
2702
3110
|
"Loader"
|
2703
3111
|
);
|
2704
|
-
this.logger =
|
2705
|
-
this.
|
2706
|
-
|
3112
|
+
this.logger = ensureLogger(sthis, "Loader");
|
3113
|
+
this.cidCache = new import_cement14.KeyedResolvOnce({
|
3114
|
+
lru: {
|
3115
|
+
maxEntries: parseInt(this.ebOpts.storeUrls.car.getParam(PARAM.CAR_CACHE_SIZE, "1000"), 10)
|
3116
|
+
}
|
2707
3117
|
});
|
2708
|
-
|
2709
|
-
|
2710
|
-
|
2711
|
-
|
2712
|
-
|
2713
|
-
|
2714
|
-
|
2715
|
-
|
2716
|
-
|
2717
|
-
|
2718
|
-
|
2719
|
-
|
2720
|
-
|
2721
|
-
return this._fileStore.once(
|
2722
|
-
async () => this.ebOpts.storeRuntime.makeDataStore({
|
2723
|
-
// sthis: this.sthis,
|
2724
|
-
gatewayInterceptor: this.ebOpts.gatewayInterceptor,
|
2725
|
-
url: this.ebOpts.storeUrls.file,
|
2726
|
-
// keybag: await this.keyBag(),
|
2727
|
-
loader: this
|
2728
|
-
})
|
2729
|
-
);
|
2730
|
-
}
|
2731
|
-
async WALStore() {
|
2732
|
-
return this._WALStore.once(
|
2733
|
-
async () => this.ebOpts.storeRuntime.makeWALStore({
|
2734
|
-
// sthis: this.sthis,
|
2735
|
-
gatewayInterceptor: this.ebOpts.gatewayInterceptor,
|
2736
|
-
url: this.ebOpts.storeUrls.wal,
|
2737
|
-
// keybag: await this.keyBag(),
|
2738
|
-
loader: this
|
2739
|
-
})
|
3118
|
+
this.seenMeta = new import_cement14.LRUSet({
|
3119
|
+
maxEntries: parseInt(this.ebOpts.storeUrls.meta.getParam(PARAM.CAR_META_CACHE_SIZE, "1000"), 10)
|
3120
|
+
});
|
3121
|
+
this.seenCompacted = new import_cement14.LRUSet({
|
3122
|
+
maxEntries: parseInt(this.ebOpts.storeUrls.car.getParam(PARAM.CAR_COMPACT_CACHE_SIZE, "1000"), 10)
|
3123
|
+
});
|
3124
|
+
this.maxConcurrentCarReader = (0, import_p_limit.default)(parseInt(this.ebOpts.storeUrls.car.getParam(PARAM.CAR_PARALLEL, "5"), 10));
|
3125
|
+
this.taskManager = new TaskManager(
|
3126
|
+
sthis,
|
3127
|
+
async (dbMeta, activeStore) => {
|
3128
|
+
await this.handleDbMetasFromStore([dbMeta], activeStore);
|
3129
|
+
},
|
3130
|
+
this.ebOpts.taskManager
|
2740
3131
|
);
|
3132
|
+
this.attachedStores = new AttachedRemotesImpl(this);
|
2741
3133
|
}
|
2742
|
-
async
|
2743
|
-
|
2744
|
-
|
2745
|
-
|
2746
|
-
|
2747
|
-
|
2748
|
-
|
2749
|
-
|
2750
|
-
|
2751
|
-
|
3134
|
+
async attach(attached) {
|
3135
|
+
const at = await this.attachedStores.attach(attached);
|
3136
|
+
if (!at.stores.wal) {
|
3137
|
+
try {
|
3138
|
+
const dbMeta = await at.stores.meta.load();
|
3139
|
+
if (!Array.isArray(dbMeta)) {
|
3140
|
+
throw this.logger.Error().Msg("missing dbMeta").AsError();
|
3141
|
+
}
|
3142
|
+
await this.handleDbMetasFromStore(dbMeta, this.attachedStores.activate(at.stores));
|
3143
|
+
} catch (e) {
|
3144
|
+
this.logger.Error().Err(e).Msg("error attaching store");
|
3145
|
+
at.detach();
|
3146
|
+
}
|
3147
|
+
}
|
3148
|
+
return at;
|
2752
3149
|
}
|
2753
3150
|
keyBag() {
|
2754
3151
|
return getKeyBag(this.sthis, this.ebOpts.keyBag);
|
2755
3152
|
}
|
2756
3153
|
async ready() {
|
2757
3154
|
return this.onceReady.once(async () => {
|
2758
|
-
|
3155
|
+
await createAttachedStores(
|
3156
|
+
{
|
3157
|
+
car: { url: this.ebOpts.storeUrls.car, gatewayInterceptor: this.ebOpts.gatewayInterceptor },
|
3158
|
+
file: { url: this.ebOpts.storeUrls.file, gatewayInterceptor: this.ebOpts.gatewayInterceptor },
|
3159
|
+
meta: { url: this.ebOpts.storeUrls.meta, gatewayInterceptor: this.ebOpts.gatewayInterceptor },
|
3160
|
+
wal: { url: this.ebOpts.storeUrls.wal, gatewayInterceptor: this.ebOpts.gatewayInterceptor }
|
3161
|
+
},
|
3162
|
+
this.attachedStores
|
3163
|
+
);
|
3164
|
+
const local = this.attachedStores.local();
|
3165
|
+
const metas = await local.active.meta.load();
|
2759
3166
|
if (this.ebOpts.meta) {
|
2760
|
-
await this.handleDbMetasFromStore([this.ebOpts.meta]);
|
3167
|
+
await this.handleDbMetasFromStore([this.ebOpts.meta, ...metas || []], local);
|
2761
3168
|
} else if (metas) {
|
2762
|
-
await this.handleDbMetasFromStore(metas);
|
3169
|
+
await this.handleDbMetasFromStore(metas, local);
|
2763
3170
|
}
|
2764
3171
|
});
|
2765
3172
|
}
|
2766
3173
|
async close() {
|
2767
3174
|
await this.commitQueue.waitIdle();
|
2768
|
-
|
2769
|
-
await Promise.all(toClose.map((store) => store.close()));
|
3175
|
+
await this.attachedStores.detach();
|
2770
3176
|
}
|
2771
3177
|
async destroy() {
|
2772
|
-
|
2773
|
-
|
3178
|
+
await Promise.all(
|
3179
|
+
this.attachedStores.local().baseStores().map((store) => store.destroy())
|
3180
|
+
);
|
2774
3181
|
}
|
2775
3182
|
// async snapToCar(carCid: AnyLink | string) {
|
2776
3183
|
// await this.ready
|
@@ -2782,28 +3189,38 @@ var Loader = class {
|
|
2782
3189
|
// await this.getMoreReaders(carHeader.cars)
|
2783
3190
|
// await this._applyCarHeader(carHeader, true)
|
2784
3191
|
// }
|
2785
|
-
async handleDbMetasFromStore(metas) {
|
2786
|
-
this.logger.Debug().Any("metas", metas).Msg("handleDbMetasFromStore");
|
3192
|
+
async handleDbMetasFromStore(metas, activeStore) {
|
3193
|
+
this.logger.Debug().Any("metas", metas).Url(activeStore.active.car.url()).Msg("handleDbMetasFromStore");
|
2787
3194
|
for (const meta of metas) {
|
2788
|
-
await this.
|
2789
|
-
await this.mergeDbMetaIntoClock(meta);
|
3195
|
+
await this.maxConcurrentWrite(async () => {
|
3196
|
+
await this.mergeDbMetaIntoClock(meta, activeStore);
|
2790
3197
|
});
|
2791
3198
|
}
|
2792
3199
|
}
|
2793
|
-
async mergeDbMetaIntoClock(meta) {
|
3200
|
+
async mergeDbMetaIntoClock(meta, activeStore) {
|
2794
3201
|
if (this.isCompacting) {
|
2795
3202
|
throw this.logger.Error().Msg("cannot merge while compacting").AsError();
|
2796
3203
|
}
|
2797
|
-
|
2798
|
-
|
2799
|
-
|
2800
|
-
return;
|
3204
|
+
try {
|
3205
|
+
this.isCompacting = true;
|
3206
|
+
const metaKey = meta.cars.map((i) => i.toString()).sort().join(",");
|
3207
|
+
if (this.seenMeta.has(metaKey)) return;
|
3208
|
+
this.seenMeta.add(metaKey);
|
3209
|
+
if (carLogIncludesGroup(this.carLog.asArray(), meta.cars)) {
|
3210
|
+
return;
|
3211
|
+
}
|
3212
|
+
const carHeader = await this.loadCarHeaderFromMeta(meta, activeStore);
|
3213
|
+
carHeader.compact.map((c) => c.toString()).forEach((k) => this.seenCompacted.add(k), this.seenCompacted);
|
3214
|
+
try {
|
3215
|
+
await this.getMoreReaders(carHeader.cars.flat(), activeStore);
|
3216
|
+
} catch (e) {
|
3217
|
+
this.logger.Error().Err(e).Msg("error getting more readers");
|
3218
|
+
}
|
3219
|
+
this.carLog.update(uniqueCids([meta.cars, ...this.carLog.asArray(), ...carHeader.cars], this.seenCompacted));
|
3220
|
+
await this.ebOpts.applyMeta?.(carHeader.meta);
|
3221
|
+
} finally {
|
3222
|
+
this.isCompacting = false;
|
2801
3223
|
}
|
2802
|
-
const carHeader = await this.loadCarHeaderFromMeta(meta);
|
2803
|
-
carHeader.compact.map((c) => c.toString()).forEach(this.seenCompacted.add, this.seenCompacted);
|
2804
|
-
await this.getMoreReaders(carHeader.cars.flat());
|
2805
|
-
this.carLog = [...uniqueCids([meta.cars, ...this.carLog, ...carHeader.cars], this.seenCompacted)];
|
2806
|
-
await this.ebOpts.applyMeta?.(carHeader.meta);
|
2807
3224
|
}
|
2808
3225
|
// protected async ingestKeyFromMeta(meta: DbMeta): Promise<void> {
|
2809
3226
|
// const { key } = meta;
|
@@ -2811,8 +3228,8 @@ var Loader = class {
|
|
2811
3228
|
// await this.setKey(key);
|
2812
3229
|
// }
|
2813
3230
|
// }
|
2814
|
-
async loadCarHeaderFromMeta(
|
2815
|
-
const reader = await this.loadCar(
|
3231
|
+
async loadCarHeaderFromMeta(dbm, astore) {
|
3232
|
+
const reader = await this.loadCar(dbm.cars[0], astore);
|
2816
3233
|
return await parseCarFile(reader, this.logger);
|
2817
3234
|
}
|
2818
3235
|
// async _getKey(): Promise<string | undefined> {
|
@@ -2825,22 +3242,22 @@ var Loader = class {
|
|
2825
3242
|
// }
|
2826
3243
|
async commitFiles(t, done) {
|
2827
3244
|
await this.ready();
|
2828
|
-
const fstore =
|
2829
|
-
const wstore =
|
3245
|
+
const fstore = this.attachedStores.local().active.file;
|
3246
|
+
const wstore = this.attachedStores.local().active.wal;
|
2830
3247
|
return this.commitQueue.enqueue(() => commitFiles(fstore, wstore, t, done));
|
2831
3248
|
}
|
2832
|
-
async loadFileCar(cid) {
|
2833
|
-
return await this.storesLoadCar(cid,
|
3249
|
+
async loadFileCar(cid, store) {
|
3250
|
+
return await this.storesLoadCar(cid, store.fileStore());
|
2834
3251
|
}
|
2835
3252
|
async commit(t, done, opts = { noLoader: false, compact: false }) {
|
2836
3253
|
await this.ready();
|
2837
|
-
const carStore =
|
3254
|
+
const carStore = this.attachedStores.local().active.car;
|
2838
3255
|
const params = {
|
2839
3256
|
encoder: (await carStore.keyedCrypto()).codec(),
|
2840
3257
|
carLog: this.carLog,
|
2841
3258
|
carStore,
|
2842
|
-
WALStore:
|
2843
|
-
metaStore:
|
3259
|
+
WALStore: this.attachedStores.local().active.wal,
|
3260
|
+
metaStore: this.attachedStores.local().active.meta,
|
2844
3261
|
threshold: this.ebOpts.threshold
|
2845
3262
|
};
|
2846
3263
|
return this.commitQueue.enqueue(async () => {
|
@@ -2850,41 +3267,54 @@ var Loader = class {
|
|
2850
3267
|
return ret.cgrp;
|
2851
3268
|
});
|
2852
3269
|
}
|
2853
|
-
async updateCarLog(cids,
|
3270
|
+
async updateCarLog(cids, cHeader, compact) {
|
2854
3271
|
if (compact) {
|
2855
|
-
const previousCompactCid =
|
2856
|
-
|
2857
|
-
this.carLog
|
2858
|
-
await this.removeCidsForCompact(previousCompactCid[0]).catch((e) => e);
|
3272
|
+
const previousCompactCid = cHeader.compact[cHeader.compact.length - 1];
|
3273
|
+
cHeader.compact.map((c) => c.toString()).forEach(this.seenCompacted.add, this.seenCompacted);
|
3274
|
+
this.carLog.update(uniqueCids([...this.carLog.asArray(), ...cHeader.cars, cids], this.seenCompacted));
|
3275
|
+
await this.removeCidsForCompact(previousCompactCid[0], this.attachedStores.local()).catch((e) => e);
|
2859
3276
|
} else {
|
2860
|
-
this.carLog.
|
3277
|
+
this.carLog.xunshift(cids);
|
2861
3278
|
}
|
2862
3279
|
}
|
2863
3280
|
async cacheTransaction(t) {
|
2864
3281
|
for await (const block of t.entries()) {
|
2865
3282
|
const sBlock = block.cid.toString();
|
2866
|
-
|
2867
|
-
|
2868
|
-
|
2869
|
-
|
2870
|
-
|
2871
|
-
|
2872
|
-
|
2873
|
-
|
2874
|
-
for await (const block of reader.blocks()) {
|
2875
|
-
const sBlock = block.cid.toString();
|
2876
|
-
if (!this.getBlockCache.has(sBlock)) {
|
2877
|
-
this.getBlockCache.set(sBlock, block);
|
2878
|
-
}
|
3283
|
+
this.cidCache.get(sBlock).once(
|
3284
|
+
() => ({
|
3285
|
+
type: "block",
|
3286
|
+
cid: block.cid,
|
3287
|
+
blocks: [block],
|
3288
|
+
roots: []
|
3289
|
+
})
|
3290
|
+
);
|
2879
3291
|
}
|
2880
3292
|
}
|
2881
|
-
|
2882
|
-
|
2883
|
-
|
2884
|
-
|
3293
|
+
// /**
|
3294
|
+
// *
|
3295
|
+
// * @returns the list of blocks which was read from the car file
|
3296
|
+
// */
|
3297
|
+
// private async readCar(reader: CarReader): Promise<AnyBlock[]> {
|
3298
|
+
// const blocks: AnyBlock[] = [];
|
3299
|
+
// for await (const block of reader.blocks()) {
|
3300
|
+
// const sBlock = block.cid.toString();
|
3301
|
+
// this.cidCache.get(sBlock).once(() => {
|
3302
|
+
// blocks.push(block);
|
3303
|
+
// return [block];
|
3304
|
+
// });
|
3305
|
+
// }
|
3306
|
+
// return blocks;
|
3307
|
+
// }
|
3308
|
+
async removeCidsForCompact(cid, store) {
|
3309
|
+
const carHeader = await this.loadCarHeaderFromMeta(
|
3310
|
+
{
|
3311
|
+
cars: [cid]
|
3312
|
+
},
|
3313
|
+
store
|
3314
|
+
);
|
2885
3315
|
for (const cids of carHeader.compact) {
|
2886
3316
|
for (const cid2 of cids) {
|
2887
|
-
await
|
3317
|
+
await this.attachedStores.local().active.car.remove(cid2);
|
2888
3318
|
}
|
2889
3319
|
}
|
2890
3320
|
}
|
@@ -2896,148 +3326,134 @@ var Loader = class {
|
|
2896
3326
|
// await this.remoteWAL!.enqueue(dbMeta, { public: false })
|
2897
3327
|
// }
|
2898
3328
|
// }
|
2899
|
-
async *entries(
|
3329
|
+
async *entries() {
|
2900
3330
|
await this.ready();
|
2901
|
-
|
2902
|
-
|
2903
|
-
|
2904
|
-
|
2905
|
-
|
2906
|
-
|
2907
|
-
|
2908
|
-
|
2909
|
-
|
2910
|
-
|
2911
|
-
|
2912
|
-
|
2913
|
-
for await (const block of reader.blocks()) {
|
2914
|
-
const sCid = block.cid.toString();
|
2915
|
-
if (!this.getBlockCache.has(sCid)) {
|
2916
|
-
yield block;
|
2917
|
-
}
|
2918
|
-
}
|
3331
|
+
const seen = /* @__PURE__ */ new Set();
|
3332
|
+
for (const carCids of this.carLog.asArray()) {
|
3333
|
+
for (const carCid of carCids) {
|
3334
|
+
const reader = await this.loadCar(carCid, this.attachedStores.local());
|
3335
|
+
if (!reader || reader.type !== "car") {
|
3336
|
+
throw this.logger.Error().Any("reader", reader.type).Str("cid", carCid.toString()).Msg("missing car reader").AsError();
|
3337
|
+
}
|
3338
|
+
for (const block of reader.blocks) {
|
3339
|
+
const cidStr = block.cid.toString();
|
3340
|
+
if (seen.has(cidStr)) continue;
|
3341
|
+
seen.add(cidStr);
|
3342
|
+
yield block;
|
2919
3343
|
}
|
2920
3344
|
}
|
2921
3345
|
}
|
2922
3346
|
}
|
2923
|
-
async getBlock(cid) {
|
3347
|
+
async getBlock(cid, store) {
|
2924
3348
|
await this.ready();
|
2925
|
-
const
|
2926
|
-
|
2927
|
-
|
2928
|
-
|
2929
|
-
|
2930
|
-
|
2931
|
-
|
2932
|
-
|
2933
|
-
|
2934
|
-
|
2935
|
-
|
2936
|
-
|
2937
|
-
|
2938
|
-
|
2939
|
-
|
2940
|
-
|
2941
|
-
|
2942
|
-
|
2943
|
-
|
2944
|
-
|
2945
|
-
|
2946
|
-
|
2947
|
-
|
2948
|
-
for (let i = 0; i < compacts.length; i += batchSize2) {
|
2949
|
-
const promises = [];
|
2950
|
-
for (let j = i; j < Math.min(i + batchSize2, compacts.length); j++) {
|
2951
|
-
for (const cid2 of compacts[j]) {
|
2952
|
-
promises.push(getCarCid(cid2));
|
3349
|
+
const cidStr = cid.toString();
|
3350
|
+
const ci = await this.cidCache.get(cidStr).once(async () => {
|
3351
|
+
const getCompactCarCids = async (carCid) => {
|
3352
|
+
const sCid = carCid.toString();
|
3353
|
+
const reader = await this.loadCar(carCid, store);
|
3354
|
+
const header = await parseCarFile(reader, this.logger);
|
3355
|
+
const compacts = header.compact;
|
3356
|
+
const got2 = await Promise.allSettled(compacts.map((compact) => compact.map((cid2) => this.loadCar(cid2, store)).flat()));
|
3357
|
+
got2.filter((result) => result.status === "rejected").forEach((result) => {
|
3358
|
+
this.logger.Error().Err(result.reason).Str("cid", sCid).Msg("error getting compacted block");
|
3359
|
+
});
|
3360
|
+
};
|
3361
|
+
let got;
|
3362
|
+
for (const carCids of this.carLog.asArray()) {
|
3363
|
+
for (const carCid of carCids) {
|
3364
|
+
const ci2 = await this.loadCar(carCid, store);
|
3365
|
+
if (!ci2) {
|
3366
|
+
this.logger.Error().Str("cid", carCid.toString()).Msg("missing CarCID");
|
3367
|
+
continue;
|
3368
|
+
}
|
3369
|
+
got = ci2.blocks.find((block) => block.cid.equals(cid));
|
3370
|
+
if (got) {
|
3371
|
+
break;
|
2953
3372
|
}
|
2954
3373
|
}
|
2955
|
-
try {
|
2956
|
-
got2 = await Promise.any(promises);
|
2957
|
-
} catch {
|
2958
|
-
}
|
2959
|
-
if (got2) break;
|
2960
|
-
}
|
2961
|
-
if (this.getBlockCache.has(sCid)) return this.getBlockCache.get(sCid);
|
2962
|
-
throw this.logger.Error().Str("cid", sCid).Msg("block not in compact reader").AsError();
|
2963
|
-
};
|
2964
|
-
let got;
|
2965
|
-
const batchSize = 5;
|
2966
|
-
for (let i = 0; i < this.carLog.length; i += batchSize) {
|
2967
|
-
const batch = this.carLog.slice(i, i + batchSize);
|
2968
|
-
const promises = batch.flatMap((slice) => slice.map(getCarCid));
|
2969
|
-
try {
|
2970
|
-
got = await Promise.any(promises);
|
2971
|
-
} catch {
|
2972
3374
|
}
|
2973
|
-
if (got)
|
2974
|
-
|
2975
|
-
if (!got) {
|
2976
|
-
try {
|
2977
|
-
got = await getCompactCarCids(this.carLog[this.carLog.length - 1][0]);
|
2978
|
-
} catch {
|
3375
|
+
if (!got) {
|
3376
|
+
await getCompactCarCids(this.carLog.last()[0]);
|
2979
3377
|
}
|
3378
|
+
return {
|
3379
|
+
type: "block",
|
3380
|
+
cid,
|
3381
|
+
blocks: got ? [got] : [],
|
3382
|
+
roots: []
|
3383
|
+
};
|
3384
|
+
});
|
3385
|
+
if (!(ci.type === "block" && ci.blocks.length === 1)) {
|
3386
|
+
throw this.logger.Error().Str("cid", cidStr).Any("block", ci).Msg("missing block").AsError();
|
2980
3387
|
}
|
2981
|
-
return
|
3388
|
+
return ci.blocks[0];
|
2982
3389
|
}
|
2983
|
-
async loadCar(cid) {
|
2984
|
-
|
2985
|
-
throw this.logger.Error().Msg("car store not initialized").AsError();
|
2986
|
-
}
|
2987
|
-
const loaded = await this.storesLoadCar(cid, await this.carStore(), this.remoteCarStore);
|
3390
|
+
async loadCar(cid, store) {
|
3391
|
+
const loaded = await this.storesLoadCar(cid, store.carStore());
|
2988
3392
|
return loaded;
|
2989
3393
|
}
|
2990
|
-
async makeDecoderAndCarReader(
|
2991
|
-
const
|
3394
|
+
async makeDecoderAndCarReader(carCid, store) {
|
3395
|
+
const carCidStr = carCid.toString();
|
2992
3396
|
let loadedCar = void 0;
|
2993
|
-
let activeStore = local;
|
3397
|
+
let activeStore = store.local();
|
2994
3398
|
try {
|
2995
|
-
this.logger.Debug().Any("cid",
|
2996
|
-
loadedCar = await local.load(
|
3399
|
+
this.logger.Debug().Any("cid", carCidStr).Msg("loading car");
|
3400
|
+
loadedCar = await store.local().load(carCid);
|
2997
3401
|
this.logger.Debug().Bool("loadedCar", loadedCar).Msg("loaded");
|
2998
3402
|
} catch (e) {
|
2999
|
-
if (
|
3000
|
-
|
3001
|
-
|
3002
|
-
|
3003
|
-
|
3004
|
-
|
3005
|
-
|
3403
|
+
if (!isNotFoundError(e)) {
|
3404
|
+
throw this.logger.Error().Str("cid", carCidStr).Err(e).Msg("loading car");
|
3405
|
+
}
|
3406
|
+
for (const remote of store.remotes()) {
|
3407
|
+
try {
|
3408
|
+
const remoteCar = await remote.load(carCid);
|
3409
|
+
if (remoteCar) {
|
3410
|
+
this.logger.Debug().Ref("cid", remoteCar.cid).Msg("saving remote car locally");
|
3411
|
+
await store.local().save(remoteCar);
|
3412
|
+
loadedCar = remoteCar;
|
3413
|
+
activeStore = remote;
|
3414
|
+
break;
|
3415
|
+
} else {
|
3416
|
+
this.logger.Error().Str("cid", carCidStr).Err(e).Msg("loading car");
|
3417
|
+
}
|
3418
|
+
} catch (e2) {
|
3419
|
+
this.logger.Warn().Str("cid", carCidStr).Url(remote.url()).Err(e2).Msg("loading car");
|
3006
3420
|
}
|
3007
|
-
} else {
|
3008
|
-
this.logger.Error().Str("cid", cidsString).Err(e).Msg("loading car");
|
3009
3421
|
}
|
3010
3422
|
}
|
3011
3423
|
if (!loadedCar) {
|
3012
|
-
throw this.logger.Error().Url(local.url()).Str("cid",
|
3424
|
+
throw this.logger.Error().Url(store.local().url()).Str("cid", carCidStr).Msg("missing car files").AsError();
|
3013
3425
|
}
|
3014
3426
|
const bytes = await decode({ bytes: loadedCar.bytes, hasher: import_sha24.sha256, codec: (await activeStore.keyedCrypto()).codec() });
|
3015
|
-
const rawReader = await import_reader.CarReader.fromBytes(bytes.value);
|
3016
|
-
const
|
3017
|
-
const
|
3018
|
-
|
3019
|
-
|
3020
|
-
|
3021
|
-
|
3022
|
-
|
3023
|
-
|
3024
|
-
|
3025
|
-
|
3427
|
+
const rawReader = await import_reader.CarReader.fromBytes(bytes.value.data);
|
3428
|
+
const blocks = [];
|
3429
|
+
for await (const block of rawReader.blocks()) {
|
3430
|
+
const sBlock = block.cid.toString();
|
3431
|
+
blocks.push(block);
|
3432
|
+
this.cidCache.get(sBlock).once(() => ({
|
3433
|
+
type: "block",
|
3434
|
+
cid: block.cid,
|
3435
|
+
blocks: [block],
|
3436
|
+
roots: []
|
3437
|
+
}));
|
3438
|
+
}
|
3439
|
+
return {
|
3440
|
+
type: "car",
|
3441
|
+
cid: carCid,
|
3442
|
+
blocks,
|
3443
|
+
roots: await rawReader.getRoots()
|
3444
|
+
};
|
3026
3445
|
}
|
3027
3446
|
//What if instead it returns an Array of CarHeader
|
3028
|
-
async storesLoadCar(
|
3029
|
-
const
|
3030
|
-
|
3031
|
-
|
3032
|
-
|
3033
|
-
this.carReaders.set(cidsString, dacr);
|
3034
|
-
}
|
3035
|
-
return dacr;
|
3447
|
+
async storesLoadCar(carCid, store) {
|
3448
|
+
const carCidStr = carCid.toString();
|
3449
|
+
return this.cidCache.get(carCidStr).once(async () => {
|
3450
|
+
return this.maxConcurrentCarReader(() => this.makeDecoderAndCarReader(carCid, store));
|
3451
|
+
});
|
3036
3452
|
}
|
3037
|
-
async getMoreReaders(cids) {
|
3038
|
-
const
|
3039
|
-
|
3040
|
-
|
3453
|
+
async getMoreReaders(cids, store) {
|
3454
|
+
for (const cid of cids) {
|
3455
|
+
await this.loadCar(cid, store);
|
3456
|
+
}
|
3041
3457
|
}
|
3042
3458
|
};
|
3043
3459
|
|
@@ -3082,12 +3498,21 @@ function getGenerateIVFn(url, opts) {
|
|
3082
3498
|
}
|
3083
3499
|
var BlockIvKeyIdCodec = class {
|
3084
3500
|
constructor(ko, iv, opts) {
|
3085
|
-
this.code =
|
3501
|
+
this.code = 24;
|
3086
3502
|
this.name = "Fireproof@encrypted-block:aes-gcm";
|
3087
3503
|
this.ko = ko;
|
3088
3504
|
this.iv = iv;
|
3089
3505
|
this.opts = opts || {};
|
3090
3506
|
}
|
3507
|
+
// hashAsBytes(data: IvKeyIdData): AsyncHashAsBytes<Uint8Array<ArrayBufferLike>> {
|
3508
|
+
// return data;
|
3509
|
+
// }
|
3510
|
+
valueToHashBytes(value) {
|
3511
|
+
return Promise.resolve(value.data);
|
3512
|
+
}
|
3513
|
+
bytesToHash(data) {
|
3514
|
+
return Promise.resolve(data);
|
3515
|
+
}
|
3091
3516
|
async encode(data) {
|
3092
3517
|
const calcIv = this.iv || await getGenerateIVFn(this.ko.url, this.opts).calc(this.ko, this.ko.crypto, data);
|
3093
3518
|
const { iv } = this.ko.algo(calcIv);
|
@@ -3119,11 +3544,16 @@ var BlockIvKeyIdCodec = class {
|
|
3119
3544
|
if (!this.opts?.noIVVerify && !await getGenerateIVFn(this.ko.url, this.opts).verify(this.ko, this.ko.crypto, iv, result)) {
|
3120
3545
|
throw this.ko.logger.Error().Msg("iv missmatch").AsError();
|
3121
3546
|
}
|
3122
|
-
return
|
3547
|
+
return {
|
3548
|
+
iv,
|
3549
|
+
keyId,
|
3550
|
+
data: result
|
3551
|
+
};
|
3123
3552
|
}
|
3124
3553
|
};
|
3125
3554
|
var cryptoAction = class {
|
3126
3555
|
constructor(url, key, cyopt, sthis) {
|
3556
|
+
this.code = 24;
|
3127
3557
|
this.ivLength = 12;
|
3128
3558
|
this.isEncrypting = true;
|
3129
3559
|
this.logger = ensureLogger(sthis, "cryptoAction");
|
@@ -3157,14 +3587,19 @@ var cryptoAction = class {
|
|
3157
3587
|
};
|
3158
3588
|
var nullCodec = class {
|
3159
3589
|
constructor() {
|
3160
|
-
this.code =
|
3590
|
+
this.code = 24;
|
3161
3591
|
this.name = "Fireproof@unencrypted-block";
|
3592
|
+
this.empty = new Uint8Array();
|
3162
3593
|
}
|
3163
|
-
encode(data) {
|
3594
|
+
async encode(data) {
|
3164
3595
|
return data;
|
3165
3596
|
}
|
3166
|
-
decode(data) {
|
3167
|
-
return
|
3597
|
+
async decode(data) {
|
3598
|
+
return {
|
3599
|
+
iv: this.empty,
|
3600
|
+
keyId: this.empty,
|
3601
|
+
data
|
3602
|
+
};
|
3168
3603
|
}
|
3169
3604
|
};
|
3170
3605
|
var noCrypto = class {
|
@@ -3232,39 +3667,39 @@ var import_p_retry = __toESM(require("p-retry"), 1);
|
|
3232
3667
|
var import_p_map = __toESM(require("p-map"), 1);
|
3233
3668
|
|
3234
3669
|
// src/blockstore/interceptor-gateway.ts
|
3235
|
-
var
|
3670
|
+
var import_cement15 = require("@adviser/cement");
|
3236
3671
|
var PassThroughGateway = class {
|
3237
3672
|
async buildUrl(ctx, url, key) {
|
3238
3673
|
const op = { url, key };
|
3239
|
-
return
|
3674
|
+
return import_cement15.Result.Ok({ op });
|
3240
3675
|
}
|
3241
3676
|
async start(ctx, url) {
|
3242
3677
|
const op = { url };
|
3243
|
-
return
|
3678
|
+
return import_cement15.Result.Ok({ op });
|
3244
3679
|
}
|
3245
3680
|
async close(ctx, url) {
|
3246
3681
|
const op = { url };
|
3247
|
-
return
|
3682
|
+
return import_cement15.Result.Ok({ op });
|
3248
3683
|
}
|
3249
3684
|
async delete(ctx, url) {
|
3250
3685
|
const op = { url };
|
3251
|
-
return
|
3686
|
+
return import_cement15.Result.Ok({ op });
|
3252
3687
|
}
|
3253
3688
|
async destroy(ctx, url) {
|
3254
3689
|
const op = { url };
|
3255
|
-
return
|
3690
|
+
return import_cement15.Result.Ok({ op });
|
3256
3691
|
}
|
3257
3692
|
async put(ctx, url, body) {
|
3258
3693
|
const op = { url, body };
|
3259
|
-
return
|
3694
|
+
return import_cement15.Result.Ok({ op });
|
3260
3695
|
}
|
3261
3696
|
async get(ctx, url) {
|
3262
3697
|
const op = { url };
|
3263
|
-
return
|
3698
|
+
return import_cement15.Result.Ok({ op });
|
3264
3699
|
}
|
3265
3700
|
async subscribe(ctx, url, callback) {
|
3266
3701
|
const op = { url, callback };
|
3267
|
-
return
|
3702
|
+
return import_cement15.Result.Ok({ op });
|
3268
3703
|
}
|
3269
3704
|
};
|
3270
3705
|
var passThrougthGateway = new PassThroughGateway();
|
@@ -3276,7 +3711,7 @@ var InterceptorGateway = class {
|
|
3276
3711
|
async buildUrl(ctx, baseUrl, key) {
|
3277
3712
|
const rret = await this.interceptor.buildUrl(ctx, baseUrl, key);
|
3278
3713
|
if (rret.isErr()) {
|
3279
|
-
return
|
3714
|
+
return import_cement15.Result.Err(rret.Err());
|
3280
3715
|
}
|
3281
3716
|
const ret = rret.unwrap();
|
3282
3717
|
if (ret.stop && ret.value) {
|
@@ -3287,7 +3722,7 @@ var InterceptorGateway = class {
|
|
3287
3722
|
async destroy(ctx, iurl) {
|
3288
3723
|
const rret = await this.interceptor.destroy(ctx, iurl);
|
3289
3724
|
if (rret.isErr()) {
|
3290
|
-
return
|
3725
|
+
return import_cement15.Result.Err(rret.Err());
|
3291
3726
|
}
|
3292
3727
|
const ret = rret.unwrap();
|
3293
3728
|
if (ret.stop && ret.value) {
|
@@ -3298,7 +3733,7 @@ var InterceptorGateway = class {
|
|
3298
3733
|
async start(ctx, url) {
|
3299
3734
|
const rret = await this.interceptor.start(ctx, url);
|
3300
3735
|
if (rret.isErr()) {
|
3301
|
-
return
|
3736
|
+
return import_cement15.Result.Err(rret.Err());
|
3302
3737
|
}
|
3303
3738
|
const ret = rret.unwrap();
|
3304
3739
|
if (ret.stop && ret.value) {
|
@@ -3309,7 +3744,7 @@ var InterceptorGateway = class {
|
|
3309
3744
|
async close(ctx, url) {
|
3310
3745
|
const rret = await this.interceptor.close(ctx, url);
|
3311
3746
|
if (rret.isErr()) {
|
3312
|
-
return
|
3747
|
+
return import_cement15.Result.Err(rret.Err());
|
3313
3748
|
}
|
3314
3749
|
const ret = rret.unwrap();
|
3315
3750
|
if (ret.stop && ret.value) {
|
@@ -3320,7 +3755,7 @@ var InterceptorGateway = class {
|
|
3320
3755
|
async put(ctx, url, fpEnv) {
|
3321
3756
|
const rret = await this.interceptor.put(ctx, url, fpEnv);
|
3322
3757
|
if (rret.isErr()) {
|
3323
|
-
return
|
3758
|
+
return import_cement15.Result.Err(rret.Err());
|
3324
3759
|
}
|
3325
3760
|
const ret = rret.unwrap();
|
3326
3761
|
if (ret.stop && ret.value) {
|
@@ -3331,7 +3766,7 @@ var InterceptorGateway = class {
|
|
3331
3766
|
async get(ctx, url) {
|
3332
3767
|
const rret = await this.interceptor.get(ctx, url);
|
3333
3768
|
if (rret.isErr()) {
|
3334
|
-
return
|
3769
|
+
return import_cement15.Result.Err(rret.Err());
|
3335
3770
|
}
|
3336
3771
|
const ret = rret.unwrap();
|
3337
3772
|
if (ret.stop && ret.value) {
|
@@ -3341,11 +3776,11 @@ var InterceptorGateway = class {
|
|
3341
3776
|
}
|
3342
3777
|
async subscribe(ctx, url, callback) {
|
3343
3778
|
if (!this.innerGW.subscribe) {
|
3344
|
-
return
|
3779
|
+
return import_cement15.Result.Err(ctx.loader.sthis.logger.Error().Url(url).Msg("subscribe not supported").AsError());
|
3345
3780
|
}
|
3346
3781
|
const rret = await this.interceptor.subscribe(ctx, url, callback);
|
3347
3782
|
if (rret.isErr()) {
|
3348
|
-
return
|
3783
|
+
return import_cement15.Result.Err(rret.Err());
|
3349
3784
|
}
|
3350
3785
|
const ret = rret.unwrap();
|
3351
3786
|
if (ret.stop && ret.value) {
|
@@ -3356,7 +3791,7 @@ var InterceptorGateway = class {
|
|
3356
3791
|
async delete(ctx, url) {
|
3357
3792
|
const rret = await this.interceptor.delete(ctx, url);
|
3358
3793
|
if (rret.isErr()) {
|
3359
|
-
return
|
3794
|
+
return import_cement15.Result.Err(rret.Err());
|
3360
3795
|
}
|
3361
3796
|
const ret = rret.unwrap();
|
3362
3797
|
if (ret.stop && ret.value) {
|
@@ -3372,9 +3807,9 @@ var InterceptorGateway = class {
|
|
3372
3807
|
// src/blockstore/store.ts
|
3373
3808
|
function guardVersion(url) {
|
3374
3809
|
if (!url.hasParam("version")) {
|
3375
|
-
return
|
3810
|
+
return import_cement16.Result.Err(`missing version: ${url.toString()}`);
|
3376
3811
|
}
|
3377
|
-
return
|
3812
|
+
return import_cement16.Result.Ok(url);
|
3378
3813
|
}
|
3379
3814
|
var BaseStoreImpl = class {
|
3380
3815
|
// readonly loader: Loadable;
|
@@ -3408,7 +3843,7 @@ var BaseStoreImpl = class {
|
|
3408
3843
|
async keyedCrypto() {
|
3409
3844
|
return keyedCryptoFactory(this._url, await this.loader.keyBag(), this.sthis);
|
3410
3845
|
}
|
3411
|
-
async start() {
|
3846
|
+
async start(dam) {
|
3412
3847
|
this.logger.Debug().Str("storeType", this.storeType).Msg("starting-gateway-pre");
|
3413
3848
|
this._url = this._url.build().setParam(PARAM.STORE, this.storeType).URI();
|
3414
3849
|
const res = await this.gateway.start({ loader: this.loader }, this._url);
|
@@ -3419,13 +3854,8 @@ var BaseStoreImpl = class {
|
|
3419
3854
|
this._url = res.Ok();
|
3420
3855
|
const kb = await this.loader.keyBag();
|
3421
3856
|
const skRes = await kb.ensureKeyFromUrl(this._url, () => {
|
3422
|
-
const
|
3423
|
-
|
3424
|
-
if (idx) {
|
3425
|
-
storeKeyName.push(idx);
|
3426
|
-
}
|
3427
|
-
storeKeyName.push(this.storeType);
|
3428
|
-
return storeKeyName.join(":");
|
3857
|
+
const key = this._url.getParam(PARAM.KEY);
|
3858
|
+
return key;
|
3429
3859
|
});
|
3430
3860
|
if (skRes.isErr()) {
|
3431
3861
|
return skRes;
|
@@ -3439,13 +3869,13 @@ var BaseStoreImpl = class {
|
|
3439
3869
|
}
|
3440
3870
|
if (this.ready) {
|
3441
3871
|
const fn = this.ready.bind(this);
|
3442
|
-
const ready = await (0,
|
3872
|
+
const ready = await (0, import_cement16.exception2Result)(fn);
|
3443
3873
|
if (ready.isErr()) {
|
3444
3874
|
await this.close();
|
3445
3875
|
return ready;
|
3446
3876
|
}
|
3447
3877
|
}
|
3448
|
-
this._onStarted.forEach((fn) => fn());
|
3878
|
+
this._onStarted.forEach((fn) => fn(dam));
|
3449
3879
|
this.logger.Debug().Msg("started");
|
3450
3880
|
return version;
|
3451
3881
|
}
|
@@ -3474,12 +3904,19 @@ var MetaStoreImpl = class extends BaseStoreImpl {
|
|
3474
3904
|
/*this.remote && */
|
3475
3905
|
opts.gateway.subscribe
|
3476
3906
|
) {
|
3477
|
-
this.onStarted(async () => {
|
3907
|
+
this.onStarted(async (dam) => {
|
3478
3908
|
this.logger.Debug().Str("url", this.url().toString()).Msg("Subscribing to the gateway");
|
3479
3909
|
opts.gateway.subscribe({ loader: this.loader }, this.url(), async ({ payload: dbMetas }) => {
|
3480
3910
|
this.logger.Debug().Msg("Received message from gateway");
|
3481
3911
|
await Promise.all(
|
3482
|
-
dbMetas.map(
|
3912
|
+
dbMetas.map(
|
3913
|
+
(dbMetaEv) => this.loader.taskManager?.handleEvent(
|
3914
|
+
dbMetaEv.eventCid,
|
3915
|
+
dbMetaEv.parents,
|
3916
|
+
dbMetaEv.dbMeta,
|
3917
|
+
this.loader.attachedStores.activate(dam)
|
3918
|
+
)
|
3919
|
+
)
|
3483
3920
|
);
|
3484
3921
|
this.updateParentsFromDbMetas(dbMetas);
|
3485
3922
|
});
|
@@ -3501,8 +3938,7 @@ var MetaStoreImpl = class extends BaseStoreImpl {
|
|
3501
3938
|
// }
|
3502
3939
|
// return (rDbMeta.Ok() as FPEnvelopeMeta).payload;
|
3503
3940
|
// }
|
3504
|
-
async load() {
|
3505
|
-
const branch = "main";
|
3941
|
+
async load(branch = "main") {
|
3506
3942
|
const url = await this.gateway.buildUrl({ loader: this.loader }, this.url(), branch);
|
3507
3943
|
if (url.isErr()) {
|
3508
3944
|
throw this.logger.Error().Result("buildUrl", url).Str("branch", branch).Msg("got error from gateway.buildUrl").AsError();
|
@@ -3514,10 +3950,11 @@ var MetaStoreImpl = class extends BaseStoreImpl {
|
|
3514
3950
|
}
|
3515
3951
|
throw this.logger.Error().Url(url.Ok()).Err(rfpEnv).Msg("gateway get").AsError();
|
3516
3952
|
}
|
3517
|
-
const
|
3518
|
-
|
3519
|
-
this.
|
3520
|
-
|
3953
|
+
const fpMeta = rfpEnv.Ok().payload;
|
3954
|
+
const dbMetas = fpMeta.map((m) => m.dbMeta);
|
3955
|
+
await this.loader.handleDbMetasFromStore(dbMetas, this.loader.attachedStores.activate(url.Ok()));
|
3956
|
+
this.updateParentsFromDbMetas(fpMeta);
|
3957
|
+
return dbMetas;
|
3521
3958
|
}
|
3522
3959
|
async save(meta, branch) {
|
3523
3960
|
branch = branch || "main";
|
@@ -3539,7 +3976,7 @@ var MetaStoreImpl = class extends BaseStoreImpl {
|
|
3539
3976
|
async close() {
|
3540
3977
|
await this.gateway.close({ loader: this.loader }, this.url());
|
3541
3978
|
this._onClosed.forEach((fn) => fn());
|
3542
|
-
return
|
3979
|
+
return import_cement16.Result.Ok(void 0);
|
3543
3980
|
}
|
3544
3981
|
async destroy() {
|
3545
3982
|
this.logger.Debug().Msg("destroy");
|
@@ -3547,9 +3984,8 @@ var MetaStoreImpl = class extends BaseStoreImpl {
|
|
3547
3984
|
}
|
3548
3985
|
};
|
3549
3986
|
var DataStoreImpl = class extends BaseStoreImpl {
|
3550
|
-
constructor(sthis, url, opts) {
|
3551
|
-
super(sthis, url, { ...opts },
|
3552
|
-
this.storeType = "data";
|
3987
|
+
constructor(sthis, url, opts, logger) {
|
3988
|
+
super(sthis, url, { ...opts }, logger);
|
3553
3989
|
}
|
3554
3990
|
async load(cid) {
|
3555
3991
|
this.logger.Debug().Any("cid", cid).Msg("loading");
|
@@ -3564,7 +4000,6 @@ var DataStoreImpl = class extends BaseStoreImpl {
|
|
3564
4000
|
const fpenv = res.Ok();
|
3565
4001
|
switch (fpenv.type) {
|
3566
4002
|
case "car":
|
3567
|
-
return { cid, bytes: fpenv.payload };
|
3568
4003
|
case "file":
|
3569
4004
|
return { cid, bytes: fpenv.payload };
|
3570
4005
|
default:
|
@@ -3580,12 +4015,11 @@ var DataStoreImpl = class extends BaseStoreImpl {
|
|
3580
4015
|
}
|
3581
4016
|
let fpMsg;
|
3582
4017
|
switch (url.Ok().getParam(PARAM.STORE)) {
|
3583
|
-
case "
|
3584
|
-
|
3585
|
-
|
3586
|
-
|
3587
|
-
|
3588
|
-
}
|
4018
|
+
case "car":
|
4019
|
+
fpMsg = Car2FPMsg(car.bytes);
|
4020
|
+
break;
|
4021
|
+
case "file":
|
4022
|
+
fpMsg = File2FPMsg(car.bytes);
|
3589
4023
|
break;
|
3590
4024
|
default:
|
3591
4025
|
throw this.logger.Error().Str("store", url.Ok().getParam(PARAM.STORE)).Msg("unexpected store").AsError();
|
@@ -3609,20 +4043,32 @@ var DataStoreImpl = class extends BaseStoreImpl {
|
|
3609
4043
|
async close() {
|
3610
4044
|
await this.gateway.close({ loader: this.loader }, this.url());
|
3611
4045
|
this._onClosed.forEach((fn) => fn());
|
3612
|
-
return
|
4046
|
+
return import_cement16.Result.Ok(void 0);
|
3613
4047
|
}
|
3614
4048
|
destroy() {
|
3615
4049
|
this.logger.Debug().Msg("destroy");
|
3616
4050
|
return this.gateway.destroy({ loader: this.loader }, this.url());
|
3617
4051
|
}
|
3618
4052
|
};
|
4053
|
+
var CarStoreImpl = class extends DataStoreImpl {
|
4054
|
+
constructor(sthis, url, opts) {
|
4055
|
+
super(sthis, url, { ...opts }, ensureLogger(sthis, "CarStoreImpl"));
|
4056
|
+
this.storeType = "car";
|
4057
|
+
}
|
4058
|
+
};
|
4059
|
+
var FileStoreImpl = class extends DataStoreImpl {
|
4060
|
+
constructor(sthis, url, opts) {
|
4061
|
+
super(sthis, url, { ...opts }, ensureLogger(sthis, "FileStoreImpl"));
|
4062
|
+
this.storeType = "file";
|
4063
|
+
}
|
4064
|
+
};
|
3619
4065
|
var WALStoreImpl = class extends BaseStoreImpl {
|
3620
4066
|
constructor(sthis, url, opts) {
|
3621
4067
|
super(sthis, url, { ...opts }, ensureLogger(sthis, "WALStoreImpl"));
|
3622
4068
|
this.storeType = "wal";
|
3623
4069
|
// readonly tag: string = "rwal-base";
|
3624
4070
|
// readonly loader: Loadable;
|
3625
|
-
this._ready = new
|
4071
|
+
this._ready = new import_cement16.ResolveOnce();
|
3626
4072
|
this.walState = { operations: [], noLoaderOps: [], fileOperations: [] };
|
3627
4073
|
this.processing = void 0;
|
3628
4074
|
this.processQueue = new CommitQueue();
|
@@ -3663,7 +4109,6 @@ var WALStoreImpl = class extends BaseStoreImpl {
|
|
3663
4109
|
}
|
3664
4110
|
async process() {
|
3665
4111
|
await this.ready();
|
3666
|
-
if (!this.loader.remoteCarStore) return;
|
3667
4112
|
await this.processQueue.enqueue(async () => {
|
3668
4113
|
try {
|
3669
4114
|
await this._doProcess();
|
@@ -3677,7 +4122,6 @@ var WALStoreImpl = class extends BaseStoreImpl {
|
|
3677
4122
|
}
|
3678
4123
|
async _doProcess() {
|
3679
4124
|
if (!this.loader) return;
|
3680
|
-
if (!this.loader.remoteCarStore) return;
|
3681
4125
|
const operations = [...this.walState.operations];
|
3682
4126
|
const noLoaderOps = [...this.walState.noLoaderOps];
|
3683
4127
|
const fileOperations = [...this.walState.fileOperations];
|
@@ -3698,13 +4142,13 @@ var WALStoreImpl = class extends BaseStoreImpl {
|
|
3698
4142
|
return;
|
3699
4143
|
}
|
3700
4144
|
for (const cid of dbMeta.cars) {
|
3701
|
-
const car = await
|
4145
|
+
const car = await this.loader.attachedStores.local().active.car.load(cid);
|
3702
4146
|
if (!car) {
|
3703
|
-
if (carLogIncludesGroup(this.loader.carLog, dbMeta.cars)) {
|
4147
|
+
if (carLogIncludesGroup(this.loader.carLog.asArray(), dbMeta.cars)) {
|
3704
4148
|
throw this.logger.Error().Ref("cid", cid).Msg("missing local car").AsError();
|
3705
4149
|
}
|
3706
4150
|
} else {
|
3707
|
-
await
|
4151
|
+
await this.loader.attachedStores.forRemotes((x) => x.active.car.save(car));
|
3708
4152
|
}
|
3709
4153
|
}
|
3710
4154
|
inplaceFilter(this.walState.noLoaderOps, (op) => op !== dbMeta);
|
@@ -3720,13 +4164,13 @@ var WALStoreImpl = class extends BaseStoreImpl {
|
|
3720
4164
|
return;
|
3721
4165
|
}
|
3722
4166
|
for (const cid of dbMeta.cars) {
|
3723
|
-
const car = await
|
4167
|
+
const car = await this.loader.attachedStores.local().active.car.load(cid);
|
3724
4168
|
if (!car) {
|
3725
|
-
if (carLogIncludesGroup(this.loader.carLog, dbMeta.cars)) {
|
4169
|
+
if (carLogIncludesGroup(this.loader.carLog.asArray(), dbMeta.cars)) {
|
3726
4170
|
throw this.logger.Error().Ref("cid", cid).Msg(`missing local car`).AsError();
|
3727
4171
|
}
|
3728
4172
|
} else {
|
3729
|
-
await
|
4173
|
+
await this.loader.attachedStores.forRemotes((x) => x.active.car.save(car));
|
3730
4174
|
}
|
3731
4175
|
}
|
3732
4176
|
inplaceFilter(this.walState.operations, (op) => op !== dbMeta);
|
@@ -3741,11 +4185,11 @@ var WALStoreImpl = class extends BaseStoreImpl {
|
|
3741
4185
|
if (!this.loader) {
|
3742
4186
|
return;
|
3743
4187
|
}
|
3744
|
-
const fileBlock = await
|
4188
|
+
const fileBlock = await this.loader.attachedStores.local().active.file.load(fileCid);
|
3745
4189
|
if (!fileBlock) {
|
3746
4190
|
throw this.logger.Error().Ref("cid", fileCid).Msg("missing file block").AsError();
|
3747
4191
|
}
|
3748
|
-
await this.loader.
|
4192
|
+
await this.loader.attachedStores.forRemotes((x) => x.active.file.save(fileBlock, { public: publicFile }));
|
3749
4193
|
inplaceFilter(this.walState.fileOperations, (op) => op.cid !== fileCid);
|
3750
4194
|
}, `fileOperation with cid=${fileCid.toString()}`);
|
3751
4195
|
},
|
@@ -3757,7 +4201,7 @@ var WALStoreImpl = class extends BaseStoreImpl {
|
|
3757
4201
|
if (!this.loader) {
|
3758
4202
|
return;
|
3759
4203
|
}
|
3760
|
-
await this.loader.
|
4204
|
+
await this.loader.attachedStores.forRemotes((x) => x.active.meta.save(lastOp));
|
3761
4205
|
}, `remoteMetaStore save with dbMeta.cars=${lastOp.cars.toString()}`);
|
3762
4206
|
}
|
3763
4207
|
} catch (error) {
|
@@ -3801,7 +4245,7 @@ var WALStoreImpl = class extends BaseStoreImpl {
|
|
3801
4245
|
async close() {
|
3802
4246
|
await this.gateway.close({ loader: this.loader }, this.url());
|
3803
4247
|
this._onClosed.forEach((fn) => fn());
|
3804
|
-
return
|
4248
|
+
return import_cement16.Result.Ok(void 0);
|
3805
4249
|
}
|
3806
4250
|
destroy() {
|
3807
4251
|
this.logger.Debug().Msg("destroy");
|
@@ -3810,71 +4254,86 @@ var WALStoreImpl = class extends BaseStoreImpl {
|
|
3810
4254
|
};
|
3811
4255
|
|
3812
4256
|
// src/blockstore/store-factory.ts
|
3813
|
-
var onceGateway = new
|
3814
|
-
var gatewayInstances = new
|
4257
|
+
var onceGateway = new import_cement17.KeyedResolvOnce();
|
4258
|
+
var gatewayInstances = new import_cement17.KeyedResolvOnce();
|
3815
4259
|
async function getStartedGateway(ctx, url) {
|
3816
4260
|
return onceGateway.get(url.toString()).once(async () => {
|
3817
4261
|
const item = getGatewayFactoryItem(url.protocol);
|
3818
4262
|
if (item) {
|
3819
4263
|
const ret = {
|
3820
4264
|
url,
|
3821
|
-
...await gatewayInstances.get(url.protocol).once(async () => ({
|
3822
|
-
|
4265
|
+
...await gatewayInstances.get(url.protocol).once(async () => ({
|
4266
|
+
gateway: await item.serdegateway(ctx.loader.sthis)
|
4267
|
+
}))
|
3823
4268
|
};
|
3824
4269
|
const res = await ret.gateway.start(ctx, url);
|
3825
4270
|
if (res.isErr()) {
|
3826
|
-
return
|
4271
|
+
return import_cement17.Result.Err(ctx.loader.sthis.logger.Error().Result("start", res).Msg("start failed").AsError());
|
3827
4272
|
}
|
3828
4273
|
ret.url = res.Ok();
|
3829
|
-
return
|
4274
|
+
return import_cement17.Result.Ok(ret);
|
3830
4275
|
}
|
3831
|
-
return
|
4276
|
+
return import_cement17.Result.Err(ctx.loader.sthis.logger.Warn().Url(url).Msg("unsupported protocol").AsError());
|
4277
|
+
});
|
4278
|
+
}
|
4279
|
+
async function carStoreFactory(ctx, uai) {
|
4280
|
+
const storeUrl = uai.url.build().setParam(PARAM.STORE, "car").URI();
|
4281
|
+
const rgateway = await getStartedGateway(ctx, storeUrl);
|
4282
|
+
if (rgateway.isErr()) {
|
4283
|
+
throw ctx.loader.sthis.logger.Error().Result("err", rgateway).Url(uai.url).Msg("notfound").AsError();
|
4284
|
+
}
|
4285
|
+
const gateway = rgateway.Ok();
|
4286
|
+
const store = new CarStoreImpl(ctx.loader.sthis, gateway.url, {
|
4287
|
+
gateway: gateway.gateway,
|
4288
|
+
gatewayInterceptor: uai.gatewayInterceptor,
|
4289
|
+
loader: ctx.loader
|
3832
4290
|
});
|
4291
|
+
return store;
|
3833
4292
|
}
|
3834
|
-
async function
|
3835
|
-
const storeUrl =
|
3836
|
-
const rgateway = await getStartedGateway(
|
4293
|
+
async function fileStoreFactory(ctx, uai) {
|
4294
|
+
const storeUrl = uai.url.build().setParam(PARAM.STORE, "file").URI();
|
4295
|
+
const rgateway = await getStartedGateway(ctx, storeUrl);
|
3837
4296
|
if (rgateway.isErr()) {
|
3838
|
-
throw
|
4297
|
+
throw ctx.loader.sthis.logger.Error().Result("err", rgateway).Url(uai.url).Msg("notfound").AsError();
|
3839
4298
|
}
|
3840
4299
|
const gateway = rgateway.Ok();
|
3841
|
-
const store = new
|
4300
|
+
const store = new FileStoreImpl(ctx.loader.sthis, gateway.url, {
|
3842
4301
|
gateway: gateway.gateway,
|
3843
|
-
gatewayInterceptor:
|
3844
|
-
loader:
|
4302
|
+
gatewayInterceptor: uai.gatewayInterceptor,
|
4303
|
+
loader: ctx.loader
|
3845
4304
|
});
|
3846
4305
|
return store;
|
3847
4306
|
}
|
3848
|
-
async function metaStoreFactory(
|
3849
|
-
const storeUrl =
|
3850
|
-
const rgateway = await getStartedGateway(
|
4307
|
+
async function metaStoreFactory(ctx, uai) {
|
4308
|
+
const storeUrl = uai.url.build().setParam(PARAM.STORE, "meta").URI();
|
4309
|
+
const rgateway = await getStartedGateway(ctx, storeUrl);
|
3851
4310
|
if (rgateway.isErr()) {
|
3852
|
-
throw
|
4311
|
+
throw ctx.loader.sthis.logger.Error().Result("err", rgateway).Url(uai.url).Msg("notfound").AsError();
|
3853
4312
|
}
|
3854
4313
|
const gateway = rgateway.Ok();
|
3855
|
-
const store = new MetaStoreImpl(
|
4314
|
+
const store = new MetaStoreImpl(ctx.loader.sthis, gateway.url, {
|
3856
4315
|
gateway: gateway.gateway,
|
3857
|
-
gatewayInterceptor:
|
3858
|
-
loader:
|
4316
|
+
gatewayInterceptor: uai.gatewayInterceptor,
|
4317
|
+
loader: ctx.loader
|
3859
4318
|
});
|
3860
4319
|
return store;
|
3861
4320
|
}
|
3862
|
-
async function WALStoreFactory(
|
3863
|
-
const storeUrl =
|
3864
|
-
const rgateway = await getStartedGateway(
|
4321
|
+
async function WALStoreFactory(ctx, uai) {
|
4322
|
+
const storeUrl = uai.url.build().setParam(PARAM.STORE, "wal").URI();
|
4323
|
+
const rgateway = await getStartedGateway(ctx, storeUrl);
|
3865
4324
|
if (rgateway.isErr()) {
|
3866
|
-
throw
|
4325
|
+
throw ctx.loader.sthis.logger.Error().Result("err", rgateway).Url(uai.url).Msg("notfound").AsError();
|
3867
4326
|
}
|
3868
4327
|
const gateway = rgateway.Ok();
|
3869
|
-
const store = new WALStoreImpl(
|
4328
|
+
const store = new WALStoreImpl(ctx.loader.sthis, gateway.url, {
|
3870
4329
|
gateway: gateway.gateway,
|
3871
|
-
gatewayInterceptor:
|
3872
|
-
loader:
|
4330
|
+
gatewayInterceptor: uai.gatewayInterceptor,
|
4331
|
+
loader: ctx.loader
|
3873
4332
|
});
|
3874
4333
|
return store;
|
3875
4334
|
}
|
3876
|
-
async function ensureStart(store) {
|
3877
|
-
const ret = await store.start();
|
4335
|
+
async function ensureStart(store, damaw) {
|
4336
|
+
const ret = await store.start(damaw);
|
3878
4337
|
if (ret.isErr()) {
|
3879
4338
|
throw store.logger.Error().Result("start", ret).Msg("start failed").AsError();
|
3880
4339
|
}
|
@@ -3890,191 +4349,32 @@ function ensureStoreEnDeFile(ende) {
|
|
3890
4349
|
}
|
3891
4350
|
function toStoreRuntime(sthis, endeOpts = {}) {
|
3892
4351
|
return {
|
3893
|
-
|
3894
|
-
|
3895
|
-
|
3896
|
-
|
3897
|
-
|
3898
|
-
|
3899
|
-
|
3900
|
-
|
3901
|
-
|
3902
|
-
|
3903
|
-
|
3904
|
-
|
3905
|
-
|
3906
|
-
|
3907
|
-
|
3908
|
-
|
3909
|
-
|
3910
|
-
|
3911
|
-
|
3912
|
-
//
|
3913
|
-
//
|
3914
|
-
//
|
3915
|
-
// return ensureStart(await (endeOpts.func?.makeWALStore || remoteWalFactory)(loader), logger);
|
3916
|
-
// },
|
4352
|
+
makeStores: async (sfi) => {
|
4353
|
+
const ctx = {
|
4354
|
+
loader: sfi.loader
|
4355
|
+
};
|
4356
|
+
const storeSet = {};
|
4357
|
+
storeSet.meta = await metaStoreFactory(ctx, sfi.byStore.meta);
|
4358
|
+
storeSet.car = await carStoreFactory(ctx, sfi.byStore.car);
|
4359
|
+
storeSet.file = await fileStoreFactory(ctx, sfi.byStore.file);
|
4360
|
+
if (sfi.byStore.wal) {
|
4361
|
+
storeSet.wal = await WALStoreFactory(ctx, sfi.byStore.wal);
|
4362
|
+
}
|
4363
|
+
await ensureStart(storeSet.meta, storeSet);
|
4364
|
+
await ensureStart(storeSet.car, storeSet);
|
4365
|
+
await ensureStart(storeSet.file, storeSet);
|
4366
|
+
if (storeSet.wal) {
|
4367
|
+
await ensureStart(storeSet.wal, storeSet);
|
4368
|
+
}
|
4369
|
+
return storeSet;
|
4370
|
+
},
|
4371
|
+
// makeMetaStore: async (sfi: StoreFactoryItem) => ensureStart(await metaStoreFactory(sfi)),
|
4372
|
+
// makeDataStore: async (sfi: StoreFactoryItem) => ensureStart(await dataStoreFactory(sfi)),
|
4373
|
+
// makeWALStore: async (sfi: StoreFactoryItem) => ensureStart(await WALStoreFactory(sfi)),
|
3917
4374
|
...ensureStoreEnDeFile(endeOpts)
|
3918
4375
|
};
|
3919
4376
|
}
|
3920
4377
|
|
3921
|
-
// src/blockstore/connection-base.ts
|
3922
|
-
var import_cement17 = require("@adviser/cement");
|
3923
|
-
|
3924
|
-
// src/blockstore/store-remote.ts
|
3925
|
-
async function RemoteDataStore(sthis, url, opts) {
|
3926
|
-
const ds = new DataStoreImpl(sthis, url, opts);
|
3927
|
-
await ds.start();
|
3928
|
-
return ds;
|
3929
|
-
}
|
3930
|
-
async function RemoteMetaStore(sthis, url, opts) {
|
3931
|
-
const ms = new MetaStoreImpl(sthis, url, opts);
|
3932
|
-
await ms.start();
|
3933
|
-
return ms;
|
3934
|
-
}
|
3935
|
-
|
3936
|
-
// src/context.ts
|
3937
|
-
var Context = class {
|
3938
|
-
constructor() {
|
3939
|
-
this.ctx = /* @__PURE__ */ new Map();
|
3940
|
-
}
|
3941
|
-
set(key, value) {
|
3942
|
-
this.ctx.set(key, value);
|
3943
|
-
}
|
3944
|
-
get(key) {
|
3945
|
-
return this.ctx.get(key);
|
3946
|
-
}
|
3947
|
-
delete(key) {
|
3948
|
-
this.ctx.delete(key);
|
3949
|
-
}
|
3950
|
-
};
|
3951
|
-
|
3952
|
-
// src/blockstore/connection-base.ts
|
3953
|
-
function coerceLoader(ref) {
|
3954
|
-
const refl = ref;
|
3955
|
-
if (refl.loader) {
|
3956
|
-
return refl.loader;
|
3957
|
-
}
|
3958
|
-
const refb = ref;
|
3959
|
-
if (refb.blockstore) {
|
3960
|
-
return coerceLoader(refb.blockstore);
|
3961
|
-
}
|
3962
|
-
return void 0;
|
3963
|
-
}
|
3964
|
-
var ConnectionBase = class {
|
3965
|
-
constructor(url, logger) {
|
3966
|
-
// loaded: Promise<void> = Promise.resolve();
|
3967
|
-
this.context = new Context();
|
3968
|
-
this._loaded = /* @__PURE__ */ new Set();
|
3969
|
-
this._metaIsLoading = false;
|
3970
|
-
this.logger = logger;
|
3971
|
-
this.url = url;
|
3972
|
-
}
|
3973
|
-
loaded() {
|
3974
|
-
const f = new import_cement17.Future();
|
3975
|
-
if (!this._metaIsLoading) {
|
3976
|
-
f.resolve();
|
3977
|
-
} else {
|
3978
|
-
this._loaded.add(f);
|
3979
|
-
}
|
3980
|
-
return f;
|
3981
|
-
}
|
3982
|
-
async refresh() {
|
3983
|
-
await throwFalsy(throwFalsy(this.loader).remoteMetaStore).load();
|
3984
|
-
await (await throwFalsy(this.loader).WALStore()).process();
|
3985
|
-
}
|
3986
|
-
async connect(refl) {
|
3987
|
-
await this.connectMeta(refl);
|
3988
|
-
await this.connectStorage(refl);
|
3989
|
-
}
|
3990
|
-
async connectMeta(refl) {
|
3991
|
-
const loader = coerceLoader(refl);
|
3992
|
-
if (!loader) throw this.logger.Error().Msg("connectMeta: loader is required").AsError();
|
3993
|
-
this.loader = loader;
|
3994
|
-
await this.onConnect();
|
3995
|
-
const metaUrl = this.url.build().defParam(PARAM.STORE, "meta").URI();
|
3996
|
-
const rgateway = await getStartedGateway({ loader }, metaUrl);
|
3997
|
-
if (rgateway.isErr())
|
3998
|
-
throw this.logger.Error().Result("err", rgateway).Url(metaUrl).Msg("connectMeta: gateway is required").AsError();
|
3999
|
-
const dbName = metaUrl.getParam(PARAM.NAME);
|
4000
|
-
if (!dbName) {
|
4001
|
-
throw this.logger.Error().Url(metaUrl).Msg("connectMeta: dbName is required").AsError();
|
4002
|
-
}
|
4003
|
-
const gateway = rgateway.Ok();
|
4004
|
-
const remote = await RemoteMetaStore(loader.sthis, metaUrl, {
|
4005
|
-
gateway: gateway.gateway,
|
4006
|
-
loader
|
4007
|
-
});
|
4008
|
-
this.loader.remoteMetaStore = remote;
|
4009
|
-
this._metaIsLoading = true;
|
4010
|
-
this.loader.ready().then(async () => {
|
4011
|
-
return remote.load().then(async () => {
|
4012
|
-
const res = await (0, import_cement17.exception2Result)(async () => {
|
4013
|
-
return await (await throwFalsy(this.loader).WALStore()).process();
|
4014
|
-
});
|
4015
|
-
this._metaIsLoading = false;
|
4016
|
-
for (const f of this._loaded) {
|
4017
|
-
if (res.isErr()) {
|
4018
|
-
f.reject(res.Err());
|
4019
|
-
} else {
|
4020
|
-
f.resolve();
|
4021
|
-
}
|
4022
|
-
}
|
4023
|
-
this._loaded.clear();
|
4024
|
-
});
|
4025
|
-
});
|
4026
|
-
}
|
4027
|
-
async connectStorage(refl) {
|
4028
|
-
const loader = coerceLoader(refl);
|
4029
|
-
if (!loader) throw this.logger.Error().Msg("connectStorage: loader is required").AsError();
|
4030
|
-
this.loader = loader;
|
4031
|
-
const dataUrl = this.url.build().defParam(PARAM.STORE, "data").URI();
|
4032
|
-
const rgateway = await getStartedGateway({ loader }, dataUrl);
|
4033
|
-
if (rgateway.isErr())
|
4034
|
-
throw this.logger.Error().Result("err", rgateway).Url(dataUrl).Msg("connectStorage: gateway is required").AsError();
|
4035
|
-
const name = dataUrl.getParam(PARAM.NAME);
|
4036
|
-
if (!name) throw this.logger.Error().Url(dataUrl).Msg("connectStorage: name is required").AsError;
|
4037
|
-
loader.remoteCarStore = await RemoteDataStore(loader.sthis, this.url, {
|
4038
|
-
gateway: rgateway.Ok().gateway,
|
4039
|
-
loader
|
4040
|
-
});
|
4041
|
-
loader.remoteFileStore = loader.remoteCarStore;
|
4042
|
-
}
|
4043
|
-
// move this stuff to connect
|
4044
|
-
// async getDashboardURL(compact = true) {
|
4045
|
-
// const baseUrl = 'https://dashboard.fireproof.storage/'
|
4046
|
-
// if (!this.loader?.remoteCarStore) return new URL('/howto', baseUrl)
|
4047
|
-
// // if (compact) {
|
4048
|
-
// // await this.compact()
|
4049
|
-
// // }
|
4050
|
-
// const currents = await this.loader?.metaStore?.load()
|
4051
|
-
// if (!currents) throw new Error("Can't sync empty ledger: save data first")
|
4052
|
-
// if (currents.length > 1)
|
4053
|
-
// throw new Error("Can't sync ledger with split heads: make an update first")
|
4054
|
-
// const current = currents[0]
|
4055
|
-
// const params = {
|
4056
|
-
// car: current.car.toString()
|
4057
|
-
// }
|
4058
|
-
// if (current.key) {
|
4059
|
-
// // @ts-ignore
|
4060
|
-
// params.key = current.key.toString()
|
4061
|
-
// }
|
4062
|
-
// // @ts-ignore
|
4063
|
-
// if (this.name) {
|
4064
|
-
// // @ts-ignore
|
4065
|
-
// params.name = this.name
|
4066
|
-
// }
|
4067
|
-
// const url = new URL('/import#' + new URLSearchParams(params).toString(), baseUrl)
|
4068
|
-
// console.log('Import to dashboard: ' + url.toString())
|
4069
|
-
// return url
|
4070
|
-
// }
|
4071
|
-
// openDashboard() {
|
4072
|
-
// void this.getDashboardURL().then(url => {
|
4073
|
-
// if (url) window.open(url.toString(), '_blank')
|
4074
|
-
// })
|
4075
|
-
// }
|
4076
|
-
};
|
4077
|
-
|
4078
4378
|
// src/crdt-helpers.ts
|
4079
4379
|
var import_link2 = require("multiformats/link");
|
4080
4380
|
var import_sha26 = require("multiformats/hashes/sha2");
|
@@ -4095,6 +4395,34 @@ function toString(key, logger) {
|
|
4095
4395
|
throw logger.Error().Msg("Invalid key type").AsError();
|
4096
4396
|
}
|
4097
4397
|
}
|
4398
|
+
function sanitizeDocumentFields(obj) {
|
4399
|
+
if (Array.isArray(obj)) {
|
4400
|
+
return obj.map((item) => {
|
4401
|
+
if (typeof item === "object" && item !== null) {
|
4402
|
+
return sanitizeDocumentFields(item);
|
4403
|
+
}
|
4404
|
+
return item;
|
4405
|
+
});
|
4406
|
+
} else if (typeof obj === "object" && obj !== null) {
|
4407
|
+
const typedObj = obj;
|
4408
|
+
const result = {};
|
4409
|
+
for (const key in typedObj) {
|
4410
|
+
if (Object.hasOwnProperty.call(typedObj, key)) {
|
4411
|
+
const value = typedObj[key];
|
4412
|
+
if (value === null || !Number.isNaN(value) && value !== void 0) {
|
4413
|
+
if (typeof value === "object" && !key.startsWith("_")) {
|
4414
|
+
const sanitized = sanitizeDocumentFields(value);
|
4415
|
+
result[key] = sanitized;
|
4416
|
+
} else {
|
4417
|
+
result[key] = value;
|
4418
|
+
}
|
4419
|
+
}
|
4420
|
+
}
|
4421
|
+
}
|
4422
|
+
return result;
|
4423
|
+
}
|
4424
|
+
return obj;
|
4425
|
+
}
|
4098
4426
|
async function applyBulkUpdateToCrdt(store, tblocks, head, updates, logger) {
|
4099
4427
|
let result = null;
|
4100
4428
|
if (updates.length > 1) {
|
@@ -4184,7 +4512,8 @@ async function getValueFromCrdt(blocks, head, key, logger) {
|
|
4184
4512
|
if (!head.length) throw logger.Debug().Msg("Getting from an empty ledger").AsError();
|
4185
4513
|
const link = await (0, import_crdt.get)(blocks, head, key);
|
4186
4514
|
if (!link) throw logger.Error().Str("key", key).Msg(`Missing key`).AsError();
|
4187
|
-
|
4515
|
+
const ret = await getValueFromLink(blocks, link, logger);
|
4516
|
+
return ret;
|
4188
4517
|
}
|
4189
4518
|
function readFiles(blocks, { doc }) {
|
4190
4519
|
if (!doc) return;
|
@@ -4282,6 +4611,9 @@ async function gatherUpdates(blocks, eventsFetcher, head, since, updates = [], k
|
|
4282
4611
|
const { key, value } = ops[i];
|
4283
4612
|
if (!keys.has(key)) {
|
4284
4613
|
const docValue = await getValueFromLink(blocks, value, logger);
|
4614
|
+
if (key === PARAM.GENESIS_CID) {
|
4615
|
+
continue;
|
4616
|
+
}
|
4285
4617
|
updates.push({ id: key, value: docValue.doc, del: docValue.del, clock: link });
|
4286
4618
|
limit--;
|
4287
4619
|
keys.add(key);
|
@@ -4295,8 +4627,10 @@ async function gatherUpdates(blocks, eventsFetcher, head, since, updates = [], k
|
|
4295
4627
|
}
|
4296
4628
|
async function* getAllEntries(blocks, head, logger) {
|
4297
4629
|
for await (const [key, link] of (0, import_crdt.entries)(blocks, head)) {
|
4298
|
-
|
4299
|
-
|
4630
|
+
if (key !== PARAM.GENESIS_CID) {
|
4631
|
+
const docValue = await getValueFromLink(blocks, link, logger);
|
4632
|
+
yield { id: key, value: docValue.doc, del: docValue.del };
|
4633
|
+
}
|
4300
4634
|
}
|
4301
4635
|
}
|
4302
4636
|
async function* clockVis(blocks, head) {
|
@@ -4441,6 +4775,10 @@ var CRDTClockImpl = class {
|
|
4441
4775
|
this.notifyWatchers(internalUpdates || []);
|
4442
4776
|
}
|
4443
4777
|
notifyWatchers(updates) {
|
4778
|
+
updates = updates.filter((update) => update.id !== PARAM.GENESIS_CID);
|
4779
|
+
if (!updates.length) {
|
4780
|
+
return;
|
4781
|
+
}
|
4444
4782
|
this.emptyWatchers.forEach((fn) => fn());
|
4445
4783
|
this.watchers.forEach((fn) => fn(updates || []));
|
4446
4784
|
}
|
@@ -4520,7 +4858,7 @@ async function advanceBlocks(logger, newHead, tblocks, head) {
|
|
4520
4858
|
try {
|
4521
4859
|
head = await (0, import_clock4.advance)(tblocks, head, cid);
|
4522
4860
|
} catch (e) {
|
4523
|
-
logger.
|
4861
|
+
logger.Error().Err(e).Msg("failed to advance head");
|
4524
4862
|
continue;
|
4525
4863
|
}
|
4526
4864
|
}
|
@@ -4579,6 +4917,17 @@ var CRDTImpl = class {
|
|
4579
4917
|
}
|
4580
4918
|
async bulk(updates) {
|
4581
4919
|
await this.ready();
|
4920
|
+
updates = updates.map((dupdate) => ({
|
4921
|
+
...dupdate,
|
4922
|
+
value: sanitizeDocumentFields(dupdate.value)
|
4923
|
+
}));
|
4924
|
+
if (this.clock.head.length === 0) {
|
4925
|
+
const value = { id: PARAM.GENESIS_CID, value: { _id: PARAM.GENESIS_CID } };
|
4926
|
+
await this._bulk([value]);
|
4927
|
+
}
|
4928
|
+
return await this._bulk(updates);
|
4929
|
+
}
|
4930
|
+
async _bulk(updates) {
|
4582
4931
|
const prevHead = [...this.clock.head];
|
4583
4932
|
const done = await this.blockstore.transaction(async (blocks) => {
|
4584
4933
|
const { head } = await applyBulkUpdateToCrdt(
|
@@ -4649,6 +4998,22 @@ var CRDTImpl = class {
|
|
4649
4998
|
}
|
4650
4999
|
};
|
4651
5000
|
|
5001
|
+
// src/context.ts
|
5002
|
+
var Context = class {
|
5003
|
+
constructor() {
|
5004
|
+
this.ctx = /* @__PURE__ */ new Map();
|
5005
|
+
}
|
5006
|
+
set(key, value) {
|
5007
|
+
this.ctx.set(key, value);
|
5008
|
+
}
|
5009
|
+
get(key) {
|
5010
|
+
return this.ctx.get(key);
|
5011
|
+
}
|
5012
|
+
delete(key) {
|
5013
|
+
this.ctx.delete(key);
|
5014
|
+
}
|
5015
|
+
};
|
5016
|
+
|
4652
5017
|
// src/ledger.ts
|
4653
5018
|
var ledgers = new import_cement20.KeyedResolvOnce();
|
4654
5019
|
function keyConfigOpts(sthis, name, opts) {
|
@@ -4693,6 +5058,9 @@ var LedgerShell = class {
|
|
4693
5058
|
this.name = ref.name;
|
4694
5059
|
ref.addShell(this);
|
4695
5060
|
}
|
5061
|
+
attach(a) {
|
5062
|
+
return this.ref.attach(a);
|
5063
|
+
}
|
4696
5064
|
get opts() {
|
4697
5065
|
return this.ref.opts;
|
4698
5066
|
}
|
@@ -4791,11 +5159,16 @@ var LedgerImpl = class {
|
|
4791
5159
|
});
|
4792
5160
|
return ret;
|
4793
5161
|
}
|
5162
|
+
async attach(a) {
|
5163
|
+
await this.ready();
|
5164
|
+
return this.crdt.blockstore.loader.attach(a);
|
5165
|
+
}
|
4794
5166
|
// readonly _asDb = new ResolveOnce<Database>();
|
4795
5167
|
// asDB(): Database {
|
4796
5168
|
// return this._asDb.once(() => new DatabaseImpl(this));
|
4797
5169
|
// }
|
4798
5170
|
subscribe(listener, updates) {
|
5171
|
+
this.ready();
|
4799
5172
|
this.logger.Debug().Bool("updates", updates).Msg("subscribe");
|
4800
5173
|
if (updates) {
|
4801
5174
|
if (!this._listening) {
|
@@ -4837,26 +5210,6 @@ var LedgerImpl = class {
|
|
4837
5210
|
}
|
4838
5211
|
}
|
4839
5212
|
};
|
4840
|
-
function defaultURI2(sthis, name, curi, uri, store, ctx) {
|
4841
|
-
ctx = ctx || {};
|
4842
|
-
const ret = (curi ? import_cement20.URI.from(curi) : uri).build().setParam(PARAM.STORE, store).defParam(PARAM.NAME, name);
|
4843
|
-
if (!ret.hasParam(PARAM.NAME)) {
|
4844
|
-
throw sthis.logger.Error().Url(ret).Any("ctx", ctx).Msg("Ledger name is required").AsError();
|
4845
|
-
}
|
4846
|
-
if (ctx.idx) {
|
4847
|
-
ret.defParam(PARAM.INDEX, "idx");
|
4848
|
-
ret.defParam(PARAM.STORE_KEY, `@${ret.getParam(PARAM.NAME)}-${store}-idx@`);
|
4849
|
-
} else {
|
4850
|
-
ret.defParam(PARAM.STORE_KEY, `@${ret.getParam(PARAM.NAME)}-${store}@`);
|
4851
|
-
}
|
4852
|
-
if (store === "data") {
|
4853
|
-
if (ctx.file) {
|
4854
|
-
} else {
|
4855
|
-
ret.defParam(PARAM.SUFFIX, ".car");
|
4856
|
-
}
|
4857
|
-
}
|
4858
|
-
return ret.URI();
|
4859
|
-
}
|
4860
5213
|
function toStoreURIRuntime(sthis, name, sopts) {
|
4861
5214
|
sopts = sopts || {};
|
4862
5215
|
if (!sopts.base) {
|
@@ -4870,16 +5223,19 @@ function toStoreURIRuntime(sthis, name, sopts) {
|
|
4870
5223
|
const base = import_cement20.URI.from(sopts.base);
|
4871
5224
|
return {
|
4872
5225
|
idx: {
|
4873
|
-
|
4874
|
-
file:
|
4875
|
-
|
4876
|
-
|
5226
|
+
car: ensureURIDefaults(sthis, name, sopts.idx?.car ?? sopts.data?.car, base, "car", { idx: true }),
|
5227
|
+
file: ensureURIDefaults(sthis, name, sopts.idx?.file ?? sopts.idx?.car ?? sopts.data?.file ?? sopts.data?.car, base, "file", {
|
5228
|
+
file: true,
|
5229
|
+
idx: true
|
5230
|
+
}),
|
5231
|
+
meta: ensureURIDefaults(sthis, name, sopts.idx?.meta ?? sopts.data?.meta, base, "meta", { idx: true }),
|
5232
|
+
wal: ensureURIDefaults(sthis, name, sopts.idx?.wal ?? sopts.data?.wal, base, "wal", { idx: true })
|
4877
5233
|
},
|
4878
5234
|
data: {
|
4879
|
-
|
4880
|
-
file:
|
4881
|
-
meta:
|
4882
|
-
wal:
|
5235
|
+
car: ensureURIDefaults(sthis, name, sopts.data?.car, base, "car"),
|
5236
|
+
file: ensureURIDefaults(sthis, name, sopts.data?.file ?? sopts.data?.car, base, "file", { file: true }),
|
5237
|
+
meta: ensureURIDefaults(sthis, name, sopts.data?.meta, base, "meta"),
|
5238
|
+
wal: ensureURIDefaults(sthis, name, sopts.data?.wal, base, "wal")
|
4883
5239
|
}
|
4884
5240
|
};
|
4885
5241
|
}
|
@@ -4943,6 +5299,6 @@ __export(file_exports, {
|
|
4943
5299
|
|
4944
5300
|
// src/version.ts
|
4945
5301
|
var PACKAGE_VERSION = Object.keys({
|
4946
|
-
"0.20.0-dev-preview-
|
5302
|
+
"0.20.0-dev-preview-50": "xxxx"
|
4947
5303
|
})[0];
|
4948
5304
|
//# sourceMappingURL=index.cjs.map
|