fedify

GitHub

用于在 JavaScript/TypeScript 中构建 ActivityPub 联邦服务器,集成 Fedify 库处理去中心化社交网络功能。

claude-plugin/skills/fedify/SKILL.md fedify-dev/fedify

Trigger Scenarios

使用 Fedify 库开发 ActivityPub 服务 实现 Fediverse 联邦化功能 提及 ActivityPub、WebFinger 或 Mastodon 互操作性

Install

npx skills add fedify-dev/fedify --skill fedify -g -y
More Options

Non-standard path

npx skills add https://github.com/fedify-dev/fedify/tree/main/claude-plugin/skills/fedify -g -y

Use without installing

npx skills use fedify-dev/fedify@fedify

指定 Agent (Claude Code)

npx skills add fedify-dev/fedify --skill fedify -a claude-code -g -y

安装 repo 全部 skill

npx skills add fedify-dev/fedify --all -g -y

预览 repo 内 skill

npx skills add fedify-dev/fedify --list

SKILL.md

Frontmatter
{
    "name": "fedify",
    "description": "Use this skill whenever writing JavaScript or TypeScript code that uses Fedify to build an ActivityPub server, handle federation activities, implement fediverse features, or integrate Fedify with a web framework such as Hono, Express, Next.js, Nuxt, Fastify, Koa, NestJS, Astro, SvelteKit, Fresh, h3, Elysia, or Cloudflare Workers. Covers the `Federation` builder pattern, actor\/inbox\/outbox\/collection dispatchers, inbox listeners, vocabulary objects from `@fedify\/vocab`, key pair management, HTTP Signatures, Object Integrity Proofs, the `KvStore` and `MessageQueue` interfaces, database adapter packages, structured logging with LogTape, OpenTelemetry tracing, the `fedify` CLI toolchain, and common mistakes. Also apply when the user mentions ActivityPub, federation, fediverse, WebFinger, NodeInfo, FEPs, or Mastodon interoperability, even if they do not name Fedify explicitly."
}

Fedify skill

Fedify is a TypeScript library for ActivityPub server applications. It works across Deno, Node.js, and Bun. The library takes care of the fiddly parts of the fediverse (HTTP Signatures, Object Integrity Proofs, WebFinger, NodeInfo, JSON-LD, delivery queues) so application code can stay focused on dispatchers and activity handlers.

Always link into the full documentation at https://fedify.dev/ instead of guessing. Every docs page is also served as raw Markdown by appending .md to its path, so https://fedify.dev/manual/federation.md returns text/markdown. This skill uses the .md form in every fedify.dev link below so you can read the source directly without HTML rendering; when you present a link to the user, strip the .md suffix so browsers render the HTML page (so https://fedify.dev/manual/federation.md becomes https://fedify.dev/manual/federation). The index at https://fedify.dev/llms.txt and the full bundle at https://fedify.dev/llms-full.txt are authoritative; this skill only points the way. Do not invent APIs; verify names against those docs or against the installed @fedify/fedify types.

Builder pattern

Two entry points reach a Federation<TContextData> object:

  • createFederationBuilder<TContextData>() returns a FederationBuilder<TContextData>. Register dispatchers and listeners on it, then await builder.build(options) to obtain the Federation<TContextData>. Prefer this in larger apps, especially when you need to split configuration across files or avoid circular imports. In serverless runtimes such as Cloudflare Workers, bindings are only available per-request, so the Federation must be constructed inside the request handler; the builder pattern is the documented approach there because dispatcher registration can happen at module load time and only the asynchronous .build(options) call runs per request.
  • createFederation<TContextData>(options) returns a Federation<TContextData> directly. Appropriate when everything fits in one module.

.build() is asynchronous; always await it. See https://fedify.dev/manual/federation.md.

import { createFederationBuilder, MemoryKvStore } from "@fedify/fedify";

const builder = createFederationBuilder<AppState>();
// ...register dispatchers on builder...
export const federation = await builder.build({
  kv: new MemoryKvStore(),  // development only
});

[!IMPORTANT] Production deployments must provide a real queue implementation. Without one, outgoing activities are sent synchronously and delivery becomes unreliable under load. See https://fedify.dev/manual/federation.md.

[!WARNING] Never set allowPrivateAddress: true outside tests. It disables the SSRF guard that blocks Fedify from fetching private or loopback addresses. See https://fedify.dev/manual/federation.md and https://fedify.dev/manual/deploy.md.

