@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.js
CHANGED
@@ -5,7 +5,7 @@ var __export = (target, all) => {
|
|
5
5
|
};
|
6
6
|
|
7
7
|
// src/ledger.ts
|
8
|
-
import { BuildURI as
|
8
|
+
import { BuildURI as BuildURI2, KeyedResolvOnce as KeyedResolvOnce6, ResolveOnce as ResolveOnce7, URI as URI13 } from "@adviser/cement";
|
9
9
|
|
10
10
|
// src/utils.ts
|
11
11
|
import {
|
@@ -14,6 +14,7 @@ import {
|
|
14
14
|
Result,
|
15
15
|
ResolveOnce,
|
16
16
|
isURL,
|
17
|
+
URI,
|
17
18
|
envFactory,
|
18
19
|
toCryptoRuntime,
|
19
20
|
JSONFormatter,
|
@@ -44,8 +45,13 @@ var PARAM = {
|
|
44
45
|
FRAG_LEN: "len",
|
45
46
|
FRAG_HEAD: "headerSize",
|
46
47
|
EXTRACTKEY: "extractKey",
|
47
|
-
SELF_REFLECT: "selfReflect"
|
48
|
+
SELF_REFLECT: "selfReflect",
|
48
49
|
// if no subscribe in Gateway see your own META updates
|
50
|
+
CAR_PARALLEL: "parallel",
|
51
|
+
CAR_CACHE_SIZE: "carCacheSize",
|
52
|
+
CAR_COMPACT_CACHE_SIZE: "carCompactCacheSize",
|
53
|
+
CAR_META_CACHE_SIZE: "carMetaCacheSize",
|
54
|
+
GENESIS_CID: "baembeiarootfireproofgenesisblockaaaafireproofgenesisblocka"
|
49
55
|
// FS = "fs",
|
50
56
|
};
|
51
57
|
function throwFalsy(value) {
|
@@ -282,21 +288,25 @@ function ensureLogger(sthis, componentName, ctx) {
|
|
282
288
|
return out;
|
283
289
|
}
|
284
290
|
function getStore(url, sthis, joiner) {
|
285
|
-
const
|
286
|
-
|
287
|
-
|
291
|
+
const fromUrl = url.getParam(PARAM.STORE);
|
292
|
+
let pathPart;
|
293
|
+
switch (fromUrl) {
|
294
|
+
case "car":
|
295
|
+
case "file":
|
296
|
+
pathPart = "data";
|
297
|
+
break;
|
288
298
|
case "wal":
|
289
299
|
case "meta":
|
300
|
+
pathPart = fromUrl;
|
290
301
|
break;
|
291
302
|
default:
|
292
303
|
throw sthis.logger.Error().Url(url).Msg(`store not found`).AsError();
|
293
|
-
throw sthis.logger.Error().Url(url).Msg(`store not found`).AsError();
|
294
304
|
}
|
295
|
-
let name =
|
305
|
+
let name = pathPart;
|
296
306
|
if (url.hasParam("index")) {
|
297
307
|
name = joiner(url.getParam(PARAM.INDEX) || "idx", name);
|
298
308
|
}
|
299
|
-
return {
|
309
|
+
return { pathPart, fromUrl, name };
|
300
310
|
}
|
301
311
|
function getKey(url, logger) {
|
302
312
|
const result = url.getParam(PARAM.KEY);
|
@@ -398,6 +408,35 @@ function makeName(fnString) {
|
|
398
408
|
return found[1];
|
399
409
|
}
|
400
410
|
}
|
411
|
+
function storeType2DataMetaWal(store) {
|
412
|
+
switch (store) {
|
413
|
+
case "car":
|
414
|
+
case "file":
|
415
|
+
return "data";
|
416
|
+
case "meta":
|
417
|
+
case "wal":
|
418
|
+
return store;
|
419
|
+
default:
|
420
|
+
throw new Error(`unknown store ${store}`);
|
421
|
+
}
|
422
|
+
}
|
423
|
+
function ensureURIDefaults(sthis, name, curi, uri, store, ctx) {
|
424
|
+
ctx = ctx || {};
|
425
|
+
const ret = (curi ? URI.from(curi) : uri).build().setParam(PARAM.STORE, store).defParam(PARAM.NAME, name);
|
426
|
+
if (!ret.hasParam(PARAM.NAME)) {
|
427
|
+
throw sthis.logger.Error().Url(ret).Any("ctx", ctx).Msg("Ledger name is required").AsError();
|
428
|
+
}
|
429
|
+
if (ctx.idx) {
|
430
|
+
ret.defParam(PARAM.INDEX, "idx");
|
431
|
+
ret.defParam(PARAM.STORE_KEY, `@${ret.getParam(PARAM.NAME)}-${storeType2DataMetaWal(store)}-idx@`);
|
432
|
+
} else {
|
433
|
+
ret.defParam(PARAM.STORE_KEY, `@${ret.getParam(PARAM.NAME)}-${storeType2DataMetaWal(store)}@`);
|
434
|
+
}
|
435
|
+
if (store === "car") {
|
436
|
+
ret.defParam(PARAM.SUFFIX, ".car");
|
437
|
+
}
|
438
|
+
return ret.URI();
|
439
|
+
}
|
401
440
|
|
402
441
|
// src/write-queue.ts
|
403
442
|
import { Future } from "@adviser/cement";
|
@@ -1087,8 +1126,10 @@ function getFileName(url, sthis) {
|
|
1087
1126
|
const key = url.getParam("key");
|
1088
1127
|
if (!key) throw sthis.logger.Error().Url(url).Msg(`key not found`).AsError();
|
1089
1128
|
const res = getStore2(url, sthis, (...a) => a.join("-"));
|
1090
|
-
switch (res.
|
1091
|
-
case "
|
1129
|
+
switch (res.fromUrl) {
|
1130
|
+
case "file":
|
1131
|
+
return sthis.pathOps.join(res.name, key);
|
1132
|
+
case "car":
|
1092
1133
|
return sthis.pathOps.join(res.name, key + ".car");
|
1093
1134
|
case "wal":
|
1094
1135
|
case "meta":
|
@@ -1236,8 +1277,13 @@ var MemoryGateway = class {
|
|
1236
1277
|
close(baseUrl) {
|
1237
1278
|
return Promise.resolve(Result4.Ok(void 0));
|
1238
1279
|
}
|
1239
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
1240
1280
|
destroy(baseUrl) {
|
1281
|
+
const keyUrl = baseUrl.toString();
|
1282
|
+
for (const key of this.memorys.keys()) {
|
1283
|
+
if (key.startsWith(keyUrl)) {
|
1284
|
+
this.memorys.delete(key);
|
1285
|
+
}
|
1286
|
+
}
|
1241
1287
|
this.memorys.clear();
|
1242
1288
|
return Promise.resolve(Result4.Ok(void 0));
|
1243
1289
|
}
|
@@ -1249,7 +1295,7 @@ var MemoryGateway = class {
|
|
1249
1295
|
get(url) {
|
1250
1296
|
const x = this.memorys.get(url.toString());
|
1251
1297
|
if (!x) {
|
1252
|
-
return Promise.resolve(Result4.Err(new NotFoundError(`not found: ${url.
|
1298
|
+
return Promise.resolve(Result4.Err(new NotFoundError(`not found: ${url.toString()}`)));
|
1253
1299
|
}
|
1254
1300
|
return Promise.resolve(Result4.Ok(x));
|
1255
1301
|
}
|
@@ -1419,10 +1465,9 @@ async function fpDeserialize(sthis, url, intoRaw, pdecoder) {
|
|
1419
1465
|
...pdecoder
|
1420
1466
|
};
|
1421
1467
|
switch (url.getParam(PARAM.STORE)) {
|
1422
|
-
case "
|
1423
|
-
|
1424
|
-
|
1425
|
-
}
|
1468
|
+
case "car":
|
1469
|
+
return makeFPEnvelope(FPEnvelopeTypes.CAR, await decoder.car(sthis, raw2));
|
1470
|
+
case "file":
|
1426
1471
|
return makeFPEnvelope(FPEnvelopeTypes.FILE, await decoder.file(sthis, raw2));
|
1427
1472
|
case "wal":
|
1428
1473
|
return makeFPEnvelope(FPEnvelopeTypes.WAL, await decode2WalState(sthis, await decoder.wal(sthis, raw2)));
|
@@ -1484,7 +1529,7 @@ var DefSerdeGateway = class {
|
|
1484
1529
|
const urlWithoutKey = url.build().delParam(PARAM.KEY).delParam(PARAM.SELF_REFLECT).toString();
|
1485
1530
|
this.subscribeFn.set(urlWithoutKey, rawCallback);
|
1486
1531
|
return Result7.Ok(() => {
|
1487
|
-
this.subscribeFn.delete(
|
1532
|
+
this.subscribeFn.delete(urlWithoutKey);
|
1488
1533
|
});
|
1489
1534
|
}
|
1490
1535
|
const unreg = await this.gw.subscribe(url, rawCallback, sthis);
|
@@ -1613,37 +1658,49 @@ var Block = mfBlock;
|
|
1613
1658
|
async function decode({
|
1614
1659
|
bytes,
|
1615
1660
|
codec: codec3,
|
1616
|
-
hasher:
|
1661
|
+
hasher: hasher6
|
1617
1662
|
}) {
|
1618
1663
|
if (bytes == null) throw new Error('Missing required argument "bytes"');
|
1619
|
-
if (codec3 == null ||
|
1664
|
+
if (codec3 == null || hasher6 == null) throw new Error("Missing required argument: codec or hasher");
|
1620
1665
|
const value = await Promise.resolve(codec3.decode(bytes));
|
1621
|
-
|
1666
|
+
let toHash = bytes;
|
1667
|
+
if (codec3.valueToHashBytes) {
|
1668
|
+
toHash = await Promise.resolve(codec3.valueToHashBytes(value));
|
1669
|
+
}
|
1670
|
+
const hash = await hasher6.digest(toHash);
|
1622
1671
|
const cid = CID2.create(1, codec3.code, hash);
|
1623
|
-
return new mfBlock({ value, bytes, cid });
|
1672
|
+
return new mfBlock({ value, bytes: toHash, cid });
|
1624
1673
|
}
|
1625
1674
|
async function encode({
|
1626
1675
|
value,
|
1627
1676
|
codec: codec3,
|
1628
|
-
hasher:
|
1677
|
+
hasher: hasher6
|
1629
1678
|
}) {
|
1630
1679
|
if (typeof value === "undefined") throw new Error('Missing required argument "value"');
|
1631
|
-
if (codec3 == null ||
|
1632
|
-
|
1633
|
-
|
1680
|
+
if (codec3 == null || hasher6 == null) throw new Error("Missing required argument: codec or hasher");
|
1681
|
+
let bytes;
|
1682
|
+
let hash;
|
1683
|
+
if (codec3.bytesToHash) {
|
1684
|
+
const hashable = await Promise.resolve(codec3.bytesToHash(value));
|
1685
|
+
hash = await hasher6.digest(hashable);
|
1686
|
+
bytes = await Promise.resolve(codec3.encode(value));
|
1687
|
+
} else {
|
1688
|
+
bytes = await Promise.resolve(codec3.encode(value));
|
1689
|
+
hash = await hasher6.digest(bytes);
|
1690
|
+
}
|
1634
1691
|
const cid = CID2.create(1, codec3.code, hash);
|
1635
|
-
return new
|
1692
|
+
return new Block({ value, bytes, cid });
|
1636
1693
|
}
|
1637
1694
|
async function create({
|
1638
1695
|
bytes,
|
1639
1696
|
cid,
|
1640
|
-
hasher:
|
1697
|
+
hasher: hasher6,
|
1641
1698
|
codec: codec3
|
1642
1699
|
}) {
|
1643
1700
|
if (bytes == null) throw new Error('Missing required argument "bytes"');
|
1644
|
-
if (
|
1701
|
+
if (hasher6 == null) throw new Error('Missing required argument "hasher"');
|
1645
1702
|
const value = await Promise.resolve(codec3.decode(bytes));
|
1646
|
-
const hash = await
|
1703
|
+
const hash = await hasher6.digest(bytes);
|
1647
1704
|
if (!binary.equals(cid.multihash.bytes, hash.bytes)) {
|
1648
1705
|
throw new Error("CID hash does not match bytes");
|
1649
1706
|
}
|
@@ -1855,7 +1912,7 @@ var Index = class {
|
|
1855
1912
|
if (this.mapFn) {
|
1856
1913
|
if (mapFn) {
|
1857
1914
|
if (this.mapFn.toString() !== mapFn.toString()) {
|
1858
|
-
|
1915
|
+
this.logger.Error().Msg("cannot apply different mapFn app2");
|
1859
1916
|
}
|
1860
1917
|
}
|
1861
1918
|
} else {
|
@@ -1864,7 +1921,7 @@ var Index = class {
|
|
1864
1921
|
}
|
1865
1922
|
if (this.mapFnString) {
|
1866
1923
|
if (this.mapFnString !== mapFn.toString()) {
|
1867
|
-
|
1924
|
+
this.logger.Error().Str("mapFnString", this.mapFnString).Str("mapFn", mapFn.toString()).Msg("cannot apply different mapFn app");
|
1868
1925
|
}
|
1869
1926
|
} else {
|
1870
1927
|
this.mapFnString = mapFn.toString();
|
@@ -2140,8 +2197,11 @@ import { ResolveOnce as ResolveOnce6 } from "@adviser/cement";
|
|
2140
2197
|
var blockstore_exports = {};
|
2141
2198
|
__export(blockstore_exports, {
|
2142
2199
|
AttachedRemotesImpl: () => AttachedRemotesImpl,
|
2200
|
+
BaseActiveStore: () => BaseActiveStore,
|
2143
2201
|
BaseBlockstoreImpl: () => BaseBlockstoreImpl,
|
2144
2202
|
Car2FPMsg: () => Car2FPMsg,
|
2203
|
+
CarActiveStore: () => CarActiveStore,
|
2204
|
+
CarLog: () => CarLog,
|
2145
2205
|
CarTransactionImpl: () => CarTransactionImpl,
|
2146
2206
|
CompactionFetcher: () => CompactionFetcher,
|
2147
2207
|
DbMetaEventEqual: () => DbMetaEventEqual,
|
@@ -2149,9 +2209,13 @@ __export(blockstore_exports, {
|
|
2149
2209
|
EncryptedBlockstore: () => EncryptedBlockstore,
|
2150
2210
|
FPEnvelopeTypes: () => FPEnvelopeTypes,
|
2151
2211
|
File2FPMsg: () => File2FPMsg,
|
2212
|
+
FileActiveStore: () => FileActiveStore,
|
2152
2213
|
InterceptorGateway: () => InterceptorGateway,
|
2153
2214
|
Loader: () => Loader,
|
2215
|
+
MetaActiveStore: () => MetaActiveStore,
|
2154
2216
|
PassThroughGateway: () => PassThroughGateway,
|
2217
|
+
TaskManager: () => TaskManager,
|
2218
|
+
WALActiveStore: () => WALActiveStore,
|
2155
2219
|
createAttachedStores: () => createAttachedStores,
|
2156
2220
|
createDbMetaEvent: () => createDbMetaEvent,
|
2157
2221
|
defaultGatewayFactoryItem: () => defaultGatewayFactoryItem,
|
@@ -2166,6 +2230,37 @@ __export(blockstore_exports, {
|
|
2166
2230
|
});
|
2167
2231
|
|
2168
2232
|
// src/blockstore/types.ts
|
2233
|
+
var CarLog = class {
|
2234
|
+
constructor() {
|
2235
|
+
this._logs = [];
|
2236
|
+
}
|
2237
|
+
get length() {
|
2238
|
+
return this._logs.length;
|
2239
|
+
}
|
2240
|
+
last() {
|
2241
|
+
const x = [...this._logs[this._logs.length - 1]];
|
2242
|
+
Object.freeze(x);
|
2243
|
+
return x;
|
2244
|
+
}
|
2245
|
+
xunshift(logs) {
|
2246
|
+
this._logs.unshift(logs);
|
2247
|
+
}
|
2248
|
+
update(logs) {
|
2249
|
+
this._logs.length = 0;
|
2250
|
+
this._logs.push(...logs);
|
2251
|
+
}
|
2252
|
+
asArray() {
|
2253
|
+
const a = [
|
2254
|
+
...this._logs.map((l) => {
|
2255
|
+
const x = [...l];
|
2256
|
+
Object.freeze(x);
|
2257
|
+
return x;
|
2258
|
+
})
|
2259
|
+
];
|
2260
|
+
Object.freeze(a);
|
2261
|
+
return a;
|
2262
|
+
}
|
2263
|
+
};
|
2169
2264
|
function toCIDBlock(block) {
|
2170
2265
|
return block;
|
2171
2266
|
}
|
@@ -2175,9 +2270,19 @@ function DbMetaEventEqual(a, b) {
|
|
2175
2270
|
function DbMetaEventsEqual(a, b) {
|
2176
2271
|
return a.length === b.length && a.every((e, i) => DbMetaEventEqual(e, b[i]));
|
2177
2272
|
}
|
2273
|
+
var BaseActiveStore = class {
|
2274
|
+
};
|
2275
|
+
var CarActiveStore = class extends BaseActiveStore {
|
2276
|
+
};
|
2277
|
+
var FileActiveStore = class extends BaseActiveStore {
|
2278
|
+
};
|
2279
|
+
var MetaActiveStore = class extends BaseActiveStore {
|
2280
|
+
};
|
2281
|
+
var WALActiveStore = class extends BaseActiveStore {
|
2282
|
+
};
|
2178
2283
|
|
2179
2284
|
// src/blockstore/store-factory.ts
|
2180
|
-
import { KeyedResolvOnce as
|
2285
|
+
import { KeyedResolvOnce as KeyedResolvOnce5, Result as Result10 } from "@adviser/cement";
|
2181
2286
|
|
2182
2287
|
// src/blockstore/store.ts
|
2183
2288
|
import { exception2Result as exception2Result3, ResolveOnce as ResolveOnce4, Result as Result9 } from "@adviser/cement";
|
@@ -2185,14 +2290,14 @@ import { exception2Result as exception2Result3, ResolveOnce as ResolveOnce4, Res
|
|
2185
2290
|
// src/blockstore/loader.ts
|
2186
2291
|
import pLimit from "p-limit";
|
2187
2292
|
import { CarReader } from "@ipld/car/reader";
|
2188
|
-
import { ResolveOnce as ResolveOnce3 } from "@adviser/cement";
|
2293
|
+
import { KeyedResolvOnce as KeyedResolvOnce4, LRUSet, ResolveOnce as ResolveOnce3 } from "@adviser/cement";
|
2189
2294
|
|
2190
2295
|
// src/blockstore/loader-helpers.ts
|
2191
2296
|
import { sha256 as hasher2 } from "multiformats/hashes/sha2";
|
2192
2297
|
import * as dagCodec from "@ipld/dag-cbor";
|
2193
2298
|
async function parseCarFile(reader, logger) {
|
2194
|
-
const roots = await reader.
|
2195
|
-
const header =
|
2299
|
+
const roots = await reader.roots;
|
2300
|
+
const header = reader.blocks.find((i) => i.cid.equals(roots[0]));
|
2196
2301
|
if (!header) throw logger.Error().Msg("missing header block").AsError();
|
2197
2302
|
const dec = await decode({ bytes: header.bytes, hasher: hasher2, codec: dagCodec });
|
2198
2303
|
const fpvalue = dec.value;
|
@@ -2207,6 +2312,7 @@ import { MemoryBlockstore } from "@fireproof/vendor/@web3-storage/pail/block";
|
|
2207
2312
|
import { toCryptoRuntime as toCryptoRuntime3 } from "@adviser/cement";
|
2208
2313
|
var CarTransactionImpl = class {
|
2209
2314
|
#memblock = new MemoryBlockstore();
|
2315
|
+
#hackUnshift;
|
2210
2316
|
constructor(parent, opts = { add: true, noLoader: false }) {
|
2211
2317
|
if (opts.add) {
|
2212
2318
|
parent.transactions.add(this);
|
@@ -2214,7 +2320,7 @@ var CarTransactionImpl = class {
|
|
2214
2320
|
this.parent = parent;
|
2215
2321
|
}
|
2216
2322
|
async get(cid) {
|
2217
|
-
return await this.superGet(cid)
|
2323
|
+
return await this.superGet(cid) ?? falsyToUndef(await this.parent.get(cid));
|
2218
2324
|
}
|
2219
2325
|
async superGet(cid) {
|
2220
2326
|
return this.#memblock.get(cid);
|
@@ -2225,7 +2331,16 @@ var CarTransactionImpl = class {
|
|
2225
2331
|
putSync(cid, bytes) {
|
2226
2332
|
this.#memblock.putSync(cid, bytes);
|
2227
2333
|
}
|
2334
|
+
unshift(cid, bytes) {
|
2335
|
+
if (this.#hackUnshift) {
|
2336
|
+
throw new Error("unshift already called");
|
2337
|
+
}
|
2338
|
+
this.#hackUnshift = { cid, bytes };
|
2339
|
+
}
|
2228
2340
|
async *entries() {
|
2341
|
+
if (this.#hackUnshift) {
|
2342
|
+
yield this.#hackUnshift;
|
2343
|
+
}
|
2229
2344
|
for await (const blk of this.#memblock.entries()) {
|
2230
2345
|
yield blk;
|
2231
2346
|
}
|
@@ -2251,6 +2366,11 @@ function defaultedBlockstoreRuntime(sthis, opts, component, ctx) {
|
|
2251
2366
|
keyBag: opts.keyBag || {},
|
2252
2367
|
crypto: toCryptoRuntime3(opts.crypto),
|
2253
2368
|
storeUrls: opts.storeUrls,
|
2369
|
+
taskManager: {
|
2370
|
+
removeAfter: 3,
|
2371
|
+
retryTimeout: 50,
|
2372
|
+
...opts.taskManager
|
2373
|
+
},
|
2254
2374
|
// storeEnDeFile: ensureStoreEnDeFile(opts.storeEnDeFile),
|
2255
2375
|
// store,
|
2256
2376
|
storeRuntime: toStoreRuntime(sthis, ensureStoreEnDeFile(opts.storeEnDeFile))
|
@@ -2343,10 +2463,8 @@ var EncryptedBlockstore = class extends BaseBlockstoreImpl {
|
|
2343
2463
|
async get(cid) {
|
2344
2464
|
const got = await super.get(cid);
|
2345
2465
|
if (got) return got;
|
2346
|
-
|
2347
|
-
|
2348
|
-
}
|
2349
|
-
return falsyToUndef(await this.loader.getBlock(cid, this.loader.attachedStores.local()));
|
2466
|
+
const ret = falsyToUndef(await this.loader.getBlock(cid, this.loader.attachedStores.local()));
|
2467
|
+
return ret;
|
2350
2468
|
}
|
2351
2469
|
async transaction(fn, opts = { noLoader: false }) {
|
2352
2470
|
this.logger.Debug().Msg("enter transaction");
|
@@ -2367,7 +2485,7 @@ var EncryptedBlockstore = class extends BaseBlockstoreImpl {
|
|
2367
2485
|
await this.ready();
|
2368
2486
|
if (!this.loader) throw this.logger.Error().Msg("loader required to get file, ledger must be named").AsError();
|
2369
2487
|
const reader = await this.loader.loadFileCar(car, this.loader.attachedStores.local());
|
2370
|
-
const block = await reader.
|
2488
|
+
const block = await reader.blocks.find((i) => i.cid.equals(cid));
|
2371
2489
|
if (!block) throw this.logger.Error().Str("cid", cid.toString()).Msg(`Missing block`).AsError();
|
2372
2490
|
return block.bytes;
|
2373
2491
|
}
|
@@ -2474,8 +2592,8 @@ var CommitQueue = class {
|
|
2474
2592
|
|
2475
2593
|
// src/blockstore/commitor.ts
|
2476
2594
|
import * as CBW from "@ipld/car/buffer-writer";
|
2477
|
-
import { sha256 as hasher3 } from "multiformats/hashes/sha2";
|
2478
2595
|
import * as dagCodec2 from "@ipld/dag-cbor";
|
2596
|
+
import { sha256 } from "multiformats/hashes/sha2";
|
2479
2597
|
async function encodeCarFile(roots, t, codec3) {
|
2480
2598
|
let size = 0;
|
2481
2599
|
const headerSize = CBW.headerLength({ roots });
|
@@ -2492,7 +2610,7 @@ async function encodeCarFile(roots, t, codec3) {
|
|
2492
2610
|
writer.write({ cid, bytes });
|
2493
2611
|
}
|
2494
2612
|
writer.close();
|
2495
|
-
return await encode({ value: writer.bytes, hasher:
|
2613
|
+
return await encode({ value: writer.bytes, hasher: sha256, codec: codec3 });
|
2496
2614
|
}
|
2497
2615
|
async function createCarFile(encoder, cid, t) {
|
2498
2616
|
return encodeCarFile([cid], t, encoder);
|
@@ -2500,7 +2618,7 @@ async function createCarFile(encoder, cid, t) {
|
|
2500
2618
|
async function commitFiles(fileStore, walStore, t, done) {
|
2501
2619
|
const { files: roots } = makeFileCarHeader(done);
|
2502
2620
|
const cids = [];
|
2503
|
-
const codec3 =
|
2621
|
+
const codec3 = await fileStore.keyedCrypto().then((i) => i.codec());
|
2504
2622
|
const cars = await prepareCarFilesFiles(codec3, roots, t);
|
2505
2623
|
for (const car of cars) {
|
2506
2624
|
const { cid, bytes } = car;
|
@@ -2526,13 +2644,13 @@ async function prepareCarFilesFiles(encoder, roots, t) {
|
|
2526
2644
|
return [await encodeCarFile(roots, t, encoder)];
|
2527
2645
|
}
|
2528
2646
|
function makeCarHeader(meta, cars, compact = false) {
|
2529
|
-
const coreHeader = compact ? { cars: [], compact: cars } : { cars, compact: [] };
|
2647
|
+
const coreHeader = compact ? { cars: [], compact: cars.asArray() } : { cars: cars.asArray(), compact: [] };
|
2530
2648
|
return { ...coreHeader, meta };
|
2531
2649
|
}
|
2532
2650
|
async function encodeCarHeader(fp) {
|
2533
2651
|
return await encode({
|
2534
2652
|
value: { fp },
|
2535
|
-
hasher:
|
2653
|
+
hasher: sha256,
|
2536
2654
|
codec: dagCodec2
|
2537
2655
|
});
|
2538
2656
|
}
|
@@ -2553,7 +2671,7 @@ async function commit(params, t, done, opts = { noLoader: false, compact: false
|
|
2553
2671
|
}
|
2554
2672
|
async function prepareCarFiles(encoder, threshold, rootBlock, t) {
|
2555
2673
|
const carFiles = [];
|
2556
|
-
threshold = threshold ||
|
2674
|
+
threshold = threshold || 16 * 65536;
|
2557
2675
|
let clonedt = new CarTransactionImpl(t.parent, { add: false, noLoader: false });
|
2558
2676
|
clonedt.putSync(rootBlock.cid, rootBlock.bytes);
|
2559
2677
|
let newsize = CBW.blockLength(toCIDBlock(rootBlock));
|
@@ -2575,17 +2693,18 @@ async function prepareCarFiles(encoder, threshold, rootBlock, t) {
|
|
2575
2693
|
}
|
2576
2694
|
|
2577
2695
|
// src/blockstore/loader.ts
|
2578
|
-
import { sha256 as
|
2696
|
+
import { sha256 as hasher3 } from "multiformats/hashes/sha2";
|
2579
2697
|
|
2580
2698
|
// src/blockstore/task-manager.ts
|
2581
2699
|
var TaskManager = class {
|
2582
|
-
constructor(sthis, callback) {
|
2700
|
+
constructor(sthis, callback, params) {
|
2583
2701
|
// we need to remove the events after some time
|
2584
2702
|
this.eventsWeHandled = /* @__PURE__ */ new Set();
|
2585
2703
|
this.queue = [];
|
2586
2704
|
this.isProcessing = false;
|
2587
2705
|
this.logger = ensureLogger(sthis, "TaskManager");
|
2588
2706
|
this.callback = callback;
|
2707
|
+
this.params = params;
|
2589
2708
|
}
|
2590
2709
|
async handleEvent(cid, parents, dbMeta, store) {
|
2591
2710
|
for (const parent of parents) {
|
@@ -2614,7 +2733,7 @@ var TaskManager = class {
|
|
2614
2733
|
this.queue = this.queue.filter(({ cid }) => cid !== first.cid);
|
2615
2734
|
}
|
2616
2735
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
2617
|
-
|
2736
|
+
this.logger.Warn().Err(err).Msg("retry to process event block");
|
2618
2737
|
} finally {
|
2619
2738
|
this.isProcessing = false;
|
2620
2739
|
if (this.queue.length > 0) {
|
@@ -2625,7 +2744,7 @@ var TaskManager = class {
|
|
2625
2744
|
};
|
2626
2745
|
|
2627
2746
|
// src/blockstore/attachable-store.ts
|
2628
|
-
import { KeyedResolvOnce as KeyedResolvOnce3,
|
2747
|
+
import { KeyedResolvOnce as KeyedResolvOnce3, isCoerceURI, URI as URI9 } from "@adviser/cement";
|
2629
2748
|
var AttachedImpl = class {
|
2630
2749
|
constructor(gws, stores, unreg) {
|
2631
2750
|
this.gatewayUrls = gws;
|
@@ -2644,11 +2763,32 @@ var AttachedImpl = class {
|
|
2644
2763
|
return "attached";
|
2645
2764
|
}
|
2646
2765
|
};
|
2647
|
-
var
|
2766
|
+
var FileActiveStoreImpl = class extends FileActiveStore {
|
2648
2767
|
constructor(ref, active, attached) {
|
2768
|
+
super();
|
2649
2769
|
this.ref = ref;
|
2650
2770
|
this.active = active;
|
2651
|
-
this.
|
2771
|
+
this.xattached = attached;
|
2772
|
+
}
|
2773
|
+
local() {
|
2774
|
+
return this.xattached.local();
|
2775
|
+
}
|
2776
|
+
remotes() {
|
2777
|
+
return this.xattached.remotes();
|
2778
|
+
}
|
2779
|
+
};
|
2780
|
+
var CarActiveStoreImpl = class extends CarActiveStore {
|
2781
|
+
constructor(ref, active, attached) {
|
2782
|
+
super();
|
2783
|
+
this.ref = ref;
|
2784
|
+
this.active = active;
|
2785
|
+
this.xattached = attached;
|
2786
|
+
}
|
2787
|
+
local() {
|
2788
|
+
return this.xattached.local();
|
2789
|
+
}
|
2790
|
+
remotes() {
|
2791
|
+
return [this.active, ...this.xattached.remotes().filter((i) => i !== this.active)];
|
2652
2792
|
}
|
2653
2793
|
};
|
2654
2794
|
var CarAttachedStoresImpl = class {
|
@@ -2673,11 +2813,18 @@ var FileAttachedStoresImpl = class {
|
|
2673
2813
|
return this.attached.remotes().map(({ active }) => active.file);
|
2674
2814
|
}
|
2675
2815
|
};
|
2676
|
-
var MetaActiveStoreImpl = class {
|
2816
|
+
var MetaActiveStoreImpl = class extends MetaActiveStore {
|
2677
2817
|
constructor(ref, active, attached) {
|
2818
|
+
super();
|
2678
2819
|
this.ref = ref;
|
2679
2820
|
this.active = active;
|
2680
|
-
this.
|
2821
|
+
this.xattached = attached;
|
2822
|
+
}
|
2823
|
+
local() {
|
2824
|
+
return this.xattached.local();
|
2825
|
+
}
|
2826
|
+
remotes() {
|
2827
|
+
return [this.active, ...this.xattached.remotes().filter((i) => i !== this.active)];
|
2681
2828
|
}
|
2682
2829
|
};
|
2683
2830
|
var MetaAttachedStoresImpl = class {
|
@@ -2691,11 +2838,18 @@ var MetaAttachedStoresImpl = class {
|
|
2691
2838
|
return this.attached.remotes().map(({ active }) => active.meta);
|
2692
2839
|
}
|
2693
2840
|
};
|
2694
|
-
var WALActiveStoreImpl = class {
|
2841
|
+
var WALActiveStoreImpl = class extends WALActiveStore {
|
2695
2842
|
constructor(ref, active, attached) {
|
2843
|
+
super();
|
2696
2844
|
this.ref = ref;
|
2697
2845
|
this.active = active;
|
2698
|
-
this.
|
2846
|
+
this.xattached = attached;
|
2847
|
+
}
|
2848
|
+
local() {
|
2849
|
+
return this.xattached.local();
|
2850
|
+
}
|
2851
|
+
remotes() {
|
2852
|
+
return this.xattached.remotes();
|
2699
2853
|
}
|
2700
2854
|
};
|
2701
2855
|
var WALAttachedStoresImpl = class {
|
@@ -2712,7 +2866,13 @@ var WALAttachedStoresImpl = class {
|
|
2712
2866
|
var ActiveStoreImpl = class {
|
2713
2867
|
constructor(active, attached) {
|
2714
2868
|
this.active = active;
|
2715
|
-
this.
|
2869
|
+
this.xattached = attached;
|
2870
|
+
}
|
2871
|
+
local() {
|
2872
|
+
return this.xattached.local();
|
2873
|
+
}
|
2874
|
+
remotes() {
|
2875
|
+
return this.xattached.remotes();
|
2716
2876
|
}
|
2717
2877
|
baseStores() {
|
2718
2878
|
const bs = [this.active.car, this.active.file, this.active.meta];
|
@@ -2722,19 +2882,19 @@ var ActiveStoreImpl = class {
|
|
2722
2882
|
return bs;
|
2723
2883
|
}
|
2724
2884
|
carStore() {
|
2725
|
-
return new
|
2885
|
+
return new CarActiveStoreImpl(this, this.active.car, new CarAttachedStoresImpl(this.xattached));
|
2726
2886
|
}
|
2727
2887
|
fileStore() {
|
2728
|
-
return new
|
2888
|
+
return new FileActiveStoreImpl(this, this.active.file, new FileAttachedStoresImpl(this.xattached));
|
2729
2889
|
}
|
2730
2890
|
metaStore() {
|
2731
|
-
return new MetaActiveStoreImpl(this, this.active.meta, new MetaAttachedStoresImpl(this.
|
2891
|
+
return new MetaActiveStoreImpl(this, this.active.meta, new MetaAttachedStoresImpl(this.xattached));
|
2732
2892
|
}
|
2733
2893
|
walStore() {
|
2734
2894
|
if (!this.active.wal) {
|
2735
|
-
throw this.
|
2895
|
+
throw this.xattached.loadable.sthis.logger.Error().Msg("wal store not set").AsError();
|
2736
2896
|
}
|
2737
|
-
return new WALActiveStoreImpl(this, this.active.wal, new WALAttachedStoresImpl(this.
|
2897
|
+
return new WALActiveStoreImpl(this, this.active.wal, new WALAttachedStoresImpl(this.xattached));
|
2738
2898
|
}
|
2739
2899
|
};
|
2740
2900
|
function isLoadable(unknown) {
|
@@ -2786,7 +2946,25 @@ var AttachedRemotesImpl = class {
|
|
2786
2946
|
}
|
2787
2947
|
activate(store) {
|
2788
2948
|
if (isCoerceURI(store)) {
|
2789
|
-
|
2949
|
+
const activateUrl = URI9.from(store);
|
2950
|
+
let maxScore = 0;
|
2951
|
+
let maxStore;
|
2952
|
+
for (const { value } of this._remotes.values()) {
|
2953
|
+
if (value.isErr()) {
|
2954
|
+
continue;
|
2955
|
+
}
|
2956
|
+
for (const url of value.Ok().stores.baseStores.map((i) => i.url())) {
|
2957
|
+
const mr = url.match(activateUrl);
|
2958
|
+
if (mr.score > maxScore) {
|
2959
|
+
maxScore = mr.score;
|
2960
|
+
maxStore = value.Ok().stores;
|
2961
|
+
}
|
2962
|
+
}
|
2963
|
+
}
|
2964
|
+
if (!maxStore) {
|
2965
|
+
throw this.loadable.sthis.logger.Error().Url(activateUrl).Msg("no store found").AsError();
|
2966
|
+
}
|
2967
|
+
store = maxStore;
|
2790
2968
|
}
|
2791
2969
|
return new ActiveStoreImpl(store, this);
|
2792
2970
|
}
|
@@ -2804,19 +2982,19 @@ var AttachedRemotesImpl = class {
|
|
2804
2982
|
const gws = {
|
2805
2983
|
car: {
|
2806
2984
|
...gwp.car,
|
2807
|
-
url:
|
2985
|
+
url: ensureURIDefaults(this.loadable.sthis, attached.name, gwp.car.url, URI9.from(gwp.car.url), "car")
|
2808
2986
|
},
|
2809
2987
|
file: {
|
2810
2988
|
...gwp.file,
|
2811
|
-
url:
|
2989
|
+
url: ensureURIDefaults(this.loadable.sthis, attached.name, void 0, URI9.from(gwp.file.url), "file", { file: true })
|
2812
2990
|
},
|
2813
2991
|
meta: {
|
2814
2992
|
...gwp.meta,
|
2815
|
-
url:
|
2993
|
+
url: ensureURIDefaults(this.loadable.sthis, attached.name, void 0, URI9.from(gwp.meta.url), "meta")
|
2816
2994
|
},
|
2817
2995
|
wal: gwp.wal ? {
|
2818
2996
|
...gwp.wal,
|
2819
|
-
url:
|
2997
|
+
url: ensureURIDefaults(this.loadable.sthis, attached.name, void 0, URI9.from(gwp.wal.url), "wal")
|
2820
2998
|
} : void 0
|
2821
2999
|
};
|
2822
3000
|
const key = JSON.stringify(
|
@@ -2835,11 +3013,6 @@ var AttachedRemotesImpl = class {
|
|
2835
3013
|
byStore: gws,
|
2836
3014
|
loader: this.loadable
|
2837
3015
|
}),
|
2838
|
-
// {
|
2839
|
-
// car: await rt.makeDataStore({ url: gws.carUrl, loader: this.loadable }),
|
2840
|
-
// file: await rt.makeDataStore({ url: gws.filesUrl, loader: this.loadable }),
|
2841
|
-
// meta: await rt.makeMetaStore({ url: gws.metaUrl, loader: this.loadable }),
|
2842
|
-
// },
|
2843
3016
|
() => {
|
2844
3017
|
this._remotes.unget(key);
|
2845
3018
|
}
|
@@ -2857,11 +3030,12 @@ var AttachedRemotesImpl = class {
|
|
2857
3030
|
|
2858
3031
|
// src/blockstore/loader.ts
|
2859
3032
|
function carLogIncludesGroup(list, cids) {
|
2860
|
-
|
2861
|
-
|
2862
|
-
|
3033
|
+
const cidSet = cids.map((cid) => cid.toString()).sort().join(",");
|
3034
|
+
return list.some(
|
3035
|
+
(arr) => cidSet === arr.map((cid) => cid.toString()).sort().join(",")
|
3036
|
+
);
|
2863
3037
|
}
|
2864
|
-
function uniqueCids(list, remove =
|
3038
|
+
function uniqueCids(list, remove = new LRUSet()) {
|
2865
3039
|
const byString = /* @__PURE__ */ new Map();
|
2866
3040
|
for (const cid of list) {
|
2867
3041
|
if (remove.has(cid.toString())) continue;
|
@@ -2873,13 +3047,8 @@ var Loader = class {
|
|
2873
3047
|
constructor(sthis, ebOpts) {
|
2874
3048
|
this.commitQueue = new CommitQueue();
|
2875
3049
|
this.isCompacting = false;
|
2876
|
-
this.
|
2877
|
-
this.
|
2878
|
-
this.processedCars = /* @__PURE__ */ new Set();
|
2879
|
-
this.carLog = [];
|
2880
|
-
this.getBlockCache = /* @__PURE__ */ new Map();
|
2881
|
-
this.seenMeta = /* @__PURE__ */ new Set();
|
2882
|
-
this.writeLimit = pLimit(1);
|
3050
|
+
this.maxConcurrentWrite = pLimit(1);
|
3051
|
+
this.carLog = new CarLog();
|
2883
3052
|
this.onceReady = new ResolveOnce3();
|
2884
3053
|
this.sthis = sthis;
|
2885
3054
|
this.ebOpts = defaultedBlockstoreRuntime(
|
@@ -2890,63 +3059,44 @@ var Loader = class {
|
|
2890
3059
|
},
|
2891
3060
|
"Loader"
|
2892
3061
|
);
|
2893
|
-
this.logger =
|
2894
|
-
this.
|
2895
|
-
|
3062
|
+
this.logger = ensureLogger(sthis, "Loader");
|
3063
|
+
this.cidCache = new KeyedResolvOnce4({
|
3064
|
+
lru: {
|
3065
|
+
maxEntries: parseInt(this.ebOpts.storeUrls.car.getParam(PARAM.CAR_CACHE_SIZE, "1000"), 10)
|
3066
|
+
}
|
2896
3067
|
});
|
3068
|
+
this.seenMeta = new LRUSet({
|
3069
|
+
maxEntries: parseInt(this.ebOpts.storeUrls.meta.getParam(PARAM.CAR_META_CACHE_SIZE, "1000"), 10)
|
3070
|
+
});
|
3071
|
+
this.seenCompacted = new LRUSet({
|
3072
|
+
maxEntries: parseInt(this.ebOpts.storeUrls.car.getParam(PARAM.CAR_COMPACT_CACHE_SIZE, "1000"), 10)
|
3073
|
+
});
|
3074
|
+
this.maxConcurrentCarReader = pLimit(parseInt(this.ebOpts.storeUrls.car.getParam(PARAM.CAR_PARALLEL, "5"), 10));
|
3075
|
+
this.taskManager = new TaskManager(
|
3076
|
+
sthis,
|
3077
|
+
async (dbMeta, activeStore) => {
|
3078
|
+
await this.handleDbMetasFromStore([dbMeta], activeStore);
|
3079
|
+
},
|
3080
|
+
this.ebOpts.taskManager
|
3081
|
+
);
|
2897
3082
|
this.attachedStores = new AttachedRemotesImpl(this);
|
2898
3083
|
}
|
2899
|
-
attach(attached) {
|
2900
|
-
|
2901
|
-
|
2902
|
-
|
2903
|
-
|
2904
|
-
|
2905
|
-
|
2906
|
-
|
2907
|
-
|
2908
|
-
|
2909
|
-
|
2910
|
-
|
2911
|
-
|
2912
|
-
|
2913
|
-
|
2914
|
-
|
2915
|
-
// async fileStore(): Promise<DataStore> {
|
2916
|
-
// return this._fileStore.once(async () =>
|
2917
|
-
// this.ebOpts.storeRuntime.makeDataStore({
|
2918
|
-
// // sthis: this.sthis,
|
2919
|
-
// gatewayInterceptor: this.ebOpts.gatewayInterceptor,
|
2920
|
-
// url: this.ebOpts.storeUrls.file,
|
2921
|
-
// // keybag: await this.keyBag(),
|
2922
|
-
// loader: this,
|
2923
|
-
// }),
|
2924
|
-
// );
|
2925
|
-
// }
|
2926
|
-
// private readonly _WALStore = new ResolveOnce<WALStore>();
|
2927
|
-
// async WALStore(): Promise<WALStore> {
|
2928
|
-
// return this._WALStore.once(async () =>
|
2929
|
-
// this.ebOpts.storeRuntime.makeWALStore({
|
2930
|
-
// // sthis: this.sthis,
|
2931
|
-
// gatewayInterceptor: this.ebOpts.gatewayInterceptor,
|
2932
|
-
// url: this.ebOpts.storeUrls.wal,
|
2933
|
-
// // keybag: await this.keyBag(),
|
2934
|
-
// loader: this,
|
2935
|
-
// }),
|
2936
|
-
// );
|
2937
|
-
// }
|
2938
|
-
// private readonly _metaStore = new ResolveOnce<MetaStore>();
|
2939
|
-
// async metaStore(): Promise<MetaStore> {
|
2940
|
-
// return this._metaStore.once(async () =>
|
2941
|
-
// this.ebOpts.storeRuntime.makeMetaStore({
|
2942
|
-
// // sthis: this.sthis,
|
2943
|
-
// gatewayInterceptor: this.ebOpts.gatewayInterceptor,
|
2944
|
-
// url: this.ebOpts.storeUrls.meta,
|
2945
|
-
// // keybag: await this.keyBag(),
|
2946
|
-
// loader: this,
|
2947
|
-
// }),
|
2948
|
-
// );
|
2949
|
-
// }
|
3084
|
+
async attach(attached) {
|
3085
|
+
const at = await this.attachedStores.attach(attached);
|
3086
|
+
if (!at.stores.wal) {
|
3087
|
+
try {
|
3088
|
+
const dbMeta = await at.stores.meta.load();
|
3089
|
+
if (!Array.isArray(dbMeta)) {
|
3090
|
+
throw this.logger.Error().Msg("missing dbMeta").AsError();
|
3091
|
+
}
|
3092
|
+
await this.handleDbMetasFromStore(dbMeta, this.attachedStores.activate(at.stores));
|
3093
|
+
} catch (e) {
|
3094
|
+
this.logger.Error().Err(e).Msg("error attaching store");
|
3095
|
+
at.detach();
|
3096
|
+
}
|
3097
|
+
}
|
3098
|
+
return at;
|
3099
|
+
}
|
2950
3100
|
keyBag() {
|
2951
3101
|
return getKeyBag(this.sthis, this.ebOpts.keyBag);
|
2952
3102
|
}
|
@@ -2990,9 +3140,9 @@ var Loader = class {
|
|
2990
3140
|
// await this._applyCarHeader(carHeader, true)
|
2991
3141
|
// }
|
2992
3142
|
async handleDbMetasFromStore(metas, activeStore) {
|
2993
|
-
this.logger.Debug().Any("metas", metas).Msg("handleDbMetasFromStore");
|
3143
|
+
this.logger.Debug().Any("metas", metas).Url(activeStore.active.car.url()).Msg("handleDbMetasFromStore");
|
2994
3144
|
for (const meta of metas) {
|
2995
|
-
await this.
|
3145
|
+
await this.maxConcurrentWrite(async () => {
|
2996
3146
|
await this.mergeDbMetaIntoClock(meta, activeStore);
|
2997
3147
|
});
|
2998
3148
|
}
|
@@ -3001,16 +3151,26 @@ var Loader = class {
|
|
3001
3151
|
if (this.isCompacting) {
|
3002
3152
|
throw this.logger.Error().Msg("cannot merge while compacting").AsError();
|
3003
3153
|
}
|
3004
|
-
|
3005
|
-
|
3006
|
-
|
3007
|
-
return;
|
3154
|
+
try {
|
3155
|
+
this.isCompacting = true;
|
3156
|
+
const metaKey = meta.cars.map((i) => i.toString()).sort().join(",");
|
3157
|
+
if (this.seenMeta.has(metaKey)) return;
|
3158
|
+
this.seenMeta.add(metaKey);
|
3159
|
+
if (carLogIncludesGroup(this.carLog.asArray(), meta.cars)) {
|
3160
|
+
return;
|
3161
|
+
}
|
3162
|
+
const carHeader = await this.loadCarHeaderFromMeta(meta, activeStore);
|
3163
|
+
carHeader.compact.map((c) => c.toString()).forEach((k) => this.seenCompacted.add(k), this.seenCompacted);
|
3164
|
+
try {
|
3165
|
+
await this.getMoreReaders(carHeader.cars.flat(), activeStore);
|
3166
|
+
} catch (e) {
|
3167
|
+
this.logger.Error().Err(e).Msg("error getting more readers");
|
3168
|
+
}
|
3169
|
+
this.carLog.update(uniqueCids([meta.cars, ...this.carLog.asArray(), ...carHeader.cars], this.seenCompacted));
|
3170
|
+
await this.ebOpts.applyMeta?.(carHeader.meta);
|
3171
|
+
} finally {
|
3172
|
+
this.isCompacting = false;
|
3008
3173
|
}
|
3009
|
-
const carHeader = await this.loadCarHeaderFromMeta(meta, activeStore);
|
3010
|
-
carHeader.compact.map((c) => c.toString()).forEach(this.seenCompacted.add, this.seenCompacted);
|
3011
|
-
await this.getMoreReaders(carHeader.cars.flat(), activeStore);
|
3012
|
-
this.carLog = [...uniqueCids([meta.cars, ...this.carLog, ...carHeader.cars], this.seenCompacted)];
|
3013
|
-
await this.ebOpts.applyMeta?.(carHeader.meta);
|
3014
3174
|
}
|
3015
3175
|
// protected async ingestKeyFromMeta(meta: DbMeta): Promise<void> {
|
3016
3176
|
// const { key } = meta;
|
@@ -3041,13 +3201,13 @@ var Loader = class {
|
|
3041
3201
|
}
|
3042
3202
|
async commit(t, done, opts = { noLoader: false, compact: false }) {
|
3043
3203
|
await this.ready();
|
3044
|
-
const carStore =
|
3204
|
+
const carStore = this.attachedStores.local().active.car;
|
3045
3205
|
const params = {
|
3046
3206
|
encoder: (await carStore.keyedCrypto()).codec(),
|
3047
3207
|
carLog: this.carLog,
|
3048
3208
|
carStore,
|
3049
|
-
WALStore:
|
3050
|
-
metaStore:
|
3209
|
+
WALStore: this.attachedStores.local().active.wal,
|
3210
|
+
metaStore: this.attachedStores.local().active.meta,
|
3051
3211
|
threshold: this.ebOpts.threshold
|
3052
3212
|
};
|
3053
3213
|
return this.commitQueue.enqueue(async () => {
|
@@ -3057,34 +3217,44 @@ var Loader = class {
|
|
3057
3217
|
return ret.cgrp;
|
3058
3218
|
});
|
3059
3219
|
}
|
3060
|
-
async updateCarLog(cids,
|
3220
|
+
async updateCarLog(cids, cHeader, compact) {
|
3061
3221
|
if (compact) {
|
3062
|
-
const previousCompactCid =
|
3063
|
-
|
3064
|
-
this.carLog
|
3222
|
+
const previousCompactCid = cHeader.compact[cHeader.compact.length - 1];
|
3223
|
+
cHeader.compact.map((c) => c.toString()).forEach(this.seenCompacted.add, this.seenCompacted);
|
3224
|
+
this.carLog.update(uniqueCids([...this.carLog.asArray(), ...cHeader.cars, cids], this.seenCompacted));
|
3065
3225
|
await this.removeCidsForCompact(previousCompactCid[0], this.attachedStores.local()).catch((e) => e);
|
3066
3226
|
} else {
|
3067
|
-
this.carLog.
|
3227
|
+
this.carLog.xunshift(cids);
|
3068
3228
|
}
|
3069
3229
|
}
|
3070
3230
|
async cacheTransaction(t) {
|
3071
3231
|
for await (const block of t.entries()) {
|
3072
3232
|
const sBlock = block.cid.toString();
|
3073
|
-
|
3074
|
-
|
3075
|
-
|
3076
|
-
|
3077
|
-
|
3078
|
-
|
3079
|
-
|
3080
|
-
|
3081
|
-
for await (const block of reader.blocks()) {
|
3082
|
-
const sBlock = block.cid.toString();
|
3083
|
-
if (!this.getBlockCache.has(sBlock)) {
|
3084
|
-
this.getBlockCache.set(sBlock, block);
|
3085
|
-
}
|
3233
|
+
this.cidCache.get(sBlock).once(
|
3234
|
+
() => ({
|
3235
|
+
type: "block",
|
3236
|
+
cid: block.cid,
|
3237
|
+
blocks: [block],
|
3238
|
+
roots: []
|
3239
|
+
})
|
3240
|
+
);
|
3086
3241
|
}
|
3087
3242
|
}
|
3243
|
+
// /**
|
3244
|
+
// *
|
3245
|
+
// * @returns the list of blocks which was read from the car file
|
3246
|
+
// */
|
3247
|
+
// private async readCar(reader: CarReader): Promise<AnyBlock[]> {
|
3248
|
+
// const blocks: AnyBlock[] = [];
|
3249
|
+
// for await (const block of reader.blocks()) {
|
3250
|
+
// const sBlock = block.cid.toString();
|
3251
|
+
// this.cidCache.get(sBlock).once(() => {
|
3252
|
+
// blocks.push(block);
|
3253
|
+
// return [block];
|
3254
|
+
// });
|
3255
|
+
// }
|
3256
|
+
// return blocks;
|
3257
|
+
// }
|
3088
3258
|
async removeCidsForCompact(cid, store) {
|
3089
3259
|
const carHeader = await this.loadCarHeaderFromMeta(
|
3090
3260
|
{
|
@@ -3106,149 +3276,134 @@ var Loader = class {
|
|
3106
3276
|
// await this.remoteWAL!.enqueue(dbMeta, { public: false })
|
3107
3277
|
// }
|
3108
3278
|
// }
|
3109
|
-
async *entries(
|
3279
|
+
async *entries() {
|
3110
3280
|
await this.ready();
|
3111
|
-
|
3112
|
-
|
3113
|
-
|
3114
|
-
|
3115
|
-
|
3116
|
-
|
3117
|
-
|
3118
|
-
|
3119
|
-
|
3120
|
-
|
3121
|
-
|
3122
|
-
|
3123
|
-
for await (const block of reader.blocks()) {
|
3124
|
-
const sCid = block.cid.toString();
|
3125
|
-
if (!this.getBlockCache.has(sCid)) {
|
3126
|
-
yield block;
|
3127
|
-
}
|
3128
|
-
}
|
3281
|
+
const seen = /* @__PURE__ */ new Set();
|
3282
|
+
for (const carCids of this.carLog.asArray()) {
|
3283
|
+
for (const carCid of carCids) {
|
3284
|
+
const reader = await this.loadCar(carCid, this.attachedStores.local());
|
3285
|
+
if (!reader || reader.type !== "car") {
|
3286
|
+
throw this.logger.Error().Any("reader", reader.type).Str("cid", carCid.toString()).Msg("missing car reader").AsError();
|
3287
|
+
}
|
3288
|
+
for (const block of reader.blocks) {
|
3289
|
+
const cidStr = block.cid.toString();
|
3290
|
+
if (seen.has(cidStr)) continue;
|
3291
|
+
seen.add(cidStr);
|
3292
|
+
yield block;
|
3129
3293
|
}
|
3130
3294
|
}
|
3131
3295
|
}
|
3132
3296
|
}
|
3133
3297
|
async getBlock(cid, store) {
|
3134
3298
|
await this.ready();
|
3135
|
-
const
|
3136
|
-
|
3137
|
-
|
3138
|
-
|
3139
|
-
|
3140
|
-
|
3141
|
-
|
3142
|
-
|
3143
|
-
|
3144
|
-
|
3145
|
-
|
3146
|
-
|
3147
|
-
|
3148
|
-
|
3149
|
-
|
3150
|
-
|
3151
|
-
|
3152
|
-
|
3153
|
-
|
3154
|
-
|
3155
|
-
|
3156
|
-
|
3157
|
-
|
3158
|
-
for (let i = 0; i < compacts.length; i += batchSize2) {
|
3159
|
-
const promises = [];
|
3160
|
-
for (let j = i; j < Math.min(i + batchSize2, compacts.length); j++) {
|
3161
|
-
for (const cid2 of compacts[j]) {
|
3162
|
-
promises.push(getCarCid(cid2));
|
3299
|
+
const cidStr = cid.toString();
|
3300
|
+
const ci = await this.cidCache.get(cidStr).once(async () => {
|
3301
|
+
const getCompactCarCids = async (carCid) => {
|
3302
|
+
const sCid = carCid.toString();
|
3303
|
+
const reader = await this.loadCar(carCid, store);
|
3304
|
+
const header = await parseCarFile(reader, this.logger);
|
3305
|
+
const compacts = header.compact;
|
3306
|
+
const got2 = await Promise.allSettled(compacts.map((compact) => compact.map((cid2) => this.loadCar(cid2, store)).flat()));
|
3307
|
+
got2.filter((result) => result.status === "rejected").forEach((result) => {
|
3308
|
+
this.logger.Error().Err(result.reason).Str("cid", sCid).Msg("error getting compacted block");
|
3309
|
+
});
|
3310
|
+
};
|
3311
|
+
let got;
|
3312
|
+
for (const carCids of this.carLog.asArray()) {
|
3313
|
+
for (const carCid of carCids) {
|
3314
|
+
const ci2 = await this.loadCar(carCid, store);
|
3315
|
+
if (!ci2) {
|
3316
|
+
this.logger.Error().Str("cid", carCid.toString()).Msg("missing CarCID");
|
3317
|
+
continue;
|
3318
|
+
}
|
3319
|
+
got = ci2.blocks.find((block) => block.cid.equals(cid));
|
3320
|
+
if (got) {
|
3321
|
+
break;
|
3163
3322
|
}
|
3164
3323
|
}
|
3165
|
-
try {
|
3166
|
-
got2 = await Promise.any(promises);
|
3167
|
-
} catch {
|
3168
|
-
}
|
3169
|
-
if (got2) break;
|
3170
|
-
}
|
3171
|
-
if (this.getBlockCache.has(sCid)) return this.getBlockCache.get(sCid);
|
3172
|
-
throw this.logger.Error().Str("cid", sCid).Msg("block not in compact reader").AsError();
|
3173
|
-
};
|
3174
|
-
let got;
|
3175
|
-
const batchSize = 5;
|
3176
|
-
for (let i = 0; i < this.carLog.length; i += batchSize) {
|
3177
|
-
const batch = this.carLog.slice(i, i + batchSize);
|
3178
|
-
const promises = batch.flatMap((slice) => slice.map(getCarCid));
|
3179
|
-
try {
|
3180
|
-
got = await Promise.any(promises);
|
3181
|
-
} catch {
|
3182
3324
|
}
|
3183
|
-
if (got)
|
3184
|
-
|
3185
|
-
if (!got) {
|
3186
|
-
try {
|
3187
|
-
got = await getCompactCarCids(this.carLog[this.carLog.length - 1][0]);
|
3188
|
-
} catch {
|
3325
|
+
if (!got) {
|
3326
|
+
await getCompactCarCids(this.carLog.last()[0]);
|
3189
3327
|
}
|
3328
|
+
return {
|
3329
|
+
type: "block",
|
3330
|
+
cid,
|
3331
|
+
blocks: got ? [got] : [],
|
3332
|
+
roots: []
|
3333
|
+
};
|
3334
|
+
});
|
3335
|
+
if (!(ci.type === "block" && ci.blocks.length === 1)) {
|
3336
|
+
throw this.logger.Error().Str("cid", cidStr).Any("block", ci).Msg("missing block").AsError();
|
3190
3337
|
}
|
3191
|
-
return
|
3338
|
+
return ci.blocks[0];
|
3192
3339
|
}
|
3193
3340
|
async loadCar(cid, store) {
|
3194
3341
|
const loaded = await this.storesLoadCar(cid, store.carStore());
|
3195
3342
|
return loaded;
|
3196
3343
|
}
|
3197
|
-
async makeDecoderAndCarReader(
|
3198
|
-
const
|
3344
|
+
async makeDecoderAndCarReader(carCid, store) {
|
3345
|
+
const carCidStr = carCid.toString();
|
3199
3346
|
let loadedCar = void 0;
|
3200
|
-
let activeStore = store.
|
3347
|
+
let activeStore = store.local();
|
3201
3348
|
try {
|
3202
|
-
this.logger.Debug().Any("cid",
|
3203
|
-
loadedCar = await store.
|
3349
|
+
this.logger.Debug().Any("cid", carCidStr).Msg("loading car");
|
3350
|
+
loadedCar = await store.local().load(carCid);
|
3204
3351
|
this.logger.Debug().Bool("loadedCar", loadedCar).Msg("loaded");
|
3205
3352
|
} catch (e) {
|
3206
3353
|
if (!isNotFoundError(e)) {
|
3207
|
-
throw this.logger.Error().Str("cid",
|
3354
|
+
throw this.logger.Error().Str("cid", carCidStr).Err(e).Msg("loading car");
|
3208
3355
|
}
|
3209
|
-
for (const remote of store.
|
3210
|
-
|
3211
|
-
|
3212
|
-
|
3213
|
-
|
3214
|
-
|
3215
|
-
|
3216
|
-
|
3217
|
-
|
3218
|
-
|
3356
|
+
for (const remote of store.remotes()) {
|
3357
|
+
try {
|
3358
|
+
const remoteCar = await remote.load(carCid);
|
3359
|
+
if (remoteCar) {
|
3360
|
+
this.logger.Debug().Ref("cid", remoteCar.cid).Msg("saving remote car locally");
|
3361
|
+
await store.local().save(remoteCar);
|
3362
|
+
loadedCar = remoteCar;
|
3363
|
+
activeStore = remote;
|
3364
|
+
break;
|
3365
|
+
} else {
|
3366
|
+
this.logger.Error().Str("cid", carCidStr).Err(e).Msg("loading car");
|
3367
|
+
}
|
3368
|
+
} catch (e2) {
|
3369
|
+
this.logger.Warn().Str("cid", carCidStr).Url(remote.url()).Err(e2).Msg("loading car");
|
3219
3370
|
}
|
3220
3371
|
}
|
3221
3372
|
}
|
3222
3373
|
if (!loadedCar) {
|
3223
|
-
throw this.logger.Error().Url(store.
|
3224
|
-
}
|
3225
|
-
const bytes = await decode({ bytes: loadedCar.bytes, hasher:
|
3226
|
-
const rawReader = await CarReader.fromBytes(bytes.value);
|
3227
|
-
const
|
3228
|
-
const
|
3229
|
-
|
3230
|
-
|
3231
|
-
|
3232
|
-
|
3233
|
-
|
3234
|
-
|
3235
|
-
|
3236
|
-
|
3374
|
+
throw this.logger.Error().Url(store.local().url()).Str("cid", carCidStr).Msg("missing car files").AsError();
|
3375
|
+
}
|
3376
|
+
const bytes = await decode({ bytes: loadedCar.bytes, hasher: hasher3, codec: (await activeStore.keyedCrypto()).codec() });
|
3377
|
+
const rawReader = await CarReader.fromBytes(bytes.value.data);
|
3378
|
+
const blocks = [];
|
3379
|
+
for await (const block of rawReader.blocks()) {
|
3380
|
+
const sBlock = block.cid.toString();
|
3381
|
+
blocks.push(block);
|
3382
|
+
this.cidCache.get(sBlock).once(() => ({
|
3383
|
+
type: "block",
|
3384
|
+
cid: block.cid,
|
3385
|
+
blocks: [block],
|
3386
|
+
roots: []
|
3387
|
+
}));
|
3388
|
+
}
|
3389
|
+
return {
|
3390
|
+
type: "car",
|
3391
|
+
cid: carCid,
|
3392
|
+
blocks,
|
3393
|
+
roots: await rawReader.getRoots()
|
3394
|
+
};
|
3237
3395
|
}
|
3238
3396
|
//What if instead it returns an Array of CarHeader
|
3239
|
-
async storesLoadCar(
|
3240
|
-
const
|
3241
|
-
|
3242
|
-
|
3243
|
-
|
3244
|
-
this.carReaders.set(cidsString, dacr);
|
3245
|
-
}
|
3246
|
-
return dacr;
|
3397
|
+
async storesLoadCar(carCid, store) {
|
3398
|
+
const carCidStr = carCid.toString();
|
3399
|
+
return this.cidCache.get(carCidStr).once(async () => {
|
3400
|
+
return this.maxConcurrentCarReader(() => this.makeDecoderAndCarReader(carCid, store));
|
3401
|
+
});
|
3247
3402
|
}
|
3248
3403
|
async getMoreReaders(cids, store) {
|
3249
|
-
const
|
3250
|
-
|
3251
|
-
|
3404
|
+
for (const cid of cids) {
|
3405
|
+
await this.loadCar(cid, store);
|
3406
|
+
}
|
3252
3407
|
}
|
3253
3408
|
};
|
3254
3409
|
|
@@ -3259,7 +3414,7 @@ __export(keyed_crypto_exports, {
|
|
3259
3414
|
keyedCryptoFactory: () => keyedCryptoFactory
|
3260
3415
|
});
|
3261
3416
|
import { base58btc as base58btc3 } from "multiformats/bases/base58";
|
3262
|
-
import { sha256 as
|
3417
|
+
import { sha256 as hasher4 } from "multiformats/hashes/sha2";
|
3263
3418
|
import * as CBOR from "cborg";
|
3264
3419
|
var generateIV = {
|
3265
3420
|
random: {
|
@@ -3274,7 +3429,7 @@ var generateIV = {
|
|
3274
3429
|
},
|
3275
3430
|
hash: {
|
3276
3431
|
calc: async (ko, crypto, data) => {
|
3277
|
-
const hash = await
|
3432
|
+
const hash = await hasher4.digest(data);
|
3278
3433
|
const hashBytes = new Uint8Array(hash.bytes);
|
3279
3434
|
const hashArray = new Uint8Array(ko.ivLength);
|
3280
3435
|
for (let i = 0; i < hashBytes.length; i++) {
|
@@ -3293,12 +3448,21 @@ function getGenerateIVFn(url, opts) {
|
|
3293
3448
|
}
|
3294
3449
|
var BlockIvKeyIdCodec = class {
|
3295
3450
|
constructor(ko, iv, opts) {
|
3296
|
-
this.code =
|
3451
|
+
this.code = 24;
|
3297
3452
|
this.name = "Fireproof@encrypted-block:aes-gcm";
|
3298
3453
|
this.ko = ko;
|
3299
3454
|
this.iv = iv;
|
3300
3455
|
this.opts = opts || {};
|
3301
3456
|
}
|
3457
|
+
// hashAsBytes(data: IvKeyIdData): AsyncHashAsBytes<Uint8Array<ArrayBufferLike>> {
|
3458
|
+
// return data;
|
3459
|
+
// }
|
3460
|
+
valueToHashBytes(value) {
|
3461
|
+
return Promise.resolve(value.data);
|
3462
|
+
}
|
3463
|
+
bytesToHash(data) {
|
3464
|
+
return Promise.resolve(data);
|
3465
|
+
}
|
3302
3466
|
async encode(data) {
|
3303
3467
|
const calcIv = this.iv || await getGenerateIVFn(this.ko.url, this.opts).calc(this.ko, this.ko.crypto, data);
|
3304
3468
|
const { iv } = this.ko.algo(calcIv);
|
@@ -3330,11 +3494,16 @@ var BlockIvKeyIdCodec = class {
|
|
3330
3494
|
if (!this.opts?.noIVVerify && !await getGenerateIVFn(this.ko.url, this.opts).verify(this.ko, this.ko.crypto, iv, result)) {
|
3331
3495
|
throw this.ko.logger.Error().Msg("iv missmatch").AsError();
|
3332
3496
|
}
|
3333
|
-
return
|
3497
|
+
return {
|
3498
|
+
iv,
|
3499
|
+
keyId,
|
3500
|
+
data: result
|
3501
|
+
};
|
3334
3502
|
}
|
3335
3503
|
};
|
3336
3504
|
var cryptoAction = class {
|
3337
3505
|
constructor(url, key, cyopt, sthis) {
|
3506
|
+
this.code = 24;
|
3338
3507
|
this.ivLength = 12;
|
3339
3508
|
this.isEncrypting = true;
|
3340
3509
|
this.logger = ensureLogger(sthis, "cryptoAction");
|
@@ -3368,14 +3537,19 @@ var cryptoAction = class {
|
|
3368
3537
|
};
|
3369
3538
|
var nullCodec = class {
|
3370
3539
|
constructor() {
|
3371
|
-
this.code =
|
3540
|
+
this.code = 24;
|
3372
3541
|
this.name = "Fireproof@unencrypted-block";
|
3542
|
+
this.empty = new Uint8Array();
|
3373
3543
|
}
|
3374
|
-
encode(data) {
|
3544
|
+
async encode(data) {
|
3375
3545
|
return data;
|
3376
3546
|
}
|
3377
|
-
decode(data) {
|
3378
|
-
return
|
3547
|
+
async decode(data) {
|
3548
|
+
return {
|
3549
|
+
iv: this.empty,
|
3550
|
+
keyId: this.empty,
|
3551
|
+
data
|
3552
|
+
};
|
3379
3553
|
}
|
3380
3554
|
};
|
3381
3555
|
var noCrypto = class {
|
@@ -3630,13 +3804,8 @@ var BaseStoreImpl = class {
|
|
3630
3804
|
this._url = res.Ok();
|
3631
3805
|
const kb = await this.loader.keyBag();
|
3632
3806
|
const skRes = await kb.ensureKeyFromUrl(this._url, () => {
|
3633
|
-
const
|
3634
|
-
|
3635
|
-
if (idx) {
|
3636
|
-
storeKeyName.push(idx);
|
3637
|
-
}
|
3638
|
-
storeKeyName.push(this.storeType);
|
3639
|
-
return storeKeyName.join(":");
|
3807
|
+
const key = this._url.getParam(PARAM.KEY);
|
3808
|
+
return key;
|
3640
3809
|
});
|
3641
3810
|
if (skRes.isErr()) {
|
3642
3811
|
return skRes;
|
@@ -3719,8 +3888,7 @@ var MetaStoreImpl = class extends BaseStoreImpl {
|
|
3719
3888
|
// }
|
3720
3889
|
// return (rDbMeta.Ok() as FPEnvelopeMeta).payload;
|
3721
3890
|
// }
|
3722
|
-
async load() {
|
3723
|
-
const branch = "main";
|
3891
|
+
async load(branch = "main") {
|
3724
3892
|
const url = await this.gateway.buildUrl({ loader: this.loader }, this.url(), branch);
|
3725
3893
|
if (url.isErr()) {
|
3726
3894
|
throw this.logger.Error().Result("buildUrl", url).Str("branch", branch).Msg("got error from gateway.buildUrl").AsError();
|
@@ -3734,7 +3902,7 @@ var MetaStoreImpl = class extends BaseStoreImpl {
|
|
3734
3902
|
}
|
3735
3903
|
const fpMeta = rfpEnv.Ok().payload;
|
3736
3904
|
const dbMetas = fpMeta.map((m) => m.dbMeta);
|
3737
|
-
await this.loader.handleDbMetasFromStore(dbMetas, this.loader.attachedStores.
|
3905
|
+
await this.loader.handleDbMetasFromStore(dbMetas, this.loader.attachedStores.activate(url.Ok()));
|
3738
3906
|
this.updateParentsFromDbMetas(fpMeta);
|
3739
3907
|
return dbMetas;
|
3740
3908
|
}
|
@@ -3766,9 +3934,8 @@ var MetaStoreImpl = class extends BaseStoreImpl {
|
|
3766
3934
|
}
|
3767
3935
|
};
|
3768
3936
|
var DataStoreImpl = class extends BaseStoreImpl {
|
3769
|
-
constructor(sthis, url, opts) {
|
3770
|
-
super(sthis, url, { ...opts },
|
3771
|
-
this.storeType = "data";
|
3937
|
+
constructor(sthis, url, opts, logger) {
|
3938
|
+
super(sthis, url, { ...opts }, logger);
|
3772
3939
|
}
|
3773
3940
|
async load(cid) {
|
3774
3941
|
this.logger.Debug().Any("cid", cid).Msg("loading");
|
@@ -3783,7 +3950,6 @@ var DataStoreImpl = class extends BaseStoreImpl {
|
|
3783
3950
|
const fpenv = res.Ok();
|
3784
3951
|
switch (fpenv.type) {
|
3785
3952
|
case "car":
|
3786
|
-
return { cid, bytes: fpenv.payload };
|
3787
3953
|
case "file":
|
3788
3954
|
return { cid, bytes: fpenv.payload };
|
3789
3955
|
default:
|
@@ -3799,12 +3965,11 @@ var DataStoreImpl = class extends BaseStoreImpl {
|
|
3799
3965
|
}
|
3800
3966
|
let fpMsg;
|
3801
3967
|
switch (url.Ok().getParam(PARAM.STORE)) {
|
3802
|
-
case "
|
3803
|
-
|
3804
|
-
|
3805
|
-
|
3806
|
-
|
3807
|
-
}
|
3968
|
+
case "car":
|
3969
|
+
fpMsg = Car2FPMsg(car.bytes);
|
3970
|
+
break;
|
3971
|
+
case "file":
|
3972
|
+
fpMsg = File2FPMsg(car.bytes);
|
3808
3973
|
break;
|
3809
3974
|
default:
|
3810
3975
|
throw this.logger.Error().Str("store", url.Ok().getParam(PARAM.STORE)).Msg("unexpected store").AsError();
|
@@ -3835,6 +4000,18 @@ var DataStoreImpl = class extends BaseStoreImpl {
|
|
3835
4000
|
return this.gateway.destroy({ loader: this.loader }, this.url());
|
3836
4001
|
}
|
3837
4002
|
};
|
4003
|
+
var CarStoreImpl = class extends DataStoreImpl {
|
4004
|
+
constructor(sthis, url, opts) {
|
4005
|
+
super(sthis, url, { ...opts }, ensureLogger(sthis, "CarStoreImpl"));
|
4006
|
+
this.storeType = "car";
|
4007
|
+
}
|
4008
|
+
};
|
4009
|
+
var FileStoreImpl = class extends DataStoreImpl {
|
4010
|
+
constructor(sthis, url, opts) {
|
4011
|
+
super(sthis, url, { ...opts }, ensureLogger(sthis, "FileStoreImpl"));
|
4012
|
+
this.storeType = "file";
|
4013
|
+
}
|
4014
|
+
};
|
3838
4015
|
var WALStoreImpl = class extends BaseStoreImpl {
|
3839
4016
|
constructor(sthis, url, opts) {
|
3840
4017
|
super(sthis, url, { ...opts }, ensureLogger(sthis, "WALStoreImpl"));
|
@@ -3917,7 +4094,7 @@ var WALStoreImpl = class extends BaseStoreImpl {
|
|
3917
4094
|
for (const cid of dbMeta.cars) {
|
3918
4095
|
const car = await this.loader.attachedStores.local().active.car.load(cid);
|
3919
4096
|
if (!car) {
|
3920
|
-
if (carLogIncludesGroup(this.loader.carLog, dbMeta.cars)) {
|
4097
|
+
if (carLogIncludesGroup(this.loader.carLog.asArray(), dbMeta.cars)) {
|
3921
4098
|
throw this.logger.Error().Ref("cid", cid).Msg("missing local car").AsError();
|
3922
4099
|
}
|
3923
4100
|
} else {
|
@@ -3939,7 +4116,7 @@ var WALStoreImpl = class extends BaseStoreImpl {
|
|
3939
4116
|
for (const cid of dbMeta.cars) {
|
3940
4117
|
const car = await this.loader.attachedStores.local().active.car.load(cid);
|
3941
4118
|
if (!car) {
|
3942
|
-
if (carLogIncludesGroup(this.loader.carLog, dbMeta.cars)) {
|
4119
|
+
if (carLogIncludesGroup(this.loader.carLog.asArray(), dbMeta.cars)) {
|
3943
4120
|
throw this.logger.Error().Ref("cid", cid).Msg(`missing local car`).AsError();
|
3944
4121
|
}
|
3945
4122
|
} else {
|
@@ -4027,16 +4204,17 @@ var WALStoreImpl = class extends BaseStoreImpl {
|
|
4027
4204
|
};
|
4028
4205
|
|
4029
4206
|
// src/blockstore/store-factory.ts
|
4030
|
-
var onceGateway = new
|
4031
|
-
var gatewayInstances = new
|
4207
|
+
var onceGateway = new KeyedResolvOnce5();
|
4208
|
+
var gatewayInstances = new KeyedResolvOnce5();
|
4032
4209
|
async function getStartedGateway(ctx, url) {
|
4033
4210
|
return onceGateway.get(url.toString()).once(async () => {
|
4034
4211
|
const item = getGatewayFactoryItem(url.protocol);
|
4035
4212
|
if (item) {
|
4036
4213
|
const ret = {
|
4037
4214
|
url,
|
4038
|
-
...await gatewayInstances.get(url.protocol).once(async () => ({
|
4039
|
-
|
4215
|
+
...await gatewayInstances.get(url.protocol).once(async () => ({
|
4216
|
+
gateway: await item.serdegateway(ctx.loader.sthis)
|
4217
|
+
}))
|
4040
4218
|
};
|
4041
4219
|
const res = await ret.gateway.start(ctx, url);
|
4042
4220
|
if (res.isErr()) {
|
@@ -4048,14 +4226,28 @@ async function getStartedGateway(ctx, url) {
|
|
4048
4226
|
return Result10.Err(ctx.loader.sthis.logger.Warn().Url(url).Msg("unsupported protocol").AsError());
|
4049
4227
|
});
|
4050
4228
|
}
|
4051
|
-
async function
|
4052
|
-
const storeUrl = uai.url.build().setParam(PARAM.STORE, "
|
4229
|
+
async function carStoreFactory(ctx, uai) {
|
4230
|
+
const storeUrl = uai.url.build().setParam(PARAM.STORE, "car").URI();
|
4053
4231
|
const rgateway = await getStartedGateway(ctx, storeUrl);
|
4054
4232
|
if (rgateway.isErr()) {
|
4055
4233
|
throw ctx.loader.sthis.logger.Error().Result("err", rgateway).Url(uai.url).Msg("notfound").AsError();
|
4056
4234
|
}
|
4057
4235
|
const gateway = rgateway.Ok();
|
4058
|
-
const store = new
|
4236
|
+
const store = new CarStoreImpl(ctx.loader.sthis, gateway.url, {
|
4237
|
+
gateway: gateway.gateway,
|
4238
|
+
gatewayInterceptor: uai.gatewayInterceptor,
|
4239
|
+
loader: ctx.loader
|
4240
|
+
});
|
4241
|
+
return store;
|
4242
|
+
}
|
4243
|
+
async function fileStoreFactory(ctx, uai) {
|
4244
|
+
const storeUrl = uai.url.build().setParam(PARAM.STORE, "file").URI();
|
4245
|
+
const rgateway = await getStartedGateway(ctx, storeUrl);
|
4246
|
+
if (rgateway.isErr()) {
|
4247
|
+
throw ctx.loader.sthis.logger.Error().Result("err", rgateway).Url(uai.url).Msg("notfound").AsError();
|
4248
|
+
}
|
4249
|
+
const gateway = rgateway.Ok();
|
4250
|
+
const store = new FileStoreImpl(ctx.loader.sthis, gateway.url, {
|
4059
4251
|
gateway: gateway.gateway,
|
4060
4252
|
gatewayInterceptor: uai.gatewayInterceptor,
|
4061
4253
|
loader: ctx.loader
|
@@ -4113,8 +4305,8 @@ function toStoreRuntime(sthis, endeOpts = {}) {
|
|
4113
4305
|
};
|
4114
4306
|
const storeSet = {};
|
4115
4307
|
storeSet.meta = await metaStoreFactory(ctx, sfi.byStore.meta);
|
4116
|
-
storeSet.car = await
|
4117
|
-
storeSet.file = await
|
4308
|
+
storeSet.car = await carStoreFactory(ctx, sfi.byStore.car);
|
4309
|
+
storeSet.file = await fileStoreFactory(ctx, sfi.byStore.file);
|
4118
4310
|
if (sfi.byStore.wal) {
|
4119
4311
|
storeSet.wal = await WALStoreFactory(ctx, sfi.byStore.wal);
|
4120
4312
|
}
|
@@ -4135,7 +4327,7 @@ function toStoreRuntime(sthis, endeOpts = {}) {
|
|
4135
4327
|
|
4136
4328
|
// src/crdt-helpers.ts
|
4137
4329
|
import { parse as parse2 } from "multiformats/link";
|
4138
|
-
import { sha256 as
|
4330
|
+
import { sha256 as hasher5 } from "multiformats/hashes/sha2";
|
4139
4331
|
import * as codec2 from "@ipld/dag-cbor";
|
4140
4332
|
import { put, get, entries, root } from "@fireproof/vendor/@web3-storage/pail/crdt";
|
4141
4333
|
import { EventFetcher, vis } from "@fireproof/vendor/@web3-storage/pail/clock";
|
@@ -4153,6 +4345,41 @@ function toString(key, logger) {
|
|
4153
4345
|
throw logger.Error().Msg("Invalid key type").AsError();
|
4154
4346
|
}
|
4155
4347
|
}
|
4348
|
+
function sanitizeDocumentFields(obj) {
|
4349
|
+
if (Array.isArray(obj)) {
|
4350
|
+
return obj.map((item) => {
|
4351
|
+
if (typeof item === "object" && item !== null) {
|
4352
|
+
return sanitizeDocumentFields(item);
|
4353
|
+
}
|
4354
|
+
return item;
|
4355
|
+
});
|
4356
|
+
} else if (typeof obj === "object" && obj !== null) {
|
4357
|
+
if (obj instanceof Date) {
|
4358
|
+
return obj.toISOString();
|
4359
|
+
}
|
4360
|
+
const typedObj = obj;
|
4361
|
+
const result = {};
|
4362
|
+
for (const key in typedObj) {
|
4363
|
+
if (Object.hasOwnProperty.call(typedObj, key)) {
|
4364
|
+
const value = typedObj[key];
|
4365
|
+
if (value === null || !Number.isNaN(value) && value !== void 0) {
|
4366
|
+
if (typeof value === "object" && !key.startsWith("_")) {
|
4367
|
+
if (value instanceof Date) {
|
4368
|
+
result[key] = value.toISOString();
|
4369
|
+
} else {
|
4370
|
+
const sanitized = sanitizeDocumentFields(value);
|
4371
|
+
result[key] = sanitized;
|
4372
|
+
}
|
4373
|
+
} else {
|
4374
|
+
result[key] = value;
|
4375
|
+
}
|
4376
|
+
}
|
4377
|
+
}
|
4378
|
+
}
|
4379
|
+
return result;
|
4380
|
+
}
|
4381
|
+
return obj;
|
4382
|
+
}
|
4156
4383
|
async function applyBulkUpdateToCrdt(store, tblocks, head, updates, logger) {
|
4157
4384
|
let result = null;
|
4158
4385
|
if (updates.length > 1) {
|
@@ -4187,7 +4414,7 @@ async function writeDocContent(store, blocks, update, logger) {
|
|
4187
4414
|
await processFiles(store, blocks, update.value, logger);
|
4188
4415
|
value = { doc: update.value };
|
4189
4416
|
}
|
4190
|
-
const block = await encode({ value, hasher:
|
4417
|
+
const block = await encode({ value, hasher: hasher5, codec: codec2 });
|
4191
4418
|
blocks.putSync(block.cid, block.bytes);
|
4192
4419
|
return block.cid;
|
4193
4420
|
}
|
@@ -4242,7 +4469,8 @@ async function getValueFromCrdt(blocks, head, key, logger) {
|
|
4242
4469
|
if (!head.length) throw logger.Debug().Msg("Getting from an empty ledger").AsError();
|
4243
4470
|
const link = await get(blocks, head, key);
|
4244
4471
|
if (!link) throw logger.Error().Str("key", key).Msg(`Missing key`).AsError();
|
4245
|
-
|
4472
|
+
const ret = await getValueFromLink(blocks, link, logger);
|
4473
|
+
return ret;
|
4246
4474
|
}
|
4247
4475
|
function readFiles(blocks, { doc }) {
|
4248
4476
|
if (!doc) return;
|
@@ -4278,7 +4506,7 @@ function readFileset(blocks, files, isPublic = false) {
|
|
4278
4506
|
async function getValueFromLink(blocks, link, logger) {
|
4279
4507
|
const block = await blocks.get(link);
|
4280
4508
|
if (!block) throw logger.Error().Str("link", link.toString()).Msg(`Missing linked block`).AsError();
|
4281
|
-
const { value } = await decode({ bytes: block.bytes, hasher:
|
4509
|
+
const { value } = await decode({ bytes: block.bytes, hasher: hasher5, codec: codec2 });
|
4282
4510
|
const cvalue = {
|
4283
4511
|
...value,
|
4284
4512
|
cid: link
|
@@ -4340,6 +4568,9 @@ async function gatherUpdates(blocks, eventsFetcher, head, since, updates = [], k
|
|
4340
4568
|
const { key, value } = ops[i];
|
4341
4569
|
if (!keys.has(key)) {
|
4342
4570
|
const docValue = await getValueFromLink(blocks, value, logger);
|
4571
|
+
if (key === PARAM.GENESIS_CID) {
|
4572
|
+
continue;
|
4573
|
+
}
|
4343
4574
|
updates.push({ id: key, value: docValue.doc, del: docValue.del, clock: link });
|
4344
4575
|
limit--;
|
4345
4576
|
keys.add(key);
|
@@ -4353,8 +4584,10 @@ async function gatherUpdates(blocks, eventsFetcher, head, since, updates = [], k
|
|
4353
4584
|
}
|
4354
4585
|
async function* getAllEntries(blocks, head, logger) {
|
4355
4586
|
for await (const [key, link] of entries(blocks, head)) {
|
4356
|
-
|
4357
|
-
|
4587
|
+
if (key !== PARAM.GENESIS_CID) {
|
4588
|
+
const docValue = await getValueFromLink(blocks, link, logger);
|
4589
|
+
yield { id: key, value: docValue.doc, del: docValue.del };
|
4590
|
+
}
|
4358
4591
|
}
|
4359
4592
|
}
|
4360
4593
|
async function* clockVis(blocks, head) {
|
@@ -4399,7 +4632,7 @@ async function doCompact(blockLog, head, logger) {
|
|
4399
4632
|
async function getBlock(blocks, cidString) {
|
4400
4633
|
const block = await blocks.get(parse2(cidString));
|
4401
4634
|
if (!block) throw new Error(`Missing block ${cidString}`);
|
4402
|
-
const { cid, value } = await decode({ bytes: block.bytes, codec: codec2, hasher:
|
4635
|
+
const { cid, value } = await decode({ bytes: block.bytes, codec: codec2, hasher: hasher5 });
|
4403
4636
|
return new Block({ cid, value, bytes: block.bytes });
|
4404
4637
|
}
|
4405
4638
|
|
@@ -4499,6 +4732,10 @@ var CRDTClockImpl = class {
|
|
4499
4732
|
this.notifyWatchers(internalUpdates || []);
|
4500
4733
|
}
|
4501
4734
|
notifyWatchers(updates) {
|
4735
|
+
updates = updates.filter((update) => update.id !== PARAM.GENESIS_CID);
|
4736
|
+
if (!updates.length) {
|
4737
|
+
return;
|
4738
|
+
}
|
4502
4739
|
this.emptyWatchers.forEach((fn) => fn());
|
4503
4740
|
this.watchers.forEach((fn) => fn(updates || []));
|
4504
4741
|
}
|
@@ -4578,7 +4815,7 @@ async function advanceBlocks(logger, newHead, tblocks, head) {
|
|
4578
4815
|
try {
|
4579
4816
|
head = await advance(tblocks, head, cid);
|
4580
4817
|
} catch (e) {
|
4581
|
-
logger.
|
4818
|
+
logger.Error().Err(e).Msg("failed to advance head");
|
4582
4819
|
continue;
|
4583
4820
|
}
|
4584
4821
|
}
|
@@ -4637,6 +4874,17 @@ var CRDTImpl = class {
|
|
4637
4874
|
}
|
4638
4875
|
async bulk(updates) {
|
4639
4876
|
await this.ready();
|
4877
|
+
updates = updates.map((dupdate) => ({
|
4878
|
+
...dupdate,
|
4879
|
+
value: sanitizeDocumentFields(dupdate.value)
|
4880
|
+
}));
|
4881
|
+
if (this.clock.head.length === 0) {
|
4882
|
+
const value = { id: PARAM.GENESIS_CID, value: { _id: PARAM.GENESIS_CID } };
|
4883
|
+
await this._bulk([value]);
|
4884
|
+
}
|
4885
|
+
return await this._bulk(updates);
|
4886
|
+
}
|
4887
|
+
async _bulk(updates) {
|
4640
4888
|
const prevHead = [...this.clock.head];
|
4641
4889
|
const done = await this.blockstore.transaction(async (blocks) => {
|
4642
4890
|
const { head } = await applyBulkUpdateToCrdt(
|
@@ -4724,7 +4972,7 @@ var Context = class {
|
|
4724
4972
|
};
|
4725
4973
|
|
4726
4974
|
// src/ledger.ts
|
4727
|
-
var ledgers = new
|
4975
|
+
var ledgers = new KeyedResolvOnce6();
|
4728
4976
|
function keyConfigOpts(sthis, name, opts) {
|
4729
4977
|
return JSON.stringify(
|
4730
4978
|
toSortedArray({
|
@@ -4868,7 +5116,8 @@ var LedgerImpl = class {
|
|
4868
5116
|
});
|
4869
5117
|
return ret;
|
4870
5118
|
}
|
4871
|
-
attach(a) {
|
5119
|
+
async attach(a) {
|
5120
|
+
await this.ready();
|
4872
5121
|
return this.crdt.blockstore.loader.attach(a);
|
4873
5122
|
}
|
4874
5123
|
// readonly _asDb = new ResolveOnce<Database>();
|
@@ -4876,6 +5125,7 @@ var LedgerImpl = class {
|
|
4876
5125
|
// return this._asDb.once(() => new DatabaseImpl(this));
|
4877
5126
|
// }
|
4878
5127
|
subscribe(listener, updates) {
|
5128
|
+
this.ready();
|
4879
5129
|
this.logger.Debug().Bool("updates", updates).Msg("subscribe");
|
4880
5130
|
if (updates) {
|
4881
5131
|
if (!this._listening) {
|
@@ -4917,49 +5167,32 @@ var LedgerImpl = class {
|
|
4917
5167
|
}
|
4918
5168
|
}
|
4919
5169
|
};
|
4920
|
-
function defaultURI2(sthis, name, curi, uri, store, ctx) {
|
4921
|
-
ctx = ctx || {};
|
4922
|
-
const ret = (curi ? URI12.from(curi) : uri).build().setParam(PARAM.STORE, store).defParam(PARAM.NAME, name);
|
4923
|
-
if (!ret.hasParam(PARAM.NAME)) {
|
4924
|
-
throw sthis.logger.Error().Url(ret).Any("ctx", ctx).Msg("Ledger name is required").AsError();
|
4925
|
-
}
|
4926
|
-
if (ctx.idx) {
|
4927
|
-
ret.defParam(PARAM.INDEX, "idx");
|
4928
|
-
ret.defParam(PARAM.STORE_KEY, `@${ret.getParam(PARAM.NAME)}-${store}-idx@`);
|
4929
|
-
} else {
|
4930
|
-
ret.defParam(PARAM.STORE_KEY, `@${ret.getParam(PARAM.NAME)}-${store}@`);
|
4931
|
-
}
|
4932
|
-
if (store === "data") {
|
4933
|
-
if (ctx.file) {
|
4934
|
-
} else {
|
4935
|
-
ret.defParam(PARAM.SUFFIX, ".car");
|
4936
|
-
}
|
4937
|
-
}
|
4938
|
-
return ret.URI();
|
4939
|
-
}
|
4940
5170
|
function toStoreURIRuntime(sthis, name, sopts) {
|
4941
5171
|
sopts = sopts || {};
|
4942
5172
|
if (!sopts.base) {
|
4943
5173
|
const fp_env = sthis.env.get("FP_STORAGE_URL");
|
4944
5174
|
if (fp_env) {
|
4945
|
-
sopts = { ...sopts, base:
|
5175
|
+
sopts = { ...sopts, base: BuildURI2.from(fp_env).setParam(PARAM.URL_GEN, "fromEnv") };
|
4946
5176
|
} else {
|
4947
5177
|
sopts = { ...sopts, base: getDefaultURI(sthis).build().setParam(PARAM.URL_GEN, "default") };
|
4948
5178
|
}
|
4949
5179
|
}
|
4950
|
-
const base =
|
5180
|
+
const base = URI13.from(sopts.base);
|
4951
5181
|
return {
|
4952
5182
|
idx: {
|
4953
|
-
car:
|
4954
|
-
file:
|
4955
|
-
|
4956
|
-
|
5183
|
+
car: ensureURIDefaults(sthis, name, sopts.idx?.car ?? sopts.data?.car, base, "car", { idx: true }),
|
5184
|
+
file: ensureURIDefaults(sthis, name, sopts.idx?.file ?? sopts.idx?.car ?? sopts.data?.file ?? sopts.data?.car, base, "file", {
|
5185
|
+
file: true,
|
5186
|
+
idx: true
|
5187
|
+
}),
|
5188
|
+
meta: ensureURIDefaults(sthis, name, sopts.idx?.meta ?? sopts.data?.meta, base, "meta", { idx: true }),
|
5189
|
+
wal: ensureURIDefaults(sthis, name, sopts.idx?.wal ?? sopts.data?.wal, base, "wal", { idx: true })
|
4957
5190
|
},
|
4958
5191
|
data: {
|
4959
|
-
car:
|
4960
|
-
file:
|
4961
|
-
meta:
|
4962
|
-
wal:
|
5192
|
+
car: ensureURIDefaults(sthis, name, sopts.data?.car, base, "car"),
|
5193
|
+
file: ensureURIDefaults(sthis, name, sopts.data?.file ?? sopts.data?.car, base, "file", { file: true }),
|
5194
|
+
meta: ensureURIDefaults(sthis, name, sopts.data?.meta, base, "meta"),
|
5195
|
+
wal: ensureURIDefaults(sthis, name, sopts.data?.wal, base, "wal")
|
4963
5196
|
}
|
4964
5197
|
};
|
4965
5198
|
}
|
@@ -5023,7 +5256,7 @@ __export(file_exports, {
|
|
5023
5256
|
|
5024
5257
|
// src/version.ts
|
5025
5258
|
var PACKAGE_VERSION = Object.keys({
|
5026
|
-
"0.20.0-dev-preview-
|
5259
|
+
"0.20.0-dev-preview-51": "xxxx"
|
5027
5260
|
})[0];
|
5028
5261
|
export {
|
5029
5262
|
CRDTImpl,
|
@@ -5044,6 +5277,7 @@ export {
|
|
5044
5277
|
ensureLogger,
|
5045
5278
|
ensureSuperLog,
|
5046
5279
|
ensureSuperThis,
|
5280
|
+
ensureURIDefaults,
|
5047
5281
|
exceptionWrapper,
|
5048
5282
|
falsyToUndef,
|
5049
5283
|
fireproof,
|
@@ -5061,6 +5295,7 @@ export {
|
|
5061
5295
|
onSuperThis,
|
5062
5296
|
runtime_exports as rt,
|
5063
5297
|
runtime_exports as runtime,
|
5298
|
+
storeType2DataMetaWal,
|
5064
5299
|
throwFalsy,
|
5065
5300
|
toSortedArray,
|
5066
5301
|
toStoreURIRuntime
|