@wovin/core 0.3.3 → 0.3.5

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.
Files changed (52) hide show
  1. package/dist/applog/applog-utils.d.ts +12 -1
  2. package/dist/applog/applog-utils.d.ts.map +1 -1
  3. package/dist/applog.js +5 -1
  4. package/dist/{chunk-H4YVJKB7.js → chunk-AFRRFDNL.js} +2 -2
  5. package/dist/{chunk-BIYQEX3N.js → chunk-B22AIVJH.js} +2 -2
  6. package/dist/{chunk-6CSJTSQP.js → chunk-EZZVLYYC.js} +3 -3
  7. package/dist/{chunk-H3JNNTVP.js → chunk-IC6WD7RV.js} +27 -6
  8. package/dist/chunk-IC6WD7RV.js.map +1 -0
  9. package/dist/{chunk-4MKPGQIM.js → chunk-OUQE6LG4.js} +138 -64
  10. package/dist/chunk-OUQE6LG4.js.map +1 -0
  11. package/dist/{chunk-N7SEGHU4.js → chunk-PNNJMXZI.js} +33 -24
  12. package/dist/chunk-PNNJMXZI.js.map +1 -0
  13. package/dist/{chunk-N5QPZNKD.js → chunk-PSIMJH6F.js} +3 -3
  14. package/dist/index.js +11 -7
  15. package/dist/ipfs.js +4 -4
  16. package/dist/ipns/ipns-record.d.ts.map +1 -1
  17. package/dist/ipns/ipns-watcher.d.ts.map +1 -1
  18. package/dist/ipns.js +6 -8
  19. package/dist/ipns.js.map +1 -1
  20. package/dist/pubsub/snap-push.d.ts.map +1 -1
  21. package/dist/pubsub.js +4 -4
  22. package/dist/query/basic.d.ts.map +1 -1
  23. package/dist/query.js +3 -3
  24. package/dist/retrieve.js +4 -4
  25. package/dist/thread/basic.d.ts +18 -1
  26. package/dist/thread/basic.d.ts.map +1 -1
  27. package/dist/thread/mapped.d.ts +3 -1
  28. package/dist/thread/mapped.d.ts.map +1 -1
  29. package/dist/thread/utils.d.ts.map +1 -1
  30. package/dist/thread/writeable.d.ts.map +1 -1
  31. package/dist/thread.js +1 -1
  32. package/dist/viewmodel/index.js +2 -2
  33. package/package.json +1 -1
  34. package/src/applog/applog-utils.ts +33 -1
  35. package/src/ipns/ipns-record.test.ts +72 -0
  36. package/src/ipns/ipns-record.ts +23 -8
  37. package/src/ipns/ipns-watcher.ts +10 -11
  38. package/src/pubsub/snap-push.ts +25 -3
  39. package/src/query/basic.ts +124 -81
  40. package/src/thread/basic.ts +52 -5
  41. package/src/thread/insertMissing-perf.test.ts +95 -0
  42. package/src/thread/mapped.ts +25 -5
  43. package/src/thread/membership-cache.test.ts +133 -0
  44. package/src/thread/utils.ts +5 -5
  45. package/src/thread/writeable.ts +2 -1
  46. package/dist/chunk-4MKPGQIM.js.map +0 -1
  47. package/dist/chunk-H3JNNTVP.js.map +0 -1
  48. package/dist/chunk-N7SEGHU4.js.map +0 -1
  49. /package/dist/{chunk-H4YVJKB7.js.map → chunk-AFRRFDNL.js.map} +0 -0
  50. /package/dist/{chunk-BIYQEX3N.js.map → chunk-B22AIVJH.js.map} +0 -0
  51. /package/dist/{chunk-6CSJTSQP.js.map → chunk-EZZVLYYC.js.map} +0 -0
  52. /package/dist/{chunk-N5QPZNKD.js.map → chunk-PSIMJH6F.js.map} +0 -0