Dispatchers

Every route Fedify serves is driven by a dispatcher callback registered on the builder (or Federation object). Do not hand-roll these routes in the web framework; the dispatcher signatures encode the library's URI template guarantees.

  • setActorDispatcher(path, dispatcher): returns an ActorCallbackSetters chain that also carries setKeyPairsDispatcher().
  • setObjectDispatcher(type, path, dispatcher): for individual Object types such as Note or Article.
  • setInboxDispatcher(path, dispatcher): the inbox collection endpoint. The inbox listener is a different API (see below).
  • setOutboxDispatcher(path, dispatcher).
  • setFollowingDispatcher(path, dispatcher) / setFollowersDispatcher(path, dispatcher) / setLikedDispatcher(path, dispatcher) / setFeaturedDispatcher(path, dispatcher) / setFeaturedTagsDispatcher(path, dispatcher).
  • setCollectionDispatcher() and setOrderedCollectionDispatcher() for custom collections.
  • setNodeInfoDispatcher(path, dispatcher) and setWebFingerLinksDispatcher(dispatcher) for protocol endpoints.

Paths use URI templates. If an identifier can contain URI characters, switch the template variable from {identifier} to {+identifier} to avoid double-encoding. See https://fedify.dev/manual/uri-template.md.

[!WARNING] Simple expansion ({identifier}) percent-encodes reserved characters a second time. If actors or objects are keyed by URIs, use reserved expansion ({+identifier}).

See https://fedify.dev/manual/actor.md, https://fedify.dev/manual/object.md, and https://fedify.dev/manual/collections.md.

Inbox listeners

setInboxListeners(inboxPath, sharedInboxPath?) returns an InboxListenerSetters object with:

  • .on(ActivityType, handler): chainable, keyed by the class (Follow, Create, Undo, etc.).
  • .onError(handler).
  • .onUnverifiedActivity(handler).
  • .setSharedKeyDispatcher(dispatcher).
  • .withIdempotency(strategy).

[!WARNING] Activities of a type that is not registered via .on() are answered with HTTP 202 and logged at error level as an unsupported activity, but never reach a listener. To catch everything, register a listener for the base Activity class.

See https://fedify.dev/manual/inbox.md.

Context and TContextData

Context<TContextData> is the per-operation handle Fedify passes to dispatchers and listeners. The TContextData generic carries application state (database handles, request id, auth session). Treat it as the single place to inject dependencies; do not reach for module-level singletons inside handlers.

RequestContext<TContextData> extends Context<TContextData> with request-scoped helpers.

Use ctx.get…Uri() helpers (for example ctx.getActorUri(identifier)) to build canonical URIs instead of string-concatenating paths.

[!CAUTION] The crossOrigin: "trust" option on context methods and on vocabulary dereferencing disables the same-origin check. Only use it when the remote document is known to be trustworthy; it was the source of prior interop bugs.

See https://fedify.dev/manual/context.md and https://fedify.dev/manual/context-advanced.md.

Framework integrations

Mount Fedify through the dedicated integration package for the target framework. Do not translate requests manually; the integration handles content negotiation, signature verification, and response streaming.

Framework Package
Astro @fedify/astro
Cloudflare Workers @fedify/cfworkers
Elysia @fedify/elysia
Express @fedify/express
Fastify @fedify/fastify
Fresh @fedify/fresh
h3 @fedify/h3
Hono @fedify/hono
Koa @fedify/koa
NestJS @fedify/nestjs
Next.js @fedify/next
Nuxt @fedify/nuxt
SolidStart @fedify/solidstart
SvelteKit @fedify/sveltekit

Two more packages are frequently useful: @fedify/debugger for a local ActivityPub dashboard, and @fedify/relay for relay implementations.

See https://fedify.dev/manual/integration.md.

Built-in protocol endpoints

Fedify serves these endpoints automatically as soon as the federation handler is mounted; do not reimplement them.

Outgoing activities

ctx.sendActivity(sender, recipients, activity, options?) is the single entry point for outbound delivery. Two overloads:

  • Explicit recipients: pass a single Recipient or an array. The sender may be a SenderKeyPair, a SenderKeyPair[], or { identifier } / { username }.
  • Fan-out: pass the literal "followers" to deliver to the sender's Followers collection. In this overload the sender must be { identifier } or { username }; a raw SenderKeyPair or SenderKeyPair[] is rejected because Fedify needs the actor identifier to resolve the followers collection.

