docs: update CLAUDE.md and README.md with v2.14.0/v2.15.0 features
Add full feature documentation for federation resilience (v2.14.0) and Hollo-inspired patterns (v2.15.0). Add credits to Hollo, Fedify, and Wafrn. Update architecture tree, collections table, routes, and gotchas in CLAUDE.md. Confab-Link: http://localhost:8080/sessions/af5f8b45-6b8d-442d-8f25-78c326190709
This commit is contained in:
@@ -17,7 +17,10 @@ An Indiekit plugin that adds full ActivityPub federation via [Fedify](https://fe
|
|||||||
index.js ← Plugin entry, route registration, syndicator
|
index.js ← Plugin entry, route registration, syndicator
|
||||||
├── lib/federation-setup.js ← Fedify Federation instance, dispatchers, collections
|
├── lib/federation-setup.js ← Fedify Federation instance, dispatchers, collections
|
||||||
├── lib/federation-bridge.js ← Express ↔ Fedify request/response bridge
|
├── lib/federation-bridge.js ← Express ↔ Fedify request/response bridge
|
||||||
├── lib/inbox-listeners.js ← Handlers for Follow, Undo, Like, Announce, Create, Delete, etc.
|
├── lib/inbox-listeners.js ← Fedify inbox listener registration + reply forwarding
|
||||||
|
├── lib/inbox-handlers.js ← Async inbox activity handlers (Create, Like, Announce, etc.)
|
||||||
|
├── lib/inbox-queue.js ← Persistent MongoDB-backed async inbox processing queue
|
||||||
|
├── lib/outbox-failure.js ← Outbox delivery failure handling (410 cleanup, 404 strikes, strike reset)
|
||||||
├── lib/jf2-to-as2.js ← JF2 → ActivityStreams conversion (plain JSON + Fedify vocab)
|
├── lib/jf2-to-as2.js ← JF2 → ActivityStreams conversion (plain JSON + Fedify vocab)
|
||||||
├── lib/kv-store.js ← MongoDB-backed KvStore for Fedify (get/set/delete/list)
|
├── lib/kv-store.js ← MongoDB-backed KvStore for Fedify (get/set/delete/list)
|
||||||
├── lib/activity-log.js ← Activity logging to ap_activities
|
├── lib/activity-log.js ← Activity logging to ap_activities
|
||||||
@@ -25,13 +28,26 @@ index.js ← Plugin entry, route registration, syndicat
|
|||||||
├── lib/timeline-store.js ← Timeline item extraction + sanitization
|
├── lib/timeline-store.js ← Timeline item extraction + sanitization
|
||||||
├── lib/timeline-cleanup.js ← Retention-based timeline pruning
|
├── lib/timeline-cleanup.js ← Retention-based timeline pruning
|
||||||
├── lib/og-unfurl.js ← Open Graph link previews + quote enrichment
|
├── lib/og-unfurl.js ← Open Graph link previews + quote enrichment
|
||||||
|
├── lib/key-refresh.js ← Remote actor key freshness tracking (skip redundant re-fetches)
|
||||||
|
├── lib/redis-cache.js ← Redis-cached actor lookups (cachedQuery wrapper)
|
||||||
|
├── lib/lookup-helpers.js ← WebFinger/actor resolution utilities
|
||||||
|
├── lib/lookup-cache.js ← In-memory LRU cache for actor lookups
|
||||||
|
├── lib/resolve-author.js ← Author resolution with fallback chain
|
||||||
|
├── lib/content-utils.js ← Content sanitization and text processing
|
||||||
|
├── lib/emoji-utils.js ← Custom emoji detection and rendering
|
||||||
|
├── lib/fedidb.js ← FediDB integration for popular accounts
|
||||||
├── lib/batch-refollow.js ← Gradual re-follow for imported Mastodon accounts
|
├── lib/batch-refollow.js ← Gradual re-follow for imported Mastodon accounts
|
||||||
├── lib/migration.js ← CSV parsing + WebFinger resolution for Mastodon import
|
├── lib/migration.js ← CSV parsing + WebFinger resolution for Mastodon import
|
||||||
├── lib/csrf.js ← CSRF token generation/validation
|
├── lib/csrf.js ← CSRF token generation/validation
|
||||||
|
├── lib/migrations/
|
||||||
|
│ └── separate-mentions.js ← Data migration: split mentions from notifications
|
||||||
├── lib/storage/
|
├── lib/storage/
|
||||||
│ ├── timeline.js ← Timeline CRUD with cursor pagination
|
│ ├── timeline.js ← Timeline CRUD with cursor pagination
|
||||||
│ ├── notifications.js ← Notification CRUD with read/unread tracking
|
│ ├── notifications.js ← Notification CRUD with read/unread tracking
|
||||||
│ └── moderation.js ← Mute/block storage
|
│ ├── moderation.js ← Mute/block storage
|
||||||
|
│ ├── server-blocks.js ← Server-level domain blocking
|
||||||
|
│ ├── followed-tags.js ← Hashtag follow/unfollow storage
|
||||||
|
│ └── messages.js ← Direct message storage
|
||||||
├── lib/controllers/ ← Express route handlers (admin UI)
|
├── lib/controllers/ ← Express route handlers (admin UI)
|
||||||
│ ├── dashboard.js, reader.js, compose.js, profile.js, profile.remote.js
|
│ ├── dashboard.js, reader.js, compose.js, profile.js, profile.remote.js
|
||||||
│ ├── public-profile.js ← Public profile page (HTML fallback for actor URL)
|
│ ├── public-profile.js ← Public profile page (HTML fallback for actor URL)
|
||||||
@@ -44,6 +60,15 @@ index.js ← Plugin entry, route registration, syndicat
|
|||||||
│ ├── featured.js, featured-tags.js
|
│ ├── featured.js, featured-tags.js
|
||||||
│ ├── interactions.js, interactions-like.js, interactions-boost.js
|
│ ├── interactions.js, interactions-like.js, interactions-boost.js
|
||||||
│ ├── moderation.js, migrate.js, refollow.js
|
│ ├── moderation.js, migrate.js, refollow.js
|
||||||
|
│ ├── messages.js ← Direct message UI
|
||||||
|
│ ├── follow-requests.js ← Manual follow approval UI
|
||||||
|
│ ├── follow-tag.js ← Hashtag follow/unfollow actions
|
||||||
|
│ ├── tabs.js ← Explore tab management
|
||||||
|
│ ├── my-profile.js ← Self-profile view
|
||||||
|
│ ├── resolve.js ← Actor/post resolution endpoint
|
||||||
|
│ ├── authorize-interaction.js ← Remote interaction authorization
|
||||||
|
│ ├── federation-mgmt.js ← Federation management (server blocks)
|
||||||
|
│ └── federation-delete.js ← Account deletion / federation cleanup
|
||||||
├── views/ ← Nunjucks templates
|
├── views/ ← Nunjucks templates
|
||||||
│ ├── activitypub-*.njk ← Page templates
|
│ ├── activitypub-*.njk ← Page templates
|
||||||
│ ├── layouts/ap-reader.njk ← Reader layout (NOT reader.njk — see gotcha below)
|
│ ├── layouts/ap-reader.njk ← Reader layout (NOT reader.njk — see gotcha below)
|
||||||
@@ -60,7 +85,9 @@ index.js ← Plugin entry, route registration, syndicat
|
|||||||
|
|
||||||
```
|
```
|
||||||
Outbound: Indiekit post → syndicator.syndicate() → jf2ToAS2Activity() → ctx.sendActivity() → follower inboxes
|
Outbound: Indiekit post → syndicator.syndicate() → jf2ToAS2Activity() → ctx.sendActivity() → follower inboxes
|
||||||
Inbound: Remote inbox POST → Fedify → inbox-listeners.js → MongoDB collections → admin UI
|
Delivery failure → outbox-failure.js → 410: full cleanup | 404: strike system → eventual cleanup
|
||||||
|
Inbound: Remote inbox POST → Fedify → inbox-listeners.js → ap_inbox_queue → inbox-handlers.js → MongoDB
|
||||||
|
Reply forwarding: inbox-listeners.js checks if reply is to our post → ctx.forwardActivity() → follower inboxes
|
||||||
Reader: Followed account posts → Create inbox → timeline-store → ap_timeline → reader UI
|
Reader: Followed account posts → Create inbox → timeline-store → ap_timeline → reader UI
|
||||||
Explore: Public Mastodon API → fetchMastodonTimeline() → mapMastodonToItem() → explore UI
|
Explore: Public Mastodon API → fetchMastodonTimeline() → mapMastodonToItem() → explore UI
|
||||||
|
|
||||||
@@ -73,7 +100,7 @@ processing pipeline via item-processing.js:
|
|||||||
|
|
||||||
| Collection | Purpose | Key fields |
|
| Collection | Purpose | Key fields |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `ap_followers` | Accounts following us | `actorUrl` (unique), `inbox`, `sharedInbox`, `source` |
|
| `ap_followers` | Accounts following us | `actorUrl` (unique), `inbox`, `sharedInbox`, `source`, `deliveryFailures`, `firstFailureAt`, `lastFailureAt` |
|
||||||
| `ap_following` | Accounts we follow | `actorUrl` (unique), `source`, `acceptedAt` |
|
| `ap_following` | Accounts we follow | `actorUrl` (unique), `source`, `acceptedAt` |
|
||||||
| `ap_activities` | Activity log (TTL-indexed) | `direction`, `type`, `actorUrl`, `objectUrl`, `receivedAt` |
|
| `ap_activities` | Activity log (TTL-indexed) | `direction`, `type`, `actorUrl`, `objectUrl`, `receivedAt` |
|
||||||
| `ap_keys` | Cryptographic key pairs | `type` ("rsa" or "ed25519"), key material |
|
| `ap_keys` | Cryptographic key pairs | `type` ("rsa" or "ed25519"), key material |
|
||||||
@@ -81,11 +108,19 @@ processing pipeline via item-processing.js:
|
|||||||
| `ap_profile` | Actor profile (single doc) | `name`, `summary`, `icon`, `attachments`, `actorType` |
|
| `ap_profile` | Actor profile (single doc) | `name`, `summary`, `icon`, `attachments`, `actorType` |
|
||||||
| `ap_featured` | Pinned posts | `postUrl`, `pinnedAt` |
|
| `ap_featured` | Pinned posts | `postUrl`, `pinnedAt` |
|
||||||
| `ap_featured_tags` | Featured hashtags | `tag`, `addedAt` |
|
| `ap_featured_tags` | Featured hashtags | `tag`, `addedAt` |
|
||||||
| `ap_timeline` | Reader timeline items | `uid` (unique), `published`, `author`, `content` |
|
| `ap_timeline` | Reader timeline items | `uid` (unique), `published`, `author`, `content`, `visibility`, `isContext` |
|
||||||
| `ap_notifications` | Likes, boosts, follows, mentions | `uid` (unique), `type`, `read` |
|
| `ap_notifications` | Likes, boosts, follows, mentions | `uid` (unique), `type`, `read` |
|
||||||
| `ap_muted` | Muted actors/keywords | `url` or `keyword` |
|
| `ap_muted` | Muted actors/keywords | `url` or `keyword` |
|
||||||
| `ap_blocked` | Blocked actors | `url` |
|
| `ap_blocked` | Blocked actors | `url` |
|
||||||
| `ap_interactions` | Like/boost tracking per post | `objectUrl`, `type` |
|
| `ap_interactions` | Like/boost tracking per post | `objectUrl`, `type` |
|
||||||
|
| `ap_messages` | Direct messages | `uid` (unique), `conversationId`, `author`, `content` |
|
||||||
|
| `ap_followed_tags` | Hashtags we follow | `tag` (unique) |
|
||||||
|
| `ap_explore_tabs` | Saved explore instances | `instance` (unique), `label` |
|
||||||
|
| `ap_reports` | Outbound Flag activities | `actorUrl`, `reportedAt` |
|
||||||
|
| `ap_pending_follows` | Follow requests awaiting approval | `actorUrl` (unique), `receivedAt` |
|
||||||
|
| `ap_blocked_servers` | Blocked server domains | `domain` (unique) |
|
||||||
|
| `ap_key_freshness` | Remote actor key verification timestamps | `actorUrl` (unique), `lastVerifiedAt` |
|
||||||
|
| `ap_inbox_queue` | Persistent async inbox queue | `activityId`, `status`, `enqueuedAt` |
|
||||||
|
|
||||||
## Critical Patterns and Gotchas
|
## Critical Patterns and Gotchas
|
||||||
|
|
||||||
@@ -281,6 +316,40 @@ Posts that quote another post (Mastodon quote feature via FEP-044f) are rendered
|
|||||||
3. **On-demand:** `post-detail.js` fetches quotes on demand for items that have `quoteUrl` but no stored `quote` data (pre-existing items)
|
3. **On-demand:** `post-detail.js` fetches quotes on demand for items that have `quoteUrl` but no stored `quote` data (pre-existing items)
|
||||||
4. **Rendering:** `partials/ap-quote-embed.njk` renders the embedded card; `stripQuoteReferences()` removes the inline `RE: <link>` paragraph to avoid duplication
|
4. **Rendering:** `partials/ap-quote-embed.njk` renders the embedded card; `stripQuoteReferences()` removes the inline `RE: <link>` paragraph to avoid duplication
|
||||||
|
|
||||||
|
### 26. Async Inbox Processing (v2.14.0+)
|
||||||
|
|
||||||
|
Inbound activities follow a two-stage pattern: `inbox-listeners.js` receives activities from Fedify, persists them to `ap_inbox_queue`, then `inbox-handlers.js` processes them asynchronously. This ensures no data loss if the server crashes mid-processing. Reply forwarding (`ctx.forwardActivity()`) happens synchronously in `inbox-listeners.js` because `forwardActivity()` is only available on `InboxContext`, not the base `Context` used by the queue processor.
|
||||||
|
|
||||||
|
### 27. Outbox Delivery Failure Handling (v2.15.0+)
|
||||||
|
|
||||||
|
`lib/outbox-failure.js` handles permanent delivery failures reported by Fedify's `setOutboxPermanentFailureHandler`:
|
||||||
|
|
||||||
|
- **410 Gone** → Immediate full cleanup: deletes follower from `ap_followers`, their items from `ap_timeline` (by `author.url`), their notifications from `ap_notifications` (by `actorUrl`)
|
||||||
|
- **404 Not Found** → Strike system: increments `deliveryFailures` on the follower doc, sets `firstFailureAt` via `$setOnInsert`. After 3 strikes over 7+ days, triggers the same full cleanup as 410
|
||||||
|
- **Strike reset** → `resetDeliveryStrikes()` is called in `inbox-listeners.js` after `touchKeyFreshness()` for every inbound activity type (except Block). If an actor is sending us activities, they're alive — `$unset` the strike fields
|
||||||
|
|
||||||
|
### 28. Reply Chain Fetching and Reply Forwarding (v2.15.0+)
|
||||||
|
|
||||||
|
- `fetchReplyChain()` in `inbox-handlers.js`: When a reply arrives, recursively fetches parent posts up to 5 levels deep using `object.getReplyTarget()`. Ancestors are stored with `isContext: true` flag. Uses `$setOnInsert` upsert so re-fetching ancestors is a no-op.
|
||||||
|
- Reply forwarding in `inbox-listeners.js`: When a Create activity is a reply to one of our posts (checked via `inReplyTo.startsWith(publicationUrl)`) and is addressed to the public collection, calls `ctx.forwardActivity()` to re-deliver the reply to our followers' inboxes.
|
||||||
|
|
||||||
|
### 29. Write-Time Visibility Classification (v2.15.0+)
|
||||||
|
|
||||||
|
`computeVisibility(object)` in `inbox-handlers.js` classifies posts at ingest time based on `to`/`cc` fields:
|
||||||
|
- `to` includes `https://www.w3.org/ns/activitystreams#Public` → `"public"`
|
||||||
|
- `cc` includes Public → `"unlisted"`
|
||||||
|
- Neither → `"private"` or `"direct"` (based on whether followers collection is in `to`)
|
||||||
|
|
||||||
|
The `visibility` field is stored on `ap_timeline` documents for future filtering.
|
||||||
|
|
||||||
|
### 30. Server Blocking (v2.14.0+)
|
||||||
|
|
||||||
|
`lib/storage/server-blocks.js` manages domain-level blocks stored in `ap_blocked_servers`. When a server is blocked, all inbound activities from that domain are rejected in `inbox-listeners.js` before any processing occurs. The `federation-mgmt.js` controller provides the admin UI.
|
||||||
|
|
||||||
|
### 31. Key Freshness Tracking (v2.14.0+)
|
||||||
|
|
||||||
|
`lib/key-refresh.js` tracks when remote actor keys were last verified in `ap_key_freshness`. `touchKeyFreshness()` is called for every inbound activity. This allows skipping redundant key re-fetches for actors we've recently verified, reducing network round-trips.
|
||||||
|
|
||||||
## Date Handling Convention
|
## Date Handling Convention
|
||||||
|
|
||||||
**All dates MUST be stored as ISO 8601 strings.** This is mandatory across all Indiekit plugins.
|
**All dates MUST be stored as ISO 8601 strings.** This is mandatory across all Indiekit plugins.
|
||||||
@@ -348,6 +417,10 @@ On restart, `refollow:pending` entries are reset to `import` to prevent stale cl
|
|||||||
| `GET` | `{mount}/admin/reader/profile` | Remote profile view | Yes |
|
| `GET` | `{mount}/admin/reader/profile` | Remote profile view | Yes |
|
||||||
| `GET` | `{mount}/admin/reader/moderation` | Moderation dashboard | Yes |
|
| `GET` | `{mount}/admin/reader/moderation` | Moderation dashboard | Yes |
|
||||||
| `POST` | `{mount}/admin/reader/mute,unmute,block,unblock` | Moderation actions | Yes |
|
| `POST` | `{mount}/admin/reader/mute,unmute,block,unblock` | Moderation actions | Yes |
|
||||||
|
| `GET/POST` | `{mount}/admin/reader/messages` | Direct messages | Yes |
|
||||||
|
| `GET/POST` | `{mount}/admin/follow-requests` | Manual follow approval | Yes |
|
||||||
|
| `POST` | `{mount}/admin/reader/follow-tag,unfollow-tag` | Follow/unfollow hashtag | Yes |
|
||||||
|
| `GET/POST` | `{mount}/admin/federation` | Server blocking management | Yes |
|
||||||
| `GET` | `{mount}/admin/followers,following,activities` | Lists | Yes |
|
| `GET` | `{mount}/admin/followers,following,activities` | Lists | Yes |
|
||||||
| `GET/POST` | `{mount}/admin/profile` | Actor profile editor | Yes |
|
| `GET/POST` | `{mount}/admin/profile` | Actor profile editor | Yes |
|
||||||
| `GET/POST` | `{mount}/admin/featured` | Pinned posts | Yes |
|
| `GET/POST` | `{mount}/admin/featured` | Pinned posts | Yes |
|
||||||
|
|||||||
@@ -12,6 +12,28 @@ ActivityPub federation endpoint for [Indiekit](https://getindiekit.com), built o
|
|||||||
- Reply delivery — replies are addressed to and delivered directly to the original post's author
|
- Reply delivery — replies are addressed to and delivered directly to the original post's author
|
||||||
- Shared inbox support with collection sync (FEP-8fcf)
|
- Shared inbox support with collection sync (FEP-8fcf)
|
||||||
- Configurable actor type (Person, Service, Organization, Group)
|
- Configurable actor type (Person, Service, Organization, Group)
|
||||||
|
- Manual follow approval — review and accept/reject follow requests before they take effect
|
||||||
|
- Direct messages — private conversations stored separately from the public timeline
|
||||||
|
|
||||||
|
**Federation Resilience** *(v2.14.0+)*
|
||||||
|
- Async inbox queue — inbound activities are persisted to MongoDB before processing, ensuring no data loss on crashes
|
||||||
|
- Server blocking — block entire remote servers by domain, rejecting all inbound activities from blocked instances
|
||||||
|
- Key freshness tracking — tracks when remote actor keys were last verified, skipping redundant re-fetches
|
||||||
|
- Redis-cached actor lookups — caches actor resolution results to reduce network round-trips
|
||||||
|
- Delivery strike tracking on `ap_followers` — counts consecutive delivery failures per follower
|
||||||
|
- FEP-fe34 security — verifies `proof.created` timestamps to reject replayed activities
|
||||||
|
|
||||||
|
**Outbox Failure Handling** *(v2.15.0+, inspired by [Hollo](https://github.com/fedify-dev/hollo))*
|
||||||
|
- **410 Gone** — immediate full cleanup: removes the follower, their timeline items, and their notifications
|
||||||
|
- **404 Not Found** — strike system: 3 consecutive failures over 7+ days triggers the same full cleanup
|
||||||
|
- Strike auto-reset — when an actor sends us any activity, their delivery failure count resets to zero
|
||||||
|
- Prevents orphaned data from accumulating over time while tolerating temporary server outages
|
||||||
|
|
||||||
|
**Reply Intelligence** *(v2.15.0+, inspired by [Hollo](https://github.com/fedify-dev/hollo))*
|
||||||
|
- Recursive reply chain fetching — when a reply arrives, fetches parent posts up to 5 levels deep for thread context
|
||||||
|
- Ancestor posts stored with `isContext: true` flag for thread view without cluttering the main timeline
|
||||||
|
- Reply forwarding to followers — when someone replies to our posts, the reply is forwarded to our followers so they see the full conversation
|
||||||
|
- Write-time visibility classification — computes `public`/`unlisted`/`private`/`direct` from `to`/`cc` fields at ingest time
|
||||||
|
|
||||||
**Reader**
|
**Reader**
|
||||||
- Timeline view showing posts from followed accounts with tab filtering (notes, articles, replies, boosts, media)
|
- Timeline view showing posts from followed accounts with tab filtering (notes, articles, replies, boosts, media)
|
||||||
@@ -36,6 +58,8 @@ ActivityPub federation endpoint for [Indiekit](https://getindiekit.com), built o
|
|||||||
**Moderation**
|
**Moderation**
|
||||||
- Mute actors or keywords
|
- Mute actors or keywords
|
||||||
- Block actors (also removes from followers)
|
- Block actors (also removes from followers)
|
||||||
|
- Block entire servers by domain
|
||||||
|
- Report remote actors to their home instance (Flag activity)
|
||||||
- All moderation actions available from the reader UI
|
- All moderation actions available from the reader UI
|
||||||
|
|
||||||
**Mastodon Migration**
|
**Mastodon Migration**
|
||||||
@@ -186,6 +210,7 @@ When remote servers send activities to your inbox:
|
|||||||
- **Accept(Follow)** → Marks our follow as accepted
|
- **Accept(Follow)** → Marks our follow as accepted
|
||||||
- **Reject(Follow)** → Marks our follow as rejected
|
- **Reject(Follow)** → Marks our follow as rejected
|
||||||
- **Block** → Removes actor from our followers
|
- **Block** → Removes actor from our followers
|
||||||
|
- **Flag** → Outbound report sent to remote actor's instance
|
||||||
|
|
||||||
### Content Negotiation
|
### Content Negotiation
|
||||||
|
|
||||||
@@ -254,7 +279,7 @@ The plugin creates these collections automatically:
|
|||||||
|
|
||||||
| Collection | Description |
|
| Collection | Description |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `ap_followers` | Accounts following your actor |
|
| `ap_followers` | Accounts following your actor (includes delivery failure strike tracking) |
|
||||||
| `ap_following` | Accounts you follow |
|
| `ap_following` | Accounts you follow |
|
||||||
| `ap_activities` | Activity log with automatic TTL cleanup |
|
| `ap_activities` | Activity log with automatic TTL cleanup |
|
||||||
| `ap_keys` | RSA and Ed25519 key pairs for HTTP Signatures |
|
| `ap_keys` | RSA and Ed25519 key pairs for HTTP Signatures |
|
||||||
@@ -262,11 +287,19 @@ The plugin creates these collections automatically:
|
|||||||
| `ap_profile` | Actor profile (single document) |
|
| `ap_profile` | Actor profile (single document) |
|
||||||
| `ap_featured` | Pinned/featured posts |
|
| `ap_featured` | Pinned/featured posts |
|
||||||
| `ap_featured_tags` | Featured hashtags |
|
| `ap_featured_tags` | Featured hashtags |
|
||||||
| `ap_timeline` | Reader timeline items from followed accounts |
|
| `ap_timeline` | Reader timeline items (includes `visibility` and `isContext` fields) |
|
||||||
| `ap_notifications` | Interaction notifications |
|
| `ap_notifications` | Interaction notifications |
|
||||||
| `ap_muted` | Muted actors and keywords |
|
| `ap_muted` | Muted actors and keywords |
|
||||||
| `ap_blocked` | Blocked actors |
|
| `ap_blocked` | Blocked actors |
|
||||||
| `ap_interactions` | Per-post like/boost tracking |
|
| `ap_interactions` | Per-post like/boost tracking |
|
||||||
|
| `ap_messages` | Direct messages / private conversations |
|
||||||
|
| `ap_followed_tags` | Hashtags you follow for timeline filtering |
|
||||||
|
| `ap_explore_tabs` | Saved Mastodon instances for the explore view |
|
||||||
|
| `ap_reports` | Outbound reports (Flag activities) sent to remote instances |
|
||||||
|
| `ap_pending_follows` | Follow requests awaiting manual approval |
|
||||||
|
| `ap_blocked_servers` | Blocked server domains (instance-level blocks) |
|
||||||
|
| `ap_key_freshness` | Tracks when remote actor keys were last verified |
|
||||||
|
| `ap_inbox_queue` | Persistent async inbox processing queue |
|
||||||
|
|
||||||
## Supported Post Types
|
## Supported Post Types
|
||||||
|
|
||||||
@@ -346,6 +379,16 @@ This is not a bug — Fedify requires explicit opt-in for signed fetches. But it
|
|||||||
- **No custom emoji rendering** — Custom emoji shortcodes display as text
|
- **No custom emoji rendering** — Custom emoji shortcodes display as text
|
||||||
- **In-process queue without Redis** — Activities may be lost on restart
|
- **In-process queue without Redis** — Activities may be lost on restart
|
||||||
|
|
||||||
|
## Acknowledgements
|
||||||
|
|
||||||
|
This plugin builds on the excellent [Fedify](https://fedify.dev) framework by [Hong Minhee](https://github.com/dahlia). Fedify provides the core ActivityPub federation layer — HTTP Signatures, content negotiation, message queues, and the vocabulary types that make all of this possible.
|
||||||
|
|
||||||
|
Several federation patterns in this plugin were inspired by studying other open-source ActivityPub implementations:
|
||||||
|
|
||||||
|
- **[Hollo](https://github.com/fedify-dev/hollo)** (by the Fedify author) — A single-user Fedify-based ActivityPub server that served as the primary reference implementation. The outbox permanent failure handling (410 cleanup and 404 strike system), recursive reply chain fetching, reply forwarding to followers, and write-time visibility classification in v2.15.0 are all adapted from Hollo's patterns for a MongoDB/single-user context.
|
||||||
|
|
||||||
|
- **[Wafrn](https://github.com/gabboman/wafrn)** — A federated social network whose ActivityPub implementation informed the operational resilience patterns added in v2.14.0. Server blocking, key freshness tracking, async inbox processing with persistent queues, and the general approach to federation hardening were inspired by studying Wafrn's production codebase.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT
|
MIT
|
||||||
|
|||||||
Reference in New Issue
Block a user