@@ -1,4 +1,15 @@
1
- import type { Applog, ApplogValue, DatalogQueryPattern, DatalogQueryResultEntry, ResultContext, SearchContext, ValueOrMatcher } from './datom-types.ts';
1
+ import type { Applog, ApplogOfSomeSort, ApplogValue, DatalogQueryPattern, DatalogQueryResultEntry, ResultContext, SearchContext, ValueOrMatcher } from './datom-types.ts';
2
+ /**
3
+ * One-line, bounded summary of a single applog — enough to trace it in logs
4
+ * (`en/at=vl@ts#cid`) without dumping the full object (and, for arrays, the whole thread).
5
+ * Handles encrypted applogs and falsy entries so it's safe on error paths.
6
+ */
7
+ export declare const applogSummary: (log: ApplogOfSomeSort | null | undefined) => string;
8
+ /**
9
+ * Bounded summary of an applog array: `[count] first, few, summaries …+N`.
10
+ * Keeps enough identity to debug (which logs, how many) while preventing log explosion.
11
+ */
12
+ export declare const applogsSummary: (logs: readonly (ApplogOfSomeSort | null | undefined)[] | null | undefined, sample?: number) => string;
2
13
  export declare const isoDateStrCompare: (strA: string, strB: string, dir?: "asc" | "desc") => number;
3
14
  export declare const objEqualByKeys: (keys: string[], objA: object, objB: object) => boolean;
4
15
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"applog-utils.d.ts","sourceRoot":"","sources":["../../src/applog/applog-utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"applog-utils.d.ts","sourceRoot":"","sources":["../../src/applog/applog-utils.ts"],"names":[],"mappings":"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"}
package/dist/applog.js CHANGED
@@ -11,6 +11,8 @@ import {
11
11
  Nullable,
12
12
  URL,
13
13
  actualize,
14
+ applogSummary,
15
+ applogsSummary,
14
16
  areApplogsEqual,
15
17
  arrStats,
16
18
  arraysContainSameElements,
@@ -52,7 +54,7 @@ import {
52
54
  withAg,
53
55
  withPvFrom,
54
56
  withTs
55
- } from "./chunk-4MKPGQIM.js";
57
+ } from "./chunk-OUQE6LG4.js";
56
58
  import "./chunk-ZAADLBSB.js";
57
59
  export {
58
60
  AppLogNoCidTB,
@@ -66,6 +68,8 @@ export {
66
68
  Nullable,
67
69
  URL,
68
70
  actualize,
71
+ applogSummary,
72
+ applogsSummary,
69
73
  areApplogsEqual,
70
74
  arrStats,
71
75
  arraysContainSameElements,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  cyrb53hash,
3
3
  ensureTsPvAndFinalizeApplog
4
- } from "./chunk-4MKPGQIM.js";
4
+ } from "./chunk-OUQE6LG4.js";
5
5
 
6
6
  // src/pubsub/pub-pull.ts
7
7
  import { Logger } from "besonders-logger";
@@ -37,4 +37,4 @@ export {
37
37
  isSubscription,
38
38
  agentToShortHash
39
39
  };
40
- //# sourceMappingURL=chunk-H4YVJKB7.js.map
40
+ //# sourceMappingURL=chunk-AFRRFDNL.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  areCidsEqual
3
- } from "./chunk-4MKPGQIM.js";
3
+ } from "./chunk-OUQE6LG4.js";
4
4
 
5
5
  // src/ipfs/fetch-snapshot-chain.ts
6
6
  import * as dagJson from "@ipld/dag-json";
@@ -83,4 +83,4 @@ function createMemoryBlockStore() {
83
83
  export {
84
84
  fetchSnapshotChainUntil
85
85
  };
86
- //# sourceMappingURL=chunk-BIYQEX3N.js.map
86
+ //# sourceMappingURL=chunk-B22AIVJH.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  unchunkApplogsBlock
3
- } from "./chunk-H3JNNTVP.js";
3
+ } from "./chunk-IC6WD7RV.js";
4
4
  import {
5
5
  areCidsEqual,
6
6
  removeDuplicateAppLogs
7
- } from "./chunk-4MKPGQIM.js";
7
+ } from "./chunk-OUQE6LG4.js";
8
8
 
9
9
  // src/retrieve/update-thread.ts
10
10
  import * as dagJson from "@ipld/dag-json";
