@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.
- package/LICENSE +674 -0
- package/README.md +1365 -0
- package/dist/hooks/accounts/accounts.d.ts +64 -0
- package/dist/hooks/accounts/accounts.d.ts.map +1 -0
- package/dist/hooks/accounts/accounts.js +706 -0
- package/dist/hooks/accounts/accounts.js.map +1 -0
- package/dist/hooks/accounts/index.d.ts +2 -0
- package/dist/hooks/accounts/index.d.ts.map +1 -0
- package/dist/hooks/accounts/index.js +2 -0
- package/dist/hooks/accounts/index.js.map +1 -0
- package/dist/hooks/accounts/utils.d.ts +6 -0
- package/dist/hooks/accounts/utils.d.ts.map +1 -0
- package/dist/hooks/accounts/utils.js +226 -0
- package/dist/hooks/accounts/utils.js.map +1 -0
- package/dist/hooks/actions/actions.d.ts +19 -0
- package/dist/hooks/actions/actions.d.ts.map +1 -0
- package/dist/hooks/actions/actions.js +552 -0
- package/dist/hooks/actions/actions.js.map +1 -0
- package/dist/hooks/actions/index.d.ts +2 -0
- package/dist/hooks/actions/index.d.ts.map +1 -0
- package/dist/hooks/actions/index.js +2 -0
- package/dist/hooks/actions/index.js.map +1 -0
- package/dist/hooks/authors/author-avatars.d.ts +28 -0
- package/dist/hooks/authors/author-avatars.d.ts.map +1 -0
- package/dist/hooks/authors/author-avatars.js +191 -0
- package/dist/hooks/authors/author-avatars.js.map +1 -0
- package/dist/hooks/authors/authors.d.ts +37 -0
- package/dist/hooks/authors/authors.d.ts.map +1 -0
- package/dist/hooks/authors/authors.js +509 -0
- package/dist/hooks/authors/authors.js.map +1 -0
- package/dist/hooks/authors/index.d.ts +2 -0
- package/dist/hooks/authors/index.d.ts.map +1 -0
- package/dist/hooks/authors/index.js +2 -0
- package/dist/hooks/authors/index.js.map +1 -0
- package/dist/hooks/authors/utils.d.ts +4 -0
- package/dist/hooks/authors/utils.d.ts.map +1 -0
- package/dist/hooks/authors/utils.js +21 -0
- package/dist/hooks/authors/utils.js.map +1 -0
- package/dist/hooks/comments.d.ts +17 -0
- package/dist/hooks/comments.d.ts.map +1 -0
- package/dist/hooks/comments.js +351 -0
- package/dist/hooks/comments.js.map +1 -0
- package/dist/hooks/communities.d.ts +31 -0
- package/dist/hooks/communities.d.ts.map +1 -0
- package/dist/hooks/communities.js +389 -0
- package/dist/hooks/communities.js.map +1 -0
- package/dist/hooks/feeds/feeds.d.ts +18 -0
- package/dist/hooks/feeds/feeds.d.ts.map +1 -0
- package/dist/hooks/feeds/feeds.js +315 -0
- package/dist/hooks/feeds/feeds.js.map +1 -0
- package/dist/hooks/feeds/index.d.ts +2 -0
- package/dist/hooks/feeds/index.d.ts.map +1 -0
- package/dist/hooks/feeds/index.js +2 -0
- package/dist/hooks/feeds/index.js.map +1 -0
- package/dist/hooks/pkc-rpc.d.ts +7 -0
- package/dist/hooks/pkc-rpc.d.ts.map +1 -0
- package/dist/hooks/pkc-rpc.js +88 -0
- package/dist/hooks/pkc-rpc.js.map +1 -0
- package/dist/hooks/replies.d.ts +5 -0
- package/dist/hooks/replies.d.ts.map +1 -0
- package/dist/hooks/replies.js +155 -0
- package/dist/hooks/replies.js.map +1 -0
- package/dist/hooks/states.d.ts +15 -0
- package/dist/hooks/states.d.ts.map +1 -0
- package/dist/hooks/states.js +213 -0
- package/dist/hooks/states.js.map +1 -0
- package/dist/hooks/utils/use-interval.d.ts +3 -0
- package/dist/hooks/utils/use-interval.d.ts.map +1 -0
- package/dist/hooks/utils/use-interval.js +36 -0
- package/dist/hooks/utils/use-interval.js.map +1 -0
- package/dist/hooks/utils/use-previous.d.ts +1 -0
- package/dist/hooks/utils/use-previous.js +10 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +128 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/chain/chain.d.ts +36 -0
- package/dist/lib/chain/chain.d.ts.map +1 -0
- package/dist/lib/chain/chain.js +195 -0
- package/dist/lib/chain/chain.js.map +1 -0
- package/dist/lib/chain/index.d.ts +4 -0
- package/dist/lib/chain/index.d.ts.map +1 -0
- package/dist/lib/chain/index.js +4 -0
- package/dist/lib/chain/index.js.map +1 -0
- package/dist/lib/community-address.d.ts +6 -0
- package/dist/lib/community-address.d.ts.map +1 -0
- package/dist/lib/community-address.js +26 -0
- package/dist/lib/community-address.js.map +1 -0
- package/dist/lib/community-ref.d.ts +23 -0
- package/dist/lib/community-ref.d.ts.map +1 -0
- package/dist/lib/community-ref.js +113 -0
- package/dist/lib/community-ref.js.map +1 -0
- package/dist/lib/debug-utils.d.ts +9 -0
- package/dist/lib/debug-utils.d.ts.map +1 -0
- package/dist/lib/debug-utils.js +21 -0
- package/dist/lib/debug-utils.js.map +1 -0
- package/dist/lib/feed-sort-type.d.ts +2 -0
- package/dist/lib/feed-sort-type.d.ts.map +1 -0
- package/dist/lib/feed-sort-type.js +22 -0
- package/dist/lib/feed-sort-type.js.map +1 -0
- package/dist/lib/localforage-lru/index.d.ts +3 -0
- package/dist/lib/localforage-lru/index.d.ts.map +1 -0
- package/dist/lib/localforage-lru/index.js +46 -0
- package/dist/lib/localforage-lru/index.js.map +1 -0
- package/dist/lib/localforage-lru/localforage-lru.d.ts +6 -0
- package/dist/lib/localforage-lru/localforage-lru.d.ts.map +1 -0
- package/dist/lib/localforage-lru/localforage-lru.js +182 -0
- package/dist/lib/localforage-lru/localforage-lru.js.map +1 -0
- package/dist/lib/pkc-compat.d.ts +25 -0
- package/dist/lib/pkc-compat.d.ts.map +1 -0
- package/dist/lib/pkc-compat.js +131 -0
- package/dist/lib/pkc-compat.js.map +1 -0
- package/dist/lib/pkc-js/fixtures/markdown-example.d.ts +3 -0
- package/dist/lib/pkc-js/fixtures/markdown-example.d.ts.map +1 -0
- package/dist/lib/pkc-js/fixtures/markdown-example.js +280 -0
- package/dist/lib/pkc-js/fixtures/markdown-example.js.map +1 -0
- package/dist/lib/pkc-js/index.d.ts +11 -0
- package/dist/lib/pkc-js/index.d.ts.map +1 -0
- package/dist/lib/pkc-js/index.js +85 -0
- package/dist/lib/pkc-js/index.js.map +1 -0
- package/dist/lib/pkc-js/pkc-js-mock-content.d.ts +3 -0
- package/dist/lib/pkc-js/pkc-js-mock-content.d.ts.map +1 -0
- package/dist/lib/pkc-js/pkc-js-mock-content.js +1235 -0
- package/dist/lib/pkc-js/pkc-js-mock-content.js.map +1 -0
- package/dist/lib/pkc-js/pkc-js-mock.d.ts +137 -0
- package/dist/lib/pkc-js/pkc-js-mock.d.ts.map +1 -0
- package/dist/lib/pkc-js/pkc-js-mock.js +644 -0
- package/dist/lib/pkc-js/pkc-js-mock.js.map +1 -0
- package/dist/lib/polyfill.d.ts +3 -0
- package/dist/lib/polyfill.d.ts.map +1 -0
- package/dist/lib/polyfill.js +14 -0
- package/dist/lib/polyfill.js.map +1 -0
- package/dist/lib/protocol-compat.d.ts +14 -0
- package/dist/lib/protocol-compat.d.ts.map +1 -0
- package/dist/lib/protocol-compat.js +67 -0
- package/dist/lib/protocol-compat.js.map +1 -0
- package/dist/lib/test-utils.d.ts +29 -0
- package/dist/lib/test-utils.d.ts.map +1 -0
- package/dist/lib/test-utils.js +184 -0
- package/dist/lib/test-utils.js.map +1 -0
- package/dist/lib/utils/comment-moderation.d.ts +4 -0
- package/dist/lib/utils/comment-moderation.d.ts.map +1 -0
- package/dist/lib/utils/comment-moderation.js +56 -0
- package/dist/lib/utils/comment-moderation.js.map +1 -0
- package/dist/lib/utils/index.d.ts +4 -0
- package/dist/lib/utils/index.d.ts.map +1 -0
- package/dist/lib/utils/index.js +4 -0
- package/dist/lib/utils/index.js.map +1 -0
- package/dist/lib/utils/utils.d.ts +23 -0
- package/dist/lib/utils/utils.d.ts.map +1 -0
- package/dist/lib/utils/utils.js +375 -0
- package/dist/lib/utils/utils.js.map +1 -0
- package/dist/lib/validator.d.ts +30 -0
- package/dist/lib/validator.d.ts.map +1 -0
- package/dist/lib/validator.js +307 -0
- package/dist/lib/validator.js.map +1 -0
- package/dist/stores/accounts/account-generator.d.ts +51 -0
- package/dist/stores/accounts/account-generator.d.ts.map +1 -0
- package/dist/stores/accounts/account-generator.js +160 -0
- package/dist/stores/accounts/account-generator.js.map +1 -0
- package/dist/stores/accounts/accounts-actions-internal.d.ts +8 -0
- package/dist/stores/accounts/accounts-actions-internal.d.ts.map +1 -0
- package/dist/stores/accounts/accounts-actions-internal.js +403 -0
- package/dist/stores/accounts/accounts-actions-internal.js.map +1 -0
- package/dist/stores/accounts/accounts-actions.d.ts +46 -0
- package/dist/stores/accounts/accounts-actions.d.ts.map +1 -0
- package/dist/stores/accounts/accounts-actions.js +1341 -0
- package/dist/stores/accounts/accounts-actions.js.map +1 -0
- package/dist/stores/accounts/accounts-database.d.ts +34 -0
- package/dist/stores/accounts/accounts-database.d.ts.map +1 -0
- package/dist/stores/accounts/accounts-database.js +685 -0
- package/dist/stores/accounts/accounts-database.js.map +1 -0
- package/dist/stores/accounts/accounts-store.d.ts +32 -0
- package/dist/stores/accounts/accounts-store.d.ts.map +1 -0
- package/dist/stores/accounts/accounts-store.js +169 -0
- package/dist/stores/accounts/accounts-store.js.map +1 -0
- package/dist/stores/accounts/index.d.ts +4 -0
- package/dist/stores/accounts/index.d.ts.map +1 -0
- package/dist/stores/accounts/index.js +4 -0
- package/dist/stores/accounts/index.js.map +1 -0
- package/dist/stores/accounts/utils.d.ts +49 -0
- package/dist/stores/accounts/utils.d.ts.map +1 -0
- package/dist/stores/accounts/utils.js +419 -0
- package/dist/stores/accounts/utils.js.map +1 -0
- package/dist/stores/authors-comments/authors-comments-store.d.ts +37 -0
- package/dist/stores/authors-comments/authors-comments-store.d.ts.map +1 -0
- package/dist/stores/authors-comments/authors-comments-store.js +338 -0
- package/dist/stores/authors-comments/authors-comments-store.js.map +1 -0
- package/dist/stores/authors-comments/index.d.ts +4 -0
- package/dist/stores/authors-comments/index.d.ts.map +1 -0
- package/dist/stores/authors-comments/index.js +4 -0
- package/dist/stores/authors-comments/index.js.map +1 -0
- package/dist/stores/authors-comments/utils.d.ts +14 -0
- package/dist/stores/authors-comments/utils.d.ts.map +1 -0
- package/dist/stores/authors-comments/utils.js +81 -0
- package/dist/stores/authors-comments/utils.js.map +1 -0
- package/dist/stores/comments/comments-store.d.ts +19 -0
- package/dist/stores/comments/comments-store.d.ts.map +1 -0
- package/dist/stores/comments/comments-store.js +385 -0
- package/dist/stores/comments/comments-store.js.map +1 -0
- package/dist/stores/comments/index.d.ts +4 -0
- package/dist/stores/comments/index.d.ts.map +1 -0
- package/dist/stores/comments/index.js +4 -0
- package/dist/stores/comments/index.js.map +1 -0
- package/dist/stores/communities/communities-store.d.ts +17 -0
- package/dist/stores/communities/communities-store.d.ts.map +1 -0
- package/dist/stores/communities/communities-store.js +304 -0
- package/dist/stores/communities/communities-store.js.map +1 -0
- package/dist/stores/communities/index.d.ts +4 -0
- package/dist/stores/communities/index.d.ts.map +1 -0
- package/dist/stores/communities/index.js +4 -0
- package/dist/stores/communities/index.js.map +1 -0
- package/dist/stores/communities-pages/communities-pages-store.d.ts +23 -0
- package/dist/stores/communities-pages/communities-pages-store.d.ts.map +1 -0
- package/dist/stores/communities-pages/communities-pages-store.js +316 -0
- package/dist/stores/communities-pages/communities-pages-store.js.map +1 -0
- package/dist/stores/communities-pages/index.d.ts +4 -0
- package/dist/stores/communities-pages/index.d.ts.map +1 -0
- package/dist/stores/communities-pages/index.js +4 -0
- package/dist/stores/communities-pages/index.js.map +1 -0
- package/dist/stores/feeds/feed-sorter.d.ts +5 -0
- package/dist/stores/feeds/feed-sorter.d.ts.map +1 -0
- package/dist/stores/feeds/feed-sorter.js +135 -0
- package/dist/stores/feeds/feed-sorter.js.map +1 -0
- package/dist/stores/feeds/feeds-store.d.ts +25 -0
- package/dist/stores/feeds/feeds-store.d.ts.map +1 -0
- package/dist/stores/feeds/feeds-store.js +459 -0
- package/dist/stores/feeds/feeds-store.js.map +1 -0
- package/dist/stores/feeds/index.d.ts +4 -0
- package/dist/stores/feeds/index.d.ts.map +1 -0
- package/dist/stores/feeds/index.js +4 -0
- package/dist/stores/feeds/index.js.map +1 -0
- package/dist/stores/feeds/utils.d.ts +43 -0
- package/dist/stores/feeds/utils.d.ts.map +1 -0
- package/dist/stores/feeds/utils.js +736 -0
- package/dist/stores/feeds/utils.js.map +1 -0
- package/dist/stores/replies/index.d.ts +4 -0
- package/dist/stores/replies/index.d.ts.map +1 -0
- package/dist/stores/replies/index.js +4 -0
- package/dist/stores/replies/index.js.map +1 -0
- package/dist/stores/replies/replies-comments-store.d.ts +8 -0
- package/dist/stores/replies/replies-comments-store.d.ts.map +1 -0
- package/dist/stores/replies/replies-comments-store.js +23 -0
- package/dist/stores/replies/replies-comments-store.js.map +1 -0
- package/dist/stores/replies/replies-store.d.ts +29 -0
- package/dist/stores/replies/replies-store.d.ts.map +1 -0
- package/dist/stores/replies/replies-store.js +413 -0
- package/dist/stores/replies/replies-store.js.map +1 -0
- package/dist/stores/replies/utils.d.ts +25 -0
- package/dist/stores/replies/utils.d.ts.map +1 -0
- package/dist/stores/replies/utils.js +549 -0
- package/dist/stores/replies/utils.js.map +1 -0
- package/dist/stores/replies-pages/index.d.ts +4 -0
- package/dist/stores/replies-pages/index.d.ts.map +1 -0
- package/dist/stores/replies-pages/index.js +4 -0
- package/dist/stores/replies-pages/index.js.map +1 -0
- package/dist/stores/replies-pages/replies-pages-store.d.ts +20 -0
- package/dist/stores/replies-pages/replies-pages-store.d.ts.map +1 -0
- package/dist/stores/replies-pages/replies-pages-store.js +270 -0
- package/dist/stores/replies-pages/replies-pages-store.js.map +1 -0
- package/dist/stores/replies-pages/utils.d.ts +3 -0
- package/dist/stores/replies-pages/utils.d.ts.map +1 -0
- package/dist/stores/replies-pages/utils.js +43 -0
- package/dist/stores/replies-pages/utils.js.map +1 -0
- package/dist/types.d.ts +638 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- 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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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"}
|