@fireproof/core 0.20.0-dev-preview-41 → 0.20.0-dev-preview-51
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/deno.json +3 -2
- package/index.cjs +576 -342
- package/index.cjs.map +1 -1
- package/index.d.cts +210 -101
- package/index.d.ts +210 -101
- package/index.js +597 -362
- 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 +6 -4
- package/react/index.cjs.map +1 -1
- package/react/index.d.cts +3 -3
- package/react/index.d.ts +3 -3
- package/react/metafile-cjs.json +1 -1
- package/react/metafile-esm.json +1 -1
- package/tests/blockstore/interceptor-gateway.test.ts +11 -1
- package/tests/blockstore/keyed-crypto.test.ts +24 -23
- package/tests/blockstore/loader.test.ts +2 -2
- package/tests/blockstore/store.test.ts +8 -9
- package/tests/fireproof/all-gateway.test.ts +4 -4
- package/tests/fireproof/attachable.test.ts +295 -21
- package/tests/fireproof/crdt.test.ts +52 -13
- package/tests/fireproof/database.test.ts +79 -25
- package/tests/fireproof/fireproof.test.ts +24 -19
- package/tests/fireproof/stable-cid.test.ts +69 -0
- package/tests/fireproof/utils.test.ts +17 -7
- package/tests/gateway/file/loader-config.test.ts +8 -8
- package/tests/gateway/fp-envelope-serialize.test.ts +8 -8
- package/tests/gateway/indexeddb/loader-config.test.ts +2 -2
- package/tests/helpers.ts +8 -7
- package/tests/react/useFireproof.test.tsx +19 -13
package/index.cjs
CHANGED
@@ -48,6 +48,7 @@ __export(index_exports, {
|
|
48
48
|
ensureLogger: () => ensureLogger,
|
49
49
|
ensureSuperLog: () => ensureSuperLog,
|
50
50
|
ensureSuperThis: () => ensureSuperThis,
|
51
|
+
ensureURIDefaults: () => ensureURIDefaults,
|
51
52
|
exceptionWrapper: () => exceptionWrapper,
|
52
53
|
falsyToUndef: () => falsyToUndef,
|
53
54
|
fireproof: () => fireproof,
|
@@ -65,6 +66,7 @@ __export(index_exports, {
|
|
65
66
|
onSuperThis: () => onSuperThis,
|
66
67
|
rt: () => runtime_exports,
|
67
68
|
runtime: () => runtime_exports,
|
69
|
+
storeType2DataMetaWal: () => storeType2DataMetaWal,
|
68
70
|
throwFalsy: () => throwFalsy,
|
69
71
|
toSortedArray: () => toSortedArray,
|
70
72
|
toStoreURIRuntime: () => toStoreURIRuntime
|
@@ -101,8 +103,13 @@ var PARAM = {
|
|
101
103
|
FRAG_LEN: "len",
|
102
104
|
FRAG_HEAD: "headerSize",
|
103
105
|
EXTRACTKEY: "extractKey",
|
104
|
-
SELF_REFLECT: "selfReflect"
|
106
|
+
SELF_REFLECT: "selfReflect",
|
105
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"
|
106
113
|
// FS = "fs",
|
107
114
|
};
|
108
115
|
function throwFalsy(value) {
|
@@ -339,21 +346,25 @@ function ensureLogger(sthis, componentName, ctx) {
|
|
339
346
|
return out;
|
340
347
|
}
|
341
348
|
function getStore(url, sthis, joiner) {
|
342
|
-
const
|
343
|
-
|
344
|
-
|
349
|
+
const fromUrl = url.getParam(PARAM.STORE);
|
350
|
+
let pathPart;
|
351
|
+
switch (fromUrl) {
|
352
|
+
case "car":
|
353
|
+
case "file":
|
354
|
+
pathPart = "data";
|
355
|
+
break;
|
345
356
|
case "wal":
|
346
357
|
case "meta":
|
358
|
+
pathPart = fromUrl;
|
347
359
|
break;
|
348
360
|
default:
|
349
361
|
throw sthis.logger.Error().Url(url).Msg(`store not found`).AsError();
|
350
|
-
throw sthis.logger.Error().Url(url).Msg(`store not found`).AsError();
|
351
362
|
}
|
352
|
-
let name =
|
363
|
+
let name = pathPart;
|
353
364
|
if (url.hasParam("index")) {
|
354
365
|
name = joiner(url.getParam(PARAM.INDEX) || "idx", name);
|
355
366
|
}
|
356
|
-
return {
|
367
|
+
return { pathPart, fromUrl, name };
|
357
368
|
}
|
358
369
|
function getKey(url, logger) {
|
359
370
|
const result = url.getParam(PARAM.KEY);
|
@@ -455,6 +466,35 @@ function makeName(fnString) {
|
|
455
466
|
return found[1];
|
456
467
|
}
|
457
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
|
+
}
|
458
498
|
|
459
499
|
// src/write-queue.ts
|
460
500
|
var import_cement2 = require("@adviser/cement");
|
@@ -1136,8 +1176,10 @@ function getFileName(url, sthis) {
|
|
1136
1176
|
const key = url.getParam("key");
|
1137
1177
|
if (!key) throw sthis.logger.Error().Url(url).Msg(`key not found`).AsError();
|
1138
1178
|
const res = (0, import_core.getStore)(url, sthis, (...a) => a.join("-"));
|
1139
|
-
switch (res.
|
1140
|
-
case "
|
1179
|
+
switch (res.fromUrl) {
|
1180
|
+
case "file":
|
1181
|
+
return sthis.pathOps.join(res.name, key);
|
1182
|
+
case "car":
|
1141
1183
|
return sthis.pathOps.join(res.name, key + ".car");
|
1142
1184
|
case "wal":
|
1143
1185
|
case "meta":
|
@@ -1285,8 +1327,13 @@ var MemoryGateway = class {
|
|
1285
1327
|
close(baseUrl) {
|
1286
1328
|
return Promise.resolve(import_cement6.Result.Ok(void 0));
|
1287
1329
|
}
|
1288
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
1289
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
|
+
}
|
1290
1337
|
this.memorys.clear();
|
1291
1338
|
return Promise.resolve(import_cement6.Result.Ok(void 0));
|
1292
1339
|
}
|
@@ -1298,7 +1345,7 @@ var MemoryGateway = class {
|
|
1298
1345
|
get(url) {
|
1299
1346
|
const x = this.memorys.get(url.toString());
|
1300
1347
|
if (!x) {
|
1301
|
-
return Promise.resolve(import_cement6.Result.Err(new NotFoundError(`not found: ${url.
|
1348
|
+
return Promise.resolve(import_cement6.Result.Err(new NotFoundError(`not found: ${url.toString()}`)));
|
1302
1349
|
}
|
1303
1350
|
return Promise.resolve(import_cement6.Result.Ok(x));
|
1304
1351
|
}
|
@@ -1468,10 +1515,9 @@ async function fpDeserialize(sthis, url, intoRaw, pdecoder) {
|
|
1468
1515
|
...pdecoder
|
1469
1516
|
};
|
1470
1517
|
switch (url.getParam(PARAM.STORE)) {
|
1471
|
-
case "
|
1472
|
-
|
1473
|
-
|
1474
|
-
}
|
1518
|
+
case "car":
|
1519
|
+
return makeFPEnvelope(FPEnvelopeTypes.CAR, await decoder.car(sthis, raw2));
|
1520
|
+
case "file":
|
1475
1521
|
return makeFPEnvelope(FPEnvelopeTypes.FILE, await decoder.file(sthis, raw2));
|
1476
1522
|
case "wal":
|
1477
1523
|
return makeFPEnvelope(FPEnvelopeTypes.WAL, await decode2WalState(sthis, await decoder.wal(sthis, raw2)));
|
@@ -1533,7 +1579,7 @@ var DefSerdeGateway = class {
|
|
1533
1579
|
const urlWithoutKey = url.build().delParam(PARAM.KEY).delParam(PARAM.SELF_REFLECT).toString();
|
1534
1580
|
this.subscribeFn.set(urlWithoutKey, rawCallback);
|
1535
1581
|
return import_cement9.Result.Ok(() => {
|
1536
|
-
this.subscribeFn.delete(
|
1582
|
+
this.subscribeFn.delete(urlWithoutKey);
|
1537
1583
|
});
|
1538
1584
|
}
|
1539
1585
|
const unreg = await this.gw.subscribe(url, rawCallback, sthis);
|
@@ -1662,37 +1708,49 @@ var Block = import_block.Block;
|
|
1662
1708
|
async function decode({
|
1663
1709
|
bytes,
|
1664
1710
|
codec: codec3,
|
1665
|
-
hasher:
|
1711
|
+
hasher: hasher6
|
1666
1712
|
}) {
|
1667
1713
|
if (bytes == null) throw new Error('Missing required argument "bytes"');
|
1668
|
-
if (codec3 == null ||
|
1714
|
+
if (codec3 == null || hasher6 == null) throw new Error("Missing required argument: codec or hasher");
|
1669
1715
|
const value = await Promise.resolve(codec3.decode(bytes));
|
1670
|
-
|
1716
|
+
let toHash = bytes;
|
1717
|
+
if (codec3.valueToHashBytes) {
|
1718
|
+
toHash = await Promise.resolve(codec3.valueToHashBytes(value));
|
1719
|
+
}
|
1720
|
+
const hash = await hasher6.digest(toHash);
|
1671
1721
|
const cid = import_multiformats2.CID.create(1, codec3.code, hash);
|
1672
|
-
return new import_block.Block({ value, bytes, cid });
|
1722
|
+
return new import_block.Block({ value, bytes: toHash, cid });
|
1673
1723
|
}
|
1674
1724
|
async function encode({
|
1675
1725
|
value,
|
1676
1726
|
codec: codec3,
|
1677
|
-
hasher:
|
1727
|
+
hasher: hasher6
|
1678
1728
|
}) {
|
1679
1729
|
if (typeof value === "undefined") throw new Error('Missing required argument "value"');
|
1680
|
-
if (codec3 == null ||
|
1681
|
-
|
1682
|
-
|
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
|
+
}
|
1683
1741
|
const cid = import_multiformats2.CID.create(1, codec3.code, hash);
|
1684
|
-
return new
|
1742
|
+
return new Block({ value, bytes, cid });
|
1685
1743
|
}
|
1686
1744
|
async function create({
|
1687
1745
|
bytes,
|
1688
1746
|
cid,
|
1689
|
-
hasher:
|
1747
|
+
hasher: hasher6,
|
1690
1748
|
codec: codec3
|
1691
1749
|
}) {
|
1692
1750
|
if (bytes == null) throw new Error('Missing required argument "bytes"');
|
1693
|
-
if (
|
1751
|
+
if (hasher6 == null) throw new Error('Missing required argument "hasher"');
|
1694
1752
|
const value = await Promise.resolve(codec3.decode(bytes));
|
1695
|
-
const hash = await
|
1753
|
+
const hash = await hasher6.digest(bytes);
|
1696
1754
|
if (!import_multiformats2.bytes.equals(cid.multihash.bytes, hash.bytes)) {
|
1697
1755
|
throw new Error("CID hash does not match bytes");
|
1698
1756
|
}
|
@@ -1904,7 +1962,7 @@ var Index = class {
|
|
1904
1962
|
if (this.mapFn) {
|
1905
1963
|
if (mapFn) {
|
1906
1964
|
if (this.mapFn.toString() !== mapFn.toString()) {
|
1907
|
-
|
1965
|
+
this.logger.Error().Msg("cannot apply different mapFn app2");
|
1908
1966
|
}
|
1909
1967
|
}
|
1910
1968
|
} else {
|
@@ -1913,7 +1971,7 @@ var Index = class {
|
|
1913
1971
|
}
|
1914
1972
|
if (this.mapFnString) {
|
1915
1973
|
if (this.mapFnString !== mapFn.toString()) {
|
1916
|
-
|
1974
|
+
this.logger.Error().Str("mapFnString", this.mapFnString).Str("mapFn", mapFn.toString()).Msg("cannot apply different mapFn app");
|
1917
1975
|
}
|
1918
1976
|
} else {
|
1919
1977
|
this.mapFnString = mapFn.toString();
|
@@ -2189,8 +2247,11 @@ var import_cement19 = require("@adviser/cement");
|
|
2189
2247
|
var blockstore_exports = {};
|
2190
2248
|
__export(blockstore_exports, {
|
2191
2249
|
AttachedRemotesImpl: () => AttachedRemotesImpl,
|
2250
|
+
BaseActiveStore: () => BaseActiveStore,
|
2192
2251
|
BaseBlockstoreImpl: () => BaseBlockstoreImpl,
|
2193
2252
|
Car2FPMsg: () => Car2FPMsg,
|
2253
|
+
CarActiveStore: () => CarActiveStore,
|
2254
|
+
CarLog: () => CarLog,
|
2194
2255
|
CarTransactionImpl: () => CarTransactionImpl,
|
2195
2256
|
CompactionFetcher: () => CompactionFetcher,
|
2196
2257
|
DbMetaEventEqual: () => DbMetaEventEqual,
|
@@ -2198,9 +2259,13 @@ __export(blockstore_exports, {
|
|
2198
2259
|
EncryptedBlockstore: () => EncryptedBlockstore,
|
2199
2260
|
FPEnvelopeTypes: () => FPEnvelopeTypes,
|
2200
2261
|
File2FPMsg: () => File2FPMsg,
|
2262
|
+
FileActiveStore: () => FileActiveStore,
|
2201
2263
|
InterceptorGateway: () => InterceptorGateway,
|
2202
2264
|
Loader: () => Loader,
|
2265
|
+
MetaActiveStore: () => MetaActiveStore,
|
2203
2266
|
PassThroughGateway: () => PassThroughGateway,
|
2267
|
+
TaskManager: () => TaskManager,
|
2268
|
+
WALActiveStore: () => WALActiveStore,
|
2204
2269
|
createAttachedStores: () => createAttachedStores,
|
2205
2270
|
createDbMetaEvent: () => createDbMetaEvent,
|
2206
2271
|
defaultGatewayFactoryItem: () => defaultGatewayFactoryItem,
|
@@ -2215,6 +2280,37 @@ __export(blockstore_exports, {
|
|
2215
2280
|
});
|
2216
2281
|
|
2217
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
|
+
};
|
2218
2314
|
function toCIDBlock(block) {
|
2219
2315
|
return block;
|
2220
2316
|
}
|
@@ -2224,6 +2320,16 @@ function DbMetaEventEqual(a, b) {
|
|
2224
2320
|
function DbMetaEventsEqual(a, b) {
|
2225
2321
|
return a.length === b.length && a.every((e, i) => DbMetaEventEqual(e, b[i]));
|
2226
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
|
+
};
|
2227
2333
|
|
2228
2334
|
// src/blockstore/store-factory.ts
|
2229
2335
|
var import_cement17 = require("@adviser/cement");
|
@@ -2240,8 +2346,8 @@ var import_cement14 = require("@adviser/cement");
|
|
2240
2346
|
var import_sha22 = require("multiformats/hashes/sha2");
|
2241
2347
|
var dagCodec = __toESM(require("@ipld/dag-cbor"), 1);
|
2242
2348
|
async function parseCarFile(reader, logger) {
|
2243
|
-
const roots = await reader.
|
2244
|
-
const header =
|
2349
|
+
const roots = await reader.roots;
|
2350
|
+
const header = reader.blocks.find((i) => i.cid.equals(roots[0]));
|
2245
2351
|
if (!header) throw logger.Error().Msg("missing header block").AsError();
|
2246
2352
|
const dec = await decode({ bytes: header.bytes, hasher: import_sha22.sha256, codec: dagCodec });
|
2247
2353
|
const fpvalue = dec.value;
|
@@ -2256,6 +2362,7 @@ var import_block4 = require("@fireproof/vendor/@web3-storage/pail/block");
|
|
2256
2362
|
var import_cement11 = require("@adviser/cement");
|
2257
2363
|
var CarTransactionImpl = class {
|
2258
2364
|
#memblock = new import_block4.MemoryBlockstore();
|
2365
|
+
#hackUnshift;
|
2259
2366
|
constructor(parent, opts = { add: true, noLoader: false }) {
|
2260
2367
|
if (opts.add) {
|
2261
2368
|
parent.transactions.add(this);
|
@@ -2263,7 +2370,7 @@ var CarTransactionImpl = class {
|
|
2263
2370
|
this.parent = parent;
|
2264
2371
|
}
|
2265
2372
|
async get(cid) {
|
2266
|
-
return await this.superGet(cid)
|
2373
|
+
return await this.superGet(cid) ?? falsyToUndef(await this.parent.get(cid));
|
2267
2374
|
}
|
2268
2375
|
async superGet(cid) {
|
2269
2376
|
return this.#memblock.get(cid);
|
@@ -2274,7 +2381,16 @@ var CarTransactionImpl = class {
|
|
2274
2381
|
putSync(cid, bytes) {
|
2275
2382
|
this.#memblock.putSync(cid, bytes);
|
2276
2383
|
}
|
2384
|
+
unshift(cid, bytes) {
|
2385
|
+
if (this.#hackUnshift) {
|
2386
|
+
throw new Error("unshift already called");
|
2387
|
+
}
|
2388
|
+
this.#hackUnshift = { cid, bytes };
|
2389
|
+
}
|
2277
2390
|
async *entries() {
|
2391
|
+
if (this.#hackUnshift) {
|
2392
|
+
yield this.#hackUnshift;
|
2393
|
+
}
|
2278
2394
|
for await (const blk of this.#memblock.entries()) {
|
2279
2395
|
yield blk;
|
2280
2396
|
}
|
@@ -2300,6 +2416,11 @@ function defaultedBlockstoreRuntime(sthis, opts, component, ctx) {
|
|
2300
2416
|
keyBag: opts.keyBag || {},
|
2301
2417
|
crypto: (0, import_cement11.toCryptoRuntime)(opts.crypto),
|
2302
2418
|
storeUrls: opts.storeUrls,
|
2419
|
+
taskManager: {
|
2420
|
+
removeAfter: 3,
|
2421
|
+
retryTimeout: 50,
|
2422
|
+
...opts.taskManager
|
2423
|
+
},
|
2303
2424
|
// storeEnDeFile: ensureStoreEnDeFile(opts.storeEnDeFile),
|
2304
2425
|
// store,
|
2305
2426
|
storeRuntime: toStoreRuntime(sthis, ensureStoreEnDeFile(opts.storeEnDeFile))
|
@@ -2392,10 +2513,8 @@ var EncryptedBlockstore = class extends BaseBlockstoreImpl {
|
|
2392
2513
|
async get(cid) {
|
2393
2514
|
const got = await super.get(cid);
|
2394
2515
|
if (got) return got;
|
2395
|
-
|
2396
|
-
|
2397
|
-
}
|
2398
|
-
return falsyToUndef(await this.loader.getBlock(cid, this.loader.attachedStores.local()));
|
2516
|
+
const ret = falsyToUndef(await this.loader.getBlock(cid, this.loader.attachedStores.local()));
|
2517
|
+
return ret;
|
2399
2518
|
}
|
2400
2519
|
async transaction(fn, opts = { noLoader: false }) {
|
2401
2520
|
this.logger.Debug().Msg("enter transaction");
|
@@ -2416,7 +2535,7 @@ var EncryptedBlockstore = class extends BaseBlockstoreImpl {
|
|
2416
2535
|
await this.ready();
|
2417
2536
|
if (!this.loader) throw this.logger.Error().Msg("loader required to get file, ledger must be named").AsError();
|
2418
2537
|
const reader = await this.loader.loadFileCar(car, this.loader.attachedStores.local());
|
2419
|
-
const block = await reader.
|
2538
|
+
const block = await reader.blocks.find((i) => i.cid.equals(cid));
|
2420
2539
|
if (!block) throw this.logger.Error().Str("cid", cid.toString()).Msg(`Missing block`).AsError();
|
2421
2540
|
return block.bytes;
|
2422
2541
|
}
|
@@ -2523,8 +2642,8 @@ var CommitQueue = class {
|
|
2523
2642
|
|
2524
2643
|
// src/blockstore/commitor.ts
|
2525
2644
|
var CBW = __toESM(require("@ipld/car/buffer-writer"), 1);
|
2526
|
-
var import_sha23 = require("multiformats/hashes/sha2");
|
2527
2645
|
var dagCodec2 = __toESM(require("@ipld/dag-cbor"), 1);
|
2646
|
+
var import_sha23 = require("multiformats/hashes/sha2");
|
2528
2647
|
async function encodeCarFile(roots, t, codec3) {
|
2529
2648
|
let size = 0;
|
2530
2649
|
const headerSize = CBW.headerLength({ roots });
|
@@ -2549,7 +2668,7 @@ async function createCarFile(encoder, cid, t) {
|
|
2549
2668
|
async function commitFiles(fileStore, walStore, t, done) {
|
2550
2669
|
const { files: roots } = makeFileCarHeader(done);
|
2551
2670
|
const cids = [];
|
2552
|
-
const codec3 =
|
2671
|
+
const codec3 = await fileStore.keyedCrypto().then((i) => i.codec());
|
2553
2672
|
const cars = await prepareCarFilesFiles(codec3, roots, t);
|
2554
2673
|
for (const car of cars) {
|
2555
2674
|
const { cid, bytes } = car;
|
@@ -2575,7 +2694,7 @@ async function prepareCarFilesFiles(encoder, roots, t) {
|
|
2575
2694
|
return [await encodeCarFile(roots, t, encoder)];
|
2576
2695
|
}
|
2577
2696
|
function makeCarHeader(meta, cars, compact = false) {
|
2578
|
-
const coreHeader = compact ? { cars: [], compact: cars } : { cars, compact: [] };
|
2697
|
+
const coreHeader = compact ? { cars: [], compact: cars.asArray() } : { cars: cars.asArray(), compact: [] };
|
2579
2698
|
return { ...coreHeader, meta };
|
2580
2699
|
}
|
2581
2700
|
async function encodeCarHeader(fp) {
|
@@ -2602,7 +2721,7 @@ async function commit(params, t, done, opts = { noLoader: false, compact: false
|
|
2602
2721
|
}
|
2603
2722
|
async function prepareCarFiles(encoder, threshold, rootBlock, t) {
|
2604
2723
|
const carFiles = [];
|
2605
|
-
threshold = threshold ||
|
2724
|
+
threshold = threshold || 16 * 65536;
|
2606
2725
|
let clonedt = new CarTransactionImpl(t.parent, { add: false, noLoader: false });
|
2607
2726
|
clonedt.putSync(rootBlock.cid, rootBlock.bytes);
|
2608
2727
|
let newsize = CBW.blockLength(toCIDBlock(rootBlock));
|
@@ -2628,13 +2747,14 @@ var import_sha24 = require("multiformats/hashes/sha2");
|
|
2628
2747
|
|
2629
2748
|
// src/blockstore/task-manager.ts
|
2630
2749
|
var TaskManager = class {
|
2631
|
-
constructor(sthis, callback) {
|
2750
|
+
constructor(sthis, callback, params) {
|
2632
2751
|
// we need to remove the events after some time
|
2633
2752
|
this.eventsWeHandled = /* @__PURE__ */ new Set();
|
2634
2753
|
this.queue = [];
|
2635
2754
|
this.isProcessing = false;
|
2636
2755
|
this.logger = ensureLogger(sthis, "TaskManager");
|
2637
2756
|
this.callback = callback;
|
2757
|
+
this.params = params;
|
2638
2758
|
}
|
2639
2759
|
async handleEvent(cid, parents, dbMeta, store) {
|
2640
2760
|
for (const parent of parents) {
|
@@ -2663,7 +2783,7 @@ var TaskManager = class {
|
|
2663
2783
|
this.queue = this.queue.filter(({ cid }) => cid !== first.cid);
|
2664
2784
|
}
|
2665
2785
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
2666
|
-
|
2786
|
+
this.logger.Warn().Err(err).Msg("retry to process event block");
|
2667
2787
|
} finally {
|
2668
2788
|
this.isProcessing = false;
|
2669
2789
|
if (this.queue.length > 0) {
|
@@ -2693,11 +2813,32 @@ var AttachedImpl = class {
|
|
2693
2813
|
return "attached";
|
2694
2814
|
}
|
2695
2815
|
};
|
2696
|
-
var
|
2816
|
+
var FileActiveStoreImpl = class extends FileActiveStore {
|
2697
2817
|
constructor(ref, active, attached) {
|
2818
|
+
super();
|
2698
2819
|
this.ref = ref;
|
2699
2820
|
this.active = active;
|
2700
|
-
this.
|
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)];
|
2701
2842
|
}
|
2702
2843
|
};
|
2703
2844
|
var CarAttachedStoresImpl = class {
|
@@ -2722,11 +2863,18 @@ var FileAttachedStoresImpl = class {
|
|
2722
2863
|
return this.attached.remotes().map(({ active }) => active.file);
|
2723
2864
|
}
|
2724
2865
|
};
|
2725
|
-
var MetaActiveStoreImpl = class {
|
2866
|
+
var MetaActiveStoreImpl = class extends MetaActiveStore {
|
2726
2867
|
constructor(ref, active, attached) {
|
2868
|
+
super();
|
2727
2869
|
this.ref = ref;
|
2728
2870
|
this.active = active;
|
2729
|
-
this.
|
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)];
|
2730
2878
|
}
|
2731
2879
|
};
|
2732
2880
|
var MetaAttachedStoresImpl = class {
|
@@ -2740,11 +2888,18 @@ var MetaAttachedStoresImpl = class {
|
|
2740
2888
|
return this.attached.remotes().map(({ active }) => active.meta);
|
2741
2889
|
}
|
2742
2890
|
};
|
2743
|
-
var WALActiveStoreImpl = class {
|
2891
|
+
var WALActiveStoreImpl = class extends WALActiveStore {
|
2744
2892
|
constructor(ref, active, attached) {
|
2893
|
+
super();
|
2745
2894
|
this.ref = ref;
|
2746
2895
|
this.active = active;
|
2747
|
-
this.
|
2896
|
+
this.xattached = attached;
|
2897
|
+
}
|
2898
|
+
local() {
|
2899
|
+
return this.xattached.local();
|
2900
|
+
}
|
2901
|
+
remotes() {
|
2902
|
+
return this.xattached.remotes();
|
2748
2903
|
}
|
2749
2904
|
};
|
2750
2905
|
var WALAttachedStoresImpl = class {
|
@@ -2761,7 +2916,13 @@ var WALAttachedStoresImpl = class {
|
|
2761
2916
|
var ActiveStoreImpl = class {
|
2762
2917
|
constructor(active, attached) {
|
2763
2918
|
this.active = active;
|
2764
|
-
this.
|
2919
|
+
this.xattached = attached;
|
2920
|
+
}
|
2921
|
+
local() {
|
2922
|
+
return this.xattached.local();
|
2923
|
+
}
|
2924
|
+
remotes() {
|
2925
|
+
return this.xattached.remotes();
|
2765
2926
|
}
|
2766
2927
|
baseStores() {
|
2767
2928
|
const bs = [this.active.car, this.active.file, this.active.meta];
|
@@ -2771,19 +2932,19 @@ var ActiveStoreImpl = class {
|
|
2771
2932
|
return bs;
|
2772
2933
|
}
|
2773
2934
|
carStore() {
|
2774
|
-
return new
|
2935
|
+
return new CarActiveStoreImpl(this, this.active.car, new CarAttachedStoresImpl(this.xattached));
|
2775
2936
|
}
|
2776
2937
|
fileStore() {
|
2777
|
-
return new
|
2938
|
+
return new FileActiveStoreImpl(this, this.active.file, new FileAttachedStoresImpl(this.xattached));
|
2778
2939
|
}
|
2779
2940
|
metaStore() {
|
2780
|
-
return new MetaActiveStoreImpl(this, this.active.meta, new MetaAttachedStoresImpl(this.
|
2941
|
+
return new MetaActiveStoreImpl(this, this.active.meta, new MetaAttachedStoresImpl(this.xattached));
|
2781
2942
|
}
|
2782
2943
|
walStore() {
|
2783
2944
|
if (!this.active.wal) {
|
2784
|
-
throw this.
|
2945
|
+
throw this.xattached.loadable.sthis.logger.Error().Msg("wal store not set").AsError();
|
2785
2946
|
}
|
2786
|
-
return new WALActiveStoreImpl(this, this.active.wal, new WALAttachedStoresImpl(this.
|
2947
|
+
return new WALActiveStoreImpl(this, this.active.wal, new WALAttachedStoresImpl(this.xattached));
|
2787
2948
|
}
|
2788
2949
|
};
|
2789
2950
|
function isLoadable(unknown) {
|
@@ -2835,7 +2996,25 @@ var AttachedRemotesImpl = class {
|
|
2835
2996
|
}
|
2836
2997
|
activate(store) {
|
2837
2998
|
if ((0, import_cement13.isCoerceURI)(store)) {
|
2838
|
-
|
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;
|
2839
3018
|
}
|
2840
3019
|
return new ActiveStoreImpl(store, this);
|
2841
3020
|
}
|
@@ -2853,19 +3032,19 @@ var AttachedRemotesImpl = class {
|
|
2853
3032
|
const gws = {
|
2854
3033
|
car: {
|
2855
3034
|
...gwp.car,
|
2856
|
-
url: import_cement13.
|
3035
|
+
url: ensureURIDefaults(this.loadable.sthis, attached.name, gwp.car.url, import_cement13.URI.from(gwp.car.url), "car")
|
2857
3036
|
},
|
2858
3037
|
file: {
|
2859
3038
|
...gwp.file,
|
2860
|
-
url: import_cement13.
|
3039
|
+
url: ensureURIDefaults(this.loadable.sthis, attached.name, void 0, import_cement13.URI.from(gwp.file.url), "file", { file: true })
|
2861
3040
|
},
|
2862
3041
|
meta: {
|
2863
3042
|
...gwp.meta,
|
2864
|
-
url: import_cement13.
|
3043
|
+
url: ensureURIDefaults(this.loadable.sthis, attached.name, void 0, import_cement13.URI.from(gwp.meta.url), "meta")
|
2865
3044
|
},
|
2866
3045
|
wal: gwp.wal ? {
|
2867
3046
|
...gwp.wal,
|
2868
|
-
url: import_cement13.
|
3047
|
+
url: ensureURIDefaults(this.loadable.sthis, attached.name, void 0, import_cement13.URI.from(gwp.wal.url), "wal")
|
2869
3048
|
} : void 0
|
2870
3049
|
};
|
2871
3050
|
const key = JSON.stringify(
|
@@ -2884,11 +3063,6 @@ var AttachedRemotesImpl = class {
|
|
2884
3063
|
byStore: gws,
|
2885
3064
|
loader: this.loadable
|
2886
3065
|
}),
|
2887
|
-
// {
|
2888
|
-
// car: await rt.makeDataStore({ url: gws.carUrl, loader: this.loadable }),
|
2889
|
-
// file: await rt.makeDataStore({ url: gws.filesUrl, loader: this.loadable }),
|
2890
|
-
// meta: await rt.makeMetaStore({ url: gws.metaUrl, loader: this.loadable }),
|
2891
|
-
// },
|
2892
3066
|
() => {
|
2893
3067
|
this._remotes.unget(key);
|
2894
3068
|
}
|
@@ -2906,11 +3080,12 @@ var AttachedRemotesImpl = class {
|
|
2906
3080
|
|
2907
3081
|
// src/blockstore/loader.ts
|
2908
3082
|
function carLogIncludesGroup(list, cids) {
|
2909
|
-
|
2910
|
-
|
2911
|
-
|
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
|
+
);
|
2912
3087
|
}
|
2913
|
-
function uniqueCids(list, remove =
|
3088
|
+
function uniqueCids(list, remove = new import_cement14.LRUSet()) {
|
2914
3089
|
const byString = /* @__PURE__ */ new Map();
|
2915
3090
|
for (const cid of list) {
|
2916
3091
|
if (remove.has(cid.toString())) continue;
|
@@ -2922,13 +3097,8 @@ var Loader = class {
|
|
2922
3097
|
constructor(sthis, ebOpts) {
|
2923
3098
|
this.commitQueue = new CommitQueue();
|
2924
3099
|
this.isCompacting = false;
|
2925
|
-
this.
|
2926
|
-
this.
|
2927
|
-
this.processedCars = /* @__PURE__ */ new Set();
|
2928
|
-
this.carLog = [];
|
2929
|
-
this.getBlockCache = /* @__PURE__ */ new Map();
|
2930
|
-
this.seenMeta = /* @__PURE__ */ new Set();
|
2931
|
-
this.writeLimit = (0, import_p_limit.default)(1);
|
3100
|
+
this.maxConcurrentWrite = (0, import_p_limit.default)(1);
|
3101
|
+
this.carLog = new CarLog();
|
2932
3102
|
this.onceReady = new import_cement14.ResolveOnce();
|
2933
3103
|
this.sthis = sthis;
|
2934
3104
|
this.ebOpts = defaultedBlockstoreRuntime(
|
@@ -2939,63 +3109,44 @@ var Loader = class {
|
|
2939
3109
|
},
|
2940
3110
|
"Loader"
|
2941
3111
|
);
|
2942
|
-
this.logger =
|
2943
|
-
this.
|
2944
|
-
|
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
|
+
}
|
3117
|
+
});
|
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)
|
2945
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
|
3131
|
+
);
|
2946
3132
|
this.attachedStores = new AttachedRemotesImpl(this);
|
2947
3133
|
}
|
2948
|
-
attach(attached) {
|
2949
|
-
|
2950
|
-
|
2951
|
-
|
2952
|
-
|
2953
|
-
|
2954
|
-
|
2955
|
-
|
2956
|
-
|
2957
|
-
|
2958
|
-
|
2959
|
-
|
2960
|
-
|
2961
|
-
|
2962
|
-
|
2963
|
-
|
2964
|
-
// async fileStore(): Promise<DataStore> {
|
2965
|
-
// return this._fileStore.once(async () =>
|
2966
|
-
// this.ebOpts.storeRuntime.makeDataStore({
|
2967
|
-
// // sthis: this.sthis,
|
2968
|
-
// gatewayInterceptor: this.ebOpts.gatewayInterceptor,
|
2969
|
-
// url: this.ebOpts.storeUrls.file,
|
2970
|
-
// // keybag: await this.keyBag(),
|
2971
|
-
// loader: this,
|
2972
|
-
// }),
|
2973
|
-
// );
|
2974
|
-
// }
|
2975
|
-
// private readonly _WALStore = new ResolveOnce<WALStore>();
|
2976
|
-
// async WALStore(): Promise<WALStore> {
|
2977
|
-
// return this._WALStore.once(async () =>
|
2978
|
-
// this.ebOpts.storeRuntime.makeWALStore({
|
2979
|
-
// // sthis: this.sthis,
|
2980
|
-
// gatewayInterceptor: this.ebOpts.gatewayInterceptor,
|
2981
|
-
// url: this.ebOpts.storeUrls.wal,
|
2982
|
-
// // keybag: await this.keyBag(),
|
2983
|
-
// loader: this,
|
2984
|
-
// }),
|
2985
|
-
// );
|
2986
|
-
// }
|
2987
|
-
// private readonly _metaStore = new ResolveOnce<MetaStore>();
|
2988
|
-
// async metaStore(): Promise<MetaStore> {
|
2989
|
-
// return this._metaStore.once(async () =>
|
2990
|
-
// this.ebOpts.storeRuntime.makeMetaStore({
|
2991
|
-
// // sthis: this.sthis,
|
2992
|
-
// gatewayInterceptor: this.ebOpts.gatewayInterceptor,
|
2993
|
-
// url: this.ebOpts.storeUrls.meta,
|
2994
|
-
// // keybag: await this.keyBag(),
|
2995
|
-
// loader: this,
|
2996
|
-
// }),
|
2997
|
-
// );
|
2998
|
-
// }
|
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;
|
3149
|
+
}
|
2999
3150
|
keyBag() {
|
3000
3151
|
return getKeyBag(this.sthis, this.ebOpts.keyBag);
|
3001
3152
|
}
|
@@ -3039,9 +3190,9 @@ var Loader = class {
|
|
3039
3190
|
// await this._applyCarHeader(carHeader, true)
|
3040
3191
|
// }
|
3041
3192
|
async handleDbMetasFromStore(metas, activeStore) {
|
3042
|
-
this.logger.Debug().Any("metas", metas).Msg("handleDbMetasFromStore");
|
3193
|
+
this.logger.Debug().Any("metas", metas).Url(activeStore.active.car.url()).Msg("handleDbMetasFromStore");
|
3043
3194
|
for (const meta of metas) {
|
3044
|
-
await this.
|
3195
|
+
await this.maxConcurrentWrite(async () => {
|
3045
3196
|
await this.mergeDbMetaIntoClock(meta, activeStore);
|
3046
3197
|
});
|
3047
3198
|
}
|
@@ -3050,16 +3201,26 @@ var Loader = class {
|
|
3050
3201
|
if (this.isCompacting) {
|
3051
3202
|
throw this.logger.Error().Msg("cannot merge while compacting").AsError();
|
3052
3203
|
}
|
3053
|
-
|
3054
|
-
|
3055
|
-
|
3056
|
-
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;
|
3057
3223
|
}
|
3058
|
-
const carHeader = await this.loadCarHeaderFromMeta(meta, activeStore);
|
3059
|
-
carHeader.compact.map((c) => c.toString()).forEach(this.seenCompacted.add, this.seenCompacted);
|
3060
|
-
await this.getMoreReaders(carHeader.cars.flat(), activeStore);
|
3061
|
-
this.carLog = [...uniqueCids([meta.cars, ...this.carLog, ...carHeader.cars], this.seenCompacted)];
|
3062
|
-
await this.ebOpts.applyMeta?.(carHeader.meta);
|
3063
3224
|
}
|
3064
3225
|
// protected async ingestKeyFromMeta(meta: DbMeta): Promise<void> {
|
3065
3226
|
// const { key } = meta;
|
@@ -3090,13 +3251,13 @@ var Loader = class {
|
|
3090
3251
|
}
|
3091
3252
|
async commit(t, done, opts = { noLoader: false, compact: false }) {
|
3092
3253
|
await this.ready();
|
3093
|
-
const carStore =
|
3254
|
+
const carStore = this.attachedStores.local().active.car;
|
3094
3255
|
const params = {
|
3095
3256
|
encoder: (await carStore.keyedCrypto()).codec(),
|
3096
3257
|
carLog: this.carLog,
|
3097
3258
|
carStore,
|
3098
|
-
WALStore:
|
3099
|
-
metaStore:
|
3259
|
+
WALStore: this.attachedStores.local().active.wal,
|
3260
|
+
metaStore: this.attachedStores.local().active.meta,
|
3100
3261
|
threshold: this.ebOpts.threshold
|
3101
3262
|
};
|
3102
3263
|
return this.commitQueue.enqueue(async () => {
|
@@ -3106,34 +3267,44 @@ var Loader = class {
|
|
3106
3267
|
return ret.cgrp;
|
3107
3268
|
});
|
3108
3269
|
}
|
3109
|
-
async updateCarLog(cids,
|
3270
|
+
async updateCarLog(cids, cHeader, compact) {
|
3110
3271
|
if (compact) {
|
3111
|
-
const previousCompactCid =
|
3112
|
-
|
3113
|
-
this.carLog
|
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));
|
3114
3275
|
await this.removeCidsForCompact(previousCompactCid[0], this.attachedStores.local()).catch((e) => e);
|
3115
3276
|
} else {
|
3116
|
-
this.carLog.
|
3277
|
+
this.carLog.xunshift(cids);
|
3117
3278
|
}
|
3118
3279
|
}
|
3119
3280
|
async cacheTransaction(t) {
|
3120
3281
|
for await (const block of t.entries()) {
|
3121
3282
|
const sBlock = block.cid.toString();
|
3122
|
-
|
3123
|
-
|
3124
|
-
|
3125
|
-
|
3126
|
-
|
3127
|
-
|
3128
|
-
|
3129
|
-
|
3130
|
-
for await (const block of reader.blocks()) {
|
3131
|
-
const sBlock = block.cid.toString();
|
3132
|
-
if (!this.getBlockCache.has(sBlock)) {
|
3133
|
-
this.getBlockCache.set(sBlock, block);
|
3134
|
-
}
|
3283
|
+
this.cidCache.get(sBlock).once(
|
3284
|
+
() => ({
|
3285
|
+
type: "block",
|
3286
|
+
cid: block.cid,
|
3287
|
+
blocks: [block],
|
3288
|
+
roots: []
|
3289
|
+
})
|
3290
|
+
);
|
3135
3291
|
}
|
3136
3292
|
}
|
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
|
+
// }
|
3137
3308
|
async removeCidsForCompact(cid, store) {
|
3138
3309
|
const carHeader = await this.loadCarHeaderFromMeta(
|
3139
3310
|
{
|
@@ -3155,149 +3326,134 @@ var Loader = class {
|
|
3155
3326
|
// await this.remoteWAL!.enqueue(dbMeta, { public: false })
|
3156
3327
|
// }
|
3157
3328
|
// }
|
3158
|
-
async *entries(
|
3329
|
+
async *entries() {
|
3159
3330
|
await this.ready();
|
3160
|
-
|
3161
|
-
|
3162
|
-
|
3163
|
-
|
3164
|
-
|
3165
|
-
|
3166
|
-
|
3167
|
-
|
3168
|
-
|
3169
|
-
|
3170
|
-
|
3171
|
-
|
3172
|
-
for await (const block of reader.blocks()) {
|
3173
|
-
const sCid = block.cid.toString();
|
3174
|
-
if (!this.getBlockCache.has(sCid)) {
|
3175
|
-
yield block;
|
3176
|
-
}
|
3177
|
-
}
|
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;
|
3178
3343
|
}
|
3179
3344
|
}
|
3180
3345
|
}
|
3181
3346
|
}
|
3182
3347
|
async getBlock(cid, store) {
|
3183
3348
|
await this.ready();
|
3184
|
-
const
|
3185
|
-
|
3186
|
-
|
3187
|
-
|
3188
|
-
|
3189
|
-
|
3190
|
-
|
3191
|
-
|
3192
|
-
|
3193
|
-
|
3194
|
-
|
3195
|
-
|
3196
|
-
|
3197
|
-
|
3198
|
-
|
3199
|
-
|
3200
|
-
|
3201
|
-
|
3202
|
-
|
3203
|
-
|
3204
|
-
|
3205
|
-
|
3206
|
-
|
3207
|
-
for (let i = 0; i < compacts.length; i += batchSize2) {
|
3208
|
-
const promises = [];
|
3209
|
-
for (let j = i; j < Math.min(i + batchSize2, compacts.length); j++) {
|
3210
|
-
for (const cid2 of compacts[j]) {
|
3211
|
-
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;
|
3212
3372
|
}
|
3213
3373
|
}
|
3214
|
-
try {
|
3215
|
-
got2 = await Promise.any(promises);
|
3216
|
-
} catch {
|
3217
|
-
}
|
3218
|
-
if (got2) break;
|
3219
3374
|
}
|
3220
|
-
if (
|
3221
|
-
|
3222
|
-
};
|
3223
|
-
let got;
|
3224
|
-
const batchSize = 5;
|
3225
|
-
for (let i = 0; i < this.carLog.length; i += batchSize) {
|
3226
|
-
const batch = this.carLog.slice(i, i + batchSize);
|
3227
|
-
const promises = batch.flatMap((slice) => slice.map(getCarCid));
|
3228
|
-
try {
|
3229
|
-
got = await Promise.any(promises);
|
3230
|
-
} catch {
|
3231
|
-
}
|
3232
|
-
if (got) break;
|
3233
|
-
}
|
3234
|
-
if (!got) {
|
3235
|
-
try {
|
3236
|
-
got = await getCompactCarCids(this.carLog[this.carLog.length - 1][0]);
|
3237
|
-
} catch {
|
3375
|
+
if (!got) {
|
3376
|
+
await getCompactCarCids(this.carLog.last()[0]);
|
3238
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();
|
3239
3387
|
}
|
3240
|
-
return
|
3388
|
+
return ci.blocks[0];
|
3241
3389
|
}
|
3242
3390
|
async loadCar(cid, store) {
|
3243
3391
|
const loaded = await this.storesLoadCar(cid, store.carStore());
|
3244
3392
|
return loaded;
|
3245
3393
|
}
|
3246
|
-
async makeDecoderAndCarReader(
|
3247
|
-
const
|
3394
|
+
async makeDecoderAndCarReader(carCid, store) {
|
3395
|
+
const carCidStr = carCid.toString();
|
3248
3396
|
let loadedCar = void 0;
|
3249
|
-
let activeStore = store.
|
3397
|
+
let activeStore = store.local();
|
3250
3398
|
try {
|
3251
|
-
this.logger.Debug().Any("cid",
|
3252
|
-
loadedCar = await store.
|
3399
|
+
this.logger.Debug().Any("cid", carCidStr).Msg("loading car");
|
3400
|
+
loadedCar = await store.local().load(carCid);
|
3253
3401
|
this.logger.Debug().Bool("loadedCar", loadedCar).Msg("loaded");
|
3254
3402
|
} catch (e) {
|
3255
3403
|
if (!isNotFoundError(e)) {
|
3256
|
-
throw this.logger.Error().Str("cid",
|
3404
|
+
throw this.logger.Error().Str("cid", carCidStr).Err(e).Msg("loading car");
|
3257
3405
|
}
|
3258
|
-
for (const remote of store.
|
3259
|
-
|
3260
|
-
|
3261
|
-
|
3262
|
-
|
3263
|
-
|
3264
|
-
|
3265
|
-
|
3266
|
-
|
3267
|
-
|
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");
|
3268
3420
|
}
|
3269
3421
|
}
|
3270
3422
|
}
|
3271
3423
|
if (!loadedCar) {
|
3272
|
-
throw this.logger.Error().Url(store.
|
3424
|
+
throw this.logger.Error().Url(store.local().url()).Str("cid", carCidStr).Msg("missing car files").AsError();
|
3273
3425
|
}
|
3274
3426
|
const bytes = await decode({ bytes: loadedCar.bytes, hasher: import_sha24.sha256, codec: (await activeStore.keyedCrypto()).codec() });
|
3275
|
-
const rawReader = await import_reader.CarReader.fromBytes(bytes.value);
|
3276
|
-
const
|
3277
|
-
const
|
3278
|
-
|
3279
|
-
|
3280
|
-
|
3281
|
-
|
3282
|
-
|
3283
|
-
|
3284
|
-
|
3285
|
-
|
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
|
+
};
|
3286
3445
|
}
|
3287
3446
|
//What if instead it returns an Array of CarHeader
|
3288
|
-
async storesLoadCar(
|
3289
|
-
const
|
3290
|
-
|
3291
|
-
|
3292
|
-
|
3293
|
-
this.carReaders.set(cidsString, dacr);
|
3294
|
-
}
|
3295
|
-
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
|
+
});
|
3296
3452
|
}
|
3297
3453
|
async getMoreReaders(cids, store) {
|
3298
|
-
const
|
3299
|
-
|
3300
|
-
|
3454
|
+
for (const cid of cids) {
|
3455
|
+
await this.loadCar(cid, store);
|
3456
|
+
}
|
3301
3457
|
}
|
3302
3458
|
};
|
3303
3459
|
|
@@ -3342,12 +3498,21 @@ function getGenerateIVFn(url, opts) {
|
|
3342
3498
|
}
|
3343
3499
|
var BlockIvKeyIdCodec = class {
|
3344
3500
|
constructor(ko, iv, opts) {
|
3345
|
-
this.code =
|
3501
|
+
this.code = 24;
|
3346
3502
|
this.name = "Fireproof@encrypted-block:aes-gcm";
|
3347
3503
|
this.ko = ko;
|
3348
3504
|
this.iv = iv;
|
3349
3505
|
this.opts = opts || {};
|
3350
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
|
+
}
|
3351
3516
|
async encode(data) {
|
3352
3517
|
const calcIv = this.iv || await getGenerateIVFn(this.ko.url, this.opts).calc(this.ko, this.ko.crypto, data);
|
3353
3518
|
const { iv } = this.ko.algo(calcIv);
|
@@ -3379,11 +3544,16 @@ var BlockIvKeyIdCodec = class {
|
|
3379
3544
|
if (!this.opts?.noIVVerify && !await getGenerateIVFn(this.ko.url, this.opts).verify(this.ko, this.ko.crypto, iv, result)) {
|
3380
3545
|
throw this.ko.logger.Error().Msg("iv missmatch").AsError();
|
3381
3546
|
}
|
3382
|
-
return
|
3547
|
+
return {
|
3548
|
+
iv,
|
3549
|
+
keyId,
|
3550
|
+
data: result
|
3551
|
+
};
|
3383
3552
|
}
|
3384
3553
|
};
|
3385
3554
|
var cryptoAction = class {
|
3386
3555
|
constructor(url, key, cyopt, sthis) {
|
3556
|
+
this.code = 24;
|
3387
3557
|
this.ivLength = 12;
|
3388
3558
|
this.isEncrypting = true;
|
3389
3559
|
this.logger = ensureLogger(sthis, "cryptoAction");
|
@@ -3417,14 +3587,19 @@ var cryptoAction = class {
|
|
3417
3587
|
};
|
3418
3588
|
var nullCodec = class {
|
3419
3589
|
constructor() {
|
3420
|
-
this.code =
|
3590
|
+
this.code = 24;
|
3421
3591
|
this.name = "Fireproof@unencrypted-block";
|
3592
|
+
this.empty = new Uint8Array();
|
3422
3593
|
}
|
3423
|
-
encode(data) {
|
3594
|
+
async encode(data) {
|
3424
3595
|
return data;
|
3425
3596
|
}
|
3426
|
-
decode(data) {
|
3427
|
-
return
|
3597
|
+
async decode(data) {
|
3598
|
+
return {
|
3599
|
+
iv: this.empty,
|
3600
|
+
keyId: this.empty,
|
3601
|
+
data
|
3602
|
+
};
|
3428
3603
|
}
|
3429
3604
|
};
|
3430
3605
|
var noCrypto = class {
|
@@ -3679,13 +3854,8 @@ var BaseStoreImpl = class {
|
|
3679
3854
|
this._url = res.Ok();
|
3680
3855
|
const kb = await this.loader.keyBag();
|
3681
3856
|
const skRes = await kb.ensureKeyFromUrl(this._url, () => {
|
3682
|
-
const
|
3683
|
-
|
3684
|
-
if (idx) {
|
3685
|
-
storeKeyName.push(idx);
|
3686
|
-
}
|
3687
|
-
storeKeyName.push(this.storeType);
|
3688
|
-
return storeKeyName.join(":");
|
3857
|
+
const key = this._url.getParam(PARAM.KEY);
|
3858
|
+
return key;
|
3689
3859
|
});
|
3690
3860
|
if (skRes.isErr()) {
|
3691
3861
|
return skRes;
|
@@ -3768,8 +3938,7 @@ var MetaStoreImpl = class extends BaseStoreImpl {
|
|
3768
3938
|
// }
|
3769
3939
|
// return (rDbMeta.Ok() as FPEnvelopeMeta).payload;
|
3770
3940
|
// }
|
3771
|
-
async load() {
|
3772
|
-
const branch = "main";
|
3941
|
+
async load(branch = "main") {
|
3773
3942
|
const url = await this.gateway.buildUrl({ loader: this.loader }, this.url(), branch);
|
3774
3943
|
if (url.isErr()) {
|
3775
3944
|
throw this.logger.Error().Result("buildUrl", url).Str("branch", branch).Msg("got error from gateway.buildUrl").AsError();
|
@@ -3783,7 +3952,7 @@ var MetaStoreImpl = class extends BaseStoreImpl {
|
|
3783
3952
|
}
|
3784
3953
|
const fpMeta = rfpEnv.Ok().payload;
|
3785
3954
|
const dbMetas = fpMeta.map((m) => m.dbMeta);
|
3786
|
-
await this.loader.handleDbMetasFromStore(dbMetas, this.loader.attachedStores.
|
3955
|
+
await this.loader.handleDbMetasFromStore(dbMetas, this.loader.attachedStores.activate(url.Ok()));
|
3787
3956
|
this.updateParentsFromDbMetas(fpMeta);
|
3788
3957
|
return dbMetas;
|
3789
3958
|
}
|
@@ -3815,9 +3984,8 @@ var MetaStoreImpl = class extends BaseStoreImpl {
|
|
3815
3984
|
}
|
3816
3985
|
};
|
3817
3986
|
var DataStoreImpl = class extends BaseStoreImpl {
|
3818
|
-
constructor(sthis, url, opts) {
|
3819
|
-
super(sthis, url, { ...opts },
|
3820
|
-
this.storeType = "data";
|
3987
|
+
constructor(sthis, url, opts, logger) {
|
3988
|
+
super(sthis, url, { ...opts }, logger);
|
3821
3989
|
}
|
3822
3990
|
async load(cid) {
|
3823
3991
|
this.logger.Debug().Any("cid", cid).Msg("loading");
|
@@ -3832,7 +4000,6 @@ var DataStoreImpl = class extends BaseStoreImpl {
|
|
3832
4000
|
const fpenv = res.Ok();
|
3833
4001
|
switch (fpenv.type) {
|
3834
4002
|
case "car":
|
3835
|
-
return { cid, bytes: fpenv.payload };
|
3836
4003
|
case "file":
|
3837
4004
|
return { cid, bytes: fpenv.payload };
|
3838
4005
|
default:
|
@@ -3848,12 +4015,11 @@ var DataStoreImpl = class extends BaseStoreImpl {
|
|
3848
4015
|
}
|
3849
4016
|
let fpMsg;
|
3850
4017
|
switch (url.Ok().getParam(PARAM.STORE)) {
|
3851
|
-
case "
|
3852
|
-
|
3853
|
-
|
3854
|
-
|
3855
|
-
|
3856
|
-
}
|
4018
|
+
case "car":
|
4019
|
+
fpMsg = Car2FPMsg(car.bytes);
|
4020
|
+
break;
|
4021
|
+
case "file":
|
4022
|
+
fpMsg = File2FPMsg(car.bytes);
|
3857
4023
|
break;
|
3858
4024
|
default:
|
3859
4025
|
throw this.logger.Error().Str("store", url.Ok().getParam(PARAM.STORE)).Msg("unexpected store").AsError();
|
@@ -3884,6 +4050,18 @@ var DataStoreImpl = class extends BaseStoreImpl {
|
|
3884
4050
|
return this.gateway.destroy({ loader: this.loader }, this.url());
|
3885
4051
|
}
|
3886
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
|
+
};
|
3887
4065
|
var WALStoreImpl = class extends BaseStoreImpl {
|
3888
4066
|
constructor(sthis, url, opts) {
|
3889
4067
|
super(sthis, url, { ...opts }, ensureLogger(sthis, "WALStoreImpl"));
|
@@ -3966,7 +4144,7 @@ var WALStoreImpl = class extends BaseStoreImpl {
|
|
3966
4144
|
for (const cid of dbMeta.cars) {
|
3967
4145
|
const car = await this.loader.attachedStores.local().active.car.load(cid);
|
3968
4146
|
if (!car) {
|
3969
|
-
if (carLogIncludesGroup(this.loader.carLog, dbMeta.cars)) {
|
4147
|
+
if (carLogIncludesGroup(this.loader.carLog.asArray(), dbMeta.cars)) {
|
3970
4148
|
throw this.logger.Error().Ref("cid", cid).Msg("missing local car").AsError();
|
3971
4149
|
}
|
3972
4150
|
} else {
|
@@ -3988,7 +4166,7 @@ var WALStoreImpl = class extends BaseStoreImpl {
|
|
3988
4166
|
for (const cid of dbMeta.cars) {
|
3989
4167
|
const car = await this.loader.attachedStores.local().active.car.load(cid);
|
3990
4168
|
if (!car) {
|
3991
|
-
if (carLogIncludesGroup(this.loader.carLog, dbMeta.cars)) {
|
4169
|
+
if (carLogIncludesGroup(this.loader.carLog.asArray(), dbMeta.cars)) {
|
3992
4170
|
throw this.logger.Error().Ref("cid", cid).Msg(`missing local car`).AsError();
|
3993
4171
|
}
|
3994
4172
|
} else {
|
@@ -4084,8 +4262,9 @@ async function getStartedGateway(ctx, url) {
|
|
4084
4262
|
if (item) {
|
4085
4263
|
const ret = {
|
4086
4264
|
url,
|
4087
|
-
...await gatewayInstances.get(url.protocol).once(async () => ({
|
4088
|
-
|
4265
|
+
...await gatewayInstances.get(url.protocol).once(async () => ({
|
4266
|
+
gateway: await item.serdegateway(ctx.loader.sthis)
|
4267
|
+
}))
|
4089
4268
|
};
|
4090
4269
|
const res = await ret.gateway.start(ctx, url);
|
4091
4270
|
if (res.isErr()) {
|
@@ -4097,14 +4276,28 @@ async function getStartedGateway(ctx, url) {
|
|
4097
4276
|
return import_cement17.Result.Err(ctx.loader.sthis.logger.Warn().Url(url).Msg("unsupported protocol").AsError());
|
4098
4277
|
});
|
4099
4278
|
}
|
4100
|
-
async function
|
4101
|
-
const storeUrl = uai.url.build().setParam(PARAM.STORE, "
|
4279
|
+
async function carStoreFactory(ctx, uai) {
|
4280
|
+
const storeUrl = uai.url.build().setParam(PARAM.STORE, "car").URI();
|
4102
4281
|
const rgateway = await getStartedGateway(ctx, storeUrl);
|
4103
4282
|
if (rgateway.isErr()) {
|
4104
4283
|
throw ctx.loader.sthis.logger.Error().Result("err", rgateway).Url(uai.url).Msg("notfound").AsError();
|
4105
4284
|
}
|
4106
4285
|
const gateway = rgateway.Ok();
|
4107
|
-
const store = new
|
4286
|
+
const store = new CarStoreImpl(ctx.loader.sthis, gateway.url, {
|
4287
|
+
gateway: gateway.gateway,
|
4288
|
+
gatewayInterceptor: uai.gatewayInterceptor,
|
4289
|
+
loader: ctx.loader
|
4290
|
+
});
|
4291
|
+
return store;
|
4292
|
+
}
|
4293
|
+
async function fileStoreFactory(ctx, uai) {
|
4294
|
+
const storeUrl = uai.url.build().setParam(PARAM.STORE, "file").URI();
|
4295
|
+
const rgateway = await getStartedGateway(ctx, storeUrl);
|
4296
|
+
if (rgateway.isErr()) {
|
4297
|
+
throw ctx.loader.sthis.logger.Error().Result("err", rgateway).Url(uai.url).Msg("notfound").AsError();
|
4298
|
+
}
|
4299
|
+
const gateway = rgateway.Ok();
|
4300
|
+
const store = new FileStoreImpl(ctx.loader.sthis, gateway.url, {
|
4108
4301
|
gateway: gateway.gateway,
|
4109
4302
|
gatewayInterceptor: uai.gatewayInterceptor,
|
4110
4303
|
loader: ctx.loader
|
@@ -4162,8 +4355,8 @@ function toStoreRuntime(sthis, endeOpts = {}) {
|
|
4162
4355
|
};
|
4163
4356
|
const storeSet = {};
|
4164
4357
|
storeSet.meta = await metaStoreFactory(ctx, sfi.byStore.meta);
|
4165
|
-
storeSet.car = await
|
4166
|
-
storeSet.file = await
|
4358
|
+
storeSet.car = await carStoreFactory(ctx, sfi.byStore.car);
|
4359
|
+
storeSet.file = await fileStoreFactory(ctx, sfi.byStore.file);
|
4167
4360
|
if (sfi.byStore.wal) {
|
4168
4361
|
storeSet.wal = await WALStoreFactory(ctx, sfi.byStore.wal);
|
4169
4362
|
}
|
@@ -4202,6 +4395,41 @@ function toString(key, logger) {
|
|
4202
4395
|
throw logger.Error().Msg("Invalid key type").AsError();
|
4203
4396
|
}
|
4204
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
|
+
if (obj instanceof Date) {
|
4408
|
+
return obj.toISOString();
|
4409
|
+
}
|
4410
|
+
const typedObj = obj;
|
4411
|
+
const result = {};
|
4412
|
+
for (const key in typedObj) {
|
4413
|
+
if (Object.hasOwnProperty.call(typedObj, key)) {
|
4414
|
+
const value = typedObj[key];
|
4415
|
+
if (value === null || !Number.isNaN(value) && value !== void 0) {
|
4416
|
+
if (typeof value === "object" && !key.startsWith("_")) {
|
4417
|
+
if (value instanceof Date) {
|
4418
|
+
result[key] = value.toISOString();
|
4419
|
+
} else {
|
4420
|
+
const sanitized = sanitizeDocumentFields(value);
|
4421
|
+
result[key] = sanitized;
|
4422
|
+
}
|
4423
|
+
} else {
|
4424
|
+
result[key] = value;
|
4425
|
+
}
|
4426
|
+
}
|
4427
|
+
}
|
4428
|
+
}
|
4429
|
+
return result;
|
4430
|
+
}
|
4431
|
+
return obj;
|
4432
|
+
}
|
4205
4433
|
async function applyBulkUpdateToCrdt(store, tblocks, head, updates, logger) {
|
4206
4434
|
let result = null;
|
4207
4435
|
if (updates.length > 1) {
|
@@ -4291,7 +4519,8 @@ async function getValueFromCrdt(blocks, head, key, logger) {
|
|
4291
4519
|
if (!head.length) throw logger.Debug().Msg("Getting from an empty ledger").AsError();
|
4292
4520
|
const link = await (0, import_crdt.get)(blocks, head, key);
|
4293
4521
|
if (!link) throw logger.Error().Str("key", key).Msg(`Missing key`).AsError();
|
4294
|
-
|
4522
|
+
const ret = await getValueFromLink(blocks, link, logger);
|
4523
|
+
return ret;
|
4295
4524
|
}
|
4296
4525
|
function readFiles(blocks, { doc }) {
|
4297
4526
|
if (!doc) return;
|
@@ -4389,6 +4618,9 @@ async function gatherUpdates(blocks, eventsFetcher, head, since, updates = [], k
|
|
4389
4618
|
const { key, value } = ops[i];
|
4390
4619
|
if (!keys.has(key)) {
|
4391
4620
|
const docValue = await getValueFromLink(blocks, value, logger);
|
4621
|
+
if (key === PARAM.GENESIS_CID) {
|
4622
|
+
continue;
|
4623
|
+
}
|
4392
4624
|
updates.push({ id: key, value: docValue.doc, del: docValue.del, clock: link });
|
4393
4625
|
limit--;
|
4394
4626
|
keys.add(key);
|
@@ -4402,8 +4634,10 @@ async function gatherUpdates(blocks, eventsFetcher, head, since, updates = [], k
|
|
4402
4634
|
}
|
4403
4635
|
async function* getAllEntries(blocks, head, logger) {
|
4404
4636
|
for await (const [key, link] of (0, import_crdt.entries)(blocks, head)) {
|
4405
|
-
|
4406
|
-
|
4637
|
+
if (key !== PARAM.GENESIS_CID) {
|
4638
|
+
const docValue = await getValueFromLink(blocks, link, logger);
|
4639
|
+
yield { id: key, value: docValue.doc, del: docValue.del };
|
4640
|
+
}
|
4407
4641
|
}
|
4408
4642
|
}
|
4409
4643
|
async function* clockVis(blocks, head) {
|
@@ -4548,6 +4782,10 @@ var CRDTClockImpl = class {
|
|
4548
4782
|
this.notifyWatchers(internalUpdates || []);
|
4549
4783
|
}
|
4550
4784
|
notifyWatchers(updates) {
|
4785
|
+
updates = updates.filter((update) => update.id !== PARAM.GENESIS_CID);
|
4786
|
+
if (!updates.length) {
|
4787
|
+
return;
|
4788
|
+
}
|
4551
4789
|
this.emptyWatchers.forEach((fn) => fn());
|
4552
4790
|
this.watchers.forEach((fn) => fn(updates || []));
|
4553
4791
|
}
|
@@ -4627,7 +4865,7 @@ async function advanceBlocks(logger, newHead, tblocks, head) {
|
|
4627
4865
|
try {
|
4628
4866
|
head = await (0, import_clock4.advance)(tblocks, head, cid);
|
4629
4867
|
} catch (e) {
|
4630
|
-
logger.
|
4868
|
+
logger.Error().Err(e).Msg("failed to advance head");
|
4631
4869
|
continue;
|
4632
4870
|
}
|
4633
4871
|
}
|
@@ -4686,6 +4924,17 @@ var CRDTImpl = class {
|
|
4686
4924
|
}
|
4687
4925
|
async bulk(updates) {
|
4688
4926
|
await this.ready();
|
4927
|
+
updates = updates.map((dupdate) => ({
|
4928
|
+
...dupdate,
|
4929
|
+
value: sanitizeDocumentFields(dupdate.value)
|
4930
|
+
}));
|
4931
|
+
if (this.clock.head.length === 0) {
|
4932
|
+
const value = { id: PARAM.GENESIS_CID, value: { _id: PARAM.GENESIS_CID } };
|
4933
|
+
await this._bulk([value]);
|
4934
|
+
}
|
4935
|
+
return await this._bulk(updates);
|
4936
|
+
}
|
4937
|
+
async _bulk(updates) {
|
4689
4938
|
const prevHead = [...this.clock.head];
|
4690
4939
|
const done = await this.blockstore.transaction(async (blocks) => {
|
4691
4940
|
const { head } = await applyBulkUpdateToCrdt(
|
@@ -4917,7 +5166,8 @@ var LedgerImpl = class {
|
|
4917
5166
|
});
|
4918
5167
|
return ret;
|
4919
5168
|
}
|
4920
|
-
attach(a) {
|
5169
|
+
async attach(a) {
|
5170
|
+
await this.ready();
|
4921
5171
|
return this.crdt.blockstore.loader.attach(a);
|
4922
5172
|
}
|
4923
5173
|
// readonly _asDb = new ResolveOnce<Database>();
|
@@ -4925,6 +5175,7 @@ var LedgerImpl = class {
|
|
4925
5175
|
// return this._asDb.once(() => new DatabaseImpl(this));
|
4926
5176
|
// }
|
4927
5177
|
subscribe(listener, updates) {
|
5178
|
+
this.ready();
|
4928
5179
|
this.logger.Debug().Bool("updates", updates).Msg("subscribe");
|
4929
5180
|
if (updates) {
|
4930
5181
|
if (!this._listening) {
|
@@ -4966,26 +5217,6 @@ var LedgerImpl = class {
|
|
4966
5217
|
}
|
4967
5218
|
}
|
4968
5219
|
};
|
4969
|
-
function defaultURI2(sthis, name, curi, uri, store, ctx) {
|
4970
|
-
ctx = ctx || {};
|
4971
|
-
const ret = (curi ? import_cement20.URI.from(curi) : uri).build().setParam(PARAM.STORE, store).defParam(PARAM.NAME, name);
|
4972
|
-
if (!ret.hasParam(PARAM.NAME)) {
|
4973
|
-
throw sthis.logger.Error().Url(ret).Any("ctx", ctx).Msg("Ledger name is required").AsError();
|
4974
|
-
}
|
4975
|
-
if (ctx.idx) {
|
4976
|
-
ret.defParam(PARAM.INDEX, "idx");
|
4977
|
-
ret.defParam(PARAM.STORE_KEY, `@${ret.getParam(PARAM.NAME)}-${store}-idx@`);
|
4978
|
-
} else {
|
4979
|
-
ret.defParam(PARAM.STORE_KEY, `@${ret.getParam(PARAM.NAME)}-${store}@`);
|
4980
|
-
}
|
4981
|
-
if (store === "data") {
|
4982
|
-
if (ctx.file) {
|
4983
|
-
} else {
|
4984
|
-
ret.defParam(PARAM.SUFFIX, ".car");
|
4985
|
-
}
|
4986
|
-
}
|
4987
|
-
return ret.URI();
|
4988
|
-
}
|
4989
5220
|
function toStoreURIRuntime(sthis, name, sopts) {
|
4990
5221
|
sopts = sopts || {};
|
4991
5222
|
if (!sopts.base) {
|
@@ -4999,16 +5230,19 @@ function toStoreURIRuntime(sthis, name, sopts) {
|
|
4999
5230
|
const base = import_cement20.URI.from(sopts.base);
|
5000
5231
|
return {
|
5001
5232
|
idx: {
|
5002
|
-
car:
|
5003
|
-
file:
|
5004
|
-
|
5005
|
-
|
5233
|
+
car: ensureURIDefaults(sthis, name, sopts.idx?.car ?? sopts.data?.car, base, "car", { idx: true }),
|
5234
|
+
file: ensureURIDefaults(sthis, name, sopts.idx?.file ?? sopts.idx?.car ?? sopts.data?.file ?? sopts.data?.car, base, "file", {
|
5235
|
+
file: true,
|
5236
|
+
idx: true
|
5237
|
+
}),
|
5238
|
+
meta: ensureURIDefaults(sthis, name, sopts.idx?.meta ?? sopts.data?.meta, base, "meta", { idx: true }),
|
5239
|
+
wal: ensureURIDefaults(sthis, name, sopts.idx?.wal ?? sopts.data?.wal, base, "wal", { idx: true })
|
5006
5240
|
},
|
5007
5241
|
data: {
|
5008
|
-
car:
|
5009
|
-
file:
|
5010
|
-
meta:
|
5011
|
-
wal:
|
5242
|
+
car: ensureURIDefaults(sthis, name, sopts.data?.car, base, "car"),
|
5243
|
+
file: ensureURIDefaults(sthis, name, sopts.data?.file ?? sopts.data?.car, base, "file", { file: true }),
|
5244
|
+
meta: ensureURIDefaults(sthis, name, sopts.data?.meta, base, "meta"),
|
5245
|
+
wal: ensureURIDefaults(sthis, name, sopts.data?.wal, base, "wal")
|
5012
5246
|
}
|
5013
5247
|
};
|
5014
5248
|
}
|
@@ -5072,6 +5306,6 @@ __export(file_exports, {
|
|
5072
5306
|
|
5073
5307
|
// src/version.ts
|
5074
5308
|
var PACKAGE_VERSION = Object.keys({
|
5075
|
-
"0.20.0-dev-preview-
|
5309
|
+
"0.20.0-dev-preview-51": "xxxx"
|
5076
5310
|
})[0];
|
5077
5311
|
//# sourceMappingURL=index.cjs.map
|