Skip to content

Conversation

@sij411
Copy link
Contributor

@sij411 sij411 commented Dec 12, 2025

Summary

This PR refactors the @fedify/relay package to introduce a factory pattern that supports multiple relay implementations, specifically Mastodon and LitePub relay protocols. The changes improve code organization, maintainability, and extensibility for future relay implementations.

Key Changes

  • Factory Pattern: Introduced createRelay() factory function that instantiates relay implementations based on type ("mastodon" or "litepub")
  • Separate Relay Implementations:
    • MastodonRelay: Implements Mastodon's relay protocol with immediate follower acceptance
    • LitePubRelay: Implements LitePub's relay protocol with reciprocal follow pattern (pending → accepted states)
  • Refactored Core Module: Extracted common relay infrastructure into relay.ts with shared:
    • Actor dispatcher for relay server actor
    • Key pair management (RSA + Ed25519)
    • Followers/Following collection dispatchers
  • Comprehensive Test Coverage: Added dedicated test suites for both implementations:
    • mastodon.test.ts: 896 lines of tests covering Mastodon relay behavior
    • litepub.test.ts: 896 lines of tests covering LitePub relay behavior with reciprocal follows
    • Removed old monolithic relay.test.ts

Protocol Differences

Mastodon Relay:

  • Immediately accepts Follow activities and adds followers to the active list
  • Simpler subscription flow without reciprocal follow requirement
  • Suitable for permissive relay scenarios

LitePub Relay:

  • Implements reciprocal follow pattern (relay follows back the follower)
  • Two-state follower lifecycle: pendingaccepted
  • Follower is only activated after accepting the relay's Follow activity
  • More secure and controlled subscription process

Architecture Improvements

  • Modular Design: Each relay type is self-contained with its own file and tests
  • Extensibility: Easy to add new relay implementations (e.g., Akkoma, Pleroma variants)
  • Shared Infrastructure: Common functionality centralized in relay.ts and relayBuilder
  • Type Safety: Strong TypeScript typing with proper interfaces (RelayOptions, LitePubFollower)

Migration Guide

Before:

import { MastodonRelay, LitePubRelay } from "@fedify/relay";
const mastodonRelay = new MastodonRelay(options);
const litepubRelay = new LitePubRelay(options);

After:

import { createRelay } from "@fedify/relay";

// For Mastodon-compatible relay
const mastodonRelay = createRelay("mastodon", options);

// For LitePub-compatible relay
const litepubRelay = createRelay("litepub", options);

Files Changed

  • packages/relay/src/relay.ts: Refactored to shared infrastructure (771 → 161 lines)
  • packages/relay/src/mastodon.ts: New Mastodon relay implementation (191 lines)
  • packages/relay/src/litepub.ts: New LitePub relay implementation (297 lines)
  • packages/relay/src/mastodon.test.ts: New comprehensive test suite (784 lines)
  • packages/relay/src/litepub.test.ts: New comprehensive test suite (896 lines)
  • packages/relay/src/relay.test.ts: Removed old monolithic tests (1128 lines deleted)
  • packages/relay/src/mod.ts: Updated exports to include new relay classes

Test Plan

  • All Mastodon relay tests pass (784 lines of test coverage)
  • All LitePub relay tests pass (896 lines of test coverage)
  • Factory function correctly instantiates both relay types
  • Follower management works correctly for both protocols
  • Activity forwarding (Create, Update, Delete, Move, Announce) tested for both
  • Subscription approval/rejection flows tested
  • Reciprocal follow pattern tested for LitePub
  • HTTP signature verification works across both implementations

Breaking Changes

This is a breaking change that requires updates to existing relay usage code:

  • The Relay class constructor is replaced with createRelay() factory function
  • Users must specify relay type: "mastodon" or "litepub"
  • Default behavior changes based on selected relay type

Related Commits

  • 36b6574: Add relay factory pattern with federation builder
  • 03ea8aa: Add create factory function for mastodon and litepub
  • 1e7c16f: Add mastodon relay and its test
  • 0e17411: Add litepub relay and its test
  • 7902d02: Delete old relay test

🤖 Generated with Claude Code

