aboutsummaryrefslogtreecommitdiffstats
path: root/src/live.js
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-10-18 23:46:18 -0700
committerAdam Soltys <[email protected]>2026-10-18 23:46:18 -0700
commitaa3fecd4f0dc39550c6ad44a19736f820201d0a3 (patch)
treefac2819d695f881fbeb73264907445aed1e3e596 /src/live.js
parent1f0b1cd2af2c2391d6706f6194bdb65c85f14ca6 (diff)
downloadcoinosv3-aa3fecd4f0dc39550c6ad44a19736f820201d0a3.tar.gz
coinosv3-aa3fecd4f0dc39550c6ad44a19736f820201d0a3.zip
A stream's chat is the app's chat: each comment is a bubble like a DM's or a group's — tap for the emoji row, reply, zap or copy; reactions (kind 7, tagged with the stream and the comment, one per person, deletable) and zap totals show on the comment for every viewer; the zap goes to the commenter, for that comment, on that stream. The composer is the one the other chats use (drafts kept per stream). A reaction no relay took is taken back. (Begun by Codex; finished here.)
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
Diffstat (limited to 'src/live.js')
-rw-r--r--src/live.js19
1 files changed, 19 insertions, 0 deletions
diff --git a/src/live.js b/src/live.js
index da18f19..d31c548 100644
--- a/src/live.js
+++ b/src/live.js
@@ -80,3 +80,22 @@ export function zapLine(ev, decode) {
const zapAddrs = new Map();
export const setZapAddr = (eventId, addr) => { if (eventId && addr) zapAddrs.set(eventId, addr); };
export const zapAddrOf = (eventId) => (eventId && zapAddrs.get(eventId)) || null;
+
+// One current reaction per person/message, independent of relay arrival order.
+// A deletion only removes reactions signed by its own author.
+export function liveReactions(events) {
+ const deleted = new Set();
+ for (const ev of events) if (ev.kind === 5)
+ for (const tag of ev.tags || []) if (tag[0] === 'e') deleted.add(ev.pubkey + ':' + tag[1]);
+ const out = new Map();
+ for (const ev of events) {
+ if (ev.kind !== 7 || deleted.has(ev.pubkey + ':' + ev.id)) continue;
+ const target = (ev.tags || []).filter(t => t[0] === 'e').at(-1)?.[1];
+ if (!target) continue;
+ const by = out.get(target) || new Map();
+ const old = by.get(ev.pubkey);
+ if (!old || ev.created_at > old.created_at || (ev.created_at === old.created_at && ev.id > old.id)) by.set(ev.pubkey, ev);
+ out.set(target, by);
+ }
+ return out;
+}