From b7592044c017bfbc629fd3c58375be2c311a78cd Mon Sep 17 00:00:00 2001 From: Agent Date: Tue, 22 Sep 2026 10:04:05 -0400 Subject: [PATCH] digest email: replace reply/reaction counts with relay URL - Replace `{{Replies}}`/`{{Reactions}}` stat items in digest.mjml with a single `{{RelayUrl}}` item showing the posting relay domain - src/digest.ts: add `RelayUrl` to template variables, derive from existing `relayByEventId` map; strip unused `spec`, `getParentId`, `repliesByParentId`, and `context` destructure - test/digest-reply-stats.test.ts: update assertion to check `parentEntry.RelayUrl` instead of `Replies`/`Reactions` - script/render-preview.mjs: update sample data to use `RelayUrl` --- script/render-preview.mjs | 6 ++---- src/digest.ts | 16 +++++++--------- src/emails/digest.mjml | 5 +---- test/digest-reply-stats.test.ts | 7 ++----- 4 files changed, 12 insertions(+), 22 deletions(-) diff --git a/script/render-preview.mjs b/script/render-preview.mjs index e2fec6d..e60011f 100644 --- a/script/render-preview.mjs +++ b/script/render-preview.mjs @@ -24,8 +24,7 @@ const sample = { Icon: 'https://i.pravatar.cc/150?img=32', Name: 'carol', Content: '

Does anyone know how relay-based groups work?

', - Replies: 5, - Reactions: 8, + RelayUrl: 'relay.damus.io', }, { Link: 'https://app.flotilla.social/spaces/nos.lol/community?at=1700000000', @@ -34,8 +33,7 @@ const sample = { Name: 'bob', Content: '

Excited to share our new community space on Flotilla! Check it out.

', - Replies: 14, - Reactions: 32, + RelayUrl: 'nos.lol', }, ], unsubscribeUrl: 'https://app.flotilla.social/unsubscribe?token=abc123', diff --git a/src/digest.ts b/src/digest.ts index c9b2714..3426865 100644 --- a/src/digest.ts +++ b/src/digest.ts @@ -1,6 +1,5 @@ import { neventEncode, decode } from 'nostr-tools/nip19' import { - spec, sortBy, groupBy, displayList, @@ -10,7 +9,6 @@ import { parse, truncate, renderAsHtml } from '@welshman/content' import { TrustedEvent, normalizeRelayUrl, - getParentId, NOTE, COMMENT, REACTION, @@ -50,23 +48,23 @@ export class Digest { const getEventVariables = (event: TrustedEvent) => { const parsed = truncate(parse(event), { minLength: 400, maxLength: 800, mediaLength: 50 }) + const relayUrl = data.relayByEventId.get(event.id) + return { - Link: buildLink(event, handler, data.relayByEventId.get(event.id)), + Link: buildLink(event, handler, relayUrl), Timestamp: formatter.format(secondsToDate(event.created_at)), Icon: profilesByPubkey.get().get(event.pubkey)?.picture, Name: displayProfileByPubkey(event.pubkey), Content: renderAsHtml(parsed, { createElement, renderEntity }).toString(), - Replies: - repliesByParentId.get(event.id)?.filter((e) => [COMMENT, NOTE].includes(e.kind)) - ?.length || 0, - Reactions: repliesByParentId.get(event.id)?.filter(spec({ kind: REACTION }))?.length || 0, + RelayUrl: relayUrl + ? normalizeRelayUrl(relayUrl).replace(/^wss:\/\//, '').replace(/\/$/, '') + : '', } } - const { events, context } = data + const { events } = data const formatter = getFormatter() const handler = await this.loadHandler() - const repliesByParentId = groupBy(getParentId, context) const eventsByPubkey = groupBy((e) => e.pubkey, events) const userProfile = profilesByPubkey.get().get(this.sub.pubkey) const sorted = sortBy((e) => e.created_at, events).slice(0, 100) diff --git a/src/emails/digest.mjml b/src/emails/digest.mjml index 58f5e2d..4cf85f3 100644 --- a/src/emails/digest.mjml +++ b/src/emails/digest.mjml @@ -64,10 +64,7 @@
{{{Content}}}
- {{Replies}} replies - - - {{Reactions}} reactions + Posted to {{RelayUrl}}
diff --git a/test/digest-reply-stats.test.ts b/test/digest-reply-stats.test.ts index 67032cf..faa09e3 100644 --- a/test/digest-reply-stats.test.ts +++ b/test/digest-reply-stats.test.ts @@ -1,6 +1,5 @@ import { describe, it, expect, vi, beforeEach } from 'vitest' import type { TrustedEvent } from '@welshman/util' -import { spec } from '@welshman/lib' // ── Shared state accessible from both vi.mock factories and test body ────── const mockRepo = vi.hoisted(() => { @@ -159,9 +158,7 @@ describe('digest reply/reaction stats', () => { expect(latest.length).toBeGreaterThanOrEqual(1) const parentEntry = latest[0] - // When context includes reply/reaction events loaded from the repository, - // Replies should be >= 1 and Reactions >= 1 - expect(parentEntry.Replies).toBeGreaterThanOrEqual(1) - expect(parentEntry.Reactions).toBeGreaterThanOrEqual(1) + // RelayUrl should be the relay domain stripped of protocol and trailing slash + expect(parentEntry.RelayUrl).toBe('relay.example.com') }) }) \ No newline at end of file -- 2.45.2