sij411 and others added 10 commits December 12, 2025 14:30
This commit addresses all 6 unresolved review comments from @dahlia on PR fedify-dev#484:

1. Add type safety to createRelay parameter by introducing RelayType union type
2. Create common Relay interface and use it as return type for createRelay factory function
3. Add missing await keyword in litepub.ts for kv.delete operation
4. Fix poorly named variable in Move handler (mastodon.ts): deleteActivity → move
5. Fix poorly named variable in Update handler (mastodon.ts): deleteActivity → update
6. Extract duplicate code in followers/following dispatchers into shared getFollowerActors function

Changes:
- Add RelayType = "mastodon" | "litepub" type alias
- Add Relay interface with fetch method
- Update MastodonRelay and LitePubRelay to implement Relay interface
- Change createRelay return type from union to abstract Relay interface
- Remove unnecessary default case in createRelay switch (exhaustive with RelayType)
- Extract getFollowerActors helper to eliminate duplicate dispatcher logic
- Fix missing await in litepub.ts:182
- Rename handler parameters to match their actual activity types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@issues-auto-labeler issues-auto-labeler bot added component/federation Federation object related component/relay good first issue Good for newcomers labels Dec 12, 2025
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @sij411, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the ActivityPub relay module by introducing separate, specialized implementations for Mastodon and LitePub protocols. It enhances modularity, improves testability with dedicated test suites for each relay type, and streamlines relay creation through a new factory function. The inclusion of a temporal polyfill ensures robust date and time handling across the system.

Highlights

  • Relay Refactoring: The ActivityPub relay implementation has been refactored, separating MastodonRelay and LitePubRelay into their own dedicated files for better organization and maintainability.
  • New Relay Implementations: Introduced distinct MastodonRelay and LitePubRelay classes, each implementing specific logic for handling ActivityPub inbox activities according to their respective protocols.
  • Factory Function for Relay Creation: A new createRelay factory function has been added to simplify the instantiation of different relay types.
  • Comprehensive Test Suites: New test files (litepub.test.ts and mastodon.test.ts) have been added to provide extensive test coverage for the functionalities of both relay types.
  • Temporal Polyfill Integration: The @js-temporal/polyfill dependency was added and configured in the build process to ensure proper handling of temporal objects within the relay logic.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@issues-auto-labeler issues-auto-labeler bot added activitypub/interop Interoperability issues activitypub/mastodon Mastodon compatibility breaking change Breaking change labels Dec 12, 2025
@sij411 sij411 changed the title Feat/relay refactor(relay): implement factory pattern with Mastodon and LitePub relay support Dec 12, 2025
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a major new feature: ActivityPub relays. It adds two types of relays, Mastodon-compatible and LitePub-compatible, by refactoring the existing code into a more modular structure. The core logic is split into mastodon.ts and litepub.ts, with common functionality in relay.ts. New comprehensive test suites are added for both relay types.

My review focuses on the new litepub.ts implementation. I've found a high-severity bug where forwarded activities are not announced correctly according to the LitePub protocol. I've also pointed out some medium-severity issues related to code consistency, clarity, and potential bugs with non-unique IDs. The overall structure and refactoring are well-done.

@codecov
Copy link

codecov bot commented Dec 12, 2025

Codecov Report

❌ Patch coverage is 82.74112% with 68 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
packages/relay/src/mastodon.ts 70.12% 23 Missing ⚠️
packages/relay/src/litepub.ts 85.82% 18 Missing ⚠️
packages/relay/src/builder.ts 82.95% 15 Missing ⚠️
packages/relay/src/follow.ts 80.00% 10 Missing and 2 partials ⚠️
Files with missing lines Coverage Δ
packages/relay/src/base.ts 100.00% <100.00%> (ø)
packages/relay/src/factory.ts 100.00% <100.00%> (ø)
packages/relay/src/mod.ts 100.00% <100.00%> (ø)
packages/relay/src/types.ts 100.00% <100.00%> (ø)
packages/relay/src/follow.ts 80.00% <80.00%> (ø)
packages/relay/src/builder.ts 82.95% <82.95%> (ø)
packages/relay/src/litepub.ts 85.82% <85.82%> (ø)
packages/relay/src/mastodon.ts 70.12% <70.12%> (ø)

