7 Commits

Author SHA1 Message Date
Ricardo
0cf49e037c fix: remove duplicate page headings across all AP templates
document.njk already renders title as h1 via the heading macro.
All 14 AP templates were also calling heading() with level 1 inside
their content block, producing two h1 elements per page. Removed
the redundant calls and moved dynamic count prefixes into the title
variable in followers/following controllers.
2026-02-21 21:32:56 +01:00
Ricardo
71851eba9b fix: use .objectId accessors to prevent fetch errors from remote servers
Inbox handlers used await activity.getObject() which HTTP-fetches remote
objects. This fails when remote servers have Authorized Fetch enabled or
are unavailable, causing Fedify to retry ~10 times per activity.

Replaced with .objectId/.actorId accessors (zero network requests) for
Like, Announce, Undo, and Delete handlers. Wrapped remaining getObject()
and getActor() calls in try-catch with fallback to ID accessors.

Also adds Pinned Posts and Featured Tags cards to the admin dashboard.
2026-02-20 23:44:18 +01:00
Ricardo
06b8509d8a fix: refollow UI - progress bar, pause button, status endpoint
Three issues fixed:

1. Progress bar invisible: used --color-accent (doesn't exist in
   Indiekit theme). Changed to --color-primary.

2. Pause/resume buttons non-functional: the /admin/refollow/status
   GET endpoint was intercepted by Fedify middleware (content
   negotiation routes) returning 404 before Express saw it. Added
   /admin path skip to content negotiation middleware. Also made
   buttons toggle dynamically via Alpine.js x-show instead of
   server-rendered {% if %}.

3. Status badge static: replaced Nunjucks badge macro with Alpine.js
   x-text bound to a computed statusLabel property.
2026-02-20 10:29:04 +01:00
Ricardo
84122cc470 feat: batch re-follow system for imported AP accounts
After Mastodon migration, imported accounts exist only locally — no
Follow activities were sent. This adds a gradual background processor
that sends Follow activities to all source:"import" accounts so remote
servers start delivering Create activities to our inbox.

- New batch engine (lib/batch-refollow.js) processes 10 accounts per
  batch with 3s between follows and 30s between batches
- Accept(Follow) inbox listener transitions source to "federation"
  and cleans up tracking fields
- Admin API: pause, resume, and status JSON endpoints
- Dashboard progress bar with Alpine.js polling (10s interval)
- Following list badges for refollow:sent and refollow:failed states
- Restart recovery resets stale refollow:pending back to import
- 3 retries with 1-hour cooldown before permanent failure
2026-02-20 08:10:45 +01:00
Ricardo
eaf0f1d126 feat: migrate to Fedify for ActivityPub federation (v0.2.0)
Replace hand-rolled federation code with Fedify's battle-tested
implementation. This gives us proper HTTP Signatures, WebFinger,
NodeInfo, typed inbox listeners, and collection dispatchers out
of the box.

New modules:
- lib/federation-setup.js — Fedify Federation configuration
- lib/federation-bridge.js — Express↔Fedify middleware bridge
- lib/inbox-listeners.js — typed inbox handlers (Follow, Undo, etc.)
- lib/kv-store.js — MongoDB-backed KvStore adapter
- lib/controllers/profile.js — admin profile management
- views/activitypub-profile.njk — profile editing form

Removed hand-rolled modules:
- lib/actor.js, lib/federation.js, lib/inbox.js
- lib/keys.js, lib/webfinger.js

Key changes:
- Actor, inbox, outbox, followers, following all delegate to Fedify
- Syndication uses ctx.sendActivity() instead of manual delivery
- Profile managed via admin UI, stored in ap_profile collection
- Legacy PKCS#8 keys imported via Web Crypto API
- Custom bridge preserves Express mount path (req.originalUrl)
2026-02-19 11:59:23 +01:00
Ricardo
43549c6334 fix: restructure locale keys to use proper nesting for migrate section
The i18n system resolves dots as nested path separators, but migrate
keys were flat strings with dots in the key name. Restructure migrate
as a nested object with a title sub-key.
2026-02-18 23:50:02 +01:00
Ricardo
deb9cb54a3 fix: prefix view templates to avoid Nunjucks name collisions
Rename all views to activitypub-*.njk to prevent collisions with other
plugins that have dashboard.njk (podroll). Fix all new Date() calls to
use .toISOString() per Indiekit convention. Add try-catch in syndicator
to prevent delivery failures from crashing post creation.
2026-02-18 23:10:35 +01:00