fix: include reply author in cc and log delivery failures
Quick replies only sent to followers, never directly to the replied-to author's server. The author was also missing from the Note's cc field, so Mastodon couldn't thread or notify. Now resolves the author before constructing the Note, includes them in ccs, sends directly to their inbox, and logs failures instead of silently swallowing them.
This commit is contained in:
+53
-32
@@ -204,32 +204,10 @@ export function submitComposeController(mountPath, plugin) {
|
|||||||
"https://www.w3.org/ns/activitystreams#Public",
|
"https://www.w3.org/ns/activitystreams#Public",
|
||||||
);
|
);
|
||||||
const followersUri = ctx.getFollowersUri(handle);
|
const followersUri = ctx.getFollowersUri(handle);
|
||||||
const note = new Note({
|
|
||||||
id: new URL(noteId),
|
|
||||||
attribution: actorUri,
|
|
||||||
content: content.trim(),
|
|
||||||
replyTarget: inReplyTo ? new URL(inReplyTo) : undefined,
|
|
||||||
published: Temporal.Now.instant(),
|
|
||||||
to: publicAddress,
|
|
||||||
cc: followersUri,
|
|
||||||
});
|
|
||||||
|
|
||||||
const create = new Create({
|
// Resolve the original author BEFORE constructing the Note,
|
||||||
id: new URL(`${noteId}#activity`),
|
// so we can include them in cc (required for threading/notification)
|
||||||
actor: actorUri,
|
let recipient = null;
|
||||||
object: note,
|
|
||||||
to: publicAddress,
|
|
||||||
cc: followersUri,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Send to followers
|
|
||||||
await ctx.sendActivity({ identifier: handle }, "followers", create, {
|
|
||||||
preferSharedInbox: true,
|
|
||||||
syncCollection: true,
|
|
||||||
orderingKey: noteId,
|
|
||||||
});
|
|
||||||
|
|
||||||
// If replying, also send to the original author
|
|
||||||
if (inReplyTo) {
|
if (inReplyTo) {
|
||||||
try {
|
try {
|
||||||
const documentLoader = await ctx.getDocumentLoader({
|
const documentLoader = await ctx.getDocumentLoader({
|
||||||
@@ -246,21 +224,64 @@ export function submitComposeController(mountPath, plugin) {
|
|||||||
const author = await remoteObject.getAttributedTo({
|
const author = await remoteObject.getAttributedTo({
|
||||||
documentLoader,
|
documentLoader,
|
||||||
});
|
});
|
||||||
const recipient = Array.isArray(author)
|
recipient = Array.isArray(author) ? author[0] : author;
|
||||||
? author[0]
|
}
|
||||||
: author;
|
} catch (error) {
|
||||||
|
console.warn(
|
||||||
|
`[ActivityPub] lookupObject failed for ${inReplyTo} (quick reply):`,
|
||||||
|
error.message,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build cc list: always include followers, add original author for replies
|
||||||
|
const ccList = [followersUri];
|
||||||
|
if (recipient?.id) {
|
||||||
|
ccList.push(recipient.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const note = new Note({
|
||||||
|
id: new URL(noteId),
|
||||||
|
attribution: actorUri,
|
||||||
|
content: content.trim(),
|
||||||
|
replyTarget: inReplyTo ? new URL(inReplyTo) : undefined,
|
||||||
|
published: Temporal.Now.instant(),
|
||||||
|
to: publicAddress,
|
||||||
|
ccs: ccList,
|
||||||
|
});
|
||||||
|
|
||||||
|
const create = new Create({
|
||||||
|
id: new URL(`${noteId}#activity`),
|
||||||
|
actor: actorUri,
|
||||||
|
object: note,
|
||||||
|
to: publicAddress,
|
||||||
|
ccs: ccList,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send to followers
|
||||||
|
await ctx.sendActivity({ identifier: handle }, "followers", create, {
|
||||||
|
preferSharedInbox: true,
|
||||||
|
syncCollection: true,
|
||||||
|
orderingKey: noteId,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Also send directly to the original author's inbox
|
||||||
if (recipient) {
|
if (recipient) {
|
||||||
|
try {
|
||||||
await ctx.sendActivity(
|
await ctx.sendActivity(
|
||||||
{ identifier: handle },
|
{ identifier: handle },
|
||||||
recipient,
|
recipient,
|
||||||
create,
|
create,
|
||||||
{ orderingKey: noteId },
|
{ orderingKey: noteId },
|
||||||
);
|
);
|
||||||
}
|
console.info(
|
||||||
}
|
`[ActivityPub] Sent quick reply directly to ${recipient.id?.href || "author"}`,
|
||||||
} catch {
|
);
|
||||||
// Non-critical — followers still got it
|
} catch (error) {
|
||||||
|
console.warn(
|
||||||
|
`[ActivityPub] Direct delivery to author failed (quick reply):`,
|
||||||
|
error.message,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@rmdes/indiekit-endpoint-activitypub",
|
"name": "@rmdes/indiekit-endpoint-activitypub",
|
||||||
"version": "2.0.6",
|
"version": "2.0.7",
|
||||||
"description": "ActivityPub federation endpoint for Indiekit via Fedify. Adds full fediverse support: actor, inbox, outbox, followers, following, syndication, and Mastodon migration.",
|
"description": "ActivityPub federation endpoint for Indiekit via Fedify. Adds full fediverse support: actor, inbox, outbox, followers, following, syndication, and Mastodon migration.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"indiekit",
|
"indiekit",
|
||||||
|
|||||||
Reference in New Issue
Block a user