Summary
Create a new @fedify/debugger package that provides an embedded real-time ActivityPub debug dashboard. It works as a proxy implementing the Federation interface, wrapping the original federation object and serving an SSR-based web UI using Hono internally.
This issue is a concrete implementation of #234, based on the architecture decision in #323 (OTel-based approach) and the FedifySpanExporter implemented in #497.
Design
A proxy implementing the Federation interface
The debugger fully implements Federation<TContextData>. It overrides only the fetch() method; all other methods (startQueue, processQueuedTask, createContext, setActorDispatcher, etc.) are delegated to the inner Federation object as-is.
This means it can be used as a drop-in replacement anywhere a Federation object is expected, including existing framework integration packages (@fedify/hono, @fedify/express, @fedify/h3, etc.):
import { createFederationDebugger } from "@fedify/debugger";
import { FedifySpanExporter } from "@fedify/fedify/otel";
import { federation } from "@fedify/hono";
import { Hono } from "hono";
import {
NodeTracerProvider,
SimpleSpanProcessor,
} from "@opentelemetry/sdk-trace-node";
const kv = new MemoryKvStore();
const exporter = new FedifySpanExporter(kv, {
ttl: Temporal.Duration.from({ hours: 1 }),
});
const tracerProvider = new NodeTracerProvider();
tracerProvider.addSpanProcessor(new SimpleSpanProcessor(exporter));
const fed = createFederation({ kv, tracerProvider });
// Wrap federation with debugger:
const dbg = createFederationDebugger(fed, { exporter });
// Use with any framework integration as-is:
const app = new Hono();
app.use(federation(dbg, (ctx) => undefined));
How fetch() works
Request
│
├─ /__debug__/* → Hono app (SSR dashboard)
│ ├─ GET / → traces list page
│ ├─ GET /traces/:id → trace detail page
│ └─ GET /api/traces → JSON API (polling)
│
└─ everything else → federation.fetch()
Requests matching the debugger path prefix are handled by the internal Hono app. Everything else is delegated to the original Federation.fetch(). This is implemented by intercepting requests at the point where the onNotFound callback would be invoked.
Internal implementation
Hono is included as a regular dependency (not a peer dependency, since it is an internal implementation detail):
- Routing: debugger path matching
- JSX SSR: dashboard page rendering via
hono/jsx
- Static assets: CSS embedded inline
API
interface FederationDebuggerOptions {
/** The path prefix for the debug dashboard. Defaults to "/__debug__". */
path?: string;
/** The FedifySpanExporter to query trace data from. */
exporter: FedifySpanExporter;
}
function createFederationDebugger<TContextData>(
federation: Federation<TContextData>,
options: FederationDebuggerOptions,
): Federation<TContextData>;
The return type is Federation<TContextData> itself, so it can be used as a drop-in replacement in any context where a Federation object is expected.
MVP scope
Pages
-
Traces list (GET /__debug__/)
- Displays recent traces via
exporter.getRecentTraces()
- Shows trace ID (first 8 characters), activity types, timestamp, and activity count for each trace
- Each trace links to its detail page
-
Trace detail (GET /__debug__/traces/:traceId)
- Displays all activities in a trace via
exporter.getActivitiesByTraceId(traceId)
- Shows direction (inbound/outbound), activity type, actor, and timestamp for each activity
- Expandable activity JSON
- Signature verification details for inbound activities
- Target inbox URL for outbound activities
Polling-based updates
- JSON API (
GET /__debug__/api/traces)
- Returns
getRecentTraces() as JSON
- The frontend polls this endpoint periodically to refresh the list
- Implemented with a simple inline
<script>
Out of scope (future work)
- WebSocket/SSE-based real-time streaming
- Filtering UI by activity type, actor, or direction
- Retry queue management
- Authentication/access control for production environments
Package structure
packages/debugger/
├── deno.json
├── package.json
├── tsdown.config.ts
└── src/
├── mod.ts # createFederationDebugger()
├── mod.test.ts
└── views/
├── layout.tsx # HTML layout
├── traces-list.tsx # Traces list page
└── trace-detail.tsx # Trace detail page
Dependencies
| Dependency |
Type |
Reason |
@fedify/fedify |
peerDependencies |
Federation, FedifySpanExporter |
hono |
dependencies |
Internal routing and JSX SSR |
Summary
Create a new
@fedify/debuggerpackage that provides an embedded real-time ActivityPub debug dashboard. It works as a proxy implementing theFederationinterface, wrapping the original federation object and serving an SSR-based web UI using Hono internally.This issue is a concrete implementation of #234, based on the architecture decision in #323 (OTel-based approach) and the
FedifySpanExporterimplemented in #497.Design
A proxy implementing the
FederationinterfaceThe debugger fully implements
Federation<TContextData>. It overrides only thefetch()method; all other methods (startQueue,processQueuedTask,createContext,setActorDispatcher, etc.) are delegated to the innerFederationobject as-is.This means it can be used as a drop-in replacement anywhere a
Federationobject is expected, including existing framework integration packages (@fedify/hono,@fedify/express,@fedify/h3, etc.):How
fetch()worksRequests matching the debugger path prefix are handled by the internal Hono app. Everything else is delegated to the original
Federation.fetch(). This is implemented by intercepting requests at the point where theonNotFoundcallback would be invoked.Internal implementation
Hono is included as a regular dependency (not a peer dependency, since it is an internal implementation detail):
hono/jsxAPI
The return type is
Federation<TContextData>itself, so it can be used as a drop-in replacement in any context where aFederationobject is expected.MVP scope
Pages
Traces list (
GET /__debug__/)exporter.getRecentTraces()Trace detail (
GET /__debug__/traces/:traceId)exporter.getActivitiesByTraceId(traceId)Polling-based updates
GET /__debug__/api/traces)getRecentTraces()as JSON<script>Out of scope (future work)
Package structure
Dependencies
@fedify/fedifypeerDependenciesFederation,FedifySpanExporterhonodependencies