Skip to content

Extensible federation lifecycle observability #323

@dahlia

Description

@dahlia

Summary

This proposal suggests adding a FederationObserver interface to provide extensible hooks into the federation lifecycle, with the primary use case being a debug dashboard (as discussed in #319) but designed to support other observability and extensibility needs.

Motivation

While reviewing PR #319 (Real-time ActivityPub debug dashboard), we identified that the current approach requires integration hooks in the core federation system to capture real ActivityPub traffic. Rather than adding debugger-specific code to the core @fedify/fedify package, we can introduce a general observer pattern that:

  1. Enables the debug dashboard without coupling debugger code to the core package
  2. Provides extensibility for other use cases like logging, metrics, analytics, security auditing
  3. Maintains separation of concerns keeping the core package focused on federation functionality
  4. Optimizes bundle size by allowing optional feature packages

Proposed API

Core Interface (in @fedify/fedify)

interface FederationObserver<TContextData> {
  onInboundActivity?(context: Context<TContextData>, activity: Activity): void |  Promise<void>;
  onOutboundActivity?(context: Context<TContextData>, activity: Activity): void | Promise<void>;
}

interface FederationOptions<TContextData> {
  // ... existing options
  observers?: FederationObserver<TContextData>[];
}

Debug Implementation (in separate @fedify/debugger package)

export class DebugObserver<TContextData> implements FederationObserver<TContextData> {
  constructor(private options: { path?: string } = {}) {}
  
  onInboundActivity(context: Context<TContextData>, activity: Activity) {
    this.store.addActivity({
      direction: 'inbound',
      activity,
      timestamp: new Date()
    });
  }
  
  onOutboundActivity(context: Context<TContextData>, activity: Activity) {
    this.store.addActivity({
      direction: 'outbound', 
      activity,
      timestamp: new Date()
    });
  }
  
  // Additional methods for serving debug dashboard UI
}

Usage

import { DebugObserver } from '@fedify/debugger';

const debugObserver = new DebugObserver({ path: '/__debugger__' });
const federation = createFederation({
  kv: new MemoryKvStore(),
  observers: [debugObserver],
});

Integration Points

The observers would be called at strategic points in the federation middleware:

  1. Inbound activities: In handleInbox after activity parsing but before listener execution
  2. Outbound activities: In sendActivity before activity transformation and delivery

Benefits

  1. Decoupled design: Debug functionality lives in separate package
  2. Extensible: Can support logging, metrics, filtering, security scanning, etc.
  3. Async support: Unlike current ActivityTransformer, observers can perform async operations
  4. Bundle optimization: Production builds don't include debug code unless imported
  5. Multiple observers: Can register multiple observers for different purposes

Future Extensions

While starting minimal for the debug use case, the interface could be extended with additional hooks:

interface FederationObserver<TContextData> {
  // Current proposal
  onInboundActivity?(context: Context<TContextData>, activity: Activity): void | Promise<void>;
  onOutboundActivity?(context: Context<TContextData>, activity: Activity): void | Promise<void>;
  
  // Potential future additions
  onActorRequest?(context: Context<TContextData>, actor: Actor): void | Promise<void>;
  onCollectionRequest?(context: Context<TContextData>, collection: Collection): void | Promise<void>;
  onWebFingerRequest?(context: Context<TContextData>, resource: string): void | Promise<void>;
}

Relationship to PR #319

This proposal would enable the debug dashboard from #319 to be implemented as:

  1. A @fedify/debugger package that implements FederationObserver
  2. Integration with the federation router to serve debug UI at configurable paths
  3. Real-time activity capture without modifying core federation logic

The excellent work in #319 (ActivityStore, WebSocket updates, terminal interface, etc.) would be reused in this new architecture.

Implementation Plan

  1. Add FederationObserver interface to core package
  2. Add observers option to FederationOptions
  3. Integrate observer calls in federation middleware
  4. Create @fedify/debugger package using work from feat(cli): Real-time ActivityPub debug dashboard #319
  5. Update documentation and examples

Metadata

Metadata

Assignees

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions