はじめに
自分の作ったブログやサービスをMastodonからフォローできるようにしたい——そう思って仕様を調べ始めると、すぐに心が折れそうになります。ActivityPubのActivity Vocabulary、WebFingerでのアカウント解決、HTTP SignaturesやHTTP Message Signaturesによるリクエストの検証、NodeInfoでのソフトウェア情報公開など、覚えることが多すぎるのです。しかもMastodon・Misskey・Lemmyといった実装ごとに微妙な癖があり、仕様書どおりに実装しても実際にはつながらない、ということも珍しくありません。
Fedifyは、この「ActivityPub実装の面倒な部分」をまるごと肩代わりしてくれるTypeScript製のフェデレーションフレームワークです。単なるプロトコルのパーサーではなく、アクターの公開・フォロー処理・署名検証・配送までを一貫してサポートしてくれるため、開発者はビジネスロジックとユーザー体験に集中できます。
この記事では、Fedifyの特徴からインストール方法、実際にアクターを公開してフォローを受け付けるまでの実装パターンを解説します。
Fedifyとは
Fedifyは、ActivityPubをはじめとするフェディバース関連の標準規格に基づいた連合型(フェデレーテッド)サーバーアプリを構築するためのTypeScriptライブラリです。Node.js・Deno・Bun・Cloudflare Workersで動作し、npmパッケージ名は@fedify/fedifyです(JSRでも@fedify/fedifyとして公開されています)。作者はロギングライブラリ「LogTape」の作者としても知られるHong Minhee氏で、Mastodonをはじめとする既存のフェディバースソフトウェアとの相互運用性を重視して設計されています。
主な特徴
- Activity Vocabularyの型安全な表現 -
PersonやFollow、AcceptといったActivityPubのオブジェクトをTypeScriptの型付きクラスとして扱えます - WebFingerクライアント・サーバー -
@user@example.com形式のアカウント解決を仕様どおりに実装済み - HTTP Signatures / HTTP Message Signatures対応 - draft-cavage-http-signatures-12とRFC 9421の両方をサポートし、リクエストの検証・署名を自動化
- Object Integrity Proofs(FEP-8b32)対応 - Linked Data Signaturesによるオブジェクトの改ざん検知
- NodeInfoプロトコル対応 - 自分のサーバーがどんなソフトウェアかを標準形式で公開できる
- Mastodon等との相互運用性の作り込み - 仕様どおりに実装しても実際のフェディバースソフトウェアとつながらない、というギャップを埋める調整が施されています
- Express・Hono・Fastify・H3・Elysia等への統合パッケージ - 既存のWebフレームワークにミドルウェアとして組み込める
- CLIツールチェーン(
@fedify/cli) - ローカルでのデバッグやActivityPubオブジェクトのlookupが行えます
インストール
ランタイムに応じて次のいずれかでインストールします。
# Node.js
npm add @fedify/fedify
# Deno
deno add jsr:@fedify/fedify
# Bun
bun add @fedify/fedify
ゼロからプロジェクトを始める場合は、対話式のセットアップウィザードを持つ@fedify/initを使うと、ランタイム・パッケージマネージャー・統合するWebフレームワークを選ぶだけで雛形を作れます。
npm init @fedify
基本的な使い方
Fedifyの中心となるのがcreateFederation()です。これがアクターのURLルーティングやアクティビティの送受信をまとめて管理する、いわばフェディバース対応サーバーの本体になります。ここではキーや設定を保存するkvにインメモリストアを使っていますが、本番ではRedisやPostgreSQLなどのドライバに差し替えられます。
import { createFederation, MemoryKvStore } from "@fedify/fedify";
const federation = createFederation<void>({
kv: new MemoryKvStore(),
});
続いてsetActorDispatcher()で、/users/{identifier}のようなURLパターンに対して、どんなアクター(Personオブジェクト)を返すかを定義します。ここで返した情報が、Mastodonなどから@me@yourdomain.comのように参照されたときのプロフィールになります。
import { Person } from "@fedify/fedify";
federation.setActorDispatcher(
"/users/{identifier}",
async (ctx, identifier) => {
if (identifier !== "me") return null;
return new Person({
id: ctx.getActorUri(identifier),
name: "Me",
summary: "This is me!",
preferredUsername: identifier,
url: new URL("/", ctx.url),
inbox: ctx.getInboxUri(identifier),
});
},
);
ctx.getActorUri()やctx.getInboxUri()のようなヘルパーが、ActivityPubの仕様どおりのURIを自動で組み立ててくれる点がポイントです。自分で文字列を組み立てて仕様違反を起こす心配がありません。
実践的なユースケース
Fedifyはサーバーサイド専用のフレームワークであり、ブラウザ単体で完結する処理を持たないため、この記事では実行可能なコードプレイグラウンドの代わりに、実際の開発でよく使う実装パターンをコード例で紹介します。
フォローを受け付けてAcceptを返す
フェディバース対応でまず必要になるのが「フォローされたら承認する」処理です。setInboxListeners()でinboxのURLパターンを登録し、.on(Follow, ...)でFollowアクティビティを受け取ったときの処理を書きます。ここでは相手を確認したうえでAcceptアクティビティを送り返し、フォロー関係を確立しています。
import { Accept, Follow } from "@fedify/fedify";
federation
.setInboxListeners("/users/{identifier}/inbox", "/inbox")
.on(Follow, async (ctx, follow) => {
if (follow.id == null || follow.actorId == null || follow.objectId == null) {
return;
}
const parsed = ctx.parseUri(follow.objectId);
if (parsed?.type !== "actor" || parsed.identifier !== "me") return;
const follower = await follow.getActor(ctx);
if (follower == null) return;
await ctx.sendActivity(
{ identifier: parsed.identifier },
follower,
new Accept({ actor: follow.objectId, object: follow.id }),
);
});
follow.getActor(ctx)はフォローしてきた相手のアクター情報をリモートから取得するメソッドです。HTTP Signaturesの検証やWebFingerでのアカウント解決はFedifyの内部で処理されるため、開発者が意識するのはビジネスロジックの部分だけになります。
既存のWebフレームワークにミドルウェアとして組み込む
ゼロから専用サーバーを書かなくても、すでに動いているExpressやHonoのアプリにFedifyを差し込むことができます。@fedify/expressや@fedify/honoといった統合パッケージが、リクエストをFedifyのfederationオブジェクトに橋渡しするミドルウェアを提供しています。
import express from "express";
import { integrateFederation } from "@fedify/express";
const app = express();
app.set("trust proxy", true);
app.use(integrateFederation(federation, (req) => undefined));
app.get("/", (req, res) => {
res.send("Hello from an ActivityPub-enabled app!");
});
これにより、既存のルーティングやミドルウェアはそのままに、/users/{identifier}や/users/{identifier}/inboxへのリクエストだけがFedify側のディスパッチャーに渡されるようになります。新規プロジェクトだけでなく、すでに運用中のNode.jsアプリにフェディバース対応を後付けする際にも使えるパターンです。
CLIでActivityPubオブジェクトをその場で確認する
実装したアクターやアクティビティが仕様どおりに解決できているかは、@fedify/cliが提供するfedifyコマンドで手早く確認できます。ブラウザやMastodonの管理画面を開かずに、ターミナルからActivityPubオブジェクトのlookupが可能です。
npm add -g @fedify/cli
# アクターやオブジェクトのURI・ハンドルを解決して中身を表示する
fedify lookup @me@yourdomain.com
デバッグ用のダッシュボードを提供する@fedify/debuggerパッケージと組み合わせれば、送受信されたアクティビティの中身をブラウザ上で確認しながら開発を進めることもできます。仕様違反による「なぜかMastodonからつながらない」という状態を、ログとlookup結果から早期に特定できるのがCLIツールチェーンの強みです。
まとめ
FedifyはActivityPub・WebFinger・HTTP Signatures・NodeInfoといった、フェディバース対応に必要な複数の仕様を横断的に肩代わりしてくれるフレームワークです。createFederation()でアクターを公開し、setInboxListeners()でフォローなどのアクティビティを処理する、という2つのAPIを押さえるだけで、Mastodonから見つけてフォローできるサービスの土台ができあがります。Express・Hono・Fastifyなど既存のWebフレームワークへの統合パッケージも揃っているため、新規開発だけでなく既存アプリへの後付けも現実的です。自分のサービスをフェディバースに開いてみたい方は、まずnpm init @fedifyで雛形を作り、チュートリアルを追いながら動かしてみることをおすすめします。