Fedify: an ActivityPub server framework<p>We're excited to announce the release of <a href="https://github.com/fedify-dev/fedify/releases/tag/1.5.0" rel="nofollow noopener noreferrer" target="_blank">Fedify 1.5.0</a>! This version brings several significant improvements to performance, configurability, and developer experience. Let's dive into what's new:</p><p><strong>Two-Stage Fan-out Architecture for Efficient Activity Delivery</strong></p><p><a class="mention hashtag" rel="nofollow noopener noreferrer" href="https://hollo.social/tags/Fedify" target="_blank">#<span>Fedify</span></a> now implements a smart fan-out mechanism for delivering activities to large audiences. This change is particularly valuable for accounts with many followers. When sending activities to many recipients, Fedify now creates a single consolidated message containing the activity payload and recipient list, which a background worker then processes to re-enqueue individual delivery tasks.</p><p>This architectural improvement delivers several benefits: <a href="https://jsr.io/@fedify/fedify@1.5.0/doc/~/Context.sendActivity" rel="nofollow noopener noreferrer" target="_blank"><code>Context.sendActivity()</code></a> returns almost instantly even with thousands of recipients, memory consumption is dramatically reduced by avoiding payload duplication, UI responsiveness improves since web requests complete quickly, and the system maintains reliability with independent retry logic for each delivery.</p><p>For specific requirements, we've added a new <a href="https://fedify.dev/manual/send#optimizing-activity-delivery-for-large-audiences" rel="nofollow noopener noreferrer" target="_blank"><code>fanout</code></a> option with three settings:</p><pre><code>// Configuring fan-out behavior
await ctx.sendActivity(
{ identifier: "alice" },
recipients,
activity,
{ fanout: "auto" } // Default: automatic based on recipient count
// Other options: "skip" (never use fan-out) or "force" (always use fan-out)
);
</code></pre><p><strong>Canonical Origin Support for Multi-Domain Setups</strong></p><p>You can now explicitly configure a canonical origin for your server, which is especially useful for multi-domain setups. This feature allows you to set different domains for WebFinger handles and <a class="mention hashtag" rel="nofollow noopener noreferrer" href="https://hollo.social/tags/ActivityPub" target="_blank">#<span>ActivityPub</span></a> URIs, configured through the new <a href="https://jsr.io/@fedify/fedify@1.5.0/doc/federation/~/CreateFederationOptions.origin" rel="nofollow noopener noreferrer" target="_blank"><code>origin</code></a> option in <a href="https://jsr.io/@fedify/fedify@1.5.0/doc/federation/~/createFederation" rel="nofollow noopener noreferrer" target="_blank"><code>createFederation()</code></a>. This enhancement prevents unexpected URL construction when requests bypass proxies and improves security by ensuring consistent domain usage.</p><pre><code>const federation = createFederation({
// Use example.com for handles but ap.example.com for ActivityPub URIs
origin: {
handleHost: "example.com",
webOrigin: "https://ap.example.com",
},
// Other options...
});
</code></pre><p><strong>Optional Followers Collection Synchronization</strong></p><p><a href="https://fedify.dev/manual/send#followers-collection-synchronization" rel="nofollow noopener noreferrer" target="_blank">Followers collection synchronization</a> (<a href="https://w3id.org/fep/8fcf" rel="nofollow noopener noreferrer" target="_blank">FEP-8fcf</a>) is now opt-in rather than automatic. This feature must now be explicitly enabled through the <a href="https://jsr.io/@fedify/fedify@1.5.0/doc/~/SendActivityOptionsForCollection.syncCollection" rel="nofollow noopener noreferrer" target="_blank"><code>syncCollection</code></a> option, giving developers more control over when to include followers collection digests. This change improves network efficiency by reducing unnecessary synchronization traffic.</p><pre><code>await ctx.sendActivity(
{ identifier: sender },
"followers",
activity,
{
preferSharedInbox: true,
syncCollection: true, // Explicitly enable collection synchronization
}
);
</code></pre><p><strong>Enhanced Key Format Compatibility</strong></p><p>Key format support has been expanded for better interoperability. Fedify now accepts PEM-PKCS<a class="mention hashtag" rel="nofollow noopener noreferrer" href="https://hollo.social/tags/1" target="_blank">#<span>1</span></a> format in addition to PEM-SPKI for RSA public keys. We've added <a href="https://jsr.io/@fedify/fedify@1.5.0/doc/~/importPkcs1" rel="nofollow noopener noreferrer" target="_blank"><code>importPkcs1()</code></a> and <a href="https://jsr.io/@fedify/fedify@1.5.0/doc/~/importPem" rel="nofollow noopener noreferrer" target="_blank"><code>importPem()</code></a> functions for additional flexibility, which improves compatibility with a wider range of ActivityPub implementations.</p><p><strong>Improved Key Selection Logic</strong></p><p>The key selection process is now more intelligent. The <a href="https://jsr.io/@fedify/fedify@1.5.0/doc/~/fetchKey" rel="nofollow noopener noreferrer" target="_blank"><code>fetchKey()</code></a> function can now select the public key of an actor if <code>keyId</code> has no fragment and the actor has only one public key. This enhancement simplifies key handling in common scenarios and provides better compatibility with implementations that don't specify fragment identifiers.</p><p><strong>New Authorization Options</strong></p><p>Authorization handling has been enhanced with new options for the <a href="https://jsr.io/@fedify/fedify@1.5.0/doc/~/RequestContext.getSignedKey" rel="nofollow noopener noreferrer" target="_blank"><code>RequestContext.getSignedKey()</code></a> and <a href="https://jsr.io/@fedify/fedify@1.5.0/doc/~/RequestContext.getSignedKeyOwner" rel="nofollow noopener noreferrer" target="_blank"><code>getSignedKeyOwner()</code></a> methods. This provides more flexible control over authentication and authorization flows. We've deprecated older parameter-based approaches in favor of the more flexible method-based approach.</p><p><strong>Efficient Bulk Message Queueing</strong></p><p>Message queue performance is improved with bulk operations. We've added an optional <a href="https://jsr.io/@fedify/fedify@1.5.0/doc/federation/~/MessageQueue.enqueueMany" rel="nofollow noopener noreferrer" target="_blank"><code>enqueueMany()</code></a> method to the <a href="https://jsr.io/@fedify/fedify@1.5.0/doc/federation/~/MessageQueue" rel="nofollow noopener noreferrer" target="_blank"><code>MessageQueue</code></a> interface, enabling efficient queueing of multiple messages in a single operation. This reduces overhead when processing batches of activities. All our message queue implementations have been updated to support this new operation:</p><ul>
<li><a href="https://github.com/fedify-dev/redis" rel="nofollow noopener noreferrer" target="_blank">@fedify/redis</a> 0.4.0</li><li><a href="https://github.com/fedify-dev/postgres" rel="nofollow noopener noreferrer" target="_blank">@fedify/postgres</a> 0.3.0</li><li><a href="https://github.com/fedify-dev/amqp" rel="nofollow noopener noreferrer" target="_blank">@fedify/amqp</a> 0.2.0</li>
</ul><p>If you're using any of these packages, make sure to update them alongside Fedify to take advantage of the more efficient bulk message queueing.</p><p><strong>CLI Improvements</strong></p><p>The Fedify command-line tools have been enhanced with an improved web interface for the <a href="https://fedify.dev/cli#fedify-inbox-ephemeral-inbox-server" rel="nofollow noopener noreferrer" target="_blank"><code>fedify inbox</code></a> command. We've added the Fedify logo with the cute dinosaur at the top of the page and made it easier to copy the fediverse handle of the ephemeral actor. We've also fixed issues with the web interface when installed via <a href="https://docs.deno.com/runtime/reference/cli/install/" rel="nofollow noopener noreferrer" target="_blank"><code>deno install</code></a> from <a href="https://jsr.io/@fedify/cli" rel="nofollow noopener noreferrer" target="_blank">JSR</a>.</p><p><strong>Additional Improvements and Bug Fixes</strong></p><ul>
<li>Updated dependencies, including <em>@js-temporal/polyfill</em> to 0.5.0 for Node.js and Bun</li><li>Fixed bundler errors with <em>uri-template-router</em> on Rollup</li><li>Improved error handling and logging for document loader when KV store operations fail</li><li>Added more log messages using the LogTape library</li><li>Internalized the multibase package for better maintenance and compatibility</li>
</ul>
<p>For the complete list of changes, please refer to the <a href="https://github.com/fedify-dev/fedify/releases/tag/1.5.0" rel="nofollow noopener noreferrer" target="_blank">changelog</a>.</p><p>To update to Fedify 1.5.0, run:</p><pre><code># For Deno
deno add jsr:@fedify/fedify@1.5.0
# For npm
npm add @fedify/fedify@1.5.0
# For Bun
bun add @fedify/fedify@1.5.0
</code></pre><p>Thank you to all contributors who helped make this release possible!</p><p><a class="mention hashtag" rel="nofollow noopener noreferrer" href="https://hollo.social/tags/fedidev" target="_blank">#<span>fedidev</span></a> <a class="mention hashtag" rel="nofollow noopener noreferrer" href="https://hollo.social/tags/fediverse" target="_blank">#<span>fediverse</span></a></p>