diff --git a/lib/jf2-to-as2.js b/lib/jf2-to-as2.js
index 03932a7..00b4824 100644
--- a/lib/jf2-to-as2.js
+++ b/lib/jf2-to-as2.js
@@ -14,7 +14,6 @@ import {
Create,
Hashtag,
Image,
- Like,
Mention,
Note,
Video,
@@ -95,24 +94,7 @@ function linkifyMentions(html, resolvedMentions) {
export function jf2ToActivityStreams(properties, actorUrl, publicationUrl, options = {}) {
const postType = properties["post-type"];
- if (postType === "like") {
- // Serve like posts as Note objects for AP content negotiation.
- // Returning a bare Like activity breaks Mastodon's authorize_interaction
- // flow because it expects a content object (Note/Article), not an activity.
- const likeOf = properties["like-of"];
- const postUrl = resolvePostUrl(properties.url, publicationUrl);
- return {
- "@context": "https://www.w3.org/ns/activitystreams",
- type: "Note",
- id: postUrl,
- attributedTo: actorUrl,
- published: properties.published,
- url: postUrl,
- to: ["https://www.w3.org/ns/activitystreams#Public"],
- cc: [`${actorUrl.replace(/\/$/, "")}/followers`],
- content: `\u2764\uFE0F ${likeOf}`,
- };
- }
+ // Likes are delivered as bookmarks — fall through to bookmark handling below
// Reposts are always public — Mastodon and other implementations expect this
if (postType === "repost") {
@@ -156,8 +138,8 @@ export function jf2ToActivityStreams(properties, actorUrl, publicationUrl, optio
: [followersUrl],
};
- if (postType === "bookmark") {
- const bookmarkUrl = properties["bookmark-of"];
+ if (postType === "bookmark" || postType === "like") {
+ const bookmarkUrl = properties["bookmark-of"] || properties["like-of"];
const commentary = linkifyUrls(properties.content?.html || properties.content || "");
object.content = commentary
? `${commentary}
\u{1F516} ${bookmarkUrl}`
@@ -178,6 +160,16 @@ export function jf2ToActivityStreams(properties, actorUrl, publicationUrl, optio
object.content += `
\u{1F517} ${postUrl}
`; } + // OG image for fediverse preview cards + const ogMatch = postUrl && postUrl.match(/\/([\w-]+)\/(\d{4})\/(\d{2})\/(\d{2})\/([\w-]+)\/?$/); + if (ogMatch) { + object.image = { + type: "Image", + url: `${publicationUrl.replace(/\/$/, "")}/og/${ogMatch[2]}-${ogMatch[3]}-${ogMatch[4]}-${ogMatch[5]}.png`, + mediaType: "image/png", + }; + } + if (isArticle) { object.name = properties.name; if (properties.summary) { @@ -253,28 +245,16 @@ export function jf2ToAS2Activity(properties, actorUrl, publicationUrl, options = const postType = properties["post-type"]; const actorUri = new URL(actorUrl); - if (postType === "like") { - const likeOf = properties["like-of"]; - if (!likeOf) return null; - const followersUrl = `${actorUrl.replace(/\/$/, "")}/followers`; - return new Like({ - actor: actorUri, - object: new URL(likeOf), - to: new URL("https://www.w3.org/ns/activitystreams#Public"), - cc: new URL(followersUrl), - }); - } + // Likes are delivered as bookmarks — fall through to bookmark handling below - // Reposts are always public — Mastodon and other implementations expect this + // Reposts are always public — upstream @rmdes addressing if (postType === "repost") { const repostOf = properties["repost-of"]; if (!repostOf) return null; - const followersUrl = `${actorUrl.replace(/\/$/, "")}/followers`; return new Announce({ actor: actorUri, object: new URL(repostOf), to: new URL("https://www.w3.org/ns/activitystreams#Public"), - cc: new URL(followersUrl), }); } @@ -336,8 +316,8 @@ export function jf2ToAS2Activity(properties, actorUrl, publicationUrl, options = } // Content - if (postType === "bookmark") { - const bookmarkUrl = properties["bookmark-of"]; + if (postType === "bookmark" || postType === "like") { + const bookmarkUrl = properties["bookmark-of"] || properties["like-of"]; const commentary = linkifyUrls(properties.content?.html || properties.content || ""); noteOptions.content = commentary ? `${commentary}