diff --git a/lib/federation-setup.js b/lib/federation-setup.js index 5461b35..608ca5f 100644 --- a/lib/federation-setup.js +++ b/lib/federation-setup.js @@ -721,6 +721,20 @@ export async function buildPersonActor( personOptions.assertionMethods = keyPairs.map((k) => k.multikey); } + // Build profile field attachments (PropertyValue). + // Always include a "Fediverse" field with the actor's handle — this serves + // two purposes: (1) shows the canonical fediverse address on the profile, + // and (2) ensures 2+ attachments when combined with user-defined fields, + // preventing Fedify's JSON-LD compaction from collapsing single-element + // arrays to plain objects (which Mastodon's update_account_fields rejects). + const actorUrl = ctx.getActorUri(identifier)?.href; + const fediverseField = actorUrl + ? new PropertyValue({ + name: "Fediverse", + value: `@${identifier}@${new URL(actorUrl).hostname}`, + }) + : null; + if (profile.attachments?.length > 0) { personOptions.attachments = profile.attachments.map( (att) => @@ -729,6 +743,12 @@ export async function buildPersonActor( value: formatAttachmentValue(att.value), }), ); + // Append fediverse field if not already present in user-defined fields + if (fediverseField && !profile.attachments.some((a) => a.name === "Fediverse")) { + personOptions.attachments.push(fediverseField); + } + } else if (fediverseField) { + personOptions.attachments = [fediverseField]; } if (profile.alsoKnownAs?.length > 0) { diff --git a/package.json b/package.json index 779baca..9c0d3e7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rmdes/indiekit-endpoint-activitypub", - "version": "2.0.21", + "version": "2.0.22", "description": "ActivityPub federation endpoint for Indiekit via Fedify. Adds full fediverse support: actor, inbox, outbox, followers, following, syndication, and Mastodon migration.", "keywords": [ "indiekit",