Always route outbound activities through the queue in production; this is the same queue provided to createFederation() or .build(). Without a queue the call blocks until every recipient responds and failed deliveries have no retry.

[!CAUTION] Do not derive an activity's id from (actor, object). The same actor can send the same activity shape to the same object more than once (for example FollowUndo(Follow)Follow again), and those must be distinct activities. Use a fresh UUID or counter in the fragment.

See https://fedify.dev/manual/send.md.

Vocabulary imports

Import ActivityStreams and ActivityPub vocabulary types from @fedify/vocab. The historical path @fedify/fedify/vocab is a deprecated shim kept for backwards compatibility; new code should not use it. Likewise, @fedify/vocab-runtime replaces the old @fedify/fedify/runtime path, and @fedify/webfinger replaces the old in-tree src/webfinger.

[!CAUTION] Several vocabulary classes collide with JavaScript globals (notably Object). When importing, either use a namespace import (import * as vocab from "@fedify/vocab") or alias the individual class.

fromJsonLd() and toJsonLd() are asynchronous; always await them.

[!WARNING] crossOrigin: "trust" on vocabulary deserialization trusts embedded objects without re-fetching. Treat it as you would dangerouslySetInnerHTML.

See https://fedify.dev/manual/vocab.md.

Key pair management

setActorDispatcher(...).setKeyPairsDispatcher(dispatcher) supplies the actor's key pairs. Return two keys per actor:

  • An RSA-PKCS#1-v1.5 key for HTTP Signatures (Mastodon interop).
  • An Ed25519 key for FEP-8b32 Object Integrity Proofs.

Fedify signs outbound activities with whatever keys are available; for interop with the widest set of peers, provide both.

[!WARNING] Private keys must live in secret storage. They are not configuration; do not check them into repositories, embed them in container images, or expose them via admin endpoints.

See https://fedify.dev/manual/actor.md.

Persistent storage

Fedify defines two storage interfaces: KvStore (key/value cache and idempotence) and MessageQueue (delivery plus inbox processing), both re-exported from @fedify/fedify. Use the built-in MemoryKvStore only in development or tests.

Package KvStore MessageQueue
@fedify/sqlite yes yes
@fedify/postgres yes yes
@fedify/mysql yes yes
@fedify/redis yes yes
@fedify/amqp no yes
@fedify/denokv yes yes
@fedify/cfworkers yes yes

[!WARNING] PostgresMessageQueue and similar implementations require connection pooling sized for parallel consumers; a single shared connection will deadlock under ParallelMessageQueue. See https://fedify.dev/manual/mq.md.

[!WARNING] Do not load-balance worker nodes that drain the queue. Each worker should take traffic independently; putting them behind a load balancer breaks idempotency tracking. See https://fedify.dev/manual/deploy.md.

See https://fedify.dev/manual/kv.md and https://fedify.dev/manual/mq.md.

Observability

LogTape

Fedify emits structured logs via LogTape under the following categories. Configure LogTape once at application start (if this project has a separate LogTape skill installed, defer to it for the generic setup):

  • fedify.compat.transformers
  • fedify.federation, fedify.federation.actor, fedify.federation.collection, fedify.federation.fanout, fedify.federation.http, fedify.federation.inbox, fedify.federation.outbox, fedify.federation.queue
  • fedify.nodeinfo.client
  • fedify.otel.exporter
  • fedify.sig.http, fedify.sig.key, fedify.sig.ld, fedify.sig.proof
  • fedify.utils.docloader, fedify.utils.kv-cache
  • fedify.webfinger.server

[!CAUTION] Since LogTape 0.7.0, implicit contexts require explicit configuration. See https://fedify.dev/manual/log.md.

OpenTelemetry

Pass a tracerProvider in FederationOptions to have Fedify instrument its internals. For trace persistence, @fedify/fedify/otel exports FedifySpanExporter, which writes traces to a KvStore so the @fedify/debugger dashboard can render them.

[!CAUTION] Initialize the OpenTelemetry SDK before importing Fedify. Later registration leaves earlier spans untraced.

See https://fedify.dev/manual/log.md and https://fedify.dev/manual/opentelemetry.md.

