diff --git a/lib/syndicator.js b/lib/syndicator.js index 8bf29c3..55b918b 100644 --- a/lib/syndicator.js +++ b/lib/syndicator.js @@ -290,49 +290,70 @@ export function createSyndicator(plugin) { // ─── Timeline helpers ─────────────────────────────────────────────────────── /** - * Build content from JF2 properties. Synthesizes content for interaction - * types (likes, bookmarks, reposts) that have no body text. + * Build content from JF2 properties for the ap_timeline entry. + * For interaction types (likes, bookmarks, reposts), always includes + * the target URL — even when there's comment text alongside it. */ function buildTimelineContent(properties) { - const content = properties.content; - if (content) { - if (typeof content === "string") return { text: content, html: `

${content}

` }; - if (content.text || content.html) { - return { - text: content.text || content.value || "", - html: content.html || content.text || content.value || "", - }; + const esc = (s) => String(s).replace(/&/g, "&").replace(//g, ">").replace(/"/g, """); + + // Extract any existing body content + const raw = properties.content; + let bodyText = ""; + let bodyHtml = ""; + if (raw) { + if (typeof raw === "string") { + bodyText = raw; + bodyHtml = `

${raw}

`; + } else { + bodyText = raw.text || raw.value || ""; + bodyHtml = raw.html || raw.text || raw.value || ""; } } - // Synthesize for interaction types - const esc = (s) => s.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """); + // Interaction types: prepend label + target URL, append any comment const likeOf = properties["like-of"]; if (likeOf) { + const prefix = `Liked: ${likeOf}`; + const prefixHtml = `

Liked: ${esc(likeOf)}

`; return { - text: `Liked: ${likeOf}`, - html: `

Liked: ${esc(likeOf)}

`, + text: bodyText ? `${prefix}\n\n${bodyText}` : prefix, + html: bodyText ? `${prefixHtml}\n${bodyHtml}` : prefixHtml, }; } + const bookmarkOf = properties["bookmark-of"]; if (bookmarkOf) { const label = properties.name || bookmarkOf; + const prefix = `Bookmarked: ${label}`; + const prefixHtml = `

Bookmarked: ${esc(label)}

`; return { - text: `Bookmarked: ${label}`, - html: `

Bookmarked: ${esc(label)}

`, + text: bodyText ? `${prefix}\n\n${bodyText}` : prefix, + html: bodyText ? `${prefixHtml}\n${bodyHtml}` : prefixHtml, }; } + const repostOf = properties["repost-of"]; if (repostOf) { const label = properties.name || repostOf; + const prefix = `Reposted: ${label}`; + const prefixHtml = `

Reposted: ${esc(label)}

`; return { - text: `Reposted: ${label}`, - html: `

Reposted: ${esc(label)}

`, + text: bodyText ? `${prefix}\n\n${bodyText}` : prefix, + html: bodyText ? `${prefixHtml}\n${bodyHtml}` : prefixHtml, }; } + + // Regular post — return body content as-is + if (bodyText || bodyHtml) { + return { text: bodyText, html: bodyHtml }; + } + + // Article with title but no body if (properties.name) { return { text: properties.name, html: `

${esc(properties.name)}

` }; } + return { text: "", html: "" }; } diff --git a/package.json b/package.json index f08d620..1955000 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rmdes/indiekit-endpoint-activitypub", - "version": "3.10.2", + "version": "3.10.3", "description": "ActivityPub federation endpoint for Indiekit via Fedify. Adds full fediverse support: actor, inbox, outbox, followers, following, syndication, and Mastodon migration.", "keywords": [ "indiekit",