@@ -141,4 +141,4 @@ export {
141
141
  withBlockCache,
142
142
  updateThreadFromSnapshot
143
143
  };
144
- //# sourceMappingURL=chunk-6CSJTSQP.js.map
144
+ //# sourceMappingURL=chunk-EZZVLYYC.js.map
@@ -3,16 +3,17 @@ import {
3
3
  } from "./chunk-YDAKBU6Q.js";
4
4
  import {
5
5
  lastWriteWins
6
- } from "./chunk-N7SEGHU4.js";
6
+ } from "./chunk-PNNJMXZI.js";
7
7
  import {
8
8
  anyOf,
9
+ applogsSummary,
9
10
  areCidsEqual,
10
11
  encodeBlockOriginal,
11
12
  ensureTsPvAndFinalizeApplog,
12
13
  getLogsFromThread,
13
14
  prepareForPub,
14
15
  rollingFilter
15
- } from "./chunk-4MKPGQIM.js";
16
+ } from "./chunk-OUQE6LG4.js";
16
17
 
17
18
  // src/pubsub/snap-push.ts
18
19
  import * as dagJson2 from "@ipld/dag-json";
@@ -333,10 +334,30 @@ async function prepareSnapshotForPush(agent, appThread, threadToPublish, share,
333
334
  const applogsToEncode = keepTruthy(maybeEncryptedApplogs);
334
335
  const infologsToEncode = keepTruthy(infoLogs);
335
336
  if (!applogsToEncode.length) {
336
- throw ERROR2("no valid applogs", { agent, maybeEncryptedApplogs, infoLogs, applogsToEncode, infologsToEncode, prevSnapCID });
337
+ throw ERROR2("no valid applogs", {
338
+ agent: agent.did,
339
+ prevSnapCID: prevSnapCID?.toString(),
340
+ counts: {
341
+ rawApplogs: maybeEncryptedApplogs.length,
342
+ keptApplogs: applogsToEncode.length,
343
+ rawInfo: infoLogs.length,
344
+ keptInfo: infologsToEncode.length
345
+ },
346
+ rawApplogsSample: applogsSummary(maybeEncryptedApplogs)
347
+ });
337
348
  }
338
349
  if (!infologsToEncode.length) {
339
- throw ERROR2("no valid infologs", { agent, maybeEncryptedApplogs, infoLogs, applogsToEncode, infologsToEncode, prevSnapCID });
350
+ throw ERROR2("no valid infologs", {
351
+ agent: agent.did,
352
+ prevSnapCID: prevSnapCID?.toString(),
353
+ counts: {
354
+ rawApplogs: maybeEncryptedApplogs.length,
355
+ keptApplogs: applogsToEncode.length,
356
+ rawInfo: infoLogs.length,
357
+ keptInfo: infologsToEncode.length
358
+ },
359
+ rawInfoSample: applogsSummary(infoLogs)
360
+ });
340
361
  }
341
362
  const encodedSnapshot = await encodeSnapshotAsCar(agent, applogsToEncode, infologsToEncode, prevSnapCID, prevCounter);
342
363
  DEBUG2("inPrepareSnapshotForPush", { encodedSnapshot });
@@ -406,7 +427,7 @@ function isSnapBlockChunks(block) {
406
427
  }
407
428
  async function encodeSnapshotApplogsAsCar(applogs) {
408
429
  const encoded = await encodeApplogsAsIPLD(applogs);
409
- if (!encoded) throw ERROR2("invalid applogs cannot continue", { applogs, encoded });
430
+ if (!encoded) throw ERROR2("invalid applogs cannot continue", { encoded, applogs: applogsSummary(applogs) });
410
431
  const { cids, encodedApplogs } = encoded;
411
432
  const root = { applogs: cids };
412
433
  const encodedRoot = await encodeBlockOriginal(root);
@@ -445,4 +466,4 @@ export {
445
466
  collectDagBlocks,
446
467
  streamReaderToIterable
447
468
  };
448
- //# sourceMappingURL=chunk-H3JNNTVP.js.map
469
+ //# sourceMappingURL=chunk-IC6WD7RV.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 { applogsSummary } from '../applog/applog-utils.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 { anyOf } from '../query/matchers.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: anyOf('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\t// all applogs were filtered out as falsy — show raw→kept counts + a sample so we can see what came in\n\t\tthrow ERROR('no valid applogs', {\n\t\t\tagent: agent.did,\n\t\t\tprevSnapCID: prevSnapCID?.toString(),\n\t\t\tcounts: {\n\t\t\t\trawApplogs: maybeEncryptedApplogs.length,\n\t\t\t\tkeptApplogs: applogsToEncode.length,\n\t\t\t\trawInfo: infoLogs.length,\n\t\t\t\tkeptInfo: infologsToEncode.length,\n\t\t\t},\n\t\t\trawApplogsSample: applogsSummary(maybeEncryptedApplogs),\n\t\t})\n\t}\n\tif (!infologsToEncode.length) {\n\t\tthrow ERROR('no valid infologs', {\n\t\t\tagent: agent.did,\n\t\t\tprevSnapCID: prevSnapCID?.toString(),\n\t\t\tcounts: {\n\t\t\t\trawApplogs: maybeEncryptedApplogs.length,\n\t\t\t\tkeptApplogs: applogsToEncode.length,\n\t\t\t\trawInfo: infoLogs.length,\n\t\t\t\tkeptInfo: infologsToEncode.length,\n\t\t\t},\n\t\t\trawInfoSample: applogsSummary(infoLogs),\n\t\t})\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 | null | undefined, blockStore: BlockStoreish): Promise<CID[]> {\n\tif (!block) return []\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 | null | undefined): block is SnapBlockChunks {\n\treturn !!block && 'chunks' in block\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', { encoded, applogs: applogsSummary(applogs) })\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\tif (!applogsBlock) {\n\t\t\t\tthrow ERROR('[decodePubFromBlocks] applogs block missing from blockStore', {\n\t\t\t\t\tcid: root.applogs.toString(),\n\t\t\t\t\trootCID: cidStr,\n\t\t\t\t})\n\t\t\t}\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\tconst decoded = (await getDecodedBlock(blockStore, root.info)) as SnapBlockLogs\n\t\t\t\tif (decoded) {\n\t\t\t\t\tfirstInfo = decoded\n\t\t\t\t\tDEBUG(`new format - infoLogs`, firstInfo.logs.map(l => ({ [l.toString()]: l })))\n\t\t\t\t} else {\n\t\t\t\t\tWARN(`[decodePubFromBlocks] info block not found for ${root.info}, using empty info`)\n\t\t\t\t\tfirstInfo = { logs: [] }\n\t\t\t\t}\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"]}
@@ -11,7 +11,76 @@ import { isBefore } from "date-fns";
11
11
  import { partial, pick } from "lodash-es";
12
12
  import { isEqual } from "lodash-es";
13
13
  import stringify from "safe-stable-stringify";
14
+
15
+ // src/applog/datom-types.ts
16
+ import { FormatRegistry, Type } from "@sinclair/typebox";
17
+ import { TypeCompiler } from "@sinclair/typebox/compiler";
18
+ var Nullable = (schema) => Type.Union([schema, Type.Null()]);
19
+ var EntityID_LENGTH = 7;
20
+ var isCID = /^(k51qz|baguq)[0-9a-z]{56,57}$/;
21
+ var isShortHash = /^[0-9A-Fa-f]{7,8}$/g;
22
+ FormatRegistry.Set("EntityID", (value) => !!value.match(isShortHash) || !!value.match(isCID));
23
+ var EntityID = Type.String();
24
+ var isEncryptedApplog = (l) => l?.enc instanceof Uint8Array;
25
+ FormatRegistry.Set("CID", (value) => !!value.match(isCID));
26
+ var CIDTB = Type.String({ pattern: isCID.source });
27
+ var isURL = /^http([s]?):\/\/.*\..*/;
28
+ FormatRegistry.Set("URL", (value) => !!value.match(isURL));
29
+ var URL = Type.String({ pattern: isURL.source });
30
+ var JsonValueTB = Type.Recursive(
31
+ (This) => Type.Union([
32
+ Type.String(),
33
+ Type.Number(),
34
+ Type.Boolean(),
35
+ Type.Null(),
36
+ Type.Array(This),
37
+ Type.Record(Type.String(), This)
38
+ ])
39
+ );
40
+ var AppLogNoCidTB = Type.Object({
41
+ en: EntityID,
42
+ // EntityID
43
+ at: Type.String(),
44
+ // Attribute
45
+ vl: JsonValueTB,
46
+ // ApplogValue (JSON-serializable: primitives, arrays, objects)
47
+ ts: Type.String(),
48
+ // Timestamp
49
+ ag: Type.String(),
50
+ // AgentHash
51
+ pv: Nullable(CIDTB)
52
+ // CidString
53
+ });
54
+ var AppLogNoCidTBC = TypeCompiler.Compile(AppLogNoCidTB);
55
+ var getApplogNoCidTypeErrors = (obj) => Array.from(AppLogNoCidTBC.Errors(obj));
56
+ var isValidApplogNoCid = AppLogNoCidTBC.Check.bind(AppLogNoCidTBC);
57
+ var AppLogTB = Type.Composite([
58
+ Type.Object({
59
+ cid: CIDTB
60
+ }),
61
+ AppLogNoCidTB
62
+ ]);
63
+ var AppLogTBC = TypeCompiler.Compile(AppLogTB);
64
+ var getApplogTypeErrors = (obj) => Array.from(AppLogTBC.Errors(obj));
65
+ var isValidApplog = AppLogTBC.Check.bind(AppLogTBC);
66
+
67
+ // src/applog/applog-utils.ts
14
68
  var { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO);
69
+ var applogSummary = (log) => {
70
+ if (!log) return "\u2205";
71
+ const a = log;
72
+ const cid = a.cid ? `#${String(a.cid).slice(-6)}` : "";
73
+ if (isEncryptedApplog(log)) return `enc[${log.enc.length}B]${cid}`;
74
+ const vl = a.vl === void 0 ? "\u2205" : JSON.stringify(a.vl) ?? String(a.vl);
75
+ const vlStr = vl.length > 32 ? `${vl.slice(0, 32)}\u2026` : vl;
76
+ return `${a.en}/${a.at}=${vlStr}${a.ts ? `@${a.ts}` : ""}${cid}`;
77
+ };
78
+ var applogsSummary = (logs, sample = 3) => {
79
+ if (!logs) return "\u2205";
80
+ if (!logs.length) return "[0]";
81
+ const shown = logs.slice(0, sample).map(applogSummary).join(", ");
82
+ return `[${logs.length}] ${shown}${logs.length > sample ? ` \u2026+${logs.length - sample}` : ""}`;
83
+ };
15
84
  var isoDateStrCompare = (strA, strB, dir = "asc") => dir === "asc" ? strA.localeCompare(strB, "en-US") : strB.localeCompare(strA, "en-US");
16
85
  var objEqualByKeys = (keys, objA, objB) => {
17
86
  return isEqual(pick(objA, keys), pick(objB, keys));
@@ -100,7 +169,9 @@ function topoSortByPv(logs, dir) {
100
169
  visited.add(log.cid);
101
170
  result.push(log);
102
171
  const children = childrenByPv.get(log.cid);
103
- if (children) for (let i = children.length - 1; i >= 0; i--) stack.push(children[i]);
172
+ if (children) {
173
+ for (let i = children.length - 1; i >= 0; i--) stack.push(children[i]);
174
+ }
104
175
  }
105
176
  if (result.length < logs.length) {
106
177
  for (const log of logs) if (!visited.has(log.cid)) result.push(log);
@@ -560,6 +631,16 @@ var Thread = class {
560
631
  _subscribers = [];
561
632
  /** Monotonic counter incremented on every mutation. Used by memoizedFn to invalidate caches. */
562
633
  _version = 0;
634
+ /**
635
+ * Memoized cid→membership lookups, rebuilt lazily on first read after a mutation.
636
+ * Previously these getters rebuilt a fresh Set/Map on EVERY access, which turned a
637
+ * bulk `insertMissing(N)` (N × hasApplog over a thread of M) into O(N·M) — pegging a
638
+ * core for tens of minutes on ~90k-applog threads. Now the collection is built once
639
+ * per mutation batch and reused across the whole filter loop. Invalidated in
640
+ * {@link invalidateApplogCaches}, called from every `_applogs` mutation path.
641
+ */
642
+ _cidSet = null;
643
+ _byCid = null;
563
644
  get readOnly() {
564
645
  if (this.parents.length !== 1) return true;
565
646
  return this.parents[0].readOnly;
@@ -584,9 +665,23 @@ var Thread = class {
584
665
  if (idx >= 0) list.splice(idx, 1);
585
666
  };
586
667
  }
668
+ /**
669
+ * Drop memoized cid lookups. MUST be called from every path that mutates `_applogs`
670
+ * (or reassigns it). {@link notifySubscribers} covers the notify-emitting mutations
671
+ * (insertRaw, MappedThread remap/parent-update); non-notifying mutations (e.g.
672
+ * {@link WriteableThread.purge}) must call this explicitly.
673
+ */
674
+ invalidateApplogCaches() {
675
+ this._cidSet = null;
676
+ this._byCid = null;
677
+ }
587
678
  notifySubscribers(event) {
588
679
  this._version++;
589
- DEBUG2(`[thread: ${this.name}] notifying`, this._derivedSubscribers.length, "derived +", this._subscribers.length, "subscribers of", { ...event, subs: this._subscribers });
680
+ this.invalidateApplogCaches();
681
+ DEBUG2(`[thread: ${this.name}] notifying`, this._derivedSubscribers.length, "derived +", this._subscribers.length, "subscribers of", {
682
+ ...event,
683
+ subs: this._subscribers
684
+ });
590
685
  const derived = [...this._derivedSubscribers];
591
686
  for (const subscriber of derived) {
592
687
  subscriber(event);
@@ -611,7 +706,10 @@ var Thread = class {
611
706
  return this._applogs.map((l) => l.cid);
612
707
  }
613
708
  get applogsCidSet() {
614
- return new Set(this._applogs.map((l) => l.cid));
709
+ if (this._cidSet === null) {
710
+ this._cidSet = new Set(this._applogs.map((l) => l.cid));
711
+ }
712
+ return this._cidSet;
615
713
  }
616
714
  map(fn) {
617
715
  return this.applogs.map(fn);
@@ -640,7 +738,10 @@ var Thread = class {
640
738
  return this.applogsCidSet.has(cid.toString());
641
739
  }
642
740
  get applogsByCid() {
643
- return new Map(this.applogs.map((log) => [log.cid, log]));
741
+ if (this._byCid === null) {
742
+ this._byCid = new Map(this._applogs.map((log) => [log.cid, log]));
743
+ }
744
+ return this._byCid;
644
745
  }
645
746
  getApplog(cid) {
646
747
  return this.applogsByCid.get(cid.toString());
@@ -676,6 +777,17 @@ var Thread = class {
676
777
  get hasParents() {
677
778
  return !!this.parents?.length;
678
779
  }
780
+ // Compact representation for server-side / plain console logging (Node's util.inspect).
781
+ // ⚠ Only consulted by Node — browser devtools ignore this symbol and keep rendering the
782
+ // live, expandable object, so passing `thread` to a logger stays clickable in devtools
783
+ // while no longer splatting every applog + the whole parent chain + subscribers to stdout.
784
+ [/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
785
+ try {
786
+ return `${this.constructor.name}<${this.nameAndSizeUntracked}${this.filters?.length ? ` |${this.filters.join(",")}` : ""}>`;
787
+ } catch {
788
+ return `${this.constructor.name}<${this.name} (size?)>`;
789
+ }
790
+ }
679
791
  };
680
792
  var getLogsFromThread = (logsOrThread) => logsOrThread instanceof Thread ? logsOrThread.applogs : logsOrThread;
681
793
  var StaticThread = class _StaticThread extends Thread {
@@ -703,60 +815,6 @@ import { sha256 } from "@noble/hashes/sha2.js";
703
815
  import { Logger as Logger3 } from "besonders-logger";
704
816
  import { CID, digest as Digest } from "multiformats";
705
817
  import { encode as multiformatsEncode } from "multiformats/block";
706
-
707
- // src/applog/datom-types.ts
708
- import { FormatRegistry, Type } from "@sinclair/typebox";
709
- import { TypeCompiler } from "@sinclair/typebox/compiler";
710
- var Nullable = (schema) => Type.Union([schema, Type.Null()]);
711
- var EntityID_LENGTH = 7;
712
- var isCID = /^(k51qz|baguq)[0-9a-z]{56,57}$/;
713
- var isShortHash = /^[0-9A-Fa-f]{7,8}$/g;
714
- FormatRegistry.Set("EntityID", (value) => !!value.match(isShortHash) || !!value.match(isCID));
715
- var EntityID = Type.String();
716
- var isEncryptedApplog = (l) => l?.enc instanceof Uint8Array;
717
- FormatRegistry.Set("CID", (value) => !!value.match(isCID));
718
- var CIDTB = Type.String({ pattern: isCID.source });
719
- var isURL = /^http([s]?):\/\/.*\..*/;
720
- FormatRegistry.Set("URL", (value) => !!value.match(isURL));
721
- var URL = Type.String({ pattern: isURL.source });
722
- var JsonValueTB = Type.Recursive(
723
- (This) => Type.Union([
724
- Type.String(),
725
- Type.Number(),
726
- Type.Boolean(),
727
- Type.Null(),
728
- Type.Array(This),
729
- Type.Record(Type.String(), This)
730
- ])
731
- );
732
- var AppLogNoCidTB = Type.Object({
733
- en: EntityID,
734
- // EntityID
735
- at: Type.String(),
736
- // Attribute
737
- vl: JsonValueTB,
738
- // ApplogValue (JSON-serializable: primitives, arrays, objects)
739
- ts: Type.String(),
740
- // Timestamp
741
- ag: Type.String(),
742
- // AgentHash
743
- pv: Nullable(CIDTB)
744
- // CidString
745
- });
746
- var AppLogNoCidTBC = TypeCompiler.Compile(AppLogNoCidTB);
747
- var getApplogNoCidTypeErrors = (obj) => Array.from(AppLogNoCidTBC.Errors(obj));
748
- var isValidApplogNoCid = AppLogNoCidTBC.Check.bind(AppLogNoCidTBC);
749
- var AppLogTB = Type.Composite([
750
- Type.Object({
751
- cid: CIDTB
752
- }),
753
- AppLogNoCidTB
754
- ]);
755
- var AppLogTBC = TypeCompiler.Compile(AppLogTB);
756
- var getApplogTypeErrors = (obj) => Array.from(AppLogTBC.Errors(obj));
757
- var isValidApplog = AppLogTBC.Check.bind(AppLogTBC);
758
-
759
- // src/ipfs/ipfs-utils.ts
760
818
  import { base36 } from "multiformats/bases/base36";
761
819
  import { sha256 as sha265Hasher } from "multiformats/hashes/sha2";
762
820
  var { WARN: WARN3, LOG: LOG3, DEBUG: DEBUG3, VERBOSE: VERBOSE3, ERROR: ERROR3 } = Logger3.setup(Logger3.INFO);
@@ -1069,6 +1127,7 @@ function refCountedMemoizedFn(name, fn, opts) {
1069
1127
  import { Logger as Logger5 } from "besonders-logger";
1070
1128
  import { sortedIndexBy } from "lodash-es";
1071
1129
  var { WARN: WARN5, LOG: LOG5, DEBUG: DEBUG5, VERBOSE: VERBOSE5, ERROR: ERROR5 } = Logger5.setup(Logger5.INFO);
1130
+ var threadEventSummary = (e) => isInitEvent(e) ? `init ${applogsSummary(e.init)}` : `added ${applogsSummary(e.added)}${e.removed ? ` removed ${applogsSummary(e.removed)}` : ""}`;
1072
1131
  var MappedThread = class _MappedThread extends Thread {
1073
1132
  // mapped to unsubscribe function
1074
1133
  constructor(name, parents, filters, _derivation, _writeMapper = null, _readOnly) {
@@ -1215,9 +1274,10 @@ var MappedThread = class _MappedThread extends Thread {
1215
1274
  this._applogs.splice(idx, 1);
1216
1275
  } else {
1217
1276
  throw ERROR5(`MappedThread{${this.name}} toRemove: log not found`, toRemove, {
1218
- thread: this,
1219
- event,
1220
- result
1277
+ thread: this.nameAndSizeUntracked,
1278
+ currentLogs: applogsSummary(this._applogs),
1279
+ event: threadEventSummary(event),
1280
+ result: threadEventSummary(result)
1221
1281
  });
1222
1282
  }
1223
1283
  }
@@ -1228,6 +1288,17 @@ var MappedThread = class _MappedThread extends Thread {
1228
1288
  get readOnly() {
1229
1289
  return this._readOnly ?? false;
1230
1290
  }
1291
+ // A no-derivation MappedThread SHARES its parent's `_applogs` array (see constructor) and never
1292
+ // mutates it itself — the parent does, and the parent invalidates only its own cid caches. So a
1293
+ // local cache here would go stale after a parent insert. Delegate membership lookups to the parent
1294
+ // (chaining up to the array's real owner), whose cache is always fresh. Derived threads own their
1295
+ // array and use the inherited, self-invalidating cache.
1296
+ get applogsCidSet() {
1297
+ return this._derivation ? super.applogsCidSet : this.parents[0].applogsCidSet;
1298
+ }
1299
+ get applogsByCid() {
1300
+ return this._derivation ? super.applogsByCid : this.parents[0].applogsByCid;
1301
+ }
1231
1302
  };
1232
1303
 
1233
1304
  // src/thread/filters.ts
@@ -1591,6 +1662,7 @@ var WriteableThread = class extends Thread {
1591
1662
  purge(cidsToPurge) {
1592
1663
  const beforeCount = this.applogs.length;
1593
1664
  this._applogs = this.applogs.filter((log) => !cidsToPurge.includes(log.cid));
1665
+ this.invalidateApplogCaches();
1594
1666
  return beforeCount - this.applogs.length;
1595
1667
  }
1596
1668
  insert(appLogsToInsert) {
@@ -1736,7 +1808,7 @@ function debounceWrites(thread, wait = 700, removeDuplicatesWith = compareApplog
1736
1808
  if (thread.readOnly) throw ERROR9(`[debounceWrites] but readOnly thread`, thread.name);
1737
1809
  let insertQueue = [];
1738
1810
  const debouncedCommit = debounce(() => {
1739
- WARN9(`Debounce tail`, { thread, mappedThread, insertQueue });
1811
+ DEBUG9(`Debounce tail`, { thread: thread.nameAndSizeUntracked, queued: applogsSummary(insertQueue) });
1740
1812
  const toInsert = ensureTsPvAndFinalizeApplogs(
1741
1813
  // ? uniq, sure - but which one is used? (update: seems the first one, so reverse)
1742
1814
  uniqWith(insertQueue.reverse(), removeDuplicatesWith),
@@ -1746,7 +1818,7 @@ function debounceWrites(thread, wait = 700, removeDuplicatesWith = compareApplog
1746
1818
  insertQueue.splice(0, insertQueue.length);
1747
1819
  }, wait);
1748
1820
  const handleInsert = (applogs) => {
1749
- DEBUG9(`Debounce input:`, applogs, { thread, mappedThread, insertQueue });
1821
+ DEBUG9(`Debounce input:`, applogsSummary(applogs), { thread: thread.nameAndSizeUntracked, queued: insertQueue.length });
1750
1822
  insertQueue.push(...applogs);
1751
1823
  debouncedCommit();
1752
1824
  return null;
@@ -1843,6 +1915,8 @@ export {
1843
1915
  ensureValidCIDinstance,
1844
1916
  areCidsEqual,
1845
1917
  containsCid,
1918
+ applogSummary,
1919
+ applogsSummary,
1846
1920
  isoDateStrCompare,
1847
1921
  objEqualByKeys,
1848
1922
  valueEq,
@@ -1919,4 +1993,4 @@ export {
1919
1993
  withPvFrom,
1920
1994
  joinThreads
1921
1995
  };
1922
- //# sourceMappingURL=chunk-4MKPGQIM.js.map
1996
+ //# sourceMappingURL=chunk-OUQE6LG4.js.map