diff options
| author | Adam Soltys <[email protected]> | 2026-10-01 06:49:19 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-10-01 06:49:19 -0700 |
| commit | 68ff290e07c0e1786cf8b8f3a87e38872ad7f8ba (patch) | |
| tree | c85847c8f4a06b0a6b7dab8abb2d2eb54fefa226 /src/thread-cache.js | |
| parent | 4b3291fdbd0b34b4d2df91a59bea93885de29508 (diff) | |
| parent | 5ff909d37fe32ba04a841941593d95c7b3498ec3 (diff) | |
| download | coinosv3-68ff290e07c0e1786cf8b8f3a87e38872ad7f8ba.tar.gz coinosv3-68ff290e07c0e1786cf8b8f3a87e38872ad7f8ba.zip | |
Merge prod into master
Diffstat (limited to 'src/thread-cache.js')
| -rw-r--r-- | src/thread-cache.js | 17 |
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); } |
