@wovin/core 0.1.35 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -12
- package/dist/applog/applog-helpers.d.ts +12 -12
- package/dist/applog/applog-helpers.d.ts.map +1 -1
- package/dist/applog/applog-utils.d.ts +25 -6
- package/dist/applog/applog-utils.d.ts.map +1 -1
- package/dist/applog/datom-types.d.ts +4 -5
- package/dist/applog/datom-types.d.ts.map +1 -1
- package/dist/applog.d.ts +3 -3
- package/dist/applog.d.ts.map +1 -1
- package/dist/{applog.min.js → applog.js} +6 -7
- package/dist/blockstore.d.ts +1 -1
- package/dist/blockstore.d.ts.map +1 -1
- package/dist/{blockstore.min.js → blockstore.js} +1 -3
- package/dist/{blockstore.min.js.map → blockstore.js.map} +1 -1
- package/dist/{chunk-KXMTKPF4.min.js → chunk-3JZMOEOD.js} +8 -8
- package/dist/chunk-3JZMOEOD.js.map +1 -0
- package/dist/chunk-3WZVG277.js +434 -0
- package/dist/chunk-3WZVG277.js.map +1 -0
- package/dist/chunk-7Z5YDQKK.js +1 -0
- package/dist/chunk-CPSDKFBG.js +147 -0
- package/dist/chunk-CPSDKFBG.js.map +1 -0
- package/dist/chunk-E46VTKTZ.js +1 -0
- package/dist/{chunk-H3VQJP56.min.js → chunk-J2FDHGOZ.js} +9 -9
- package/dist/chunk-J2FDHGOZ.js.map +1 -0
- package/dist/chunk-L5EEEGE6.js +1862 -0
- package/dist/chunk-L5EEEGE6.js.map +1 -0
- package/dist/{chunk-BRC7LSM6.min.js → chunk-PD3C7XUM.js} +5 -5
- package/dist/chunk-PD3C7XUM.js.map +1 -0
- package/dist/chunk-QZXKQCAY.js +1026 -0
- package/dist/chunk-QZXKQCAY.js.map +1 -0
- package/dist/{chunk-QPGEBDMJ.min.js → chunk-YDAKBU6Q.js} +1 -1
- package/dist/chunk-YDAKBU6Q.js.map +1 -0
- package/dist/chunk-ZAADLBSB.js +36 -0
- package/dist/chunk-ZAADLBSB.js.map +1 -0
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/{index.min.js → index.js} +73 -46
- package/dist/ipfs/car.d.ts +11 -11
- package/dist/ipfs/car.d.ts.map +1 -1
- package/dist/ipfs/ipfs-utils.d.ts +2 -2
- package/dist/ipfs/ipfs-utils.d.ts.map +1 -1
- package/dist/ipfs.d.ts +3 -3
- package/dist/ipfs.d.ts.map +1 -1
- package/dist/{ipfs.min.js → ipfs.js} +7 -10
- package/dist/ipns.d.ts +1 -1
- package/dist/ipns.d.ts.map +1 -1
- package/dist/ipns.js +64 -0
- package/dist/ipns.js.map +1 -0
- package/dist/pubsub/pub-pull.d.ts +3 -3
- package/dist/pubsub/pub-pull.d.ts.map +1 -1
- package/dist/pubsub/pubsub-types.d.ts +3 -3
- package/dist/pubsub/pubsub-types.d.ts.map +1 -1
- package/dist/pubsub/snap-push.d.ts +4 -4
- package/dist/pubsub/snap-push.d.ts.map +1 -1
- package/dist/pubsub/ucan.d.ts +1 -1
- package/dist/pubsub/ucan.d.ts.map +1 -1
- package/dist/pubsub.d.ts +4 -4
- package/dist/pubsub.d.ts.map +1 -1
- package/dist/{pubsub.min.js → pubsub.js} +7 -10
- package/dist/query/attr-helpers.d.ts +5 -0
- package/dist/query/attr-helpers.d.ts.map +1 -0
- package/dist/query/basic.d.ts +85 -21
- package/dist/query/basic.d.ts.map +1 -1
- package/dist/query/divergences.d.ts +5 -5
- package/dist/query/divergences.d.ts.map +1 -1
- package/dist/query/entity-collection.d.ts +19 -0
- package/dist/query/entity-collection.d.ts.map +1 -0
- package/dist/query/matchers.d.ts +1 -1
- package/dist/query/matchers.d.ts.map +1 -1
- package/dist/query/memoized.d.ts +66 -0
- package/dist/query/memoized.d.ts.map +1 -0
- package/dist/query/situations.d.ts +2 -1
- package/dist/query/situations.d.ts.map +1 -1
- package/dist/query/subscribable.d.ts +111 -0
- package/dist/query/subscribable.d.ts.map +1 -0
- package/dist/query/types.d.ts +54 -14
- package/dist/query/types.d.ts.map +1 -1
- package/dist/query.d.ts +9 -5
- package/dist/query.d.ts.map +1 -1
- package/dist/{query.min.js → query.js} +51 -32
- package/dist/retrieve/index.d.ts +1 -1
- package/dist/retrieve/index.d.ts.map +1 -1
- package/dist/retrieve/update-thread.d.ts +3 -3
- package/dist/retrieve/update-thread.d.ts.map +1 -1
- package/dist/retrieve.d.ts +1 -1
- package/dist/retrieve.d.ts.map +1 -1
- package/dist/retrieve.js +14 -0
- package/dist/thread/basic.d.ts +15 -19
- package/dist/thread/basic.d.ts.map +1 -1
- package/dist/thread/filters.d.ts +8 -10
- package/dist/thread/filters.d.ts.map +1 -1
- package/dist/thread/indexes.d.ts +56 -0
- package/dist/thread/indexes.d.ts.map +1 -0
- package/dist/thread/mapped.d.ts +40 -11
- package/dist/thread/mapped.d.ts.map +1 -1
- package/dist/thread/utils.d.ts +5 -5
- package/dist/thread/utils.d.ts.map +1 -1
- package/dist/thread/writeable.d.ts +2 -2
- package/dist/thread/writeable.d.ts.map +1 -1
- package/dist/thread.d.ts +6 -5
- package/dist/thread.d.ts.map +1 -1
- package/dist/{thread.min.js → thread.js} +9 -6
- package/dist/types/typescript-utils.d.ts +6 -5
- package/dist/types/typescript-utils.d.ts.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/{types.min.js → types.js} +3 -4
- package/dist/utils/debug-name.d.ts +13 -0
- package/dist/utils/debug-name.d.ts.map +1 -0
- package/dist/utils.d.ts +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +9 -0
- package/package.json +32 -23
- package/src/applog/applog-helpers.ts +155 -0
- package/src/applog/applog-utils.test.ts +108 -0
- package/src/applog/applog-utils.ts +507 -0
- package/src/applog/datom-types.ts +148 -0
- package/src/applog.ts +3 -0
- package/src/blockstore/index.ts +36 -0
- package/src/blockstore.ts +1 -0
- package/src/index.ts +8 -0
- package/src/ipfs/car.ts +291 -0
- package/src/ipfs/fetch-snapshot-chain.ts +135 -0
- package/src/ipfs/ipfs-utils.ts +132 -0
- package/src/ipfs.ts +3 -0
- package/src/ipns/ipns-record.ts +115 -0
- package/src/ipns.ts +1 -0
- package/src/pubsub/UCAN Specs Overview.md +217 -0
- package/src/pubsub/connector.ts +9 -0
- package/src/pubsub/pub-pull.ts +31 -0
- package/src/pubsub/pubsub-types.ts +90 -0
- package/src/pubsub/snap-push.ts +277 -0
- package/src/pubsub/ucan-example.ts +61 -0
- package/src/pubsub/ucan.ts +56 -0
- package/src/pubsub.ts +4 -0
- package/src/query/attr-helpers.ts +5 -0
- package/src/query/basic.ts +1245 -0
- package/src/query/divergences.ts +50 -0
- package/src/query/entity-collection.ts +131 -0
- package/src/query/liveFilterAndMap.test.ts +102 -0
- package/src/query/matchers.ts +8 -0
- package/src/query/memoized.test.ts +151 -0
- package/src/query/memoized.ts +180 -0
- package/src/query/query-steps.ts +4 -0
- package/src/query/query.test.ts +538 -0
- package/src/query/situations.ts +261 -0
- package/src/query/subscribable.test.ts +245 -0
- package/src/query/subscribable.ts +234 -0
- package/src/query/types.ts +155 -0
- package/src/query/withoutDeleted.test.ts +204 -0
- package/src/query.ts +9 -0
- package/src/retrieve/index.ts +1 -0
- package/src/retrieve/update-thread.ts +248 -0
- package/src/retrieve.ts +1 -0
- package/src/test/perf/query.1m.perf.test.ts +94 -0
- package/src/test/perf/query.perf.test.ts +389 -0
- package/src/test/perf/query.realdata.perf.test.ts +182 -0
- package/src/thread/basic.ts +209 -0
- package/src/thread/filters.ts +227 -0
- package/src/thread/indexes.ts +250 -0
- package/src/thread/joinThreads.test.ts +304 -0
- package/src/thread/mapped.ts +226 -0
- package/src/thread/utils.ts +144 -0
- package/src/thread/writeable.ts +163 -0
- package/src/thread.ts +6 -0
- package/src/types/typescript-utils.ts +64 -0
- package/src/types.ts +1 -0
- package/src/utils/debug-name.ts +54 -0
- package/src/utils.ts +4 -0
- package/dist/chunk-2Y2PYHGR.min.js +0 -65
- package/dist/chunk-2Y2PYHGR.min.js.map +0 -1
- package/dist/chunk-5MMGBK2U.min.js +0 -1
- package/dist/chunk-7IDQIMQO.min.js +0 -1
- package/dist/chunk-BRC7LSM6.min.js.map +0 -1
- package/dist/chunk-COXXILXC.min.js +0 -512
- package/dist/chunk-COXXILXC.min.js.map +0 -1
- package/dist/chunk-GDX2OO7L.min.js +0 -9080
- package/dist/chunk-GDX2OO7L.min.js.map +0 -1
- package/dist/chunk-H3VQJP56.min.js.map +0 -1
- package/dist/chunk-HYMC7W6S.min.js +0 -1549
- package/dist/chunk-HYMC7W6S.min.js.map +0 -1
- package/dist/chunk-KEHU7HGZ.min.js +0 -5216
- package/dist/chunk-KEHU7HGZ.min.js.map +0 -1
- package/dist/chunk-KXMTKPF4.min.js.map +0 -1
- package/dist/chunk-PHITDXZT.min.js +0 -36
- package/dist/chunk-QO2KMGDN.min.js +0 -3771
- package/dist/chunk-QO2KMGDN.min.js.map +0 -1
- package/dist/chunk-QPGEBDMJ.min.js.map +0 -1
- package/dist/chunk-WXLCBTHX.min.js +0 -1606
- package/dist/chunk-WXLCBTHX.min.js.map +0 -1
- package/dist/ipns.min.js +0 -6419
- package/dist/ipns.min.js.map +0 -1
- package/dist/mobx/mobx-utils.d.ts +0 -82
- package/dist/mobx/mobx-utils.d.ts.map +0 -1
- package/dist/mobx.d.ts +0 -2
- package/dist/mobx.d.ts.map +0 -1
- package/dist/mobx.min.js +0 -141
- package/dist/retrieve.min.js +0 -17
- package/dist/types.min.js.map +0 -1
- package/dist/utils.min.js +0 -10
- package/dist/utils.min.js.map +0 -1
- /package/dist/{applog.min.js.map → applog.js.map} +0 -0
- /package/dist/{chunk-5MMGBK2U.min.js.map → chunk-7Z5YDQKK.js.map} +0 -0
- /package/dist/{chunk-7IDQIMQO.min.js.map → chunk-E46VTKTZ.js.map} +0 -0
- /package/dist/{chunk-PHITDXZT.min.js.map → index.js.map} +0 -0
- /package/dist/{index.min.js.map → ipfs.js.map} +0 -0
- /package/dist/{ipfs.min.js.map → pubsub.js.map} +0 -0
- /package/dist/{mobx.min.js.map → query.js.map} +0 -0
- /package/dist/{pubsub.min.js.map → retrieve.js.map} +0 -0
- /package/dist/{query.min.js.map → thread.js.map} +0 -0
- /package/dist/{retrieve.min.js.map → types.js.map} +0 -0
- /package/dist/{thread.min.js.map → utils.js.map} +0 -0
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
import {
|
|
2
|
+
keepTruthy
|
|
3
|
+
} from "./chunk-YDAKBU6Q.js";
|
|
4
|
+
import {
|
|
5
|
+
lastWriteWins
|
|
6
|
+
} from "./chunk-QZXKQCAY.js";
|
|
7
|
+
import {
|
|
8
|
+
areCidsEqual,
|
|
9
|
+
encodeBlockOriginal,
|
|
10
|
+
ensureTsPvAndFinalizeApplog,
|
|
11
|
+
getLogsFromThread,
|
|
12
|
+
prepareForPub,
|
|
13
|
+
rollingFilter
|
|
14
|
+
} from "./chunk-L5EEEGE6.js";
|
|
15
|
+
|
|
16
|
+
// src/pubsub/snap-push.ts
|
|
17
|
+
import * as dagJson2 from "@ipld/dag-json";
|
|
18
|
+
import { Logger as Logger2 } from "besonders-logger";
|
|
19
|
+
import stringify from "safe-stable-stringify";
|
|
20
|
+
|
|
21
|
+
// src/ipfs/car.ts
|
|
22
|
+
import { CarReader, CarWriter } from "@ipld/car";
|
|
23
|
+
import * as dagJson from "@ipld/dag-json";
|
|
24
|
+
import { Logger } from "besonders-logger";
|
|
25
|
+
import { CID } from "multiformats";
|
|
26
|
+
var { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO);
|
|
27
|
+
async function decodePubFromCar(car) {
|
|
28
|
+
const decoded = await getBlocksOfCar(car);
|
|
29
|
+
return await decodePubFromBlocks(decoded);
|
|
30
|
+
}
|
|
31
|
+
async function decodePubFromBlocks({ rootCID, blockStore }, _recursionTrace = [], stopAtCID) {
|
|
32
|
+
if (!rootCID || !blockStore) {
|
|
33
|
+
throw ERROR("Empty roots/blocks", { rootCID, blockStore });
|
|
34
|
+
}
|
|
35
|
+
let allApplogs = [];
|
|
36
|
+
let firstInfo = null;
|
|
37
|
+
let currentCID = rootCID;
|
|
38
|
+
const visited = /* @__PURE__ */ new Set();
|
|
39
|
+
let applogsCID = null;
|
|
40
|
+
while (currentCID) {
|
|
41
|
+
const cidStr = currentCID.toString();
|
|
42
|
+
if (visited.has(cidStr)) {
|
|
43
|
+
throw ERROR("[decodePubFromBlocks] pub chain has a loop", {
|
|
44
|
+
currentCID: cidStr,
|
|
45
|
+
visited: [...visited]
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
visited.add(cidStr);
|
|
49
|
+
const root = await getDecodedBlock(blockStore, currentCID);
|
|
50
|
+
VERBOSE(`[decodePubFromBlocks] root:`, cidStr, root, { blockStore });
|
|
51
|
+
if (!root) {
|
|
52
|
+
throw ERROR("[decodePubFromBlocks] root not found in blockStore", { blockStore, currentCID: cidStr });
|
|
53
|
+
}
|
|
54
|
+
let pubLogsArray;
|
|
55
|
+
if (root?.info) {
|
|
56
|
+
if (!applogsCID) applogsCID = root.applogs;
|
|
57
|
+
const applogsBlock = await getDecodedBlock(blockStore, root.applogs);
|
|
58
|
+
pubLogsArray = await unchunkApplogsBlock(applogsBlock, blockStore);
|
|
59
|
+
if (!firstInfo) {
|
|
60
|
+
firstInfo = await getDecodedBlock(blockStore, root.info);
|
|
61
|
+
DEBUG(`new format - infoLogs`, firstInfo.logs.map((l) => ({ [l.toString()]: l })));
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
pubLogsArray = root.applogs;
|
|
65
|
+
}
|
|
66
|
+
const resolveLogFromCidLink = async (cidOrLink) => {
|
|
67
|
+
const cid = cidOrLink;
|
|
68
|
+
const applog = await getDecodedBlock(blockStore, cid);
|
|
69
|
+
if (!applog) {
|
|
70
|
+
ERROR(`Could not find applog CID in pub blocks:`, cid.toString(), { cid, root, blockStore });
|
|
71
|
+
throw new Error(`Could not find applog CID in pub blocks: ${cid.toString()}`);
|
|
72
|
+
}
|
|
73
|
+
if (applog.pv instanceof CID) applog.pv = applog.pv.toV1().toString();
|
|
74
|
+
return {
|
|
75
|
+
...applog,
|
|
76
|
+
cid: cid.toV1().toString()
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
const snapshotApplogs = await Promise.all(pubLogsArray.map(resolveLogFromCidLink));
|
|
80
|
+
allApplogs = allApplogs.concat(snapshotApplogs);
|
|
81
|
+
if (!root.prev) {
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
if (stopAtCID && areCidsEqual(root.prev, stopAtCID)) {
|
|
85
|
+
DEBUG("[decodePubFromBlocks] stopping at stopAtCID:", stopAtCID.toString());
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
const prevBytes = await blockStore.get(root.prev);
|
|
89
|
+
if (!prevBytes) {
|
|
90
|
+
throw ERROR("[decodePubFromBlocks] prev snapshot missing from blockStore", {
|
|
91
|
+
currentCID: cidStr,
|
|
92
|
+
prev: root.prev.toString(),
|
|
93
|
+
stopAtCID: stopAtCID?.toString(),
|
|
94
|
+
visited: [...visited]
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
currentCID = root.prev;
|
|
98
|
+
}
|
|
99
|
+
const result = {
|
|
100
|
+
cid: rootCID,
|
|
101
|
+
info: firstInfo ? {
|
|
102
|
+
...firstInfo,
|
|
103
|
+
logs: await Promise.all(firstInfo.logs.map(async (cidOrLink) => {
|
|
104
|
+
const cid = cidOrLink;
|
|
105
|
+
const applog = await getDecodedBlock(blockStore, cid);
|
|
106
|
+
if (!applog) {
|
|
107
|
+
ERROR(`Could not find info log CID in pub blocks:`, cid.toString(), { cid, blockStore });
|
|
108
|
+
throw new Error(`Could not find info log CID in pub blocks: ${cid.toString()}`);
|
|
109
|
+
}
|
|
110
|
+
if (applog.pv instanceof CID) applog.pv = applog.pv.toV1().toString();
|
|
111
|
+
return {
|
|
112
|
+
...applog,
|
|
113
|
+
cid: cid.toV1().toString()
|
|
114
|
+
};
|
|
115
|
+
}))
|
|
116
|
+
} : null,
|
|
117
|
+
applogsCID,
|
|
118
|
+
applogs: allApplogs
|
|
119
|
+
};
|
|
120
|
+
DEBUG("[decodePubFromBlocks] result:", result, { rootCID: rootCID.toString(), blockStore, applogs: allApplogs });
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
async function getBlocksOfCar(car) {
|
|
124
|
+
const rootsFromCar = await car.getRoots();
|
|
125
|
+
const roots = rootsFromCar.map((c) => (typeof c.toV1 === "function" ? c : CID.decode(c.bytes)).toV1().toString());
|
|
126
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
127
|
+
for await (const { cid: cidFromCarblocks, bytes } of car.blocks()) {
|
|
128
|
+
const cid = typeof cidFromCarblocks.toV1 === "function" ? cidFromCarblocks : CID.decode(cidFromCarblocks.bytes);
|
|
129
|
+
VERBOSE({ cidFromCarblocks, cid });
|
|
130
|
+
blocks.set(cid.toV1().toString(), bytes);
|
|
131
|
+
}
|
|
132
|
+
if (roots.length !== 1) {
|
|
133
|
+
WARN("Unexpected roots count:", roots);
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
rootCID: CID.parse(roots[0]),
|
|
137
|
+
blockStore: {
|
|
138
|
+
get: (cid) => blocks.get(cid.toV1().toString())
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
async function getDecodedBlock(blockStore, cid) {
|
|
143
|
+
try {
|
|
144
|
+
var blob = await blockStore.get(cid);
|
|
145
|
+
if (!blob) {
|
|
146
|
+
WARN("returning null");
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
} catch (err) {
|
|
150
|
+
if (err.message === "Not Found") return null;
|
|
151
|
+
throw err;
|
|
152
|
+
}
|
|
153
|
+
return dagJson.decode(blob);
|
|
154
|
+
}
|
|
155
|
+
async function makeCarOut(roots, blocks) {
|
|
156
|
+
const { writer, out } = CarWriter.create(Array.isArray(roots) ? roots : [roots]);
|
|
157
|
+
VERBOSE(`Writing ${blocks.length} blocks to CAR`, { roots, blocks });
|
|
158
|
+
blocks.forEach((b) => writer.put(b));
|
|
159
|
+
writer.close();
|
|
160
|
+
return out;
|
|
161
|
+
}
|
|
162
|
+
async function makeCarBlob(roots, blocks) {
|
|
163
|
+
const carOut = await makeCarOut(roots, blocks);
|
|
164
|
+
const chunks = [];
|
|
165
|
+
for await (const chunk of carOut) {
|
|
166
|
+
chunks.push(chunk);
|
|
167
|
+
}
|
|
168
|
+
const blob = new Blob(chunks);
|
|
169
|
+
return blob;
|
|
170
|
+
}
|
|
171
|
+
async function carFromBlob(blob) {
|
|
172
|
+
return CarReader.fromBytes(new Uint8Array(await blob.arrayBuffer()));
|
|
173
|
+
}
|
|
174
|
+
function extractCids(value) {
|
|
175
|
+
if (value instanceof CID) return [value];
|
|
176
|
+
if (Array.isArray(value)) return value.flatMap(extractCids);
|
|
177
|
+
if (value && typeof value === "object") return Object.values(value).flatMap(extractCids);
|
|
178
|
+
return [];
|
|
179
|
+
}
|
|
180
|
+
var MAX_COLLECT_BLOCKS = 1e6;
|
|
181
|
+
async function collectDagBlocks(startCID, blockStore) {
|
|
182
|
+
const visited = /* @__PURE__ */ new Set();
|
|
183
|
+
const blocks = [];
|
|
184
|
+
const queue = [startCID];
|
|
185
|
+
while (queue.length > 0) {
|
|
186
|
+
if (blocks.length >= MAX_COLLECT_BLOCKS) {
|
|
187
|
+
WARN(`[collectDagBlocks] hit ${MAX_COLLECT_BLOCKS} block limit, returning partial result`);
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
const cid = queue.shift();
|
|
191
|
+
const cidStr = cid.toString();
|
|
192
|
+
if (visited.has(cidStr)) continue;
|
|
193
|
+
visited.add(cidStr);
|
|
194
|
+
let bytes;
|
|
195
|
+
try {
|
|
196
|
+
bytes = await blockStore.get(cid);
|
|
197
|
+
} catch {
|
|
198
|
+
WARN(`[collectDagBlocks] block not found: ${cidStr}, stopping this branch`);
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
if (!bytes) {
|
|
202
|
+
WARN(`[collectDagBlocks] block not found: ${cidStr}, stopping this branch`);
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
blocks.push({ cid, bytes });
|
|
206
|
+
if (blocks.length % 1e3 === 0) {
|
|
207
|
+
LOG(`[collectDagBlocks] collected ${blocks.length} blocks...`);
|
|
208
|
+
}
|
|
209
|
+
try {
|
|
210
|
+
const decoded = dagJson.decode(bytes);
|
|
211
|
+
const childCids = extractCids(decoded);
|
|
212
|
+
for (const child of childCids) {
|
|
213
|
+
if (!visited.has(child.toString())) {
|
|
214
|
+
queue.push(child);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
} catch {
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
DEBUG(`[collectDagBlocks] collected ${blocks.length} blocks from ${startCID.toString()}`);
|
|
221
|
+
return blocks;
|
|
222
|
+
}
|
|
223
|
+
function streamReaderToIterable(bodyReader) {
|
|
224
|
+
return (async function* () {
|
|
225
|
+
while (true) {
|
|
226
|
+
const { done, value } = await bodyReader.read();
|
|
227
|
+
VERBOSE(`[car] chunk`, { done, value });
|
|
228
|
+
if (done) {
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
yield value;
|
|
232
|
+
}
|
|
233
|
+
})();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// src/pubsub/snap-push.ts
|
|
237
|
+
var { WARN: WARN2, LOG: LOG2, DEBUG: DEBUG2, VERBOSE: VERBOSE2, ERROR: ERROR2 } = Logger2.setup(Logger2.INFO);
|
|
238
|
+
async function prepareSnapshotForPush(agent, appThread, threadToPublish, share, prevSnapCID, prevCounter) {
|
|
239
|
+
if (prevCounter !== null && !prevSnapCID) {
|
|
240
|
+
throw ERROR2("[prepareSnapshotForPush] prevCounter provided without prevSnapCID");
|
|
241
|
+
}
|
|
242
|
+
let logsToPublish = getLogsFromThread(threadToPublish);
|
|
243
|
+
DEBUG2(`[preparePubForPush] Collected ${logsToPublish.length} logs :`, {
|
|
244
|
+
logsToPublish,
|
|
245
|
+
threadOrLogsCount: threadToPublish.nameAndSizeUntracked || `[${threadToPublish.length}]`
|
|
246
|
+
});
|
|
247
|
+
const { sharedAgents, sharedKeyMap, sharedKey, pubCounter } = share ?? {};
|
|
248
|
+
const getExistingOrNewLog = (thread, share2, ag, at, vl) => {
|
|
249
|
+
let logInQuestion = rollingFilter(lastWriteWins(thread), { en: share2.id, at }).latestLog;
|
|
250
|
+
if (!logInQuestion && vl !== void 0) {
|
|
251
|
+
logInQuestion = ensureTsPvAndFinalizeApplog({ ag, en: share2.id, at, vl }, thread);
|
|
252
|
+
}
|
|
253
|
+
return logInQuestion;
|
|
254
|
+
};
|
|
255
|
+
const shareNameLog = getExistingOrNewLog(appThread, share, agent.ag, "share/name", share.name);
|
|
256
|
+
const shareCounterLog = getExistingOrNewLog(appThread, share, agent.ag, "share/counter", `${agent.did}<::>${pubCounter}`);
|
|
257
|
+
const encryptApplog = async (applog, keyToUse) => {
|
|
258
|
+
const { log: eachLog, cid } = prepareForPub(applog);
|
|
259
|
+
const enc = new TextEncoder();
|
|
260
|
+
const stringified = stringify(eachLog);
|
|
261
|
+
const stringifiedEncodedAppLogPayload = enc.encode(stringified);
|
|
262
|
+
VERBOSE2("[odd]", { eachLog, stringified, stringifiedEncodedAppLogPayload });
|
|
263
|
+
try {
|
|
264
|
+
const encPayload = await agent.crypto?.aes.encrypt(stringifiedEncodedAppLogPayload, keyToUse, "AES-GCM");
|
|
265
|
+
VERBOSE2("[odd] encrypted length:", stringifiedEncodedAppLogPayload.length, { encPayload });
|
|
266
|
+
return encPayload;
|
|
267
|
+
} catch (err) {
|
|
268
|
+
throw ERROR2("FAILED TO ENC payload length:", stringifiedEncodedAppLogPayload.length, { err });
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
let maybeEncryptedApplogs;
|
|
272
|
+
const encryptedApplogs = [];
|
|
273
|
+
const agentSharedKeyLogs = [];
|
|
274
|
+
if (sharedAgents) {
|
|
275
|
+
if (!sharedKey || !sharedKeyMap) {
|
|
276
|
+
throw ERROR2("sharedAgents but no Keys/Map", { sharedAgents, sharedKeyMap, sharedKey });
|
|
277
|
+
}
|
|
278
|
+
VERBOSE2("encrypting", { sharedAgents, sharedKeyMap });
|
|
279
|
+
for (const [eachAgent, eachEncKey] of Array.from(sharedKeyMap.entries())) {
|
|
280
|
+
VERBOSE2("adding key", { eachAgent, eachEncKey });
|
|
281
|
+
agentSharedKeyLogs.push({
|
|
282
|
+
ag: agent.ag,
|
|
283
|
+
en: eachAgent,
|
|
284
|
+
at: "share/sharedKey",
|
|
285
|
+
vl: eachEncKey
|
|
286
|
+
// these are encrypted with the derived key from the local agent private and remote agent public keys
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
const CIDlist = [];
|
|
290
|
+
const pubCIDmap = {};
|
|
291
|
+
for (const eachLog of logsToPublish) {
|
|
292
|
+
VERBOSE2("[crypto] encrypting ", { eachLog, sharedKey });
|
|
293
|
+
const encPayload = await encryptApplog(eachLog, sharedKey);
|
|
294
|
+
DEBUG2("[crypto] encrypted ", { eachLog, encPayload, sharedKey });
|
|
295
|
+
encryptedApplogs.push({ enc: encPayload });
|
|
296
|
+
}
|
|
297
|
+
maybeEncryptedApplogs = encryptedApplogs;
|
|
298
|
+
} else {
|
|
299
|
+
maybeEncryptedApplogs = logsToPublish;
|
|
300
|
+
}
|
|
301
|
+
DEBUG2("adding all agent info and shareAtoms", {
|
|
302
|
+
share,
|
|
303
|
+
agent,
|
|
304
|
+
logsToPublish,
|
|
305
|
+
// threadToPublish, - very verbose
|
|
306
|
+
agentSharedKeyLogs
|
|
307
|
+
});
|
|
308
|
+
const infoLogs = [
|
|
309
|
+
...rollingFilter(lastWriteWins(appThread), {
|
|
310
|
+
// TODO: use static filter for performance
|
|
311
|
+
en: agent.ag,
|
|
312
|
+
at: ["agent/ecdh", "agent/jwkd", "agent/appAgent"]
|
|
313
|
+
}).applogs,
|
|
314
|
+
...shareNameLog ? [shareNameLog] : [],
|
|
315
|
+
...shareCounterLog ? [shareCounterLog] : [],
|
|
316
|
+
...agentSharedKeyLogs
|
|
317
|
+
];
|
|
318
|
+
DEBUG2(`[prepareSnapshotForPush] info logs:`, infoLogs);
|
|
319
|
+
if (!infoLogs.find(({ at }) => at === "agent/appAgent")) throw ERROR2(`[prepareSnapshotForPush] appThread missing agent/appAgent log`);
|
|
320
|
+
const applogsToEncode = keepTruthy(maybeEncryptedApplogs);
|
|
321
|
+
const infologsToEncode = keepTruthy(infoLogs);
|
|
322
|
+
if (!applogsToEncode.length) {
|
|
323
|
+
throw ERROR2("no valid applogs", { agent, maybeEncryptedApplogs, infoLogs, applogsToEncode, infologsToEncode, prevSnapCID });
|
|
324
|
+
}
|
|
325
|
+
if (!infologsToEncode.length) {
|
|
326
|
+
throw ERROR2("no valid infologs", { agent, maybeEncryptedApplogs, infoLogs, applogsToEncode, infologsToEncode, prevSnapCID });
|
|
327
|
+
}
|
|
328
|
+
const encodedSnapshot = await encodeSnapshotAsCar(agent, applogsToEncode, infologsToEncode, prevSnapCID, prevCounter);
|
|
329
|
+
DEBUG2("inPrepareSnapshotForPush", { encodedSnapshot });
|
|
330
|
+
return encodedSnapshot;
|
|
331
|
+
}
|
|
332
|
+
async function encodeSnapshotAsCar(agent, applogs, infoLogs, prevSnapCID, prevCounter) {
|
|
333
|
+
DEBUG2(`[encodeSnapshotAsCar] encoding`, { agent, applogs, infoLogs });
|
|
334
|
+
const { cids: infoLogCids, encodedApplogs: encodedInfoLogs } = await encodeApplogsAsIPLD(infoLogs);
|
|
335
|
+
const { cids: applogCids, encodedApplogs } = await encodeApplogsAsIPLD(applogs);
|
|
336
|
+
let blocks = encodedApplogs.concat(encodedInfoLogs);
|
|
337
|
+
const infoLogsWrap = await encodeBlockOriginal({ logs: infoLogCids });
|
|
338
|
+
blocks.push(infoLogsWrap);
|
|
339
|
+
const { rootCID: chunkRootCID, blocks: chunkBlocks } = await chunkApplogs(applogCids);
|
|
340
|
+
blocks = blocks.concat(chunkBlocks);
|
|
341
|
+
const infoSignature = await agent.sign(infoLogsWrap.cid.bytes);
|
|
342
|
+
const applogsSignature = await agent.sign(chunkRootCID.bytes);
|
|
343
|
+
const root = {
|
|
344
|
+
info: infoLogsWrap.cid,
|
|
345
|
+
applogs: chunkRootCID,
|
|
346
|
+
infoSignature,
|
|
347
|
+
applogsSignature,
|
|
348
|
+
prev: prevSnapCID,
|
|
349
|
+
prevCounter: !prevSnapCID ? 0 : prevCounter !== null ? prevCounter + 1 : null
|
|
350
|
+
};
|
|
351
|
+
DEBUG2("[encodeSnapshotAsCar] encoding root", { root, logCids: applogCids, infoLogCids });
|
|
352
|
+
const encodedRoot = await encodeBlockOriginal(root);
|
|
353
|
+
blocks.push(encodedRoot);
|
|
354
|
+
DEBUG2("[encodeSnapshotAsCar] => root", { encodedRoot });
|
|
355
|
+
return {
|
|
356
|
+
cid: encodedRoot.cid,
|
|
357
|
+
blob: await makeCarBlob(encodedRoot.cid, blocks),
|
|
358
|
+
// TODO: create CarBuilder (incl .encodeAndAdd({...}))
|
|
359
|
+
blocks,
|
|
360
|
+
infoLogCids,
|
|
361
|
+
applogCids
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
async function chunkApplogs(applogCids, size = 1e4) {
|
|
365
|
+
if (!applogCids.length) throw ERROR2(`[chunkApplogs] called with empty array`);
|
|
366
|
+
const chunks = [];
|
|
367
|
+
for (let i = 0; i < applogCids.length; i += size) {
|
|
368
|
+
const chunk = await encodeBlockOriginal({ logs: applogCids.slice(i, Math.min(i + applogCids.length, i + size)) });
|
|
369
|
+
chunks.push(chunk);
|
|
370
|
+
}
|
|
371
|
+
if (chunks.length === 1) return { rootCID: chunks[0].cid, blocks: chunks };
|
|
372
|
+
const root = await encodeBlockOriginal({ chunks: chunks.map((chunk) => chunk.cid) });
|
|
373
|
+
const blocks = [root, ...chunks];
|
|
374
|
+
DEBUG2(`[chunkApplogs] ${applogCids.length} logs chunked into ${chunks.length}`, { applogCids, root, blocks, chunks, dagJson: dagJson2 });
|
|
375
|
+
return { rootCID: root.cid, blocks, chunks };
|
|
376
|
+
}
|
|
377
|
+
async function unchunkApplogsBlock(block, blockStore) {
|
|
378
|
+
if (isSnapBlockChunks(block)) {
|
|
379
|
+
return (await Promise.all(
|
|
380
|
+
block.chunks.map(async (chunkCid) => {
|
|
381
|
+
const block2 = await getDecodedBlock(blockStore, chunkCid);
|
|
382
|
+
if (!block2.logs) throw ERROR2(`Weird chunk`, block2);
|
|
383
|
+
return block2.logs;
|
|
384
|
+
})
|
|
385
|
+
)).flat();
|
|
386
|
+
} else {
|
|
387
|
+
return block.logs;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
function isSnapBlockChunks(block) {
|
|
391
|
+
return block.chunks;
|
|
392
|
+
}
|
|
393
|
+
async function encodeSnapshotApplogsAsCar(applogs) {
|
|
394
|
+
const encoded = await encodeApplogsAsIPLD(applogs);
|
|
395
|
+
if (!encoded) throw ERROR2("invalid applogs cannot continue", { applogs, encoded });
|
|
396
|
+
const { cids, encodedApplogs } = encoded;
|
|
397
|
+
const root = { applogs: cids };
|
|
398
|
+
const encodedRoot = await encodeBlockOriginal(root);
|
|
399
|
+
DEBUG2("[encodeSnapshotApplogsAsCar] encoded root", { cids, encodedRoot });
|
|
400
|
+
return await makeCarBlob(encodedRoot.cid, [encodedRoot, ...encodedApplogs]);
|
|
401
|
+
}
|
|
402
|
+
async function encodeApplogsAsIPLD(applogs) {
|
|
403
|
+
DEBUG2({ applogs });
|
|
404
|
+
const validApplogs = applogs.filter((eachLog) => !!eachLog);
|
|
405
|
+
DEBUG2({ validApplogs });
|
|
406
|
+
if (!validApplogs.length) throw ERROR2("no valid applogs");
|
|
407
|
+
const preppedLogs = validApplogs.map((log) => prepareForPub(log).log);
|
|
408
|
+
const encodedApplogs = await Promise.all(preppedLogs.map(encodeBlockOriginal));
|
|
409
|
+
DEBUG2("[encodeApplogsAsIpld] encoded applogs", { preppedLogs, encodedApplogs });
|
|
410
|
+
const cids = encodedApplogs.map((b) => {
|
|
411
|
+
if (!b.cid) throw ERROR2(`[publish] no cid for encoded log:`, b);
|
|
412
|
+
return b.cid;
|
|
413
|
+
});
|
|
414
|
+
return { cids, encodedApplogs };
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
export {
|
|
418
|
+
prepareSnapshotForPush,
|
|
419
|
+
encodeSnapshotAsCar,
|
|
420
|
+
chunkApplogs,
|
|
421
|
+
unchunkApplogsBlock,
|
|
422
|
+
isSnapBlockChunks,
|
|
423
|
+
encodeSnapshotApplogsAsCar,
|
|
424
|
+
decodePubFromCar,
|
|
425
|
+
decodePubFromBlocks,
|
|
426
|
+
getBlocksOfCar,
|
|
427
|
+
getDecodedBlock,
|
|
428
|
+
makeCarOut,
|
|
429
|
+
makeCarBlob,
|
|
430
|
+
carFromBlob,
|
|
431
|
+
collectDagBlocks,
|
|
432
|
+
streamReaderToIterable
|
|
433
|
+
};
|
|
434
|
+
//# sourceMappingURL=chunk-3WZVG277.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/pubsub/snap-push.ts","../src/ipfs/car.ts"],"sourcesContent":["import * as dagJson from '@ipld/dag-json'\nimport { Logger } from 'besonders-logger'\nimport { CID } from 'multiformats/cid'\nimport stringify from 'safe-stable-stringify'\nimport { ensureTsPvAndFinalizeApplog } from '../applog/applog-helpers.ts'\nimport type {\n\tApplog,\n\tApplogArrayMaybeEncrypted,\n\tApplogArrayMaybeEncryptedRO,\n\tApplogArrayNoCIDMaybeEncryptedRO,\n\tApplogEnc,\n\tApplogEncNoCid,\n\tCidString,\n} from '../applog/datom-types.ts'\nimport { BlockStoreish, DecodedCar, getDecodedBlock, makeCarBlob } from '../ipfs/car.ts'\nimport { encodeBlockOriginal, prepareForPub } from '../ipfs/ipfs-utils.ts'\nimport { lastWriteWins } from './../query/basic.ts'\nimport { ApplogsOrThread, getLogsFromThread, Thread } from '../thread.ts'\nimport { rollingFilter } from '../thread/filters.ts'\nimport { keepTruthy } from '../utils.ts'\nimport type { AppAgent, IShare, SnapBlockChunks, SnapBlockLogs, SnapBlockLogsOrChunks } from './pubsub-types.ts'\n\nconst { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO) // eslint-disable-line no-unused-vars\n\n// export const neverEncryptAttrs = [\n// \t'agent/jwkd',\n// \t'agent/appAgent',\n// \t'pub/encryptedFor',\n// \t'pub/sharedKey',\n// ]\n\n// export interface WovinPublicationInfo {\n// \tid: string\n// }\n\nexport async function prepareSnapshotForPush(\n\tagent: AppAgent,\n\tappThread: Thread,\n\tthreadToPublish: ApplogsOrThread,\n\tshare: IShare,\n\tprevSnapCID: CID | null,\n\tprevCounter: number | null,\n) {\n\tif (prevCounter !== null && !prevSnapCID) {\n\t\tthrow ERROR('[prepareSnapshotForPush] prevCounter provided without prevSnapCID')\n\t}\n\t// TODO prevent publish if there is no new info\n\tlet logsToPublish = getLogsFromThread(threadToPublish)\n\n\t// const logsFromLastPush = await getLogsFromPub(publication)\n\t// logsToPublish = logsToPublish.filter(eachLog => !logsFromLastPush.includes(eachLog.cid)) // TODO deep compare includes\n\t// const prevPushCIDs = [\n\t// \tpublication.lastCID,\n\t// \t//TODO add this one and update the publication data after push\n\t// ]\n\t// const includedLogCIDs = [\n\t// \t'full array of CIDS from all previous pushes'\n\t// ]\n\n\tDEBUG(`[preparePubForPush] Collected ${logsToPublish.length} logs :`, {\n\t\tlogsToPublish,\n\t\tthreadOrLogsCount: (threadToPublish as any).nameAndSizeUntracked || (`[${(threadToPublish as any).length}]`),\n\t})\n\n\tconst { sharedAgents, sharedKeyMap, sharedKey, pubCounter } = share ?? {}\n\n\tconst getExistingOrNewLog = (thread: Thread, share: IShare, ag: string, at: string, vl) => {\n\t\tlet logInQuestion = rollingFilter(lastWriteWins(thread), { en: share.id, at }).latestLog\n\t\tif (!logInQuestion && vl !== undefined) {\n\t\t\tlogInQuestion = ensureTsPvAndFinalizeApplog({ ag, en: share.id, at, vl }, thread)\n\t\t}\n\t\treturn logInQuestion // can be undefined if the passed vl is undefined and the log is not found\n\t}\n\tconst shareNameLog = getExistingOrNewLog(appThread, share, agent.ag, 'share/name', share.name)\n\n\t// ? using did as it is derived from the same ecdh in note3 and part of the minimal AppAgent type required here in wovin core\n\tconst shareCounterLog = getExistingOrNewLog(appThread, share, agent.ag, 'share/counter', `${agent.did}<::>${pubCounter}`)\n\t// ? discuss if this works to bind the counter to a specific derivation key - did is not necessarily derived from the same key by all lib users\n\n\tconst encryptApplog = async (applog: Applog, keyToUse: CryptoKey): Promise<Uint8Array> => {\n\t\tconst { log: eachLog, cid } = prepareForPub(applog) // without cid\n\t\tconst enc = new TextEncoder()\n\t\tconst stringified = stringify(eachLog)\n\t\tconst stringifiedEncodedAppLogPayload = enc.encode(stringified) // TODO: consider encodeToDagJson instead\n\t\tVERBOSE('[odd]', { eachLog, stringified, stringifiedEncodedAppLogPayload })\n\n\t\ttry {\n\t\t\t// @ts-expect-error\n\t\t\tconst encPayload = await agent.crypto?.aes.encrypt(stringifiedEncodedAppLogPayload, keyToUse, 'AES-GCM')\n\t\t\t// TODO get rid of odd down here\n\t\t\tVERBOSE('[odd] encrypted length:', stringifiedEncodedAppLogPayload.length, { encPayload })\n\t\t\treturn encPayload\n\t\t} catch (err) {\n\t\t\tthrow ERROR('FAILED TO ENC payload length:', stringifiedEncodedAppLogPayload.length, { err })\n\t\t}\n\n\t\t// const decrypted = await decryptWithAesSharedKey(encPayload, keyToUse, 'string')\n\t}\n\n\tlet maybeEncryptedApplogs: ApplogEncNoCid[] | readonly Applog[]\n\tconst encryptedApplogs = [] as { enc: Uint8Array }[]\n\tconst agentSharedKeyLogs = []\n\tif (sharedAgents) { // encrypt all Applogs\n\t\tif (!sharedKey || !sharedKeyMap) {\n\t\t\tthrow ERROR('sharedAgents but no Keys/Map', { sharedAgents, sharedKeyMap, sharedKey })\n\t\t}\n\t\tVERBOSE('encrypting', { sharedAgents, sharedKeyMap })\n\n\t\tfor (const [eachAgent, eachEncKey] of Array.from(sharedKeyMap.entries())) {\n\t\t\tVERBOSE('adding key', { eachAgent, eachEncKey })\n\t\t\tagentSharedKeyLogs.push({\n\t\t\t\tag: agent.ag,\n\t\t\t\ten: eachAgent,\n\t\t\t\tat: 'share/sharedKey',\n\t\t\t\tvl: eachEncKey, // these are encrypted with the derived key from the local agent private and remote agent public keys\n\t\t\t})\n\t\t}\n\t\t// const encryptedForLogs = await insertApplogsInAppDB(agentSharedKeyLogs)\n\t\t// DEBUG(`[publish] adding agentSharedKeyLogs:`, encryptedForLogs)\n\t\tconst CIDlist: { cid: CidString; encCID?: CidString }[] = []\n\t\tconst pubCIDmap: Record<CidString, typeof CIDlist> = {}\n\t\t// TODO ensure that all needed keys are in\n\t\tfor (const eachLog of logsToPublish) {\n\t\t\tVERBOSE('[crypto] encrypting ', { eachLog, sharedKey })\n\t\t\t// try {\n\t\t\tconst encPayload = await encryptApplog(eachLog, sharedKey)\n\t\t\tDEBUG('[crypto] encrypted ', { eachLog, encPayload, sharedKey })\n\t\t\t// } catch (err) {\n\t\t\t// \t// its already traced in encryptAndTestDecrypt\n\t\t\t// \t// continue\n\t\t\t// }\n\t\t\tencryptedApplogs.push({ enc: encPayload })\n\t\t}\n\t\tmaybeEncryptedApplogs = encryptedApplogs\n\t} else {\n\t\tmaybeEncryptedApplogs = logsToPublish // publish nonEncrypted\n\t}\n\n\tDEBUG('adding all agent info and shareAtoms', {\n\t\tshare,\n\t\tagent,\n\t\tlogsToPublish,\n\t\t// threadToPublish, - very verbose\n\t\tagentSharedKeyLogs,\n\t})\n\tconst infoLogs = [\n\t\t...rollingFilter(lastWriteWins(appThread), { // TODO: use static filter for performance\n\t\t\ten: agent.ag,\n\t\t\tat: ['agent/ecdh', 'agent/jwkd', 'agent/appAgent'],\n\t\t}).applogs,\n\t\t...(shareNameLog ? [shareNameLog] : []),\n\t\t...(shareCounterLog ? [shareCounterLog] : []),\n\t\t...agentSharedKeyLogs,\n\t]\n\tDEBUG(`[prepareSnapshotForPush] info logs:`, infoLogs)\n\tif (!infoLogs.find(({ at }) => at === 'agent/appAgent')) throw ERROR(`[prepareSnapshotForPush] appThread missing agent/appAgent log`)\n\n\tconst applogsToEncode = keepTruthy(maybeEncryptedApplogs)\n\tconst infologsToEncode = keepTruthy(infoLogs)\n\tif (!applogsToEncode.length) {\n\t\tthrow ERROR('no valid applogs', { agent, maybeEncryptedApplogs, infoLogs, applogsToEncode, infologsToEncode, prevSnapCID })\n\t}\n\tif (!infologsToEncode.length) {\n\t\tthrow ERROR('no valid infologs', { agent, maybeEncryptedApplogs, infoLogs, applogsToEncode, infologsToEncode, prevSnapCID })\n\t}\n\tconst encodedSnapshot = await encodeSnapshotAsCar(agent, applogsToEncode, infologsToEncode, prevSnapCID, prevCounter)\n\tDEBUG('inPrepareSnapshotForPush', { encodedSnapshot })\n\treturn encodedSnapshot\n}\n\n/**\n * @param applogs Encrypted or plain applogs\n * @returns Car file\n */\nexport async function encodeSnapshotAsCar(\n\tagent: AppAgent,\n\tapplogs: ApplogArrayNoCIDMaybeEncryptedRO,\n\tinfoLogs: readonly Applog[],\n\tprevSnapCID: CID | null,\n\tprevCounter: number | null,\n) {\n\tDEBUG(`[encodeSnapshotAsCar] encoding`, { agent, applogs, infoLogs })\n\tconst { cids: infoLogCids, encodedApplogs: encodedInfoLogs } = await encodeApplogsAsIPLD(infoLogs)\n\tconst { cids: applogCids, encodedApplogs } = await encodeApplogsAsIPLD(applogs)\n\tlet blocks = encodedApplogs.concat(encodedInfoLogs)\n\t// We need to wrap the array to get a CID\n\tconst infoLogsWrap = await encodeBlockOriginal({ logs: infoLogCids })\n\tblocks.push(infoLogsWrap)\n\tconst { rootCID: chunkRootCID, blocks: chunkBlocks } = await chunkApplogs(applogCids)\n\tblocks = blocks.concat(chunkBlocks) // (i) concat bc. https://stackoverflow.com/a/51860949\n\tconst infoSignature = await agent.sign(infoLogsWrap.cid.bytes)\n\tconst applogsSignature = await agent.sign(chunkRootCID.bytes)\n\tconst root = {\n\t\tinfo: infoLogsWrap.cid,\n\t\tapplogs: chunkRootCID,\n\t\tinfoSignature,\n\t\tapplogsSignature,\n\t\tprev: prevSnapCID,\n\t\tprevCounter: !prevSnapCID ? 0 : prevCounter !== null ? prevCounter + 1 : null,\n\t}\n\tDEBUG('[encodeSnapshotAsCar] encoding root', { root, logCids: applogCids, infoLogCids })\n\tconst encodedRoot = await encodeBlockOriginal(root)\n\tblocks.push(encodedRoot)\n\tDEBUG('[encodeSnapshotAsCar] => root', { encodedRoot })\n\n\treturn {\n\t\tcid: encodedRoot.cid,\n\t\tblob: await makeCarBlob(encodedRoot.cid, blocks), // TODO: create CarBuilder (incl .encodeAndAdd({...}))\n\t\tblocks,\n\t\tinfoLogCids,\n\t\tapplogCids,\n\t}\n}\n\n/** (i) IPFS has a block size limit of 1MB - which is about 15K CIDs */\nexport async function chunkApplogs(applogCids: CID<unknown, 297, 18, 1>[], size = 10000) {\n\tif (!applogCids.length) throw ERROR(`[chunkApplogs] called with empty array`)\n\tconst chunks = []\n\t// TODO: chunk by stable btree based on size or something like that\n\tfor (let i = 0; i < applogCids.length; i += size) {\n\t\tconst chunk = await encodeBlockOriginal({ logs: applogCids.slice(i, Math.min(i + applogCids.length, i + size)) })\n\t\tchunks.push(chunk)\n\t}\n\tif (chunks.length === 1) return { rootCID: chunks[0].cid, blocks: chunks }\n\tconst root = await encodeBlockOriginal({ chunks: chunks.map(chunk => chunk.cid) })\n\tconst blocks = [root, ...chunks]\n\tDEBUG(`[chunkApplogs] ${applogCids.length} logs chunked into ${chunks.length}`, { applogCids, root, blocks, chunks, dagJson })\n\treturn { rootCID: root.cid, blocks, chunks }\n}\nexport async function unchunkApplogsBlock(block: SnapBlockLogsOrChunks, blockStore: BlockStoreish): Promise<CID[]> {\n\tif (isSnapBlockChunks(block)) {\n\t\treturn (await Promise.all(\n\t\t\tblock.chunks.map(async (chunkCid) => {\n\t\t\t\tconst block = (await getDecodedBlock(blockStore, chunkCid)) as SnapBlockLogs\n\t\t\t\tif (!block.logs) throw ERROR(`Weird chunk`, block)\n\t\t\t\treturn block.logs\n\t\t\t}),\n\t\t)).flat()\n\t} else {\n\t\treturn block.logs\n\t}\n}\nexport function isSnapBlockChunks(block: SnapBlockLogsOrChunks): block is SnapBlockChunks {\n\treturn (block as any).chunks\n}\n/**\n * @param applogs Encrypted or plain applogs\n * @returns Car file\n */\nexport async function encodeSnapshotApplogsAsCar(\n\tapplogs: ApplogArrayMaybeEncryptedRO,\n) {\n\tconst encoded = await encodeApplogsAsIPLD(applogs)\n\tif (!encoded) throw ERROR('invalid applogs cannot continue', { applogs, encoded })\n\tconst { cids, encodedApplogs } = encoded\n\tconst root = { applogs: cids }\n\tconst encodedRoot = await encodeBlockOriginal(root)\n\tDEBUG('[encodeSnapshotApplogsAsCar] encoded root', { cids, encodedRoot })\n\n\treturn await makeCarBlob(encodedRoot.cid, [encodedRoot, ...encodedApplogs])\n}\n\nasync function encodeApplogsAsIPLD(applogs: ApplogArrayNoCIDMaybeEncryptedRO) {\n\tDEBUG({ applogs })\n\tconst validApplogs = applogs.filter(eachLog => !!eachLog)\n\tDEBUG({ validApplogs })\n\tif (!validApplogs.length) throw ERROR('no valid applogs')\n\tconst preppedLogs = validApplogs.map(log => prepareForPub(log as Applog).log)\n\tconst encodedApplogs = await Promise.all(preppedLogs.map(encodeBlockOriginal))\n\tDEBUG('[encodeApplogsAsIpld] encoded applogs', { preppedLogs, encodedApplogs })\n\n\tconst cids = encodedApplogs.map(b => {\n\t\tif (!b.cid) throw ERROR(`[publish] no cid for encoded log:`, b)\n\t\treturn b.cid\n\t})\n\treturn { cids, encodedApplogs }\n}\n","import { CarReader, CarWriter } from '@ipld/car'\nimport * as dagJson from '@ipld/dag-json'\nimport { Logger } from 'besonders-logger'\nimport { BlockView, CID } from 'multiformats'\nimport { sortApplogsByTs } from '../applog/applog-utils.ts'\nimport { Applog, ApplogArrayMaybeEncrypted, CidString } from '../applog/datom-types.ts'\nimport { unchunkApplogsBlock } from '../pubsub/snap-push.ts'\nimport { SnapBlockLogs, SnapBlockLogsOrChunks, SnapRootBlock } from '../pubsub/pubsub-types.ts'\nimport { areCidsEqual, containsCid } from './ipfs-utils.ts'\n\nconst { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO) // eslint-disable-line no-unused-vars\n\nexport type CIDForCar = CID // Exclude<Parameters<(typeof CarWriter)['create']>[0], void>\nexport type BlockForCar = Parameters<CarWriter['put']>[0]\n\nexport interface BlockStoreish {\n\tget(cid: CID): PromiseLike<Uint8Array> // (i) not using decoded version to be similar to blockstore-idb\n}\n\nexport interface DecodedCar {\n\trootCID: CID\n\t// blocks: Map<CidString, any>\n\tblockStore: BlockStoreish\n}\n\n/** Warning: unsorted & maybe encrypted */\nexport async function decodePubFromCar(car: CarReader) {\n\tconst decoded = await getBlocksOfCar(car)\n\treturn await decodePubFromBlocks(decoded)\n}\n\nexport async function decodePubFromBlocks(\n\t{ rootCID, blockStore }: DecodedCar,\n\t_recursionTrace: CID[] = [], // DEPRECATED: kept for API compat, unused in iterative version\n\tstopAtCID?: CID // NEW: stop iteration when we hit this CID\n) {\n\tif (!rootCID || !blockStore) {\n\t\tthrow ERROR('Empty roots/blocks', { rootCID, blockStore })\n\t}\n\n\tlet allApplogs: ApplogArrayMaybeEncrypted = []\n\tlet firstInfo: { logs: CID[] } | null = null\n\tlet currentCID: CID | undefined = rootCID\n\tconst visited = new Set<string>() // Loop detection (replaces recursionTrace)\n\tlet applogsCID: CID | null = null // From first snapshot only\n\n\twhile (currentCID) {\n\t\tconst cidStr = currentCID.toString()\n\n\t\t// Loop detection\n\t\tif (visited.has(cidStr)) {\n\t\t\tthrow ERROR('[decodePubFromBlocks] pub chain has a loop', {\n\t\t\t\tcurrentCID: cidStr,\n\t\t\t\tvisited: [...visited]\n\t\t\t})\n\t\t}\n\t\tvisited.add(cidStr)\n\n\t\t// Decode current snapshot\n\t\tconst root = (await getDecodedBlock(blockStore, currentCID)) as SnapRootBlock\n\t\tVERBOSE(`[decodePubFromBlocks] root:`, cidStr, root, { blockStore })\n\t\tif (!root) {\n\t\t\tthrow ERROR('[decodePubFromBlocks] root not found in blockStore', { blockStore, currentCID: cidStr })\n\t\t}\n\n\t\t// Decode applogs for this snapshot\n\t\tlet pubLogsArray: CID[]\n\t\tif (root?.info) {\n\t\t\t// New(er) format\n\t\t\tif (!applogsCID) applogsCID = root.applogs // Save from first snapshot\n\t\t\tconst applogsBlock = (await getDecodedBlock(blockStore, root.applogs)) as SnapBlockLogsOrChunks\n\t\t\tpubLogsArray = await unchunkApplogsBlock(applogsBlock, blockStore)\n\t\t\t// Info only from first (most recent) snapshot\n\t\t\tif (!firstInfo) {\n\t\t\t\tfirstInfo = (await getDecodedBlock(blockStore, root.info)) as SnapBlockLogs\n\t\t\t\tDEBUG(`new format - infoLogs`, firstInfo.logs.map(l => ({ [l.toString()]: l })))\n\t\t\t}\n\t\t\t// TODO: verify signatures\n\t\t} else {\n\t\t\t// Old format\n\t\t\tpubLogsArray = root.applogs as any as CID[]\n\t\t}\n\n\t\tconst resolveLogFromCidLink = async (cidOrLink: CID) => {\n\t\t\tconst cid = cidOrLink\n\t\t\tconst applog = (await getDecodedBlock(blockStore, cid)) as Applog\n\t\t\tif (!applog) {\n\t\t\t\tERROR(`Could not find applog CID in pub blocks:`, cid.toString(), { cid, root, blockStore })\n\t\t\t\tthrow new Error(`Could not find applog CID in pub blocks: ${cid.toString()}`)\n\t\t\t}\n\t\t\tif ((applog.pv as any) instanceof CID) applog.pv = (applog.pv as any as CID).toV1().toString()\n\t\t\treturn {\n\t\t\t\t...applog,\n\t\t\t\tcid: cid.toV1().toString(),\n\t\t\t}\n\t\t}\n\n\t\tconst snapshotApplogs = await Promise.all(pubLogsArray.map(resolveLogFromCidLink))\n\t\tallApplogs = allApplogs.concat(snapshotApplogs)\n\n\t\t// Check if we should stop\n\t\tif (!root.prev) {\n\t\t\tbreak // End of chain\n\t\t}\n\t\tif (stopAtCID && areCidsEqual(root.prev, stopAtCID)) {\n\t\t\tDEBUG('[decodePubFromBlocks] stopping at stopAtCID:', stopAtCID.toString())\n\t\t\tbreak // Reached already-pulled snapshot\n\t\t}\n\n\t\t// Verify prev exists before continuing\n\t\tconst prevBytes = await blockStore.get(root.prev)\n\t\tif (!prevBytes) {\n\t\t\tthrow ERROR('[decodePubFromBlocks] prev snapshot missing from blockStore', {\n\t\t\t\tcurrentCID: cidStr,\n\t\t\t\tprev: root.prev.toString(),\n\t\t\t\tstopAtCID: stopAtCID?.toString(),\n\t\t\t\tvisited: [...visited]\n\t\t\t})\n\t\t}\n\n\t\tcurrentCID = root.prev // Move to previous snapshot\n\t}\n\n\tconst result = {\n\t\tcid: rootCID,\n\t\tinfo: firstInfo ? {\n\t\t\t...firstInfo,\n\t\t\tlogs: await Promise.all(firstInfo.logs.map(async (cidOrLink: CID) => {\n\t\t\t\tconst cid = cidOrLink\n\t\t\t\tconst applog = (await getDecodedBlock(blockStore, cid)) as Applog\n\t\t\t\tif (!applog) {\n\t\t\t\t\tERROR(`Could not find info log CID in pub blocks:`, cid.toString(), { cid, blockStore })\n\t\t\t\t\tthrow new Error(`Could not find info log CID in pub blocks: ${cid.toString()}`)\n\t\t\t\t}\n\t\t\t\tif ((applog.pv as any) instanceof CID) applog.pv = (applog.pv as any as CID).toV1().toString()\n\t\t\t\treturn {\n\t\t\t\t\t...applog,\n\t\t\t\t\tcid: cid.toV1().toString(),\n\t\t\t\t}\n\t\t\t})),\n\t\t} : null,\n\t\tapplogsCID,\n\t\tapplogs: allApplogs,\n\t}\n\tDEBUG('[decodePubFromBlocks] result:', result, { rootCID: rootCID.toString(), blockStore, applogs: allApplogs })\n\treturn result\n}\n\nexport async function getBlocksOfCar(car: CarReader) {\n\tconst rootsFromCar = await car.getRoots()\n\tconst roots = rootsFromCar.map(c => ((typeof c.toV1 === 'function') ? c : CID.decode(c.bytes)).toV1().toString() as CidString) // HACK\n\tconst blocks = new Map<CidString, any>()\n\tfor await (const { cid: cidFromCarblocks, bytes } of car.blocks()) {\n\t\tconst cid = (typeof cidFromCarblocks.toV1 === 'function') ? cidFromCarblocks : CID.decode(cidFromCarblocks.bytes)\n\t\tVERBOSE({ cidFromCarblocks, cid })\n\t\t// blocks.set(cid.toV1().toString(), dagJson.decode(bytes)) // HACK: tried using CID as map key, but because it's based on referential equality it's not working\n\t\tblocks.set(cid.toV1().toString(), bytes) // HACK: tried using CID as map key, but because it's based on referential equality it's not working\n\t}\n\tif (roots.length !== 1) {\n\t\tWARN('Unexpected roots count:', roots)\n\t}\n\treturn {\n\t\trootCID: CID.parse(roots[0]),\n\t\tblockStore: {\n\t\t\tget: (cid) => blocks.get(cid.toV1().toString()),\n\t\t},\n\t} satisfies DecodedCar\n}\nexport async function getDecodedBlock(blockStore: BlockStoreish, cid: CID) {\n\ttry {\n\t\tvar blob = await blockStore.get(cid)\n\t\tif (!blob) {\n\t\t\tWARN('returning null')\n\t\t\treturn null // I don't think this ever happens actually\n\t\t}\n\t} catch (err) {\n\t\tif ((err as any).message === 'Not Found') return null\n\t\tthrow err\n\t}\n\treturn dagJson.decode(blob)\n}\n\n// make out in the car... been a while but also sounds nice\nexport async function makeCarOut(roots: CIDForCar, blocks: BlockForCar[]) {\n\tconst { writer, out } = CarWriter.create(Array.isArray(roots) ? roots : [roots])\n\n\t// add the blocks to the CAR and close it\n\tVERBOSE(`Writing ${blocks.length} blocks to CAR`, { roots, blocks })\n\tblocks.forEach(b => writer.put(b))\n\twriter.close()\n\t// VERBOSE(`Wrote ${blocks.length} blocks to CAR`, writer)\n\treturn out\n} /** create a new CarWriter, with the encoded block as the root */\n\n// export async function makeCarReader(roots: CIDForCar, blocks: BlockForCar[]) {\n// \tconst out = await makeCarOut(roots, blocks)\n\n// \t// create a new CarReader we can hand to web3.storage.putCar\n// \tconst reader = await CarReader.fromIterable(out)\n// \tVERBOSE(`CAR reader`, reader)\n// \treturn reader\n// } /** create a new CarWriter, with the encoded block as the root */\n\nexport async function makeCarBlob(roots: CIDForCar, blocks: BlockForCar[]) {\n\tconst carOut = await makeCarOut(roots, blocks)\n\tconst chunks = []\n\tfor await (const chunk of carOut) {\n\t\tchunks.push(chunk)\n\t}\n\tconst blob = new Blob(chunks)\n\treturn blob\n}\nexport async function carFromBlob(blob: Blob | File): Promise<CarReader> {\n\treturn CarReader.fromBytes(new Uint8Array(await blob.arrayBuffer()))\n}\n\nfunction extractCids(value: unknown): CID[] {\n\tif (value instanceof CID) return [value]\n\tif (Array.isArray(value)) return value.flatMap(extractCids)\n\tif (value && typeof value === 'object') return Object.values(value).flatMap(extractCids)\n\treturn []\n}\n\nconst MAX_COLLECT_BLOCKS = 1_000_000\n\nexport async function collectDagBlocks(\n\tstartCID: CID,\n\tblockStore: BlockStoreish,\n): Promise<BlockForCar[]> {\n\tconst visited = new Set<string>()\n\tconst blocks: BlockForCar[] = []\n\tconst queue: CID[] = [startCID]\n\n\twhile (queue.length > 0) {\n\t\tif (blocks.length >= MAX_COLLECT_BLOCKS) {\n\t\t\tWARN(`[collectDagBlocks] hit ${MAX_COLLECT_BLOCKS} block limit, returning partial result`)\n\t\t\tbreak\n\t\t}\n\n\t\tconst cid = queue.shift()!\n\t\tconst cidStr = cid.toString()\n\t\tif (visited.has(cidStr)) continue\n\t\tvisited.add(cidStr)\n\n\t\tlet bytes: Uint8Array\n\t\ttry {\n\t\t\tbytes = await blockStore.get(cid)\n\t\t} catch {\n\t\t\tWARN(`[collectDagBlocks] block not found: ${cidStr}, stopping this branch`)\n\t\t\tcontinue\n\t\t}\n\t\tif (!bytes) {\n\t\t\tWARN(`[collectDagBlocks] block not found: ${cidStr}, stopping this branch`)\n\t\t\tcontinue\n\t\t}\n\n\t\tblocks.push({ cid, bytes })\n\n\t\tif (blocks.length % 1000 === 0) {\n\t\t\tLOG(`[collectDagBlocks] collected ${blocks.length} blocks...`)\n\t\t}\n\n\t\ttry {\n\t\t\tconst decoded = dagJson.decode(bytes)\n\t\t\tconst childCids = extractCids(decoded)\n\t\t\tfor (const child of childCids) {\n\t\t\t\tif (!visited.has(child.toString())) {\n\t\t\t\t\tqueue.push(child)\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Not dag-json — leaf block, no children to walk\n\t\t}\n\t}\n\n\tDEBUG(`[collectDagBlocks] collected ${blocks.length} blocks from ${startCID.toString()}`)\n\treturn blocks\n}\n\nexport function streamReaderToIterable(bodyReader: ReadableStreamDefaultReader<Uint8Array>): AsyncIterable<Uint8Array> {\n\treturn (async function*() {\n\t\twhile (true) {\n\t\t\tconst { done, value } = await bodyReader.read()\n\t\t\tVERBOSE(`[car] chunk`, { done, value })\n\t\t\tif (done) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tyield value\n\t\t}\n\t})()\n}\n"],"mappings":"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","names":["dagJson","Logger","WARN","LOG","DEBUG","VERBOSE","ERROR","Logger","share","dagJson","block"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=chunk-7Z5YDQKK.js.map
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveKeyMapper
|
|
3
|
+
} from "./chunk-QZXKQCAY.js";
|
|
4
|
+
import {
|
|
5
|
+
SubscribableImpl,
|
|
6
|
+
ThreadInMemory,
|
|
7
|
+
createDebugName,
|
|
8
|
+
isInitEvent,
|
|
9
|
+
makeFilter,
|
|
10
|
+
memoizedFn,
|
|
11
|
+
rollingFilter
|
|
12
|
+
} from "./chunk-L5EEEGE6.js";
|
|
13
|
+
|
|
14
|
+
// src/query/divergences.ts
|
|
15
|
+
import { Logger } from "besonders-logger";
|
|
16
|
+
var { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO);
|
|
17
|
+
var queryDivergencesByPrev = memoizedFn("queryDivergencesByPrev", function queryConflictingByPrev(sourceThread) {
|
|
18
|
+
DEBUG(`queryDivergencesByPrev<${sourceThread.nameAndSizeUntracked}>`);
|
|
19
|
+
if (sourceThread.filters.includes("lastWriteWins")) WARN(`queryDivergencesByPrev on thread lastWriteWins`, sourceThread);
|
|
20
|
+
const logsForNode = /* @__PURE__ */ new Map();
|
|
21
|
+
const leafs = /* @__PURE__ */ new Set();
|
|
22
|
+
VERBOSE("all applogs:", sourceThread.applogs);
|
|
23
|
+
for (const log of sourceThread.applogs) {
|
|
24
|
+
let prevLogs;
|
|
25
|
+
if (log.pv) {
|
|
26
|
+
prevLogs = log.pv && logsForNode.get(log.pv.toString());
|
|
27
|
+
leafs.delete(log.pv.toString());
|
|
28
|
+
}
|
|
29
|
+
VERBOSE("traversing log", { log, prevLogs, leafs: Array.from(leafs) });
|
|
30
|
+
logsForNode.set(log.cid, prevLogs ? [...prevLogs, log] : [log]);
|
|
31
|
+
leafs.add(log.cid);
|
|
32
|
+
}
|
|
33
|
+
const divergences = Array.from(leafs).map((leafID) => {
|
|
34
|
+
const thread = new ThreadInMemory(
|
|
35
|
+
createDebugName({
|
|
36
|
+
caller: "DivergenceLeaf",
|
|
37
|
+
thread: sourceThread,
|
|
38
|
+
pattern: `leaf: ${leafID}`
|
|
39
|
+
}),
|
|
40
|
+
logsForNode.get(leafID),
|
|
41
|
+
sourceThread.filters,
|
|
42
|
+
true
|
|
43
|
+
);
|
|
44
|
+
return { log: thread.latestLog, thread };
|
|
45
|
+
});
|
|
46
|
+
return divergences;
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// src/query/matchers.ts
|
|
50
|
+
function includes(str) {
|
|
51
|
+
return (vl) => vl?.includes?.(str);
|
|
52
|
+
}
|
|
53
|
+
function includedIn(arr) {
|
|
54
|
+
return (vl) => arr?.includes?.(vl);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// src/query/entity-collection.ts
|
|
58
|
+
import { Logger as Logger2 } from "besonders-logger";
|
|
59
|
+
var { DEBUG: DEBUG2 } = Logger2.setup(Logger2.INFO);
|
|
60
|
+
function liveEntityCollection(thread, discoveryPattern, liveAttributes, opts) {
|
|
61
|
+
return _liveEntityCollection(
|
|
62
|
+
thread,
|
|
63
|
+
discoveryPattern,
|
|
64
|
+
liveAttributes,
|
|
65
|
+
opts
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
var _liveEntityCollection = memoizedFn(
|
|
69
|
+
"liveEntityCollection",
|
|
70
|
+
function liveEntityCollection2(thread, discoveryPattern, liveAttributes, opts) {
|
|
71
|
+
DEBUG2("liveEntityCollection", discoveryPattern, liveAttributes);
|
|
72
|
+
const discoveryAttr = discoveryPattern.at;
|
|
73
|
+
const allAttrs = /* @__PURE__ */ new Set([discoveryAttr, ...liveAttributes]);
|
|
74
|
+
const filtered = rollingFilter(thread, { at: [...allAttrs] });
|
|
75
|
+
const isDiscoveryMatch = makeFilter(discoveryPattern);
|
|
76
|
+
const attrSet = new Set(liveAttributes);
|
|
77
|
+
const key = resolveKeyMapper(opts);
|
|
78
|
+
const map = /* @__PURE__ */ new Map();
|
|
79
|
+
function makeRecord(entityId) {
|
|
80
|
+
const record = {};
|
|
81
|
+
for (const attr of liveAttributes) record[key(attr)] = null;
|
|
82
|
+
for (const log of filtered.applogs) {
|
|
83
|
+
if (log.en === entityId && attrSet.has(log.at)) {
|
|
84
|
+
record[key(log.at)] = log.vl;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return record;
|
|
88
|
+
}
|
|
89
|
+
function buildFull(applogs) {
|
|
90
|
+
map.clear();
|
|
91
|
+
for (const log of isDiscoveryMatch(applogs)) {
|
|
92
|
+
if (!map.has(log.en)) map.set(log.en, makeRecord(log.en));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function addLog(log) {
|
|
96
|
+
if (isDiscoveryMatch([log]).length > 0 && !map.has(log.en)) {
|
|
97
|
+
map.set(log.en, makeRecord(log.en));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (attrSet.has(log.at)) {
|
|
101
|
+
const record = map.get(log.en);
|
|
102
|
+
if (record) record[key(log.at)] = log.vl;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function removeLog(log) {
|
|
106
|
+
if (isDiscoveryMatch([log]).length > 0) {
|
|
107
|
+
const stillDiscovered = filtered.applogs.some(
|
|
108
|
+
(l) => l.en === log.en && isDiscoveryMatch([l]).length > 0
|
|
109
|
+
);
|
|
110
|
+
if (!stillDiscovered) {
|
|
111
|
+
map.delete(log.en);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (attrSet.has(log.at)) {
|
|
116
|
+
const record = map.get(log.en);
|
|
117
|
+
if (record) {
|
|
118
|
+
const current = filtered.applogs.find((l) => l.en === log.en && l.at === log.at);
|
|
119
|
+
record[key(log.at)] = current?.vl ?? null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
buildFull(filtered.applogs);
|
|
124
|
+
const result = new SubscribableImpl(
|
|
125
|
+
map,
|
|
126
|
+
() => filtered.subscribe((event) => {
|
|
127
|
+
if (isInitEvent(event)) {
|
|
128
|
+
buildFull(event.init);
|
|
129
|
+
} else {
|
|
130
|
+
if (event.removed) for (const log of event.removed) removeLog(log);
|
|
131
|
+
for (const log of event.added) addLog(log);
|
|
132
|
+
}
|
|
133
|
+
result._set(map);
|
|
134
|
+
}, "derived"),
|
|
135
|
+
{ equals: false }
|
|
136
|
+
);
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
export {
|
|
142
|
+
queryDivergencesByPrev,
|
|
143
|
+
includes,
|
|
144
|
+
includedIn,
|
|
145
|
+
liveEntityCollection
|
|
146
|
+
};
|
|
147
|
+
//# sourceMappingURL=chunk-CPSDKFBG.js.map
|