Looking up FEPs

When the user references a Fediverse Enhancement Proposal (for example FEP-8fcf or FEP-1b12), clone the proposals repository locally and read the relevant file; Codeberg blocks web scraping and WebFetch-style requests fail:

git clone https://codeberg.org/fediverse/fep.git

Files are under fep/ keyed by the four-hex-digit identifier (for example fep/8fcf/fep-8fcf.md). If the project is configured with the FEP MCP server, prefer that instead.

CLI helpers

The fedify CLI (distributed as @fedify/cli) covers bootstrapping and debugging:

  • fedify init: scaffold a new project (pick web framework, package manager, KV store, and message queue).
  • fedify lookup: resolve a handle, URL, or WebFinger identifier and print the dereferenced document.
  • fedify inbox: spin up a temporary inbox with a tunnel to inspect incoming activities from real peers.
  • fedify webfinger, fedify nodeinfo, fedify tunnel, fedify relay.

[!WARNING] fedify inbox and fedify tunnel are development tools. They open a public tunnel to your local process; do not run them against production data.

See https://fedify.dev/cli.md.

Common mistakes to avoid

  • Forgetting to await builder.build(...) or await ctx.sendActivity(...). Both are asynchronous.
  • Hand-rolling /.well-known/webfinger or /.well-known/nodeinfo routes; Fedify already serves them.
  • Importing from the deprecated shims @fedify/fedify/vocab or @fedify/fedify/runtime, or from the old in-tree src/webfinger path, instead of the dedicated packages @fedify/vocab, @fedify/vocab-runtime, and @fedify/webfinger.
  • Omitting the queue option in production; outgoing delivery becomes synchronous and unreliable.
  • Running with MemoryKvStore in production; it evaporates on every restart.
  • Running behind a reverse proxy, a tunnel (fedify tunnel, ngrok, Cloudflare Tunnel, Tailscale Funnel), or a load balancer without propagating the original origin. Fedify reads request.url, so without X-Forwarded-* handling it will mint actor IDs and activity URLs using the internal origin (for example http://localhost:3000) instead of the public https://… address that remote peers dereference. Fix one of two ways: pin FederationOptions.origin to the canonical URL, or pipe requests through x-forwarded-fetch before they reach Fedify (gated on a BEHIND_PROXY flag, since X-Forwarded-Host is spoofable from the open internet). See https://fedify.dev/manual/deploy.md.
  • Enabling allowPrivateAddress: true outside tests; that disables the SSRF guard.
  • Using crossOrigin: "trust" without verifying the remote is actually trusted.
  • Registering inbox handlers only for specific activity types and expecting delivery-level error handling; unregistered types are answered with HTTP 202 and logged at error level as unsupported, but never reach a listener. Add a catch-all on Activity if you need to observe them.
  • Wiring Fedify into a web framework by writing custom routes instead of importing the matching @fedify/<framework> package.
  • Load-balancing queue worker nodes; each worker must take traffic independently.
  • Using simple URI-template expansion ({identifier}) when identifiers contain reserved URI characters; switch to {+identifier}.
  • Deriving an activity's id from (actor, object); the same pair can legitimately produce multiple activities of the same shape.
  • Returning Tombstone from an actor dispatcher without checking RequestContext.getActor({ tombstone: "passthrough" }) semantics; see https://fedify.dev/manual/actor.md.
  • Committing private keys, embedding them in bundles, or exposing them through admin endpoints.

Version History

  • 2.3.4 Current 2026-08-20 14:19

Same Skill Collection

.agents/skills/add-to-fedify-init/SKILL.md
.agents/skills/add-vocab/SKILL.md
.agents/skills/commit/SKILL.md
.agents/skills/create-example-app-with-integration/SKILL.md
.agents/skills/create-integration-package/SKILL.md
.agents/skills/get-reviews/SKILL.md
claude-plugin/skills/actor/SKILL.md
claude-plugin/skills/docs/SKILL.md
claude-plugin/skills/fep/SKILL.md
claude-plugin/skills/inbox/SKILL.md
claude-plugin/skills/migration/SKILL.md
.agents/skills/sacho/SKILL.md

Metadata

Files
0
Version
2.3.4
Hash
e4942ee8
Indexed
2026-08-20 14:19

- 위키
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-25 09:31
浙ICP备14020137号-1 $방문자$