diff --git a/lib/batch-refollow.js b/lib/batch-refollow.js index 8a8e73a..b56fbae 100644 --- a/lib/batch-refollow.js +++ b/lib/batch-refollow.js @@ -233,23 +233,32 @@ async function processOneFollow(options, entry) { throw new Error("Could not resolve remote actor"); } - // Send Follow activity + // Use the canonical actor URL (may differ from imported URL) + const canonicalUrl = remoteActor.id?.href || entry.actorUrl; + + // Send Follow activity using canonical URL const follow = new Follow({ actor: ctx.getActorUri(handle), - object: new URL(entry.actorUrl), + object: new URL(canonicalUrl), }); await ctx.sendActivity({ identifier: handle }, remoteActor, follow); - // Mark as sent + // Mark as sent — update actorUrl to canonical form so Accept handler + // can match when the remote server responds + const updateFields = { + source: "refollow:sent", + refollowLastAttempt: new Date().toISOString(), + refollowError: null, + }; + if (canonicalUrl !== entry.actorUrl) { + updateFields.actorUrl = canonicalUrl; + } + await collections.ap_following.updateOne( { _id: entry._id }, { - $set: { - source: "refollow:sent", - refollowLastAttempt: new Date().toISOString(), - refollowError: null, - }, + $set: updateFields, $inc: { refollowAttempts: 1 }, }, ); diff --git a/lib/inbox-listeners.js b/lib/inbox-listeners.js index f6775f0..c63648b 100644 --- a/lib/inbox-listeners.js +++ b/lib/inbox-listeners.js @@ -125,8 +125,23 @@ export function registerInboxListeners(inboxChain, options) { const actorUrl = actorObj?.id?.href || ""; if (!actorUrl) return; - const inner = await accept.getObject(); - if (!(inner instanceof Follow)) return; + // Check if the inner object is a Follow. Some servers send the full + // Follow object, others send only a reference URL that Fedify can't + // resolve (since the original Follow was our outgoing activity). + let isFollow = false; + try { + const inner = await accept.getObject(); + isFollow = inner instanceof Follow; + // If inner resolved to a non-Follow activity, skip + if (inner && !isFollow) { + console.info( + `[ActivityPub] Accept from ${actorUrl}: inner is ${inner.constructor?.name}, not Follow — skipping`, + ); + return; + } + } catch { + // getObject() failed — proceed anyway if we have a pending follow + } // Match against our following list for refollow or microsub-reader follows const result = await collections.ap_following.findOneAndUpdate( diff --git a/package.json b/package.json index d0b2d76..bb74e9c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rmdes/indiekit-endpoint-activitypub", - "version": "1.0.14", + "version": "1.0.15", "description": "ActivityPub federation endpoint for Indiekit via Fedify. Adds full fediverse support: actor, inbox, outbox, followers, following, syndication, and Mastodon migration.", "keywords": [ "indiekit",