... and 4 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Add relayBuilder with actor, key pairs dispatchers
- Add shared followers/following dispatchers
- Extract getFollowerActors and dispatchRelayActors helpers
- Add validateFollowActivity for common validation
- Add sendFollowResponse for Accept/Reject responses
- Add handleUndoFollow for unsubscription handling
- These functions are shared by both relay types
- Provides common fetch() method and federation setup
- Defines abstract setupInboxListeners() for protocol-specific logic
- Base for both Mastodon and LitePub relay implementations
- MastodonRelay: Use forwardActivity for direct forwarding
- LitePubRelay: Use Announce wrapping and reciprocal follows
- Both now extend BaseRelay and implement setupInboxListeners()
- Add createRelay() factory for instantiating relay types
- Update mod.ts to export new structure
- Remove old relay.ts interface
@dahlia
Copy link
Member

dahlia commented Dec 24, 2025

Apparently the deno.lock file seems broken. Try to remove it and run deno task install to regenerate it.

@sij411
Copy link
Contributor Author

sij411 commented Dec 24, 2025

Merry Christmas 🎅 I refactored Relay classes and the package's structure as @dahlia reviewed previously.

Relay Package Refactoring (80858b6ac2ada3)

Major refactoring to eliminate code duplication between MastodonRelay and LitePubRelay implementations using Template Method pattern.

Stats: 15 commits, 12 files changed, 541 insertions(+), 489 deletions(-)


Key Changes

  1. New Architecture
  • Added BaseRelay abstract class (src/base.ts) - common functionality for both relay types
  • Both MastodonRelay and LitePubRelay now extend BaseRelay
  • Each implements setupInboxListeners() for protocol-specific behaviour
  1. Code Extracted into Modules
  • types.ts: Type definitions and constants
  • builder.ts: FederationBuilder setup and shared dispatchers
  • follow.ts: Follow/Undo activity validation and response handling
  • factory.ts: createRelay() factory function
  • base.ts: Abstract base class
  1. Code Reduction
  • MastodonRelay: -125 lines (uses direct forwarding)
  • LitePubRelay: -180 lines (uses Announce wrapping)
  • Deleted old monolithic relay.ts (283 lines)
  1. Documentation
  • Updated README.md to reflect new structure
  • Fixed package.json typo

Review Checklist

Must verify:

  • Public API remains compatible
  • Mastodon and LitePub protocols still work correctly
  • No circular dependencies introduced
  • Error handling preserved
  • Tests cover both implementations

Key files to review:

  1. src/base.ts - abstract base class
  2. src/mastodon.ts & src/litepub.ts - protocol implementations
  3. src/factory.ts - factory pattern
  4. src/builder.ts & src/follow.ts - extracted helpers

p.s.

  • I left Litepub specific Accept inbox listener codes without extracting it with helper functions because only Litepub needs to handle Accept responses. Not sure on this is the right decision?

  • For minor fixes check out this commit

@sij411
Copy link
Contributor Author

sij411 commented Dec 24, 2025

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request is a great refactoring of the @fedify/relay package. The introduction of the factory pattern for Mastodon and LitePub relays significantly improves the code's structure, maintainability, and extensibility. The separation of concerns into different files (base.ts, builder.ts, follow.ts, etc.) and the comprehensive new test suites are excellent.

I've found a critical correctness issue related to potential race conditions when updating the list of followers in both MastodonRelay and LitePubRelay implementations. These race conditions could lead to data loss (followers not being added or removed correctly) under concurrent requests. I've left detailed comments with suggestions on how to resolve this using atomic operations provided by the KvStore.

Copy link
Member

@dahlia dahlia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly looks good now.

@sij411
Copy link
Contributor Author

sij411 commented Dec 25, 2025

Alright, since those race condition problems seem bit out of this PR scope, I'll be handling in another PR. I'll keep those in mind and resolve conversations for now.

Copy link
Member

@dahlia dahlia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job, @sij411!

@dahlia dahlia merged commit 0b00165 into fedify-dev:next Dec 25, 2025
9 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

activitypub/interop Interoperability issues activitypub/mastodon Mastodon compatibility breaking change Breaking change component/federation Federation object related component/relay good first issue Good for newcomers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants