@bitsocial/bitsocial-react-hooks 0.1.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.
Files changed (269) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +1365 -0
  3. package/dist/hooks/accounts/accounts.d.ts +64 -0
  4. package/dist/hooks/accounts/accounts.d.ts.map +1 -0
  5. package/dist/hooks/accounts/accounts.js +706 -0
  6. package/dist/hooks/accounts/accounts.js.map +1 -0
  7. package/dist/hooks/accounts/index.d.ts +2 -0
  8. package/dist/hooks/accounts/index.d.ts.map +1 -0
  9. package/dist/hooks/accounts/index.js +2 -0
  10. package/dist/hooks/accounts/index.js.map +1 -0
  11. package/dist/hooks/accounts/utils.d.ts +6 -0
  12. package/dist/hooks/accounts/utils.d.ts.map +1 -0
  13. package/dist/hooks/accounts/utils.js +226 -0
  14. package/dist/hooks/accounts/utils.js.map +1 -0
  15. package/dist/hooks/actions/actions.d.ts +19 -0
  16. package/dist/hooks/actions/actions.d.ts.map +1 -0
  17. package/dist/hooks/actions/actions.js +552 -0
  18. package/dist/hooks/actions/actions.js.map +1 -0
  19. package/dist/hooks/actions/index.d.ts +2 -0
  20. package/dist/hooks/actions/index.d.ts.map +1 -0
  21. package/dist/hooks/actions/index.js +2 -0
  22. package/dist/hooks/actions/index.js.map +1 -0
  23. package/dist/hooks/authors/author-avatars.d.ts +28 -0
  24. package/dist/hooks/authors/author-avatars.d.ts.map +1 -0
  25. package/dist/hooks/authors/author-avatars.js +191 -0
  26. package/dist/hooks/authors/author-avatars.js.map +1 -0
  27. package/dist/hooks/authors/authors.d.ts +37 -0
  28. package/dist/hooks/authors/authors.d.ts.map +1 -0
  29. package/dist/hooks/authors/authors.js +509 -0
  30. package/dist/hooks/authors/authors.js.map +1 -0
  31. package/dist/hooks/authors/index.d.ts +2 -0
  32. package/dist/hooks/authors/index.d.ts.map +1 -0
  33. package/dist/hooks/authors/index.js +2 -0
  34. package/dist/hooks/authors/index.js.map +1 -0
  35. package/dist/hooks/authors/utils.d.ts +4 -0
  36. package/dist/hooks/authors/utils.d.ts.map +1 -0
  37. package/dist/hooks/authors/utils.js +21 -0
  38. package/dist/hooks/authors/utils.js.map +1 -0
  39. package/dist/hooks/comments.d.ts +17 -0
  40. package/dist/hooks/comments.d.ts.map +1 -0
  41. package/dist/hooks/comments.js +351 -0
  42. package/dist/hooks/comments.js.map +1 -0
  43. package/dist/hooks/communities.d.ts +31 -0
  44. package/dist/hooks/communities.d.ts.map +1 -0
  45. package/dist/hooks/communities.js +389 -0
  46. package/dist/hooks/communities.js.map +1 -0
  47. package/dist/hooks/feeds/feeds.d.ts +18 -0
  48. package/dist/hooks/feeds/feeds.d.ts.map +1 -0
  49. package/dist/hooks/feeds/feeds.js +315 -0
  50. package/dist/hooks/feeds/feeds.js.map +1 -0
  51. package/dist/hooks/feeds/index.d.ts +2 -0
  52. package/dist/hooks/feeds/index.d.ts.map +1 -0
  53. package/dist/hooks/feeds/index.js +2 -0
  54. package/dist/hooks/feeds/index.js.map +1 -0
  55. package/dist/hooks/pkc-rpc.d.ts +7 -0
  56. package/dist/hooks/pkc-rpc.d.ts.map +1 -0
  57. package/dist/hooks/pkc-rpc.js +88 -0
  58. package/dist/hooks/pkc-rpc.js.map +1 -0
  59. package/dist/hooks/replies.d.ts +5 -0
  60. package/dist/hooks/replies.d.ts.map +1 -0
  61. package/dist/hooks/replies.js +155 -0
  62. package/dist/hooks/replies.js.map +1 -0
  63. package/dist/hooks/states.d.ts +15 -0
  64. package/dist/hooks/states.d.ts.map +1 -0
  65. package/dist/hooks/states.js +213 -0
  66. package/dist/hooks/states.js.map +1 -0
  67. package/dist/hooks/utils/use-interval.d.ts +3 -0
  68. package/dist/hooks/utils/use-interval.d.ts.map +1 -0
  69. package/dist/hooks/utils/use-interval.js +36 -0
  70. package/dist/hooks/utils/use-interval.js.map +1 -0
  71. package/dist/hooks/utils/use-previous.d.ts +1 -0
  72. package/dist/hooks/utils/use-previous.js +10 -0
  73. package/dist/index.d.ts +82 -0
  74. package/dist/index.d.ts.map +1 -0
  75. package/dist/index.js +128 -0
  76. package/dist/index.js.map +1 -0
  77. package/dist/lib/chain/chain.d.ts +36 -0
  78. package/dist/lib/chain/chain.d.ts.map +1 -0
  79. package/dist/lib/chain/chain.js +195 -0
  80. package/dist/lib/chain/chain.js.map +1 -0
  81. package/dist/lib/chain/index.d.ts +4 -0
  82. package/dist/lib/chain/index.d.ts.map +1 -0
  83. package/dist/lib/chain/index.js +4 -0
  84. package/dist/lib/chain/index.js.map +1 -0
  85. package/dist/lib/community-address.d.ts +6 -0
  86. package/dist/lib/community-address.d.ts.map +1 -0
  87. package/dist/lib/community-address.js +26 -0
  88. package/dist/lib/community-address.js.map +1 -0
  89. package/dist/lib/community-ref.d.ts +23 -0
  90. package/dist/lib/community-ref.d.ts.map +1 -0
  91. package/dist/lib/community-ref.js +113 -0
  92. package/dist/lib/community-ref.js.map +1 -0
  93. package/dist/lib/debug-utils.d.ts +9 -0
  94. package/dist/lib/debug-utils.d.ts.map +1 -0
  95. package/dist/lib/debug-utils.js +21 -0
  96. package/dist/lib/debug-utils.js.map +1 -0
  97. package/dist/lib/feed-sort-type.d.ts +2 -0
  98. package/dist/lib/feed-sort-type.d.ts.map +1 -0
  99. package/dist/lib/feed-sort-type.js +22 -0
  100. package/dist/lib/feed-sort-type.js.map +1 -0
  101. package/dist/lib/localforage-lru/index.d.ts +3 -0
  102. package/dist/lib/localforage-lru/index.d.ts.map +1 -0
  103. package/dist/lib/localforage-lru/index.js +46 -0
  104. package/dist/lib/localforage-lru/index.js.map +1 -0
  105. package/dist/lib/localforage-lru/localforage-lru.d.ts +6 -0
  106. package/dist/lib/localforage-lru/localforage-lru.d.ts.map +1 -0
  107. package/dist/lib/localforage-lru/localforage-lru.js +182 -0
  108. package/dist/lib/localforage-lru/localforage-lru.js.map +1 -0
  109. package/dist/lib/pkc-compat.d.ts +25 -0
  110. package/dist/lib/pkc-compat.d.ts.map +1 -0
  111. package/dist/lib/pkc-compat.js +131 -0
  112. package/dist/lib/pkc-compat.js.map +1 -0
  113. package/dist/lib/pkc-js/fixtures/markdown-example.d.ts +3 -0
  114. package/dist/lib/pkc-js/fixtures/markdown-example.d.ts.map +1 -0
  115. package/dist/lib/pkc-js/fixtures/markdown-example.js +280 -0
  116. package/dist/lib/pkc-js/fixtures/markdown-example.js.map +1 -0
  117. package/dist/lib/pkc-js/index.d.ts +11 -0
  118. package/dist/lib/pkc-js/index.d.ts.map +1 -0
  119. package/dist/lib/pkc-js/index.js +85 -0
  120. package/dist/lib/pkc-js/index.js.map +1 -0
  121. package/dist/lib/pkc-js/pkc-js-mock-content.d.ts +3 -0
  122. package/dist/lib/pkc-js/pkc-js-mock-content.d.ts.map +1 -0
  123. package/dist/lib/pkc-js/pkc-js-mock-content.js +1235 -0
  124. package/dist/lib/pkc-js/pkc-js-mock-content.js.map +1 -0
  125. package/dist/lib/pkc-js/pkc-js-mock.d.ts +137 -0
  126. package/dist/lib/pkc-js/pkc-js-mock.d.ts.map +1 -0
  127. package/dist/lib/pkc-js/pkc-js-mock.js +644 -0
  128. package/dist/lib/pkc-js/pkc-js-mock.js.map +1 -0
  129. package/dist/lib/polyfill.d.ts +3 -0
  130. package/dist/lib/polyfill.d.ts.map +1 -0
  131. package/dist/lib/polyfill.js +14 -0
  132. package/dist/lib/polyfill.js.map +1 -0
  133. package/dist/lib/protocol-compat.d.ts +14 -0
  134. package/dist/lib/protocol-compat.d.ts.map +1 -0
  135. package/dist/lib/protocol-compat.js +67 -0
  136. package/dist/lib/protocol-compat.js.map +1 -0
  137. package/dist/lib/test-utils.d.ts +29 -0
  138. package/dist/lib/test-utils.d.ts.map +1 -0
  139. package/dist/lib/test-utils.js +184 -0
  140. package/dist/lib/test-utils.js.map +1 -0
  141. package/dist/lib/utils/comment-moderation.d.ts +4 -0
  142. package/dist/lib/utils/comment-moderation.d.ts.map +1 -0
  143. package/dist/lib/utils/comment-moderation.js +56 -0
  144. package/dist/lib/utils/comment-moderation.js.map +1 -0
  145. package/dist/lib/utils/index.d.ts +4 -0
  146. package/dist/lib/utils/index.d.ts.map +1 -0
  147. package/dist/lib/utils/index.js +4 -0
  148. package/dist/lib/utils/index.js.map +1 -0
  149. package/dist/lib/utils/utils.d.ts +23 -0
  150. package/dist/lib/utils/utils.d.ts.map +1 -0
  151. package/dist/lib/utils/utils.js +375 -0
  152. package/dist/lib/utils/utils.js.map +1 -0
  153. package/dist/lib/validator.d.ts +30 -0
  154. package/dist/lib/validator.d.ts.map +1 -0
  155. package/dist/lib/validator.js +307 -0
  156. package/dist/lib/validator.js.map +1 -0
  157. package/dist/stores/accounts/account-generator.d.ts +51 -0
  158. package/dist/stores/accounts/account-generator.d.ts.map +1 -0
  159. package/dist/stores/accounts/account-generator.js +160 -0
  160. package/dist/stores/accounts/account-generator.js.map +1 -0
  161. package/dist/stores/accounts/accounts-actions-internal.d.ts +8 -0
  162. package/dist/stores/accounts/accounts-actions-internal.d.ts.map +1 -0
  163. package/dist/stores/accounts/accounts-actions-internal.js +403 -0
  164. package/dist/stores/accounts/accounts-actions-internal.js.map +1 -0
  165. package/dist/stores/accounts/accounts-actions.d.ts +46 -0
  166. package/dist/stores/accounts/accounts-actions.d.ts.map +1 -0
  167. package/dist/stores/accounts/accounts-actions.js +1341 -0
  168. package/dist/stores/accounts/accounts-actions.js.map +1 -0
  169. package/dist/stores/accounts/accounts-database.d.ts +34 -0
  170. package/dist/stores/accounts/accounts-database.d.ts.map +1 -0
  171. package/dist/stores/accounts/accounts-database.js +685 -0
  172. package/dist/stores/accounts/accounts-database.js.map +1 -0
  173. package/dist/stores/accounts/accounts-store.d.ts +32 -0
  174. package/dist/stores/accounts/accounts-store.d.ts.map +1 -0
  175. package/dist/stores/accounts/accounts-store.js +169 -0
  176. package/dist/stores/accounts/accounts-store.js.map +1 -0
  177. package/dist/stores/accounts/index.d.ts +4 -0
  178. package/dist/stores/accounts/index.d.ts.map +1 -0
  179. package/dist/stores/accounts/index.js +4 -0
  180. package/dist/stores/accounts/index.js.map +1 -0
  181. package/dist/stores/accounts/utils.d.ts +49 -0
  182. package/dist/stores/accounts/utils.d.ts.map +1 -0
  183. package/dist/stores/accounts/utils.js +419 -0
  184. package/dist/stores/accounts/utils.js.map +1 -0
  185. package/dist/stores/authors-comments/authors-comments-store.d.ts +37 -0
  186. package/dist/stores/authors-comments/authors-comments-store.d.ts.map +1 -0
  187. package/dist/stores/authors-comments/authors-comments-store.js +338 -0
  188. package/dist/stores/authors-comments/authors-comments-store.js.map +1 -0
  189. package/dist/stores/authors-comments/index.d.ts +4 -0
  190. package/dist/stores/authors-comments/index.d.ts.map +1 -0
  191. package/dist/stores/authors-comments/index.js +4 -0
  192. package/dist/stores/authors-comments/index.js.map +1 -0
  193. package/dist/stores/authors-comments/utils.d.ts +14 -0
  194. package/dist/stores/authors-comments/utils.d.ts.map +1 -0
  195. package/dist/stores/authors-comments/utils.js +81 -0
  196. package/dist/stores/authors-comments/utils.js.map +1 -0
  197. package/dist/stores/comments/comments-store.d.ts +19 -0
  198. package/dist/stores/comments/comments-store.d.ts.map +1 -0
  199. package/dist/stores/comments/comments-store.js +385 -0
  200. package/dist/stores/comments/comments-store.js.map +1 -0
  201. package/dist/stores/comments/index.d.ts +4 -0
  202. package/dist/stores/comments/index.d.ts.map +1 -0
  203. package/dist/stores/comments/index.js +4 -0
  204. package/dist/stores/comments/index.js.map +1 -0
  205. package/dist/stores/communities/communities-store.d.ts +17 -0
  206. package/dist/stores/communities/communities-store.d.ts.map +1 -0
  207. package/dist/stores/communities/communities-store.js +304 -0
  208. package/dist/stores/communities/communities-store.js.map +1 -0
  209. package/dist/stores/communities/index.d.ts +4 -0
  210. package/dist/stores/communities/index.d.ts.map +1 -0
  211. package/dist/stores/communities/index.js +4 -0
  212. package/dist/stores/communities/index.js.map +1 -0
  213. package/dist/stores/communities-pages/communities-pages-store.d.ts +23 -0
  214. package/dist/stores/communities-pages/communities-pages-store.d.ts.map +1 -0
  215. package/dist/stores/communities-pages/communities-pages-store.js +316 -0
  216. package/dist/stores/communities-pages/communities-pages-store.js.map +1 -0
  217. package/dist/stores/communities-pages/index.d.ts +4 -0
  218. package/dist/stores/communities-pages/index.d.ts.map +1 -0
  219. package/dist/stores/communities-pages/index.js +4 -0
  220. package/dist/stores/communities-pages/index.js.map +1 -0
  221. package/dist/stores/feeds/feed-sorter.d.ts +5 -0
  222. package/dist/stores/feeds/feed-sorter.d.ts.map +1 -0
  223. package/dist/stores/feeds/feed-sorter.js +135 -0
  224. package/dist/stores/feeds/feed-sorter.js.map +1 -0
  225. package/dist/stores/feeds/feeds-store.d.ts +25 -0
  226. package/dist/stores/feeds/feeds-store.d.ts.map +1 -0
  227. package/dist/stores/feeds/feeds-store.js +459 -0
  228. package/dist/stores/feeds/feeds-store.js.map +1 -0
  229. package/dist/stores/feeds/index.d.ts +4 -0
  230. package/dist/stores/feeds/index.d.ts.map +1 -0
  231. package/dist/stores/feeds/index.js +4 -0
  232. package/dist/stores/feeds/index.js.map +1 -0
  233. package/dist/stores/feeds/utils.d.ts +43 -0
  234. package/dist/stores/feeds/utils.d.ts.map +1 -0
  235. package/dist/stores/feeds/utils.js +736 -0
  236. package/dist/stores/feeds/utils.js.map +1 -0
  237. package/dist/stores/replies/index.d.ts +4 -0
  238. package/dist/stores/replies/index.d.ts.map +1 -0
  239. package/dist/stores/replies/index.js +4 -0
  240. package/dist/stores/replies/index.js.map +1 -0
  241. package/dist/stores/replies/replies-comments-store.d.ts +8 -0
  242. package/dist/stores/replies/replies-comments-store.d.ts.map +1 -0
  243. package/dist/stores/replies/replies-comments-store.js +23 -0
  244. package/dist/stores/replies/replies-comments-store.js.map +1 -0
  245. package/dist/stores/replies/replies-store.d.ts +29 -0
  246. package/dist/stores/replies/replies-store.d.ts.map +1 -0
  247. package/dist/stores/replies/replies-store.js +413 -0
  248. package/dist/stores/replies/replies-store.js.map +1 -0
  249. package/dist/stores/replies/utils.d.ts +25 -0
  250. package/dist/stores/replies/utils.d.ts.map +1 -0
  251. package/dist/stores/replies/utils.js +549 -0
  252. package/dist/stores/replies/utils.js.map +1 -0
  253. package/dist/stores/replies-pages/index.d.ts +4 -0
  254. package/dist/stores/replies-pages/index.d.ts.map +1 -0
  255. package/dist/stores/replies-pages/index.js +4 -0
  256. package/dist/stores/replies-pages/index.js.map +1 -0
  257. package/dist/stores/replies-pages/replies-pages-store.d.ts +20 -0
  258. package/dist/stores/replies-pages/replies-pages-store.d.ts.map +1 -0
  259. package/dist/stores/replies-pages/replies-pages-store.js +270 -0
  260. package/dist/stores/replies-pages/replies-pages-store.js.map +1 -0
  261. package/dist/stores/replies-pages/utils.d.ts +3 -0
  262. package/dist/stores/replies-pages/utils.d.ts.map +1 -0
  263. package/dist/stores/replies-pages/utils.js +43 -0
  264. package/dist/stores/replies-pages/utils.js.map +1 -0
  265. package/dist/types.d.ts +638 -0
  266. package/dist/types.d.ts.map +1 -0
  267. package/dist/types.js +3 -0
  268. package/dist/types.js.map +1 -0
  269. package/package.json +160 -0
@@ -0,0 +1,316 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import utils from "../../lib/utils/index.js";
11
+ import Logger from "@pkcprotocol/pkc-logger";
12
+ // include communities pages store with feeds for debugging
13
+ export const log = Logger("bitsocial-react-hooks:feeds:stores");
14
+ import accountsStore from "../accounts/index.js";
15
+ import communitiesStore from "../communities/index.js";
16
+ import localForageLru from "../../lib/localforage-lru/index.js";
17
+ import createStore from "zustand";
18
+ import assert from "assert";
19
+ import { createPkcCommunity, getPkcCreateCommunity, normalizeCommentCommunityAddress, } from "../../lib/pkc-compat.js";
20
+ const communitiesPagesDatabase = localForageLru.createInstance({
21
+ name: "bitsocialReactHooks-communitiesPages",
22
+ size: 500,
23
+ });
24
+ const getCommunityPageStoreKey = (pageCid, pageType, accountId) => {
25
+ if (pageType === "modQueue") {
26
+ assert(accountId && typeof accountId === "string", `getCommunityPageStoreKey accountId '${accountId}' invalid for modQueue`);
27
+ return `${accountId}:${pageCid}`;
28
+ }
29
+ return pageCid;
30
+ };
31
+ /** Freshness for comparison: max(updatedAt, timestamp, 0). Used to decide add vs replace per CID. Exported for coverage. */
32
+ export const getCommentFreshness = (comment) => { var _a, _b; return Math.max((_a = comment === null || comment === void 0 ? void 0 : comment.updatedAt) !== null && _a !== void 0 ? _a : 0, (_b = comment === null || comment === void 0 ? void 0 : comment.timestamp) !== null && _b !== void 0 ? _b : 0, 0); };
33
+ // reset all event listeners in between tests
34
+ const listeners = [];
35
+ const communitiesPagesStore = createStore((setState, getState) => ({
36
+ // TODO: eventually clear old pages and comments from memory
37
+ communitiesPages: {},
38
+ comments: {},
39
+ addNextCommunityPageToStore: (community, sortType, account, modQueue) => __awaiter(void 0, void 0, void 0, function* () {
40
+ var _a;
41
+ assert((community === null || community === void 0 ? void 0 : community.address) && typeof (community === null || community === void 0 ? void 0 : community.address) === "string", `communitiesPagesStore.addNextCommunityPageToStore community '${community}' invalid`);
42
+ assert(sortType && typeof sortType === "string", `communitiesPagesStore.addNextCommunityPageToStore sortType '${sortType}' invalid`);
43
+ assert(typeof getPkcCreateCommunity(account === null || account === void 0 ? void 0 : account.pkc) === "function", `communitiesPagesStore.addNextCommunityPageToStore account '${account}' invalid`);
44
+ assert(!modQueue || Array.isArray(modQueue), `communitiesPagesStore.addNextCommunityPageToStore modQueue '${modQueue}' invalid`);
45
+ let pageType = "posts";
46
+ if (modQueue === null || modQueue === void 0 ? void 0 : modQueue[0]) {
47
+ // TODO: allow multiple modQueue at once, fow now only use first in array
48
+ // TODO: fix 'sortType' is not accurate variable name when pageType is 'modQueue'
49
+ sortType = modQueue[0];
50
+ pageType = "modQueue";
51
+ }
52
+ // check the preloaded posts on community.posts.pages first, then the community.posts.pageCids
53
+ const communityFirstPageCid = getCommunityFirstPageCid(community, sortType, pageType);
54
+ if (!communityFirstPageCid) {
55
+ log(`communitiesPagesStore.addNextCommunityPageToStore community '${community === null || community === void 0 ? void 0 : community.address}' sortType '${sortType}' no communityFirstPageCid`);
56
+ return;
57
+ }
58
+ // all communities pages in store
59
+ const { communitiesPages } = getState();
60
+ // only specific pages of the community+sortType
61
+ const communityPages = getCommunityPages(community, sortType, communitiesPages, pageType, account.id);
62
+ // if no pages exist yet, add the first page
63
+ let pageCidToAdd;
64
+ if (!communityPages.length) {
65
+ pageCidToAdd = communityFirstPageCid;
66
+ }
67
+ else {
68
+ const nextCid = (_a = communityPages[communityPages.length - 1]) === null || _a === void 0 ? void 0 : _a.nextCid;
69
+ // if last nextCid is undefined, reached end of pages
70
+ if (!nextCid) {
71
+ log.trace("communitiesPagesStore.addNextCommunityPageToStore no more pages", {
72
+ communityAddress: community.address,
73
+ sortType,
74
+ account,
75
+ });
76
+ return;
77
+ }
78
+ pageCidToAdd = nextCid;
79
+ }
80
+ // page is already added or pending
81
+ const pageStoreKeyToAdd = getCommunityPageStoreKey(pageCidToAdd, pageType, account.id);
82
+ if (communitiesPages[pageStoreKeyToAdd] || fetchPagePending[pageStoreKeyToAdd]) {
83
+ return;
84
+ }
85
+ fetchPagePending[pageStoreKeyToAdd] = true;
86
+ let page;
87
+ try {
88
+ page = yield fetchPage(pageCidToAdd, community.address, account, pageType);
89
+ log.trace("communitiesPagesStore.addNextCommunityPageToStore community.posts.getPage", {
90
+ pageCid: pageCidToAdd,
91
+ communityAddress: community.address,
92
+ account,
93
+ });
94
+ }
95
+ catch (e) {
96
+ throw e;
97
+ }
98
+ finally {
99
+ fetchPagePending[pageStoreKeyToAdd] = false;
100
+ }
101
+ // find new comments in the page
102
+ const flattenedComments = utils.flattenCommentsPages(page);
103
+ const { comments } = getState();
104
+ let hasNewComments = false;
105
+ const newComments = {};
106
+ if (pageType !== "modQueue") {
107
+ for (const comment of flattenedComments) {
108
+ const normalizedComment = normalizeCommentCommunityAddress(comment);
109
+ const existing = comments[normalizedComment.cid];
110
+ if (normalizedComment.cid &&
111
+ (!existing || getCommentFreshness(normalizedComment) > getCommentFreshness(existing))) {
112
+ // don't clone the comment to save memory, comments remain a pointer to the page object
113
+ newComments[normalizedComment.cid] = normalizedComment;
114
+ hasNewComments = true;
115
+ }
116
+ }
117
+ }
118
+ setState(({ communitiesPages, comments }) => {
119
+ const newState = {
120
+ communitiesPages: Object.assign(Object.assign({}, communitiesPages), { [pageStoreKeyToAdd]: page }),
121
+ };
122
+ if (hasNewComments) {
123
+ newState.comments = Object.assign(Object.assign({}, comments), newComments);
124
+ }
125
+ return newState;
126
+ });
127
+ log("communitiesPagesStore.addNextCommunityPageToStore", {
128
+ pageCid: pageCidToAdd,
129
+ communityAddress: community.address,
130
+ sortType,
131
+ page,
132
+ account,
133
+ });
134
+ // when publishing a comment, you don't yet know its CID
135
+ // so when a new comment is fetched, check to see if it's your own
136
+ // comment, and if yes, add the CID to your account comments database
137
+ for (const comment of flattenedComments) {
138
+ accountsStore
139
+ .getState()
140
+ .accountsActionsInternal.addCidToAccountComment(normalizeCommentCommunityAddress(comment))
141
+ .catch((error) => log.error("communitiesPagesStore.addNextCommunityPageToStore addCidToAccountComment error", { comment, error }));
142
+ }
143
+ }),
144
+ invalidateCommunityPages: (community, sortType, modQueue, accountId) => __awaiter(void 0, void 0, void 0, function* () {
145
+ var _a, _b;
146
+ assert((community === null || community === void 0 ? void 0 : community.address) && typeof (community === null || community === void 0 ? void 0 : community.address) === "string", `communitiesPagesStore.invalidateCommunityPages community '${community}' invalid`);
147
+ assert(sortType && typeof sortType === "string", `communitiesPagesStore.invalidateCommunityPages sortType '${sortType}' invalid`);
148
+ assert(!modQueue || Array.isArray(modQueue), `communitiesPagesStore.invalidateCommunityPages modQueue '${modQueue}' invalid`);
149
+ let pageType = "posts";
150
+ if (modQueue === null || modQueue === void 0 ? void 0 : modQueue[0]) {
151
+ // TODO: allow multiple modQueue at once, for now only use first in array
152
+ // TODO: fix 'sortType' is not accurate variable name when pageType is 'modQueue'
153
+ sortType = modQueue[0];
154
+ pageType = "modQueue";
155
+ }
156
+ const firstPageCid = getCommunityFirstPageCid(community, sortType, pageType);
157
+ if (!firstPageCid) {
158
+ return;
159
+ }
160
+ const { communitiesPages } = getState();
161
+ const firstPageKey = getCommunityPageStoreKey(firstPageCid, pageType, accountId);
162
+ const pageKeysToInvalidate = new Set([firstPageKey]);
163
+ let nextPageCid = (_a = communitiesPages[firstPageKey]) === null || _a === void 0 ? void 0 : _a.nextCid;
164
+ while (nextPageCid) {
165
+ const nextPageKey = getCommunityPageStoreKey(nextPageCid, pageType, accountId);
166
+ pageKeysToInvalidate.add(nextPageKey);
167
+ nextPageCid = (_b = communitiesPages[nextPageKey]) === null || _b === void 0 ? void 0 : _b.nextCid;
168
+ }
169
+ yield Promise.all([...pageKeysToInvalidate].map((pageKey) => communitiesPagesDatabase.removeItem(pageKey)));
170
+ setState(({ communitiesPages }) => {
171
+ const nextCommunitiesPages = Object.assign({}, communitiesPages);
172
+ for (const pageKey of pageKeysToInvalidate) {
173
+ delete nextCommunitiesPages[pageKey];
174
+ }
175
+ return { communitiesPages: nextCommunitiesPages };
176
+ });
177
+ }),
178
+ // communities contain preloaded pages, those page comments must be added separately
179
+ addCommunityPageCommentsToStore: (community) => {
180
+ var _a;
181
+ if (!((_a = community.posts) === null || _a === void 0 ? void 0 : _a.pages)) {
182
+ return;
183
+ }
184
+ // find new comments in the page
185
+ const flattenedComments = utils.flattenCommentsPages(community.posts.pages);
186
+ const { comments } = getState();
187
+ let hasNewComments = false;
188
+ const newComments = {};
189
+ for (const comment of flattenedComments) {
190
+ const existing = comments[comment.cid];
191
+ if (comment.cid &&
192
+ (!existing || getCommentFreshness(comment) > getCommentFreshness(existing))) {
193
+ // don't clone the comment to save memory, comments remain a pointer to the page object
194
+ newComments[comment.cid] = comment;
195
+ hasNewComments = true;
196
+ }
197
+ }
198
+ if (!hasNewComments) {
199
+ return;
200
+ }
201
+ setState(({ comments }) => {
202
+ return { comments: Object.assign(Object.assign({}, comments), newComments) };
203
+ });
204
+ log("communitiesPagesStore.addCommunityPageCommentsToStore", { community, newComments });
205
+ },
206
+ }));
207
+ // set clients states on communities store so the frontend can display it, dont persist in db because a reload cancels updating
208
+ const onCommunityPostsClientsStateChange = (communityAddress) => (clientState, clientType, sortType, clientUrl) => {
209
+ communitiesStore.setState((state) => {
210
+ // make sure not undefined, sometimes happens in e2e tests
211
+ if (!state.communities[communityAddress]) {
212
+ return {};
213
+ }
214
+ const client = { state: clientState };
215
+ const community = Object.assign({}, state.communities[communityAddress]);
216
+ community.posts = Object.assign({}, community.posts);
217
+ community.posts.clients = Object.assign({}, community.posts.clients);
218
+ community.posts.clients[clientType] = Object.assign({}, community.posts.clients[clientType]);
219
+ community.posts.clients[clientType][sortType] = Object.assign({}, community.posts.clients[clientType][sortType]);
220
+ community.posts.clients[clientType][sortType][clientUrl] = client;
221
+ return { communities: Object.assign(Object.assign({}, state.communities), { [community.address]: community }) };
222
+ });
223
+ };
224
+ const fetchPageCommunities = {}; // cache created community clients per account because creating them can be slow
225
+ let fetchPagePending = {};
226
+ const fetchPage = (pageCid, communityAddress, account, pageType) => __awaiter(void 0, void 0, void 0, function* () {
227
+ var _a;
228
+ // community page is cached
229
+ const pageStoreKey = getCommunityPageStoreKey(pageCid, pageType, account.id);
230
+ const cachedCommunityPage = yield communitiesPagesDatabase.getItem(pageStoreKey);
231
+ if (cachedCommunityPage) {
232
+ return cachedCommunityPage;
233
+ }
234
+ if (!fetchPageCommunities[account.id] || fetchPageCommunities[account.id].pkc !== account.pkc) {
235
+ fetchPageCommunities[account.id] = { pkc: account.pkc, communities: {} };
236
+ }
237
+ const accountCommunities = fetchPageCommunities[account.id].communities;
238
+ if (!accountCommunities[communityAddress]) {
239
+ accountCommunities[communityAddress] = yield createPkcCommunity(account.pkc, {
240
+ address: communityAddress,
241
+ });
242
+ listeners.push(accountCommunities[communityAddress]);
243
+ // set clients states on communities store so the frontend can display it
244
+ utils.pageClientsOnStateChange((_a = accountCommunities[communityAddress][pageType]) === null || _a === void 0 ? void 0 : _a.clients, onCommunityPostsClientsStateChange(communityAddress));
245
+ }
246
+ const onError = (error) => log.error(`communitiesPagesStore community '${communityAddress}' failed community.posts.getPage page cid '${pageCid}':`, error);
247
+ const fetchedCommunityPage = yield utils.retryInfinity(() => accountCommunities[communityAddress][pageType].getPage({ cid: pageCid }), { onError });
248
+ yield communitiesPagesDatabase.setItem(pageStoreKey, utils.clone(fetchedCommunityPage));
249
+ return fetchedCommunityPage;
250
+ });
251
+ /**
252
+ * Util function to get all pages in the store for a
253
+ * specific community+sortType using `CommunityPage.nextCid`
254
+ */
255
+ export const getCommunityPages = (community, sortType, communitiesPages, pageType, accountId) => {
256
+ var _a;
257
+ assert(communitiesPages && typeof communitiesPages === "object", `getCommunityPages communitiesPages '${communitiesPages}' invalid`);
258
+ const pages = [];
259
+ const firstPageCid = getCommunityFirstPageCid(community, sortType, pageType);
260
+ // community has no pages
261
+ // TODO: if a loaded community doesn't have a first page, it's unclear what we should do
262
+ // should we try to use another sort type by default, like 'hot', or should we just ignore it?
263
+ // 'return pages' to ignore it for now
264
+ if (!firstPageCid) {
265
+ return pages;
266
+ }
267
+ const firstPage = communitiesPages[getCommunityPageStoreKey(firstPageCid, pageType, accountId)];
268
+ if (!firstPage) {
269
+ return pages;
270
+ }
271
+ pages.push(firstPage);
272
+ while (true) {
273
+ const nextCid = (_a = pages[pages.length - 1]) === null || _a === void 0 ? void 0 : _a.nextCid;
274
+ const nextPageKey = nextCid && getCommunityPageStoreKey(nextCid, pageType, accountId);
275
+ const communityPage = nextPageKey && communitiesPages[nextPageKey];
276
+ if (!communityPage) {
277
+ return pages;
278
+ }
279
+ pages.push(communityPage);
280
+ }
281
+ };
282
+ export const getCommunityFirstPageCid = (community, sortType, pageType = "posts") => {
283
+ var _a, _b, _c, _d, _e, _f, _g, _h;
284
+ assert(community && typeof community === "object", `getCommunityFirstPageCid community '${community}' invalid`);
285
+ assert(sortType && typeof sortType === "string", `getCommunityFirstPageCid sortType '${sortType}' invalid`);
286
+ // community has preloaded posts for sort type
287
+ if ((_c = (_b = (_a = community[pageType]) === null || _a === void 0 ? void 0 : _a.pages) === null || _b === void 0 ? void 0 : _b[sortType]) === null || _c === void 0 ? void 0 : _c.comments) {
288
+ return (_f = (_e = (_d = community[pageType]) === null || _d === void 0 ? void 0 : _d.pages) === null || _e === void 0 ? void 0 : _e[sortType]) === null || _f === void 0 ? void 0 : _f.nextCid;
289
+ }
290
+ return (_h = (_g = community[pageType]) === null || _g === void 0 ? void 0 : _g.pageCids) === null || _h === void 0 ? void 0 : _h[sortType];
291
+ // TODO: if a loaded community doesn't have a first page, it's unclear what we should do
292
+ // should we try to use another sort type by default, like 'hot', or should we just ignore it?
293
+ };
294
+ // reset store in between tests
295
+ const originalState = communitiesPagesStore.getState();
296
+ // async function because some stores have async init
297
+ export const resetCommunitiesPagesStore = () => __awaiter(void 0, void 0, void 0, function* () {
298
+ fetchPagePending = {};
299
+ for (const accountId in fetchPageCommunities) {
300
+ delete fetchPageCommunities[accountId];
301
+ }
302
+ // remove all event listeners
303
+ listeners.forEach((listener) => listener.removeAllListeners());
304
+ listeners.length = 0;
305
+ // destroy all component subscriptions to the store
306
+ communitiesPagesStore.destroy();
307
+ // restore original state
308
+ communitiesPagesStore.setState(originalState);
309
+ });
310
+ // reset database and store in between tests
311
+ export const resetCommunitiesPagesDatabaseAndStore = () => __awaiter(void 0, void 0, void 0, function* () {
312
+ yield localForageLru.createInstance({ name: "bitsocialReactHooks-communitiesPages" }).clear();
313
+ yield resetCommunitiesPagesStore();
314
+ });
315
+ export default communitiesPagesStore;
316
+ //# sourceMappingURL=communities-pages-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"communities-pages-store.js","sourceRoot":"","sources":["../../../src/stores/communities-pages/communities-pages-store.ts"],"names":[],"mappings":"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","sourcesContent":["import utils from \"../../lib/utils\";\nimport Logger from \"@pkcprotocol/pkc-logger\";\n// include communities pages store with feeds for debugging\nexport const log = Logger(\"bitsocial-react-hooks:feeds:stores\");\nimport {\n Community,\n CommunityPage,\n CommunitiesPages,\n Account,\n Comment,\n Comments,\n} from \"../../types\";\nimport accountsStore from \"../accounts\";\nimport communitiesStore, { CommunitiesState } from \"../communities\";\nimport localForageLru from \"../../lib/localforage-lru\";\nimport createStore from \"zustand\";\nimport assert from \"assert\";\nimport {\n createPkcCommunity,\n getPkcCreateCommunity,\n normalizeCommentCommunityAddress,\n} from \"../../lib/pkc-compat\";\n\nconst communitiesPagesDatabase = localForageLru.createInstance({\n name: \"bitsocialReactHooks-communitiesPages\",\n size: 500,\n});\n\nconst getCommunityPageStoreKey = (pageCid: string, pageType: string, accountId?: string) => {\n if (pageType === \"modQueue\") {\n assert(\n accountId && typeof accountId === \"string\",\n `getCommunityPageStoreKey accountId '${accountId}' invalid for modQueue`,\n );\n return `${accountId}:${pageCid}`;\n }\n return pageCid;\n};\n\n/** Freshness for comparison: max(updatedAt, timestamp, 0). Used to decide add vs replace per CID. Exported for coverage. */\nexport const getCommentFreshness = (comment: Comment | undefined): number =>\n Math.max(comment?.updatedAt ?? 0, comment?.timestamp ?? 0, 0);\n\n// reset all event listeners in between tests\nconst listeners: any = [];\n\ntype CommunitiesPagesState = {\n communitiesPages: CommunitiesPages;\n comments: Comments;\n addNextCommunityPageToStore: Function;\n invalidateCommunityPages: Function;\n addCommunityPageCommentsToStore: Function;\n};\n\nconst communitiesPagesStore = createStore<CommunitiesPagesState>(\n (setState: Function, getState: Function) => ({\n // TODO: eventually clear old pages and comments from memory\n communitiesPages: {},\n comments: {},\n\n addNextCommunityPageToStore: async (\n community: Community,\n sortType: string,\n account: Account,\n modQueue?: string[],\n ) => {\n assert(\n community?.address && typeof community?.address === \"string\",\n `communitiesPagesStore.addNextCommunityPageToStore community '${community}' invalid`,\n );\n assert(\n sortType && typeof sortType === \"string\",\n `communitiesPagesStore.addNextCommunityPageToStore sortType '${sortType}' invalid`,\n );\n assert(\n typeof getPkcCreateCommunity(account?.pkc) === \"function\",\n `communitiesPagesStore.addNextCommunityPageToStore account '${account}' invalid`,\n );\n assert(\n !modQueue || Array.isArray(modQueue),\n `communitiesPagesStore.addNextCommunityPageToStore modQueue '${modQueue}' invalid`,\n );\n\n let pageType = \"posts\";\n if (modQueue?.[0]) {\n // TODO: allow multiple modQueue at once, fow now only use first in array\n // TODO: fix 'sortType' is not accurate variable name when pageType is 'modQueue'\n sortType = modQueue[0];\n pageType = \"modQueue\";\n }\n\n // check the preloaded posts on community.posts.pages first, then the community.posts.pageCids\n const communityFirstPageCid = getCommunityFirstPageCid(community, sortType, pageType);\n if (!communityFirstPageCid) {\n log(\n `communitiesPagesStore.addNextCommunityPageToStore community '${community?.address}' sortType '${sortType}' no communityFirstPageCid`,\n );\n return;\n }\n\n // all communities pages in store\n const { communitiesPages } = getState();\n // only specific pages of the community+sortType\n const communityPages = getCommunityPages(\n community,\n sortType,\n communitiesPages,\n pageType,\n account.id,\n );\n\n // if no pages exist yet, add the first page\n let pageCidToAdd: string;\n if (!communityPages.length) {\n pageCidToAdd = communityFirstPageCid;\n } else {\n const nextCid = communityPages[communityPages.length - 1]?.nextCid;\n // if last nextCid is undefined, reached end of pages\n if (!nextCid) {\n log.trace(\"communitiesPagesStore.addNextCommunityPageToStore no more pages\", {\n communityAddress: community.address,\n sortType,\n account,\n });\n return;\n }\n\n pageCidToAdd = nextCid;\n }\n\n // page is already added or pending\n const pageStoreKeyToAdd = getCommunityPageStoreKey(pageCidToAdd, pageType, account.id);\n if (communitiesPages[pageStoreKeyToAdd] || fetchPagePending[pageStoreKeyToAdd]) {\n return;\n }\n\n fetchPagePending[pageStoreKeyToAdd] = true;\n let page: CommunityPage;\n try {\n page = await fetchPage(pageCidToAdd, community.address, account, pageType);\n log.trace(\"communitiesPagesStore.addNextCommunityPageToStore community.posts.getPage\", {\n pageCid: pageCidToAdd,\n communityAddress: community.address,\n account,\n });\n } catch (e) {\n throw e;\n } finally {\n fetchPagePending[pageStoreKeyToAdd] = false;\n }\n\n // find new comments in the page\n const flattenedComments = utils.flattenCommentsPages(page);\n const { comments } = getState();\n let hasNewComments = false;\n const newComments: Comments = {};\n if (pageType !== \"modQueue\") {\n for (const comment of flattenedComments) {\n const normalizedComment = normalizeCommentCommunityAddress(comment) as Comment;\n const existing = comments[normalizedComment.cid];\n if (\n normalizedComment.cid &&\n (!existing || getCommentFreshness(normalizedComment) > getCommentFreshness(existing))\n ) {\n // don't clone the comment to save memory, comments remain a pointer to the page object\n newComments[normalizedComment.cid] = normalizedComment;\n hasNewComments = true;\n }\n }\n }\n\n setState(({ communitiesPages, comments }: any) => {\n const newState: any = {\n communitiesPages: { ...communitiesPages, [pageStoreKeyToAdd]: page },\n };\n if (hasNewComments) {\n newState.comments = { ...comments, ...newComments };\n }\n return newState;\n });\n log(\"communitiesPagesStore.addNextCommunityPageToStore\", {\n pageCid: pageCidToAdd,\n communityAddress: community.address,\n sortType,\n page,\n account,\n });\n\n // when publishing a comment, you don't yet know its CID\n // so when a new comment is fetched, check to see if it's your own\n // comment, and if yes, add the CID to your account comments database\n for (const comment of flattenedComments) {\n accountsStore\n .getState()\n .accountsActionsInternal.addCidToAccountComment(\n normalizeCommentCommunityAddress(comment) as Comment,\n )\n .catch((error: unknown) =>\n log.error(\n \"communitiesPagesStore.addNextCommunityPageToStore addCidToAccountComment error\",\n { comment, error },\n ),\n );\n }\n },\n\n invalidateCommunityPages: async (\n community: Community,\n sortType: string,\n modQueue?: string[],\n accountId?: string,\n ) => {\n assert(\n community?.address && typeof community?.address === \"string\",\n `communitiesPagesStore.invalidateCommunityPages community '${community}' invalid`,\n );\n assert(\n sortType && typeof sortType === \"string\",\n `communitiesPagesStore.invalidateCommunityPages sortType '${sortType}' invalid`,\n );\n assert(\n !modQueue || Array.isArray(modQueue),\n `communitiesPagesStore.invalidateCommunityPages modQueue '${modQueue}' invalid`,\n );\n\n let pageType = \"posts\";\n if (modQueue?.[0]) {\n // TODO: allow multiple modQueue at once, for now only use first in array\n // TODO: fix 'sortType' is not accurate variable name when pageType is 'modQueue'\n sortType = modQueue[0];\n pageType = \"modQueue\";\n }\n\n const firstPageCid = getCommunityFirstPageCid(community, sortType, pageType);\n if (!firstPageCid) {\n return;\n }\n\n const { communitiesPages } = getState();\n const firstPageKey = getCommunityPageStoreKey(firstPageCid, pageType, accountId);\n const pageKeysToInvalidate = new Set<string>([firstPageKey]);\n let nextPageCid = communitiesPages[firstPageKey]?.nextCid;\n while (nextPageCid) {\n const nextPageKey = getCommunityPageStoreKey(nextPageCid, pageType, accountId);\n pageKeysToInvalidate.add(nextPageKey);\n nextPageCid = communitiesPages[nextPageKey]?.nextCid;\n }\n\n await Promise.all(\n [...pageKeysToInvalidate].map((pageKey) => communitiesPagesDatabase.removeItem(pageKey)),\n );\n\n setState(({ communitiesPages }: any) => {\n const nextCommunitiesPages = { ...communitiesPages };\n for (const pageKey of pageKeysToInvalidate) {\n delete nextCommunitiesPages[pageKey];\n }\n return { communitiesPages: nextCommunitiesPages };\n });\n },\n\n // communities contain preloaded pages, those page comments must be added separately\n addCommunityPageCommentsToStore: (community: Community) => {\n if (!community.posts?.pages) {\n return;\n }\n\n // find new comments in the page\n const flattenedComments = utils.flattenCommentsPages(community.posts.pages);\n const { comments } = getState();\n let hasNewComments = false;\n const newComments: Comments = {};\n for (const comment of flattenedComments) {\n const existing = comments[comment.cid];\n if (\n comment.cid &&\n (!existing || getCommentFreshness(comment) > getCommentFreshness(existing))\n ) {\n // don't clone the comment to save memory, comments remain a pointer to the page object\n newComments[comment.cid] = comment;\n hasNewComments = true;\n }\n }\n\n if (!hasNewComments) {\n return;\n }\n\n setState(({ comments }: any) => {\n return { comments: { ...comments, ...newComments } };\n });\n log(\"communitiesPagesStore.addCommunityPageCommentsToStore\", { community, newComments });\n },\n }),\n);\n\n// set clients states on communities store so the frontend can display it, dont persist in db because a reload cancels updating\nconst onCommunityPostsClientsStateChange =\n (communityAddress: string) =>\n (clientState: string, clientType: string, sortType: string, clientUrl: string) => {\n communitiesStore.setState((state: CommunitiesState) => {\n // make sure not undefined, sometimes happens in e2e tests\n if (!state.communities[communityAddress]) {\n return {};\n }\n const client = { state: clientState };\n const community = { ...state.communities[communityAddress] };\n community.posts = { ...community.posts };\n community.posts.clients = { ...community.posts.clients };\n community.posts.clients[clientType] = { ...community.posts.clients[clientType] };\n community.posts.clients[clientType][sortType] = {\n ...community.posts.clients[clientType][sortType],\n };\n community.posts.clients[clientType][sortType][clientUrl] = client;\n return { communities: { ...state.communities, [community.address]: community } };\n });\n };\n\nconst fetchPageCommunities: {\n [accountId: string]: { pkc: any; communities: { [communityAddress: string]: any } };\n} = {}; // cache created community clients per account because creating them can be slow\nlet fetchPagePending: { [key: string]: boolean } = {};\nconst fetchPage = async (\n pageCid: string,\n communityAddress: string,\n account: Account,\n pageType: string,\n) => {\n // community page is cached\n const pageStoreKey = getCommunityPageStoreKey(pageCid, pageType, account.id);\n const cachedCommunityPage = await communitiesPagesDatabase.getItem(pageStoreKey);\n if (cachedCommunityPage) {\n return cachedCommunityPage;\n }\n if (!fetchPageCommunities[account.id] || fetchPageCommunities[account.id].pkc !== account.pkc) {\n fetchPageCommunities[account.id] = { pkc: account.pkc, communities: {} };\n }\n const accountCommunities = fetchPageCommunities[account.id].communities;\n if (!accountCommunities[communityAddress]) {\n accountCommunities[communityAddress] = await createPkcCommunity(account.pkc, {\n address: communityAddress,\n });\n listeners.push(accountCommunities[communityAddress]);\n\n // set clients states on communities store so the frontend can display it\n utils.pageClientsOnStateChange(\n accountCommunities[communityAddress][pageType]?.clients,\n onCommunityPostsClientsStateChange(communityAddress),\n );\n }\n\n const onError = (error: any) =>\n log.error(\n `communitiesPagesStore community '${communityAddress}' failed community.posts.getPage page cid '${pageCid}':`,\n error,\n );\n const fetchedCommunityPage = await utils.retryInfinity(\n () => accountCommunities[communityAddress][pageType].getPage({ cid: pageCid }),\n { onError },\n );\n await communitiesPagesDatabase.setItem(pageStoreKey, utils.clone(fetchedCommunityPage));\n return fetchedCommunityPage;\n};\n\n/**\n * Util function to get all pages in the store for a\n * specific community+sortType using `CommunityPage.nextCid`\n */\nexport const getCommunityPages = (\n community: Community,\n sortType: string,\n communitiesPages: CommunitiesPages,\n pageType: string,\n accountId?: string,\n) => {\n assert(\n communitiesPages && typeof communitiesPages === \"object\",\n `getCommunityPages communitiesPages '${communitiesPages}' invalid`,\n );\n const pages: CommunityPage[] = [];\n const firstPageCid = getCommunityFirstPageCid(community, sortType, pageType);\n // community has no pages\n // TODO: if a loaded community doesn't have a first page, it's unclear what we should do\n // should we try to use another sort type by default, like 'hot', or should we just ignore it?\n // 'return pages' to ignore it for now\n if (!firstPageCid) {\n return pages;\n }\n const firstPage = communitiesPages[getCommunityPageStoreKey(firstPageCid, pageType, accountId)];\n if (!firstPage) {\n return pages;\n }\n pages.push(firstPage);\n while (true) {\n const nextCid = pages[pages.length - 1]?.nextCid;\n const nextPageKey = nextCid && getCommunityPageStoreKey(nextCid, pageType, accountId);\n const communityPage = nextPageKey && communitiesPages[nextPageKey];\n if (!communityPage) {\n return pages;\n }\n pages.push(communityPage);\n }\n};\n\nexport const getCommunityFirstPageCid = (\n community: Community,\n sortType: string,\n pageType = \"posts\",\n) => {\n assert(\n community && typeof community === \"object\",\n `getCommunityFirstPageCid community '${community}' invalid`,\n );\n assert(\n sortType && typeof sortType === \"string\",\n `getCommunityFirstPageCid sortType '${sortType}' invalid`,\n );\n // community has preloaded posts for sort type\n if (community[pageType]?.pages?.[sortType]?.comments) {\n return community[pageType]?.pages?.[sortType]?.nextCid;\n }\n return community[pageType]?.pageCids?.[sortType];\n\n // TODO: if a loaded community doesn't have a first page, it's unclear what we should do\n // should we try to use another sort type by default, like 'hot', or should we just ignore it?\n};\n\n// reset store in between tests\nconst originalState = communitiesPagesStore.getState();\n// async function because some stores have async init\nexport const resetCommunitiesPagesStore = async () => {\n fetchPagePending = {};\n for (const accountId in fetchPageCommunities) {\n delete fetchPageCommunities[accountId];\n }\n // remove all event listeners\n listeners.forEach((listener: any) => listener.removeAllListeners());\n listeners.length = 0;\n // destroy all component subscriptions to the store\n communitiesPagesStore.destroy();\n // restore original state\n communitiesPagesStore.setState(originalState);\n};\n\n// reset database and store in between tests\nexport const resetCommunitiesPagesDatabaseAndStore = async () => {\n await localForageLru.createInstance({ name: \"bitsocialReactHooks-communitiesPages\" }).clear();\n await resetCommunitiesPagesStore();\n};\n\nexport default communitiesPagesStore;\n"]}
@@ -0,0 +1,4 @@
1
+ import communitiesPagesStore from "./communities-pages-store.js";
2
+ export * from "./communities-pages-store.js";
3
+ export default communitiesPagesStore;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/stores/communities-pages/index.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,MAAM,2BAA2B,CAAC;AAC9D,cAAc,2BAA2B,CAAC;AAC1C,eAAe,qBAAqB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import communitiesPagesStore from "./communities-pages-store.js";
2
+ export * from "./communities-pages-store.js";
3
+ export default communitiesPagesStore;
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/stores/communities-pages/index.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,MAAM,2BAA2B,CAAC;AAC9D,cAAc,2BAA2B,CAAC;AAC1C,eAAe,qBAAqB,CAAC","sourcesContent":["import communitiesPagesStore from \"./communities-pages-store\";\nexport * from \"./communities-pages-store\";\nexport default communitiesPagesStore;\n"]}
@@ -0,0 +1,5 @@
1
+ declare const _default: {
2
+ sort: (sortType: string, feed: any[]) => any[];
3
+ };
4
+ export default _default;
5
+ //# sourceMappingURL=feed-sorter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feed-sorter.d.ts","sourceRoot":"","sources":["../../../src/stores/feeds/feed-sorter.ts"],"names":[],"mappings":";qBAsHwB,MAAM,QAAQ,GAAG,EAAE;;AA8B3C,wBAAwB"}
@@ -0,0 +1,135 @@
1
+ /** Single fallback for numeric values to reduce Istanbul branch sites */
2
+ const n = (v) => (typeof v === "number" && !Number.isNaN(v) ? v : 0);
3
+ const sortByTop = (feed) => {
4
+ const postScores = {};
5
+ for (const post of feed) {
6
+ const score = post.upvoteCount - post.downvoteCount || 0;
7
+ postScores[post.cid] = score;
8
+ }
9
+ return feed
10
+ .sort((a, b) => n(b.timestamp) - n(a.timestamp))
11
+ .sort((a, b) => n(b.upvoteCount) - n(a.upvoteCount))
12
+ .sort((a, b) => n(postScores[b.cid]) - n(postScores[a.cid]));
13
+ };
14
+ /**
15
+ * Sort by controversial is made using relative score, to encourage small communities to grow
16
+ * and to not incentivize communities to inflate their vote counts
17
+ */
18
+ const sortByControversial = (feed) => {
19
+ const postScores = {};
20
+ for (const post of feed) {
21
+ let upvoteCount = n(post.upvoteCount) + 1; // reddit initial upvotes is 1, pkc is 0
22
+ const downvoteCount = n(post.downvoteCount);
23
+ const magnitude = upvoteCount + downvoteCount;
24
+ const balance = upvoteCount > downvoteCount
25
+ ? downvoteCount / upvoteCount
26
+ : upvoteCount / (downvoteCount || 1);
27
+ postScores[post.cid] = Math.pow(magnitude, balance);
28
+ }
29
+ return feed
30
+ .sort((a, b) => n(b.timestamp) - n(a.timestamp))
31
+ .sort((a, b) => n(b.upvoteCount) - n(a.upvoteCount))
32
+ .sort((a, b) => n(postScores[b.cid]) - n(postScores[a.cid]));
33
+ };
34
+ /**
35
+ * Sort by hot is made using relative score, to encourage small communities to grow
36
+ * and to not incentivize communities to inflate their vote counts
37
+ * Note: a sub with not many posts will be given very high priority
38
+ */
39
+ const sortByHot = (feed) => {
40
+ const postScores = {};
41
+ const round = (number, decimalPlaces) => {
42
+ const factorOfTen = Math.pow(10, decimalPlaces);
43
+ return Math.round(number * factorOfTen) / factorOfTen;
44
+ };
45
+ for (const post of feed) {
46
+ let score = n(post.upvoteCount) - n(post.downvoteCount) + 1;
47
+ const order = Math.log10(Math.max(Math.abs(score), 1));
48
+ let sign = 0;
49
+ if (score > 0)
50
+ sign = 1;
51
+ else if (score < 0)
52
+ sign = -1;
53
+ const seconds = n(post.timestamp) - 1134028003;
54
+ postScores[post.cid] = round(sign * order + seconds / 45000, 7);
55
+ }
56
+ return feed
57
+ .sort((a, b) => n(b.timestamp) - n(a.timestamp))
58
+ .sort((a, b) => n(b.upvoteCount) - n(a.upvoteCount))
59
+ .sort((a, b) => n(postScores[b.cid]) - n(postScores[a.cid]));
60
+ };
61
+ /**
62
+ * Sort by new is made using relative timestamp score, to encourage small communities to grow
63
+ * and to not incentivize communities to inflate their timestamp
64
+ */
65
+ const sortByNew = (feed) => feed
66
+ .sort((a, b) => n(b.upvoteCount) - n(a.upvoteCount))
67
+ .sort((a, b) => n(b.timestamp) - n(a.timestamp));
68
+ /**
69
+ * Sort by active is made using relative lastReplyTimestamp score, to encourage small communities to grow
70
+ * and to not incentivize communities to inflate their lastReplyTimestamp
71
+ */
72
+ const sortByActive = (feed) => feed
73
+ .sort((a, b) => n(b.timestamp) - n(a.timestamp))
74
+ .sort((a, b) => n(b.upvoteCount) - n(a.upvoteCount))
75
+ .sort((a, b) => { var _a, _b; return n((_a = b.lastReplyTimestamp) !== null && _a !== void 0 ? _a : b.timestamp) - n((_b = a.lastReplyTimestamp) !== null && _b !== void 0 ? _b : a.timestamp); });
76
+ const sortByOld = (feed) => feed
77
+ .sort((a, b) => n(b.upvoteCount) - n(a.upvoteCount))
78
+ .sort((a, b) => n(a.timestamp) - n(b.timestamp));
79
+ // "best" sort from reddit replies
80
+ // https://web.archive.org/web/20100305052116/http://blog.reddit.com/2009/10/reddits-new-comment-sorting-system.html
81
+ // https://medium.com/hacking-and-gonzo/how-reddit-ranking-algorithms-work-ef111e33d0d9
82
+ // http://www.evanmiller.org/how-not-to-sort-by-average-rating.html
83
+ // https://github.com/reddit-archive/reddit/blob/753b17407e9a9dca09558526805922de24133d53/r2/r2/lib/db/_sorts.pyx#L70
84
+ const sortByBest = (feed) => {
85
+ const postScores = {};
86
+ for (const post of feed) {
87
+ const upvoteCount = n(post.upvoteCount) + 1;
88
+ const downvoteCount = n(post.downvoteCount);
89
+ const total = upvoteCount + downvoteCount;
90
+ const score = total === 0
91
+ ? 0
92
+ : (() => {
93
+ const z = 1.281551565545;
94
+ const p = upvoteCount / total;
95
+ const left = p + (1 / (2 * total)) * z * z;
96
+ const right = z * Math.sqrt((p * (1 - p)) / total + (z * z) / (4 * total * total));
97
+ const under = 1 + (1 / total) * z * z;
98
+ return (left - right) / under;
99
+ })();
100
+ postScores[post.cid] = score;
101
+ }
102
+ return feed
103
+ .sort((a, b) => n(a.timestamp) - n(b.timestamp))
104
+ .sort((a, b) => n(postScores[b.cid]) - n(postScores[a.cid]));
105
+ };
106
+ const sort = (sortType, feed) => {
107
+ // NOTE: pinned posts are not sorted, maybe in a future version we can sort them based on something
108
+ // NOTE: with useReplies({flat: true}), nested pins are at the top, unclear yet what we should do with them
109
+ const pinnedPosts = feed.filter((post) => post.pinned);
110
+ feed = feed.filter((post) => !post.pinned);
111
+ if (sortType.match("new")) {
112
+ return [...pinnedPosts, ...sortByNew(feed)];
113
+ }
114
+ if (sortType.match("hot")) {
115
+ return [...pinnedPosts, ...sortByHot(feed)];
116
+ }
117
+ if (sortType.match("top")) {
118
+ return [...pinnedPosts, ...sortByTop(feed)];
119
+ }
120
+ if (sortType.match("controversial")) {
121
+ return [...pinnedPosts, ...sortByControversial(feed)];
122
+ }
123
+ if (sortType.match("active")) {
124
+ return [...pinnedPosts, ...sortByActive(feed)];
125
+ }
126
+ if (sortType.match("old")) {
127
+ return [...pinnedPosts, ...sortByOld(feed)];
128
+ }
129
+ if (sortType.match("best")) {
130
+ return [...pinnedPosts, ...sortByBest(feed)];
131
+ }
132
+ throw Error(`feedsStore feedSorter sort type '${sortType}' doesn't exist`);
133
+ };
134
+ export default { sort };
135
+ //# sourceMappingURL=feed-sorter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feed-sorter.js","sourceRoot":"","sources":["../../../src/stores/feeds/feed-sorter.ts"],"names":[],"mappings":"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","sourcesContent":["/** Single fallback for numeric values to reduce Istanbul branch sites */\nconst n = (v: unknown): number => (typeof v === \"number\" && !Number.isNaN(v) ? v : 0);\n\nconst sortByTop = (feed: any[]) => {\n const postScores: { [key: string]: number } = {};\n for (const post of feed) {\n const score = post.upvoteCount - post.downvoteCount || 0;\n postScores[post.cid] = score;\n }\n return feed\n .sort((a, b) => n(b.timestamp) - n(a.timestamp))\n .sort((a, b) => n(b.upvoteCount) - n(a.upvoteCount))\n .sort((a, b) => n(postScores[b.cid]) - n(postScores[a.cid]));\n};\n\n/**\n * Sort by controversial is made using relative score, to encourage small communities to grow\n * and to not incentivize communities to inflate their vote counts\n */\nconst sortByControversial = (feed: any[]) => {\n const postScores: { [key: string]: number } = {};\n for (const post of feed) {\n let upvoteCount = n(post.upvoteCount) + 1; // reddit initial upvotes is 1, pkc is 0\n const downvoteCount = n(post.downvoteCount);\n const magnitude = upvoteCount + downvoteCount;\n const balance =\n upvoteCount > downvoteCount\n ? downvoteCount / upvoteCount\n : upvoteCount / (downvoteCount || 1);\n postScores[post.cid] = Math.pow(magnitude, balance);\n }\n return feed\n .sort((a, b) => n(b.timestamp) - n(a.timestamp))\n .sort((a, b) => n(b.upvoteCount) - n(a.upvoteCount))\n .sort((a, b) => n(postScores[b.cid]) - n(postScores[a.cid]));\n};\n\n/**\n * Sort by hot is made using relative score, to encourage small communities to grow\n * and to not incentivize communities to inflate their vote counts\n * Note: a sub with not many posts will be given very high priority\n */\nconst sortByHot = (feed: any[]) => {\n const postScores: { [key: string]: number } = {};\n const round = (number: number, decimalPlaces: number) => {\n const factorOfTen = Math.pow(10, decimalPlaces);\n return Math.round(number * factorOfTen) / factorOfTen;\n };\n for (const post of feed) {\n let score = n(post.upvoteCount) - n(post.downvoteCount) + 1;\n const order = Math.log10(Math.max(Math.abs(score), 1));\n let sign = 0;\n if (score > 0) sign = 1;\n else if (score < 0) sign = -1;\n const seconds = n(post.timestamp) - 1134028003;\n postScores[post.cid] = round(sign * order + seconds / 45000, 7);\n }\n return feed\n .sort((a, b) => n(b.timestamp) - n(a.timestamp))\n .sort((a, b) => n(b.upvoteCount) - n(a.upvoteCount))\n .sort((a, b) => n(postScores[b.cid]) - n(postScores[a.cid]));\n};\n\n/**\n * Sort by new is made using relative timestamp score, to encourage small communities to grow\n * and to not incentivize communities to inflate their timestamp\n */\nconst sortByNew = (feed: any[]) =>\n feed\n .sort((a, b) => n(b.upvoteCount) - n(a.upvoteCount))\n .sort((a, b) => n(b.timestamp) - n(a.timestamp));\n\n/**\n * Sort by active is made using relative lastReplyTimestamp score, to encourage small communities to grow\n * and to not incentivize communities to inflate their lastReplyTimestamp\n */\nconst sortByActive = (feed: any[]) =>\n feed\n .sort((a, b) => n(b.timestamp) - n(a.timestamp))\n .sort((a, b) => n(b.upvoteCount) - n(a.upvoteCount))\n .sort(\n (a, b) => n(b.lastReplyTimestamp ?? b.timestamp) - n(a.lastReplyTimestamp ?? a.timestamp),\n );\n\nconst sortByOld = (feed: any[]) =>\n feed\n .sort((a, b) => n(b.upvoteCount) - n(a.upvoteCount))\n .sort((a, b) => n(a.timestamp) - n(b.timestamp));\n\n// \"best\" sort from reddit replies\n// https://web.archive.org/web/20100305052116/http://blog.reddit.com/2009/10/reddits-new-comment-sorting-system.html\n// https://medium.com/hacking-and-gonzo/how-reddit-ranking-algorithms-work-ef111e33d0d9\n// http://www.evanmiller.org/how-not-to-sort-by-average-rating.html\n// https://github.com/reddit-archive/reddit/blob/753b17407e9a9dca09558526805922de24133d53/r2/r2/lib/db/_sorts.pyx#L70\nconst sortByBest = (feed: any[]) => {\n const postScores: { [key: string]: number } = {};\n for (const post of feed) {\n const upvoteCount = n(post.upvoteCount) + 1;\n const downvoteCount = n(post.downvoteCount);\n const total = upvoteCount + downvoteCount;\n const score =\n total === 0\n ? 0\n : (() => {\n const z = 1.281551565545;\n const p = upvoteCount / total;\n const left = p + (1 / (2 * total)) * z * z;\n const right = z * Math.sqrt((p * (1 - p)) / total + (z * z) / (4 * total * total));\n const under = 1 + (1 / total) * z * z;\n return (left - right) / under;\n })();\n postScores[post.cid] = score;\n }\n return feed\n .sort((a, b) => n(a.timestamp) - n(b.timestamp))\n .sort((a, b) => n(postScores[b.cid]) - n(postScores[a.cid]));\n};\n\nconst sort = (sortType: string, feed: any[]) => {\n // NOTE: pinned posts are not sorted, maybe in a future version we can sort them based on something\n // NOTE: with useReplies({flat: true}), nested pins are at the top, unclear yet what we should do with them\n const pinnedPosts = feed.filter((post) => post.pinned);\n\n feed = feed.filter((post) => !post.pinned);\n if (sortType.match(\"new\")) {\n return [...pinnedPosts, ...sortByNew(feed)];\n }\n if (sortType.match(\"hot\")) {\n return [...pinnedPosts, ...sortByHot(feed)];\n }\n if (sortType.match(\"top\")) {\n return [...pinnedPosts, ...sortByTop(feed)];\n }\n if (sortType.match(\"controversial\")) {\n return [...pinnedPosts, ...sortByControversial(feed)];\n }\n if (sortType.match(\"active\")) {\n return [...pinnedPosts, ...sortByActive(feed)];\n }\n if (sortType.match(\"old\")) {\n return [...pinnedPosts, ...sortByOld(feed)];\n }\n if (sortType.match(\"best\")) {\n return [...pinnedPosts, ...sortByBest(feed)];\n }\n throw Error(`feedsStore feedSorter sort type '${sortType}' doesn't exist`);\n};\n\nexport default { sort };\n"]}
@@ -0,0 +1,25 @@
1
+ import { Feeds, FeedsOptions, FeedsCommunitiesPostCounts } from "../../types.js";
2
+ export declare const defaultPostsPerPage = 25;
3
+ type FeedsState = {
4
+ feedsOptions: FeedsOptions;
5
+ bufferedFeeds: Feeds;
6
+ loadedFeeds: Feeds;
7
+ updatedFeeds: Feeds;
8
+ bufferedFeedsCommunitiesPostCounts: FeedsCommunitiesPostCounts;
9
+ feedsHaveMore: {
10
+ [feedName: string]: boolean;
11
+ };
12
+ feedsCommunityKeysWithNewerPosts: {
13
+ [feedName: string]: string[];
14
+ };
15
+ addFeedToStore: Function;
16
+ incrementFeedPageNumber: Function;
17
+ expandFeedTimeWindow: Function;
18
+ resetFeed: Function;
19
+ updateFeeds: Function;
20
+ };
21
+ declare const feedsStore: import("zustand").UseBoundStore<import("zustand").StoreApi<FeedsState>>;
22
+ export declare const resetFeedsStore: () => Promise<void>;
23
+ export declare const resetFeedsDatabaseAndStore: () => Promise<void>;
24
+ export default feedsStore;
25
+ //# sourceMappingURL=feeds-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feeds-store.d.ts","sourceRoot":"","sources":["../../../src/stores/feeds/feeds-store.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,EAIL,YAAY,EAEZ,0BAA0B,EAI3B,MAAM,aAAa,CAAC;AAiCrB,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAKtC,KAAK,UAAU,GAAG;IAChB,YAAY,EAAE,YAAY,CAAC;IAC3B,aAAa,EAAE,KAAK,CAAC;IACrB,WAAW,EAAE,KAAK,CAAC;IACnB,YAAY,EAAE,KAAK,CAAC;IACpB,kCAAkC,EAAE,0BAA0B,CAAC;IAC/D,aAAa,EAAE;QAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAC/C,gCAAgC,EAAE;QAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;KAAE,CAAC;IACnE,cAAc,EAAE,QAAQ,CAAC;IACzB,uBAAuB,EAAE,QAAQ,CAAC;IAClC,oBAAoB,EAAE,QAAQ,CAAC;IAC/B,SAAS,EAAE,QAAQ,CAAC;IACpB,WAAW,EAAE,QAAQ,CAAC;CACvB,CAAC;AAMF,QAAA,MAAM,UAAU,yEAgWb,CAAC;AAuSJ,eAAO,MAAM,eAAe,qBAqB3B,CAAC;AAGF,eAAO,MAAM,0BAA0B,qBAGtC,CAAC;AAEF,eAAe,UAAU,CAAC"}