aboutsummaryrefslogtreecommitdiffstats
path: root/src/thread-cache.js
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-09-30 18:03:33 +0000
committerAdam Soltys <[email protected]>2026-09-30 18:03:33 +0000
commit0570f48910ddc4ea10d27fb8ab7992fbd013a0b7 (patch)
treedbc1e5ece94bc71fcd8bb7e89f61043933c1992c /src/thread-cache.js
parent95eaf11d116260b101c81346ba41810aacf49a7d (diff)
parentcfeacb1a7a10766565ed3eaab13154096478c837 (diff)
downloadcoinosv3-0570f48910ddc4ea10d27fb8ab7992fbd013a0b7.tar.gz
coinosv3-0570f48910ddc4ea10d27fb8ab7992fbd013a0b7.zip
Merge remote-tracking branch 'cs/prod'
Diffstat (limited to 'src/thread-cache.js')
-rw-r--r--src/thread-cache.js17
1 files changed, 13 insertions, 4 deletions
diff --git a/src/thread-cache.js b/src/thread-cache.js
index e11660e..fca64e6 100644
--- a/src/thread-cache.js
+++ b/src/thread-cache.js
@@ -4,12 +4,18 @@
const KEY = 'btc-wallet-note-threads';
const MAX_THREADS = 12;
const MAX_EVENTS = 160;
+const MAX_QUOTES = 24; // posts quoted inside the thread, so a reload paints them too
const MAX_BYTES = 1_000_000; // JSON code units; at most about 2 MB in storage
-const validNote = (e) => e?.kind === 1 && typeof e.id === 'string'
+// Any kind: a thread can hang off a poll (1068), a picture (20), a comment
+// (1111)… — requiring kind 1 left those threads uncached, so every reload
+// sat on a spinner while the relays answered.
+const validNote = (e) => Number.isSafeInteger(e?.kind) && e.kind >= 0 && typeof e.id === 'string'
&& /^[0-9a-f]{64}$/.test(e.id) && typeof e.pubkey === 'string'
&& /^[0-9a-f]{64}$/.test(e.pubkey) && typeof e.content === 'string'
&& Number.isFinite(e.created_at) && Array.isArray(e.tags)
&& e.tags.every((t) => Array.isArray(t) && t.every((v) => typeof v === 'string'));
+// A quote can be any kind of event (a poll, an article…), not only a note.
+const validQuote = validNote;
const savedNote = ({ id, pubkey, kind, created_at, content, tags }) => ({ id, pubkey, kind, created_at, content, tags });
const savedProfile = (p) => {
if (!p || typeof p !== 'object') return null;
@@ -46,7 +52,7 @@ export function createThreadStore(storage) {
find(id) {
return read().find((c) => c.rootId === id || c.replies.some((e) => e.id === id)) || null;
},
- save(thread, focusId, profiles = {}, counts = {}) {
+ save(thread, focusId, profiles = {}, counts = {}, quotes = []) {
if (!validNote(thread.root)) return;
const events = new Map([thread.root, ...thread.replies.filter(validNote)].map((e) => [e.id, e]));
const keep = new Map([[thread.root.id, thread.root]]);
@@ -65,7 +71,9 @@ export function createThreadStore(storage) {
visit(e.id);
}
const previous = read().find((c) => c.rootId === thread.root.id);
- const authors = [...new Set([...keep.values()].map((e) => e.pubkey))].slice(0, 24);
+ const quoteMap = new Map([...(previous?.quotes || []), ...quotes].filter(validQuote).map((e) => [e.id, e]));
+ const kept = [...quoteMap.values()].slice(-MAX_QUOTES);
+ const authors = [...new Set([...keep.values(), ...kept].map((e) => e.pubkey))].slice(0, 24 + MAX_QUOTES);
const faces = {};
for (const pk of authors) {
const fresh = savedProfile(profiles[pk]);
@@ -83,7 +91,8 @@ export function createThreadStore(storage) {
}
const entry = { rootId: thread.root.id, root: savedNote(thread.root),
profiles: faces, counts: tallies,
- replies: [...keep.values()].filter((e) => e.id !== thread.root.id).map(savedNote) };
+ replies: [...keep.values()].filter((e) => e.id !== thread.root.id).map(savedNote),
+ quotes: kept.map(savedNote) };
const entries = [entry, ...read().filter((c) => c.rootId !== entry.rootId)].slice(0, MAX_THREADS);
let json = JSON.stringify(entries);
while (json.length > MAX_BYTES && entries.length > 1) { entries.pop(); json = JSON.stringify(entries); }