@pkcprotocol/pkc-js 0.0.18 → 0.0.20

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 (149) hide show
  1. package/dist/browser/clients/base-client-manager.d.ts +6 -0
  2. package/dist/browser/clients/base-client-manager.js +36 -2
  3. package/dist/browser/clients/base-client-manager.js.map +1 -1
  4. package/dist/browser/community/community-client-manager.js +2 -2
  5. package/dist/browser/community/community-client-manager.js.map +1 -1
  6. package/dist/browser/errors.d.ts +1 -0
  7. package/dist/browser/errors.js +1 -0
  8. package/dist/browser/errors.js.map +1 -1
  9. package/dist/browser/generated-version.d.ts +1 -1
  10. package/dist/browser/generated-version.js +1 -1
  11. package/dist/browser/pages/pages-client-manager.d.ts +16 -3
  12. package/dist/browser/pages/pages-client-manager.js +32 -14
  13. package/dist/browser/pages/pages-client-manager.js.map +1 -1
  14. package/dist/browser/pages/pages.d.ts +5 -1
  15. package/dist/browser/pages/pages.js +16 -8
  16. package/dist/browser/pages/pages.js.map +1 -1
  17. package/dist/browser/pages/schema-util.js +2 -2
  18. package/dist/browser/pages/schema-util.js.map +1 -1
  19. package/dist/browser/pages/schema.d.ts +1 -1
  20. package/dist/browser/pages/schema.js +1 -1
  21. package/dist/browser/pages/schema.js.map +1 -1
  22. package/dist/browser/pages/types.d.ts +5 -2
  23. package/dist/browser/pages/util.js +15 -5
  24. package/dist/browser/pages/util.js.map +1 -1
  25. package/dist/browser/pkc/pkc.d.ts +2 -0
  26. package/dist/browser/pkc/pkc.js +8 -0
  27. package/dist/browser/pkc/pkc.js.map +1 -1
  28. package/dist/browser/pkc/tracked-instance-registry-util.js +2 -1
  29. package/dist/browser/pkc/tracked-instance-registry-util.js.map +1 -1
  30. package/dist/browser/pkc-error.d.ts +1 -1
  31. package/dist/browser/publications/comment/comment-client-manager.d.ts +3 -0
  32. package/dist/browser/publications/comment/comment-client-manager.js +33 -3
  33. package/dist/browser/publications/comment/comment-client-manager.js.map +1 -1
  34. package/dist/browser/publications/comment/comment.js +4 -4
  35. package/dist/browser/publications/comment/comment.js.map +1 -1
  36. package/dist/browser/publications/comment/schema.d.ts +16 -190
  37. package/dist/browser/publications/comment/schema.js +10 -1
  38. package/dist/browser/publications/comment/schema.js.map +1 -1
  39. package/dist/browser/publications/comment/types.d.ts +8 -1
  40. package/dist/browser/publications/publication-author.d.ts +1 -2
  41. package/dist/browser/publications/publication-author.js +2 -6
  42. package/dist/browser/publications/publication-author.js.map +1 -1
  43. package/dist/browser/publications/publication.js +21 -1
  44. package/dist/browser/publications/publication.js.map +1 -1
  45. package/dist/browser/rpc/src/index.d.ts +2 -1
  46. package/dist/browser/rpc/src/index.js +24 -8
  47. package/dist/browser/rpc/src/index.js.map +1 -1
  48. package/dist/browser/rpc/src/schema.d.ts +1 -0
  49. package/dist/browser/rpc/src/schema.js +4 -1
  50. package/dist/browser/rpc/src/schema.js.map +1 -1
  51. package/dist/browser/runtime/node/community/db-handler-types.d.ts +3 -3
  52. package/dist/browser/runtime/node/community/db-handler.d.ts +19 -4
  53. package/dist/browser/runtime/node/community/db-handler.js +367 -78
  54. package/dist/browser/runtime/node/community/db-handler.js.map +1 -1
  55. package/dist/browser/runtime/node/community/local-community.d.ts +1 -0
  56. package/dist/browser/runtime/node/community/local-community.js +108 -33
  57. package/dist/browser/runtime/node/community/local-community.js.map +1 -1
  58. package/dist/browser/runtime/node/community/page-generator.d.ts +11 -5
  59. package/dist/browser/runtime/node/community/page-generator.js +13 -8
  60. package/dist/browser/runtime/node/community/page-generator.js.map +1 -1
  61. package/dist/browser/runtime/node/util.d.ts +13 -1
  62. package/dist/browser/runtime/node/util.js +88 -1
  63. package/dist/browser/runtime/node/util.js.map +1 -1
  64. package/dist/browser/signer/encryption.js +8 -4
  65. package/dist/browser/signer/encryption.js.map +1 -1
  66. package/dist/browser/signer/signatures.d.ts +1 -1
  67. package/dist/browser/signer/signatures.js +3 -3
  68. package/dist/browser/signer/signatures.js.map +1 -1
  69. package/dist/browser/signer/util.js +4 -4
  70. package/dist/browser/signer/util.js.map +1 -1
  71. package/dist/browser/util.d.ts +11 -0
  72. package/dist/browser/util.js +43 -1
  73. package/dist/browser/util.js.map +1 -1
  74. package/dist/browser/version.js +1 -1
  75. package/dist/node/clients/base-client-manager.d.ts +6 -0
  76. package/dist/node/clients/base-client-manager.js +36 -2
  77. package/dist/node/clients/base-client-manager.js.map +1 -1
  78. package/dist/node/community/community-client-manager.js +2 -2
  79. package/dist/node/community/community-client-manager.js.map +1 -1
  80. package/dist/node/errors.d.ts +1 -0
  81. package/dist/node/errors.js +1 -0
  82. package/dist/node/errors.js.map +1 -1
  83. package/dist/node/generated-version.d.ts +1 -1
  84. package/dist/node/generated-version.js +1 -1
  85. package/dist/node/pages/pages-client-manager.d.ts +16 -3
  86. package/dist/node/pages/pages-client-manager.js +32 -14
  87. package/dist/node/pages/pages-client-manager.js.map +1 -1
  88. package/dist/node/pages/pages.d.ts +5 -1
  89. package/dist/node/pages/pages.js +16 -8
  90. package/dist/node/pages/pages.js.map +1 -1
  91. package/dist/node/pages/schema-util.js +2 -2
  92. package/dist/node/pages/schema-util.js.map +1 -1
  93. package/dist/node/pages/schema.d.ts +1 -1
  94. package/dist/node/pages/schema.js +1 -1
  95. package/dist/node/pages/schema.js.map +1 -1
  96. package/dist/node/pages/types.d.ts +5 -2
  97. package/dist/node/pages/util.js +15 -5
  98. package/dist/node/pages/util.js.map +1 -1
  99. package/dist/node/pkc/pkc.d.ts +2 -0
  100. package/dist/node/pkc/pkc.js +8 -0
  101. package/dist/node/pkc/pkc.js.map +1 -1
  102. package/dist/node/pkc/tracked-instance-registry-util.js +2 -1
  103. package/dist/node/pkc/tracked-instance-registry-util.js.map +1 -1
  104. package/dist/node/pkc-error.d.ts +1 -1
  105. package/dist/node/publications/comment/comment-client-manager.d.ts +3 -0
  106. package/dist/node/publications/comment/comment-client-manager.js +33 -3
  107. package/dist/node/publications/comment/comment-client-manager.js.map +1 -1
  108. package/dist/node/publications/comment/comment.js +4 -4
  109. package/dist/node/publications/comment/comment.js.map +1 -1
  110. package/dist/node/publications/comment/schema.d.ts +16 -190
  111. package/dist/node/publications/comment/schema.js +10 -1
  112. package/dist/node/publications/comment/schema.js.map +1 -1
  113. package/dist/node/publications/comment/types.d.ts +8 -1
  114. package/dist/node/publications/publication-author.d.ts +1 -2
  115. package/dist/node/publications/publication-author.js +2 -6
  116. package/dist/node/publications/publication-author.js.map +1 -1
  117. package/dist/node/publications/publication.js +21 -1
  118. package/dist/node/publications/publication.js.map +1 -1
  119. package/dist/node/rpc/src/index.d.ts +2 -1
  120. package/dist/node/rpc/src/index.js +24 -8
  121. package/dist/node/rpc/src/index.js.map +1 -1
  122. package/dist/node/rpc/src/schema.d.ts +1 -0
  123. package/dist/node/rpc/src/schema.js +4 -1
  124. package/dist/node/rpc/src/schema.js.map +1 -1
  125. package/dist/node/runtime/node/community/db-handler-types.d.ts +3 -3
  126. package/dist/node/runtime/node/community/db-handler.d.ts +19 -4
  127. package/dist/node/runtime/node/community/db-handler.js +367 -78
  128. package/dist/node/runtime/node/community/db-handler.js.map +1 -1
  129. package/dist/node/runtime/node/community/local-community.d.ts +1 -0
  130. package/dist/node/runtime/node/community/local-community.js +108 -33
  131. package/dist/node/runtime/node/community/local-community.js.map +1 -1
  132. package/dist/node/runtime/node/community/page-generator.d.ts +11 -5
  133. package/dist/node/runtime/node/community/page-generator.js +13 -8
  134. package/dist/node/runtime/node/community/page-generator.js.map +1 -1
  135. package/dist/node/runtime/node/util.d.ts +13 -1
  136. package/dist/node/runtime/node/util.js +88 -1
  137. package/dist/node/runtime/node/util.js.map +1 -1
  138. package/dist/node/signer/encryption.js +8 -4
  139. package/dist/node/signer/encryption.js.map +1 -1
  140. package/dist/node/signer/signatures.d.ts +1 -1
  141. package/dist/node/signer/signatures.js +3 -3
  142. package/dist/node/signer/signatures.js.map +1 -1
  143. package/dist/node/signer/util.js +4 -4
  144. package/dist/node/signer/util.js.map +1 -1
  145. package/dist/node/util.d.ts +11 -0
  146. package/dist/node/util.js +43 -1
  147. package/dist/node/util.js.map +1 -1
  148. package/dist/node/version.js +1 -1
  149. package/package.json +21 -22
@@ -23,7 +23,7 @@ import { TIMEFRAMES_TO_SECONDS } from "../../../pages/util.js";
23
23
  import { parseCommentEditsRow, parseCommentUpdateRow, parseCommentsTableRow, parsePrefixedComment, parseVoteRow } from "./db-row-parser.js";
24
24
  import { ZodError } from "zod";
25
25
  import { messages } from "../../../errors.js";
26
- import { getAuthorDomainFromWire } from "../../../publications/publication-author.js";
26
+ import { getAuthorNameFromWire } from "../../../publications/publication-author.js";
27
27
  const TABLES = Object.freeze({
28
28
  COMMENTS: "comments",
29
29
  COMMENT_UPDATES: "commentUpdates",
@@ -332,8 +332,8 @@ export class DbHandler {
332
332
  CREATE TABLE IF NOT EXISTS ${tableName} (
333
333
  commentCid TEXT NOT NULL PRIMARY KEY UNIQUE REFERENCES ${TABLES.COMMENTS}(cid) ON DELETE CASCADE,
334
334
  aliasPrivateKey TEXT NOT NULL,
335
- originalAuthorSignerPublicKey TEXT NOT NULL,
336
- originalAuthorDomain TEXT NULLABLE, -- the original author's domain address (e.g., user.eth) if they used one
335
+ originalAuthorPublicKey TEXT NOT NULL,
336
+ originalAuthorName TEXT NULLABLE, -- the original author's name (e.g., user.eth) if they used one
337
337
  mode TEXT NOT NULL CHECK(mode IN ('per-post', 'per-reply', 'per-author')),
338
338
  insertedAt INTEGER NOT NULL
339
339
  )
@@ -489,7 +489,7 @@ export class DbHandler {
489
489
  const moderationsToUpdate = this._db
490
490
  .prepare(`
491
491
  SELECT cm.rowid, cm.commentCid, c.authorSignerAddress,
492
- pa.originalAuthorSignerPublicKey
492
+ pa.originalAuthorPublicKey
493
493
  FROM ${TABLES.COMMENT_MODERATIONS} cm
494
494
  LEFT JOIN ${TABLES.COMMENTS} c ON cm.commentCid = c.cid
495
495
  LEFT JOIN ${TABLES.PSEUDONYMITY_ALIASES} pa ON cm.commentCid = pa.commentCid
@@ -504,9 +504,9 @@ export class DbHandler {
504
504
  for (const mod of items) {
505
505
  let targetAddress = null;
506
506
  // If the comment was published with pseudonymity, use the original author's address
507
- if (mod.originalAuthorSignerPublicKey) {
507
+ if (mod.originalAuthorPublicKey) {
508
508
  try {
509
- targetAddress = getPKCAddressFromPublicKeySync(mod.originalAuthorSignerPublicKey);
509
+ targetAddress = getPKCAddressFromPublicKeySync(mod.originalAuthorPublicKey);
510
510
  }
511
511
  catch {
512
512
  // If we can't derive the address from the public key, fall back to authorSignerAddress
@@ -531,7 +531,7 @@ export class DbHandler {
531
531
  const moderationsToUpdate = this._db
532
532
  .prepare(`
533
533
  SELECT cm.rowid, c.author as commentAuthor,
534
- pa.originalAuthorDomain
534
+ pa.originalAuthorName
535
535
  FROM ${TABLES.COMMENT_MODERATIONS} cm
536
536
  LEFT JOIN ${TABLES.COMMENTS} c ON cm.commentCid = c.cid
537
537
  LEFT JOIN ${TABLES.PSEUDONYMITY_ALIASES} pa ON cm.commentCid = pa.commentCid
@@ -547,13 +547,13 @@ export class DbHandler {
547
547
  for (const mod of items) {
548
548
  let targetDomain = null;
549
549
  // If the comment was published with pseudonymity, use the original author's domain
550
- if (mod.originalAuthorDomain) {
551
- targetDomain = mod.originalAuthorDomain;
550
+ if (mod.originalAuthorName) {
551
+ targetDomain = mod.originalAuthorName;
552
552
  }
553
553
  else if (mod.commentAuthor) {
554
554
  try {
555
555
  const author = JSON.parse(mod.commentAuthor);
556
- targetDomain = getAuthorDomainFromWire(author) || null;
556
+ targetDomain = getAuthorNameFromWire(author) || null;
557
557
  }
558
558
  catch {
559
559
  // Ignore parse errors
@@ -622,6 +622,17 @@ export class DbHandler {
622
622
  srcRecord.extraProps = { ...existingExtra, subplebbitAddress: addr };
623
623
  delete srcRecord["subplebbitAddress"];
624
624
  }
625
+ // Rename pseudonymityAliases columns (v38 → v39)
626
+ if (currentDbVersion < 39 && srcTable === TABLES.PSEUDONYMITY_ALIASES) {
627
+ if (srcRecord["originalAuthorSignerPublicKey"] !== undefined) {
628
+ srcRecord["originalAuthorPublicKey"] = srcRecord["originalAuthorSignerPublicKey"];
629
+ delete srcRecord["originalAuthorSignerPublicKey"];
630
+ }
631
+ if (srcRecord["originalAuthorDomain"] !== undefined) {
632
+ srcRecord["originalAuthorName"] = srcRecord["originalAuthorDomain"];
633
+ delete srcRecord["originalAuthorDomain"];
634
+ }
635
+ }
625
636
  // Prepare record for insertion (stringify JSONs, convert booleans)
626
637
  const processedRecord = this._processRecordsForDbBeforeInsert([srcRecord])[0];
627
638
  // Map values including rowid (preserve the original rowid value)
@@ -857,8 +868,8 @@ export class DbHandler {
857
868
  const processedAliases = this._processRecordsForDbBeforeInsert(aliases);
858
869
  const stmt = this._db.prepare(`
859
870
  INSERT OR REPLACE INTO ${TABLES.PSEUDONYMITY_ALIASES}
860
- (commentCid, aliasPrivateKey, originalAuthorSignerPublicKey, originalAuthorDomain, mode, insertedAt)
861
- VALUES (@commentCid, @aliasPrivateKey, @originalAuthorSignerPublicKey, @originalAuthorDomain, @mode, @insertedAt)
871
+ (commentCid, aliasPrivateKey, originalAuthorPublicKey, originalAuthorName, mode, insertedAt)
872
+ VALUES (@commentCid, @aliasPrivateKey, @originalAuthorPublicKey, @originalAuthorName, @mode, @insertedAt)
862
873
  `);
863
874
  const insertMany = this._db.transaction((items) => {
864
875
  for (const alias of items)
@@ -1070,6 +1081,294 @@ export class DbHandler {
1070
1081
  return { comment, commentUpdate };
1071
1082
  });
1072
1083
  }
1084
+ queryPageCommentsWithResolvedReplies(options) {
1085
+ // Fetch ALL descendants by following CID-ref lists stored in the DB `replies` column.
1086
+ // Base case: direct children of parentCid.
1087
+ // Recursive case: follow $.best.commentCids from each node's replies JSON.
1088
+ // Returns flat rows with tree_parent for JS tree assembly.
1089
+ const commentUpdateCols = remeda.keys.strict(CommentUpdateSchema.shape);
1090
+ const commentIpfsCols = [...remeda.keys.strict(CommentIpfsSchema.shape), "extraProps"];
1091
+ // Base case uses full table names (not aliases) to match _buildPageQueryParts WHERE clauses
1092
+ const baseCommentUpdateSelects = commentUpdateCols.map((col) => `${TABLES.COMMENT_UPDATES}.${col} AS commentUpdate_${col}`);
1093
+ const baseCommentIpfsSelects = commentIpfsCols.map((col) => `${TABLES.COMMENTS}.${col} AS commentIpfs_${col}`);
1094
+ // Recursive part uses aliases since it joins fresh tables
1095
+ const recCommentUpdateSelects = commentUpdateCols.map((col) => `cu2.${col} AS commentUpdate_${col}`);
1096
+ const recCommentIpfsSelects = commentIpfsCols.map((col) => `c2.${col} AS commentIpfs_${col}`);
1097
+ const { whereClauses, params } = this._buildPageQueryParts(options);
1098
+ // Build recursive filter clauses (same pattern as queryFlattenedPageReplies)
1099
+ const recursiveFilterClauses = [];
1100
+ if (options.excludeCommentsWithDifferentCommunityAddress) {
1101
+ const { clause, params: addrParams } = this._communityAddressClause("c2");
1102
+ recursiveFilterClauses.push(clause);
1103
+ params.push(...addrParams);
1104
+ }
1105
+ if (options.excludeCommentPendingApproval)
1106
+ recursiveFilterClauses.push(this._pendingApprovalClause("c2"));
1107
+ if (options.excludeRemovedComments)
1108
+ recursiveFilterClauses.push(this._removedClause("cu2"));
1109
+ if (options.excludeDeletedComments)
1110
+ recursiveFilterClauses.push(this._deletedFromLookupClause("d2"));
1111
+ if (options.excludeCommentWithApprovedFalse)
1112
+ recursiveFilterClauses.push(this._approvedClause("cu2"));
1113
+ const recursiveWhereExtra = recursiveFilterClauses.length > 0 ? `AND ${recursiveFilterClauses.join(" AND ")}` : "";
1114
+ const deletedLookupJoin = options.excludeDeletedComments
1115
+ ? `LEFT JOIN (SELECT cid, json_extract(edit, '$.deleted') AS deleted_flag FROM ${TABLES.COMMENT_UPDATES}) AS d2 ON c2.cid = d2.cid`
1116
+ : "";
1117
+ const queryStr = `
1118
+ WITH RECURSIVE reply_tree AS (
1119
+ -- Base: direct children of the target comment
1120
+ SELECT ${baseCommentIpfsSelects.join(", ")}, ${baseCommentUpdateSelects.join(", ")},
1121
+ ${TABLES.COMMENTS}.parentCid AS tree_parent
1122
+ FROM ${TABLES.COMMENTS}
1123
+ INNER JOIN ${TABLES.COMMENT_UPDATES} ON ${TABLES.COMMENTS}.cid = ${TABLES.COMMENT_UPDATES}.cid
1124
+ WHERE ${whereClauses.join(" AND ")}
1125
+
1126
+ UNION ALL
1127
+
1128
+ -- Recursive: follow commentCids from each parent's replies
1129
+ SELECT ${recCommentIpfsSelects.join(", ")}, ${recCommentUpdateSelects.join(", ")},
1130
+ rt.commentUpdate_cid AS tree_parent
1131
+ FROM reply_tree rt
1132
+ CROSS JOIN json_each(
1133
+ json_extract(rt.commentUpdate_replies, '$.best.commentCids')
1134
+ ) child_ref
1135
+ JOIN ${TABLES.COMMENTS} c2 ON c2.cid = child_ref.value
1136
+ JOIN ${TABLES.COMMENT_UPDATES} cu2 ON c2.cid = cu2.cid
1137
+ ${deletedLookupJoin}
1138
+ WHERE rt.commentUpdate_replies IS NOT NULL
1139
+ AND json_type(rt.commentUpdate_replies, '$.best.commentCids') = 'array'
1140
+ ${recursiveWhereExtra}
1141
+ )
1142
+ SELECT * FROM reply_tree
1143
+ `;
1144
+ const rowsRaw = this._db.prepare(queryStr).all(...params);
1145
+ // Group by tree_parent to reconstruct the hierarchy
1146
+ const parsedByCid = new Map();
1147
+ const childrenByParent = new Map();
1148
+ for (const row of rowsRaw) {
1149
+ const { comment, commentUpdate } = this._parsePrefixedComment(row);
1150
+ parsedByCid.set(commentUpdate.cid, { comment, commentUpdate });
1151
+ const parent = row.tree_parent;
1152
+ if (!childrenByParent.has(parent))
1153
+ childrenByParent.set(parent, []);
1154
+ childrenByParent.get(parent).push({ comment, commentUpdate });
1155
+ }
1156
+ // Build a commentUpdate for wire format: strip DB replies, only add resolved replies if present
1157
+ const buildWireCommentUpdate = (commentUpdate, resolvedReplies) => {
1158
+ const { replies: dbReplies, ...rest } = commentUpdate;
1159
+ if (resolvedReplies)
1160
+ return { ...rest, replies: resolvedReplies };
1161
+ // If no resolved inline replies but DB has allPageCids, reconstruct pageCids so clients can fetch pages
1162
+ if (dbReplies) {
1163
+ const dbEntries = dbReplies;
1164
+ const pageCids = {};
1165
+ for (const [sortName, sortEntry] of Object.entries(dbEntries)) {
1166
+ if (sortEntry?.allPageCids?.[0])
1167
+ pageCids[sortName] = sortEntry.allPageCids[0];
1168
+ }
1169
+ if (Object.keys(pageCids).length > 0)
1170
+ return { ...rest, replies: { pages: {}, pageCids } };
1171
+ }
1172
+ return rest;
1173
+ };
1174
+ // Recursively attach nested replies
1175
+ const attachReplies = (cid) => {
1176
+ const children = childrenByParent.get(cid);
1177
+ if (!children?.length)
1178
+ return undefined;
1179
+ // Sort children by the parent's commentCids order.
1180
+ // SQLite's recursive CTE does not guarantee row order matches json_each array order
1181
+ // when additional JOINs are involved, so we must explicitly reorder.
1182
+ const parent = parsedByCid.get(cid);
1183
+ const parentDbReplies = parent?.commentUpdate?.replies;
1184
+ const cidOrder = parentDbReplies?.best?.commentCids;
1185
+ const orderedChildren = cidOrder
1186
+ ? cidOrder.map((childCid) => children.find((c) => c.commentUpdate.cid === childCid)).filter(Boolean)
1187
+ : children;
1188
+ return {
1189
+ pages: {
1190
+ best: {
1191
+ comments: orderedChildren.map((child) => ({
1192
+ comment: child.comment,
1193
+ commentUpdate: buildWireCommentUpdate(child.commentUpdate, attachReplies(child.commentUpdate.cid))
1194
+ }))
1195
+ }
1196
+ }
1197
+ };
1198
+ };
1199
+ // Direct children with nested replies attached
1200
+ const directChildren = childrenByParent.get(options.parentCid) ?? [];
1201
+ return directChildren.map((child) => ({
1202
+ comment: child.comment,
1203
+ commentUpdate: buildWireCommentUpdate(child.commentUpdate, attachReplies(child.commentUpdate.cid))
1204
+ }));
1205
+ }
1206
+ resolveRepliesCidRefsForEntries(entries) {
1207
+ // For entries whose replies are in CID-ref format, resolve them by fetching descendants.
1208
+ // Collects all root CIDs from all entries, runs a single recursive query, then distributes results.
1209
+ const commentUpdateCols = remeda.keys.strict(CommentUpdateSchema.shape);
1210
+ const commentIpfsCols = [...remeda.keys.strict(CommentIpfsSchema.shape), "extraProps"];
1211
+ // Gather all CIDs from CID-ref replies across all entries
1212
+ const allCids = [];
1213
+ for (const entry of entries) {
1214
+ const replies = entry.commentUpdate.replies;
1215
+ if (!replies)
1216
+ continue;
1217
+ for (const sortEntry of Object.values(replies)) {
1218
+ if (sortEntry?.commentCids)
1219
+ allCids.push(...sortEntry.commentCids);
1220
+ }
1221
+ }
1222
+ // Build lookup maps from recursive query (only if we have CIDs to resolve)
1223
+ const parsedByCid = new Map();
1224
+ const childrenByParent = new Map();
1225
+ if (allCids.length > 0) {
1226
+ // Fetch all descendant trees starting from these CIDs using a recursive CTE
1227
+ const placeholders = allCids.map(() => "?").join(",");
1228
+ const commentUpdateSelects = commentUpdateCols.map((col) => `cu.${col} AS commentUpdate_${col}`);
1229
+ const commentIpfsSelects = commentIpfsCols.map((col) => `c.${col} AS commentIpfs_${col}`);
1230
+ const recCommentUpdateSelects = commentUpdateCols.map((col) => `cu2.${col} AS commentUpdate_${col}`);
1231
+ const recCommentIpfsSelects = commentIpfsCols.map((col) => `c2.${col} AS commentIpfs_${col}`);
1232
+ const queryStr = `
1233
+ WITH RECURSIVE reply_tree AS (
1234
+ SELECT ${commentIpfsSelects.join(", ")}, ${commentUpdateSelects.join(", ")},
1235
+ c.parentCid AS tree_parent
1236
+ FROM ${TABLES.COMMENTS} c
1237
+ INNER JOIN ${TABLES.COMMENT_UPDATES} cu ON c.cid = cu.cid
1238
+ WHERE c.cid IN (${placeholders})
1239
+
1240
+ UNION ALL
1241
+
1242
+ SELECT ${recCommentIpfsSelects.join(", ")}, ${recCommentUpdateSelects.join(", ")},
1243
+ rt.commentUpdate_cid AS tree_parent
1244
+ FROM reply_tree rt
1245
+ CROSS JOIN json_each(
1246
+ json_extract(rt.commentUpdate_replies, '$.best.commentCids')
1247
+ ) child_ref
1248
+ JOIN ${TABLES.COMMENTS} c2 ON c2.cid = child_ref.value
1249
+ JOIN ${TABLES.COMMENT_UPDATES} cu2 ON c2.cid = cu2.cid
1250
+ WHERE rt.commentUpdate_replies IS NOT NULL
1251
+ AND json_type(rt.commentUpdate_replies, '$.best.commentCids') = 'array'
1252
+ )
1253
+ SELECT * FROM reply_tree
1254
+ `;
1255
+ const rowsRaw = this._db.prepare(queryStr).all(...allCids);
1256
+ // Build lookup: cid -> parsed entry
1257
+ for (const row of rowsRaw) {
1258
+ const { comment, commentUpdate } = this._parsePrefixedComment(row);
1259
+ parsedByCid.set(commentUpdate.cid, { comment, commentUpdate });
1260
+ const parent = row.tree_parent;
1261
+ if (!childrenByParent.has(parent))
1262
+ childrenByParent.set(parent, []);
1263
+ childrenByParent.get(parent).push({ comment, commentUpdate });
1264
+ }
1265
+ }
1266
+ // Build a commentUpdate for wire format: strip DB replies, attach resolved replies or reconstruct pageCids
1267
+ const buildWireCommentUpdate = (commentUpdate, resolvedReplies) => {
1268
+ const { replies: dbReplies, ...rest } = commentUpdate;
1269
+ if (resolvedReplies)
1270
+ return { ...rest, replies: resolvedReplies };
1271
+ // If no resolved inline replies but DB has allPageCids, reconstruct pageCids so clients can fetch pages
1272
+ if (dbReplies) {
1273
+ const dbEntries = dbReplies;
1274
+ const pageCids = {};
1275
+ for (const [sortName, sortEntry] of Object.entries(dbEntries)) {
1276
+ if (sortEntry?.allPageCids?.[0])
1277
+ pageCids[sortName] = sortEntry.allPageCids[0];
1278
+ }
1279
+ if (Object.keys(pageCids).length > 0)
1280
+ return { ...rest, replies: { pages: {}, pageCids } };
1281
+ }
1282
+ return rest;
1283
+ };
1284
+ const attachReplies = (cid) => {
1285
+ const children = childrenByParent.get(cid);
1286
+ if (!children?.length)
1287
+ return undefined;
1288
+ // Sort children by the parent's commentCids order.
1289
+ // SQLite's recursive CTE does not guarantee row order matches json_each array order
1290
+ // when additional JOINs are involved, so we must explicitly reorder.
1291
+ const parent = parsedByCid.get(cid);
1292
+ const parentDbReplies = parent?.commentUpdate?.replies;
1293
+ const cidOrder = parentDbReplies?.best?.commentCids;
1294
+ const orderedChildren = cidOrder
1295
+ ? cidOrder.map((childCid) => children.find((c) => c.commentUpdate.cid === childCid)).filter(Boolean)
1296
+ : children;
1297
+ return {
1298
+ pages: {
1299
+ best: {
1300
+ comments: orderedChildren.map((child) => ({
1301
+ comment: child.comment,
1302
+ commentUpdate: buildWireCommentUpdate(child.commentUpdate, attachReplies(child.commentUpdate.cid))
1303
+ }))
1304
+ }
1305
+ }
1306
+ };
1307
+ };
1308
+ // Resolve each entry's CID-ref replies into full nested data
1309
+ return entries.map((entry) => {
1310
+ const replies = entry.commentUpdate.replies;
1311
+ if (!replies)
1312
+ return entry;
1313
+ // Check if it's DB CID-ref format (has commentCids or allPageCids)
1314
+ const isDbFormat = Object.values(replies).some((s) => s?.commentCids || s?.allPageCids);
1315
+ if (!isDbFormat)
1316
+ return entry;
1317
+ // Build resolved pages and pageCids from CID refs
1318
+ const resolvedPages = {};
1319
+ const resolvedPageCids = {};
1320
+ for (const [sortName, sortEntry] of Object.entries(replies)) {
1321
+ if (sortEntry?.commentCids) {
1322
+ const resolvedComments = sortEntry.commentCids
1323
+ .map((cid) => parsedByCid.get(cid))
1324
+ .filter(Boolean)
1325
+ .map((child) => ({
1326
+ comment: child.comment,
1327
+ commentUpdate: buildWireCommentUpdate(child.commentUpdate, attachReplies(child.commentUpdate.cid))
1328
+ }));
1329
+ // Derive nextCid from allPageCids[0]; fall back to legacy nextCid field for old DB rows
1330
+ const nextCidForSort = sortEntry.allPageCids?.[0] ?? sortEntry.nextCid;
1331
+ resolvedPages[sortName] = {
1332
+ comments: resolvedComments,
1333
+ ...(nextCidForSort ? { nextCid: nextCidForSort } : {})
1334
+ };
1335
+ }
1336
+ // Derive pageCid from allPageCids[0] (first page CID for this sort)
1337
+ if (sortEntry?.allPageCids?.[0]) {
1338
+ resolvedPageCids[sortName] = sortEntry.allPageCids[0];
1339
+ }
1340
+ }
1341
+ const { replies: _dbReplies, ...entryCommentUpdateRest } = entry.commentUpdate;
1342
+ return {
1343
+ ...entry,
1344
+ commentUpdate: {
1345
+ ...entryCommentUpdateRest,
1346
+ replies: {
1347
+ pages: resolvedPages,
1348
+ ...(Object.keys(resolvedPageCids).length > 0 ? { pageCids: resolvedPageCids } : {})
1349
+ }
1350
+ }
1351
+ };
1352
+ });
1353
+ }
1354
+ queryCommentAndCommentUpdateByCids(cids, opts) {
1355
+ if (cids.length === 0)
1356
+ return [];
1357
+ const placeholders = cids.map(() => "?").join(",");
1358
+ const commentUpdateSelects = opts.commentUpdateCols.map((col) => `cu.${col} AS commentUpdate_${col}`);
1359
+ const commentIpfsSelects = opts.commentIpfsCols.map((col) => `c.${col} AS commentIpfs_${col}`);
1360
+ const queryStr = `
1361
+ SELECT ${commentIpfsSelects.join(", ")}, ${commentUpdateSelects.join(", ")}
1362
+ FROM ${TABLES.COMMENTS} c
1363
+ INNER JOIN ${TABLES.COMMENT_UPDATES} cu ON c.cid = cu.cid
1364
+ WHERE c.cid IN (${placeholders})
1365
+ `;
1366
+ const rows = this._db.prepare(queryStr).all(...cids);
1367
+ return rows.map((row) => {
1368
+ const { comment, commentUpdate } = this._parsePrefixedComment(row);
1369
+ return { comment, commentUpdate };
1370
+ });
1371
+ }
1073
1372
  queryFlattenedPageReplies(options) {
1074
1373
  const commentUpdateCols = remeda.keys.strict(options.commentUpdateFieldsToExclude
1075
1374
  ? remeda.omit(CommentUpdateSchema.shape, options.commentUpdateFieldsToExclude)
@@ -1146,6 +1445,27 @@ export class DbHandler {
1146
1445
  return undefined;
1147
1446
  return this._parseCommentUpdatesRow(row);
1148
1447
  }
1448
+ queryCommentUpdateTimestampBucketReplies(opts) {
1449
+ const row = this._db
1450
+ .prepare(`SELECT updatedAt, postUpdatesBucket, replies FROM ${TABLES.COMMENT_UPDATES} WHERE cid = ?`)
1451
+ .get(opts.cid);
1452
+ if (!row)
1453
+ return undefined;
1454
+ return {
1455
+ updatedAt: row.updatedAt,
1456
+ postUpdatesBucket: row.postUpdatesBucket ?? undefined,
1457
+ replies: typeof row.replies === "string" ? JSON.parse(row.replies) : undefined
1458
+ };
1459
+ }
1460
+ queryCommentUpdateBucketAndReplies(opts) {
1461
+ const row = this._db.prepare(`SELECT postUpdatesBucket, replies FROM ${TABLES.COMMENT_UPDATES} WHERE cid = ?`).get(opts.cid);
1462
+ if (!row)
1463
+ return undefined;
1464
+ return {
1465
+ postUpdatesBucket: row.postUpdatesBucket ?? undefined,
1466
+ replies: typeof row.replies === "string" ? JSON.parse(row.replies) : undefined
1467
+ };
1468
+ }
1149
1469
  hasCommentWithSignatureEncoded(signatureEncoded) {
1150
1470
  const row = this._db
1151
1471
  .prepare(`SELECT 1 FROM ${TABLES.COMMENTS}
@@ -1267,42 +1587,22 @@ export class DbHandler {
1267
1587
  WHERE (parent.pendingApproval IS NULL OR parent.pendingApproval != 1)
1268
1588
  AND COALESCE(lc.actual_last_child_cid, '') != COALESCE(cu_parent.lastChildCid, '')
1269
1589
  ),
1270
- replies_json AS (
1271
- SELECT
1272
- cu_parent.cid AS parentCid,
1273
- json_extract(comment_entry.value, '$.comment.cid') AS comment_child_cid,
1274
- json_extract(comment_entry.value, '$.commentUpdate.cid') AS update_child_cid,
1275
- json_extract(comment_entry.value, '$.commentUpdate.updatedAt') AS json_child_updated_at
1590
+ stale_replies AS (
1591
+ SELECT DISTINCT cu_parent.cid
1276
1592
  FROM ${TABLES.COMMENT_UPDATES} cu_parent
1277
- INNER JOIN ${TABLES.COMMENTS} parent ON parent.cid = cu_parent.cid
1278
- JOIN json_each(cu_parent.replies, '$.pages') pages
1279
- JOIN json_each(pages.value, '$.comments') comment_entry
1593
+ CROSS JOIN json_each(
1594
+ json_extract(cu_parent.replies, '$.best.commentCids')
1595
+ ) child_ref
1596
+ JOIN ${TABLES.COMMENT_UPDATES} cu_child ON cu_child.cid = child_ref.value
1280
1597
  WHERE cu_parent.replies IS NOT NULL
1281
- AND json_type(cu_parent.replies, '$.pages') = 'object'
1282
- AND (parent.pendingApproval IS NULL OR parent.pendingApproval != 1)
1283
- ),
1284
- stale_replies_json AS (
1285
- SELECT r.parentCid AS cid
1286
- FROM replies_json r
1287
- LEFT JOIN ${TABLES.COMMENTS} existing_child ON existing_child.cid = COALESCE(r.comment_child_cid, r.update_child_cid)
1288
- LEFT JOIN ${TABLES.COMMENT_UPDATES} actual_child_update ON actual_child_update.cid = COALESCE(r.comment_child_cid, r.update_child_cid)
1289
- WHERE COALESCE(r.comment_child_cid, r.update_child_cid) IS NOT NULL
1290
- AND (
1291
- existing_child.cid IS NULL
1292
- OR actual_child_update.cid IS NULL
1293
- OR (
1294
- r.json_child_updated_at IS NOT NULL
1295
- AND actual_child_update.cid IS NOT NULL
1296
- AND CAST(r.json_child_updated_at AS INTEGER) < actual_child_update.updatedAt
1297
- )
1298
- )
1299
- GROUP BY r.parentCid
1598
+ AND json_type(cu_parent.replies, '$.best.commentCids') = 'array'
1599
+ AND cu_child.updatedAt > cu_parent.insertedAt
1300
1600
  ),
1301
1601
  base_updates AS (
1302
1602
  SELECT * FROM direct_updates
1303
1603
  UNION SELECT c.* FROM ${TABLES.COMMENTS} c JOIN stale_child_counts scc ON c.cid = scc.cid
1304
1604
  UNION SELECT c.* FROM ${TABLES.COMMENTS} c JOIN stale_last_child_cids slc ON c.cid = slc.cid
1305
- UNION SELECT c.* FROM ${TABLES.COMMENTS} c JOIN stale_replies_json srj ON c.cid = srj.cid
1605
+ UNION SELECT c.* FROM ${TABLES.COMMENTS} c JOIN stale_replies sr ON c.cid = sr.cid
1306
1606
  ),
1307
1607
  authors_to_update AS (SELECT DISTINCT authorSignerAddress FROM base_updates),
1308
1608
  author_comments AS (
@@ -1411,7 +1711,7 @@ export class DbHandler {
1411
1711
  const aliasesQuery = `
1412
1712
  SELECT DISTINCT
1413
1713
  comments.authorSignerAddress AS aliasSignerAddress,
1414
- alias.originalAuthorSignerPublicKey AS originalAuthorSignerPublicKey
1714
+ alias.originalAuthorPublicKey AS originalAuthorPublicKey
1415
1715
  FROM ${TABLES.PSEUDONYMITY_ALIASES} AS alias
1416
1716
  INNER JOIN ${TABLES.COMMENTS} AS comments ON comments.cid = alias.commentCid
1417
1717
  WHERE comments.authorSignerAddress IN (${aliasPlaceholders})
@@ -1420,7 +1720,7 @@ export class DbHandler {
1420
1720
  for (const aliasRow of aliasRows) {
1421
1721
  let originalAuthorAddress;
1422
1722
  try {
1423
- originalAuthorAddress = getPKCAddressFromPublicKeySync(aliasRow.originalAuthorSignerPublicKey);
1723
+ originalAuthorAddress = getPKCAddressFromPublicKeySync(aliasRow.originalAuthorPublicKey);
1424
1724
  }
1425
1725
  catch {
1426
1726
  throw new Error(`Failed to resolve original author address for alias signer address ${aliasRow.aliasSignerAddress}`);
@@ -1521,33 +1821,33 @@ export class DbHandler {
1521
1821
  }
1522
1822
  queryPseudonymityAliasByCommentCid(commentCid) {
1523
1823
  const row = this._db
1524
- .prepare(`SELECT commentCid, aliasPrivateKey, originalAuthorSignerPublicKey, originalAuthorDomain, mode, insertedAt FROM ${TABLES.PSEUDONYMITY_ALIASES} WHERE commentCid = ?`)
1824
+ .prepare(`SELECT commentCid, aliasPrivateKey, originalAuthorPublicKey, originalAuthorName, mode, insertedAt FROM ${TABLES.PSEUDONYMITY_ALIASES} WHERE commentCid = ?`)
1525
1825
  .get(commentCid);
1526
1826
  return row;
1527
1827
  }
1528
- queryPseudonymityAliasForPost(originalAuthorSignerPublicKey, postCid) {
1828
+ queryPseudonymityAliasForPost(originalAuthorPublicKey, postCid) {
1529
1829
  const row = this._db
1530
1830
  .prepare(`
1531
- SELECT alias.commentCid, alias.aliasPrivateKey, alias.originalAuthorSignerPublicKey, alias.originalAuthorDomain, alias.mode, alias.insertedAt
1831
+ SELECT alias.commentCid, alias.aliasPrivateKey, alias.originalAuthorPublicKey, alias.originalAuthorName, alias.mode, alias.insertedAt
1532
1832
  FROM ${TABLES.PSEUDONYMITY_ALIASES} AS alias
1533
1833
  INNER JOIN ${TABLES.COMMENTS} AS comments ON comments.cid = alias.commentCid
1534
- WHERE alias.mode = 'per-post' AND alias.originalAuthorSignerPublicKey = ? AND comments.postCid = ?
1834
+ WHERE alias.mode = 'per-post' AND alias.originalAuthorPublicKey = ? AND comments.postCid = ?
1535
1835
  ORDER BY alias.insertedAt ASC
1536
1836
  LIMIT 1
1537
1837
  `)
1538
- .get(originalAuthorSignerPublicKey, postCid);
1838
+ .get(originalAuthorPublicKey, postCid);
1539
1839
  return row;
1540
1840
  }
1541
- queryPseudonymityAliasForAuthor(originalAuthorSignerPublicKey) {
1841
+ queryPseudonymityAliasForAuthor(originalAuthorPublicKey) {
1542
1842
  const row = this._db
1543
1843
  .prepare(`
1544
- SELECT commentCid, aliasPrivateKey, originalAuthorSignerPublicKey, originalAuthorDomain, mode, insertedAt
1844
+ SELECT commentCid, aliasPrivateKey, originalAuthorPublicKey, originalAuthorName, mode, insertedAt
1545
1845
  FROM ${TABLES.PSEUDONYMITY_ALIASES}
1546
- WHERE mode = 'per-author' AND originalAuthorSignerPublicKey = ?
1846
+ WHERE mode = 'per-author' AND originalAuthorPublicKey = ?
1547
1847
  ORDER BY insertedAt ASC
1548
1848
  LIMIT 1
1549
1849
  `)
1550
- .get(originalAuthorSignerPublicKey);
1850
+ .get(originalAuthorPublicKey);
1551
1851
  return row;
1552
1852
  }
1553
1853
  _queryCommentAuthorAndParentWithoutParsing(cid) {
@@ -1979,13 +2279,13 @@ export class DbHandler {
1979
2279
  // If the provided address is the original signer, include all alias signer addresses for that author.
1980
2280
  const aliasRowsForOriginal = this._db
1981
2281
  .prepare(`
1982
- SELECT alias.commentCid, alias.originalAuthorSignerPublicKey
2282
+ SELECT alias.commentCid, alias.originalAuthorPublicKey
1983
2283
  FROM ${TABLES.PSEUDONYMITY_ALIASES} AS alias
1984
2284
  `)
1985
2285
  .all();
1986
2286
  for (const aliasRow of aliasRowsForOriginal) {
1987
2287
  try {
1988
- const originalAddress = getPKCAddressFromPublicKeySync(aliasRow.originalAuthorSignerPublicKey);
2288
+ const originalAddress = getPKCAddressFromPublicKeySync(aliasRow.originalAuthorPublicKey);
1989
2289
  if (originalAddress === authorSignerAddress) {
1990
2290
  const commentRow = this._db
1991
2291
  .prepare(`SELECT authorSignerAddress FROM ${TABLES.COMMENTS} WHERE cid = ?`)
@@ -2001,7 +2301,7 @@ export class DbHandler {
2001
2301
  // If the provided address is an alias, include the original signer address for that alias.
2002
2302
  const aliasRowsForAliasAddress = this._db
2003
2303
  .prepare(`
2004
- SELECT alias.originalAuthorSignerPublicKey
2304
+ SELECT alias.originalAuthorPublicKey
2005
2305
  FROM ${TABLES.PSEUDONYMITY_ALIASES} AS alias
2006
2306
  INNER JOIN ${TABLES.COMMENTS} AS comments ON comments.cid = alias.commentCid
2007
2307
  WHERE comments.authorSignerAddress = ?
@@ -2009,7 +2309,7 @@ export class DbHandler {
2009
2309
  .all(authorSignerAddress);
2010
2310
  for (const aliasRow of aliasRowsForAliasAddress) {
2011
2311
  try {
2012
- const originalAddress = getPKCAddressFromPublicKeySync(aliasRow.originalAuthorSignerPublicKey);
2312
+ const originalAddress = getPKCAddressFromPublicKeySync(aliasRow.originalAuthorPublicKey);
2013
2313
  authorSignerAddresses.add(originalAddress);
2014
2314
  }
2015
2315
  catch {
@@ -2073,7 +2373,7 @@ export class DbHandler {
2073
2373
  // Get original author's address for mod edits (bans/flairs are applied to original author)
2074
2374
  const modEditAddresses = [authorSignerAddress];
2075
2375
  try {
2076
- const originalAddress = getPKCAddressFromPublicKeySync(aliasRow.originalAuthorSignerPublicKey);
2376
+ const originalAddress = getPKCAddressFromPublicKeySync(aliasRow.originalAuthorPublicKey);
2077
2377
  if (originalAddress !== authorSignerAddress) {
2078
2378
  modEditAddresses.push(originalAddress);
2079
2379
  }
@@ -2082,7 +2382,7 @@ export class DbHandler {
2082
2382
  // ignore malformed keys
2083
2383
  }
2084
2384
  // For mod edits (bans/flairs), use the original author's domain if available
2085
- const modEditDomain = aliasRow.originalAuthorDomain || authorDomain;
2385
+ const modEditDomain = aliasRow.originalAuthorName || authorDomain;
2086
2386
  // Query karma for just this alias, but mod edits from both alias and original
2087
2387
  return this._queryCommunityAuthorByAddresses([authorSignerAddress], modEditAddresses, modEditDomain);
2088
2388
  }
@@ -2140,7 +2440,7 @@ export class DbHandler {
2140
2440
  this._db.prepare(`DELETE FROM ${TABLES.VOTES} WHERE commentCid = ?`).run(cid);
2141
2441
  this._db.prepare(`DELETE FROM ${TABLES.COMMENT_EDITS} WHERE commentCid = ?`).run(cid);
2142
2442
  this._db.prepare(`DELETE FROM ${TABLES.PSEUDONYMITY_ALIASES} WHERE commentCid = ?`).run(cid);
2143
- const commentUpdate = this.queryStoredCommentUpdate({ cid });
2443
+ const commentUpdate = this.queryCommentUpdateBucketAndReplies({ cid });
2144
2444
  if (commentUpdate) {
2145
2445
  this._db.prepare(`DELETE FROM ${TABLES.COMMENT_UPDATES} WHERE cid = ?`).run(cid);
2146
2446
  }
@@ -2326,36 +2626,25 @@ export class DbHandler {
2326
2626
  queryAllCommentCidsAndTheirReplies() {
2327
2627
  const log = Logger("pkc-js:local-community:db-handler:queryAllCidsUnderThisCommunity");
2328
2628
  const rows = this._db
2329
- .prepare(`SELECT
2330
- c.cid AS cid,
2331
- CASE
2332
- WHEN cu.replies IS NULL THEN NULL
2333
- ELSE json_set(
2334
- cu.replies,
2335
- '$.pages',
2336
- (
2337
- SELECT json_group_object(
2338
- pages.key,
2339
- json_set(pages.value, '$.comments', json('[]'))
2340
- )
2341
- FROM json_each(cu.replies, '$.pages') AS pages
2342
- )
2343
- )
2344
- END AS replies
2629
+ .prepare(`SELECT c.cid AS cid, cu.replies AS replies
2345
2630
  FROM ${TABLES.COMMENTS} c
2346
2631
  LEFT JOIN ${TABLES.COMMENT_UPDATES} cu ON c.cid = cu.cid`)
2347
2632
  .all();
2348
2633
  return rows.map((row) => {
2349
- let parsedReplies;
2634
+ const allPageCids = [];
2350
2635
  if (typeof row.replies === "string" && row.replies.length > 0) {
2351
2636
  try {
2352
- parsedReplies = JSON.parse(row.replies);
2637
+ const parsed = JSON.parse(row.replies);
2638
+ for (const sortEntry of Object.values(parsed)) {
2639
+ if (sortEntry?.allPageCids)
2640
+ allPageCids.push(...sortEntry.allPageCids);
2641
+ }
2353
2642
  }
2354
2643
  catch (e) {
2355
2644
  log.error(`Failed to parse replies JSON for comment ${row.cid} when collecting cids`, e);
2356
2645
  }
2357
2646
  }
2358
- return { cid: row.cid, replies: parsedReplies };
2647
+ return { cid: row.cid, allPageCids };
2359
2648
  });
2360
2649
  }
2361
2650
  queryPostsWithActiveScore(pageOptions) {