36 Commits

Author SHA1 Message Date
svemagie
230bfd105e merge: upstream c1a6f7e — Fedify 2.1.0, 5 FEPs, security/perf audit, v3.9.x
Upstream commits merged (0820067..c1a6f7e):
- Fedify 2.1.0 upgrade (FEP-5feb, FEP-f1d5/0151, FEP-4f05 Tombstone,
  FEP-3b86 Activity Intents, FEP-8fcf Collection Sync)
- Comprehensive security/perf audit: XSS/CSRF fixes, OAuth scopes,
  rate limiting, secret hashing, token expiry/rotation, SSRF fix
- Architecture refactoring: syndicator.js, batch-broadcast.js,
  init-indexes.js, federation-actions.js; index.js -35%
- CSS split into 15 feature-scoped files + reader-interactions.js
- Mastodon API status creation: content-warning field, linkify fix

Fork-specific resolutions:
- syndicator.js: added addTimelineItem mirror for own Micropub posts
- syndicator.js: fixed missing await on jf2ToAS2Activity (async fn)
- statuses.js: kept DM path, pin/unpin routes, edit post route,
  processStatusContent (used by edit), addTimelineItem/lookupWithSecurity/
  addNotification imports
- compose.js: kept addNotification + added federation-actions.js imports
- enrich-accounts.js: kept cache-first approach for avatar updates
- ap-notification-card.njk: kept DM lock icon (🔒) for isDirect mentions
2026-03-27 09:30:34 +01:00
Ricardo
12454749ad fix: comprehensive security, performance, and architecture audit fixes
27 issues fixed from multi-dimensional code review (4 Critical, 6 High, 11 Medium, 6 Low):

Security (Critical):
- Escape HTML in OAuth authorization page to prevent XSS (C1)
- Add CSRF protection to OAuth authorize flow (C2)
- Replace bypassable regex sanitizer with sanitize-html library (C3)
- Enforce OAuth scopes on all Mastodon API routes (C4)

Security (Medium/Low):
- Fix SSRF via DNS resolution before private IP check (M1)
- Add rate limiting to API, auth, and app registration endpoints (M2)
- Validate redirect_uri on POST /oauth/authorize (M4)
- Fix custom emoji URL injection with scheme validation + escaping (M5)
- Remove data: scheme from allowed image sources (L6)
- Add access token expiry (1hr) and refresh token rotation (90d) (M3)
- Hash client secrets before storage (L3)

Architecture:
- Extract batch-broadcast.js — shared delivery logic (H1a)
- Extract init-indexes.js — MongoDB index creation (H1b)
- Extract syndicator.js — syndication logic (H1c)
- Create federation-actions.js facade for controllers (M6)
- index.js reduced from 1810 to ~1169 lines (35%)

Performance:
- Cache moderation data with 30s TTL + write invalidation (H6)
- Increase inbox queue throughput to 10 items/sec (H5)
- Make account enrichment non-blocking with fire-and-forget (H4)
- Remove ephemeral getReplies/getLikes/getShares from ingest (M11)
- Fix LRU caches to use true LRU eviction (L1)
- Fix N+1 backfill queries with batch $in lookup (L2)

UI/UX:
- Split 3441-line reader.css into 15 feature-scoped files (H2)
- Extract inline Alpine.js interaction component (H3)
- Reduce sidebar navigation from 7 to 3 items (M7)
- Add ARIA live regions for dynamic content updates (M8)
- Extract shared CW/non-CW content partial (M9)
- Document form handling pattern convention (M10)
- Add accessible labels to functional emoji icons (L4)
- Convert profile editor to Alpine.js (L5)

Audit: documentation-central/audits/2026-03-24-activitypub-code-review.md
Plan: documentation-central/plans/2026-03-24-activitypub-audit-fixes.md
2026-03-25 07:41:20 +01:00
svemagie
b99f5fb73e Merge upstream rmdes:main — v2.13.0–v2.15.4 into svemagie/main
New upstream features:
- v2.13.0: FEP-8fcf/fe34 compliance, custom emoji, manual follow approval
- v2.14.0: Server blocking, Redis caching, key refresh, async inbox queue
- v2.15.0: Outbox failure handling (strike system), reply chain forwarding
- v2.15.1: Reply intelligence in reader (visibility badges, thread reconstruction)
- v2.15.2: Strip invalid as:Endpoints type from actor serialization
- v2.15.3: Exclude soft-deleted posts from outbox/content negotiation
- v2.15.4: Wire content-warning property for CW text

Conflict resolution:
- federation-setup.js: merged our draft/unlisted/visibility filters with
  upstream's soft-delete filter
- compose.js: kept our DM compose path, adopted upstream's
  lookupWithSecurity for remote object resolution
- notifications.js: kept our separate reply/mention tabs, added upstream's
  follow_request grouping
- inbox-listeners.js: took upstream's thin-shim rewrite (handlers moved to
  inbox-handlers.js which already has DM detection)
- notification-card.njk: merged DM badge with follow_request support

Preserved from our fork:
- Like/Announce to:Public cc:followers addressing
- Nested tag normalization (cat.split("/").at(-1))
- DM compose/reply path in compose controller

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 00:42:31 +01:00
Ricardo
c8aa0383b9 feat: wire reply intelligence to frontend — timeline filtering, thread reconstruction, visibility badges
- Filter isContext items and private/direct posts from main timeline, new post count, and unread count
- Post detail: query local replies from ap_timeline before remote fetch, deduplicate, sort chronologically
- Add visibility badge (unlisted/private/direct) on item cards next to timestamp

Confab-Link: http://localhost:8080/sessions/af5f8b45-6b8d-442d-8f25-78c326190709
2026-03-17 13:13:51 +01:00
Ricardo
9a61145d97 feat: FEP-8fcf/fe34 compliance, custom emoji, manual follow approval (v2.13.0)
- FEP-8fcf: add syncCollection to Undo(Announce) sendActivity
- FEP-fe34: centralized lookupWithSecurity() helper with crossOrigin: "ignore" on all 23 lookupObject call sites
- Custom emoji: replaceCustomEmoji() renders :shortcode: as inline <img> in content and actor display names
- Manual follow approval: profile toggle, ap_pending_follows collection, approve/reject controllers with federation, pending tab on followers page, follow_request notification type
- Coverage audit updated to v2.12.x (overall ~70% → ~82%)

Confab-Link: http://localhost:8080/sessions/1f1e729b-0087-499e-a991-f36f46211fe4
2026-03-17 08:21:36 +01:00
Sven Giersig
eefa46f0c1 Merge upstream rmdes:main — v2.10.0 (Delete, visibility, CW, polls, Flag) into svemagie/main (v2.10.1)
Upstream v2.10.0 adds: outbound Delete, visibility addressing (unlisted/
followers-only), Content Warning (sensitive flag + summary), inbound poll
rendering, Flag/report handler, DM support files.

Conflict resolution — all four conflicts were additive (no code removed):

  lib/controllers/reader.js: union of validTabs — fork added "mention",
    upstream added "dm" and "report"; result keeps all five additions.

  lib/storage/notifications.js: union of count keys — fork added mention:0,
    upstream added dm:0 and report:0; result keeps the fork's mention split
    logic alongside the new upstream keys.

  views/partials/ap-notification-card.njk: fork kept isDirect 🔒 badge for
    direct mentions; upstream added ✉ for dm and ⚑ for report; result keeps
    the isDirect branch and appends the two new type badges.

  package.json: upstream bumped to 2.10.0; we bump to 2.10.1 to reflect our
    own Alpine.js and publication-aware docloader bug fixes on top.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 13:00:58 +01:00
Ricardo
1dc42ad5e5 feat: outbound Delete, visibility addressing, CW/sensitive, polls, Flag reports (v2.10.0)
- Outbound Delete: broadcastDelete() + POST /admin/federation/delete route
- Visibility: unlisted + followers-only addressing via defaultVisibility config
- Content Warning: outbound sensitive flag + summary as CW text
- Polls: inbound Question/poll parsing with progress bar rendering
- Flag: inbound report handler with ap_reports collection + Reports tab
- Includes DM support files from v2.9.x (messages controller, storage, templates)
- Includes coverage audit and high-impact gaps implementation plan

Confab-Link: http://localhost:8080/sessions/cc343b15-8d10-43cd-a48f-ca912eb79b83
2026-03-14 08:51:44 +01:00
svemagie
5806133dff Merge branch 'rmdes:main' into main 2026-03-13 18:51:10 +01:00
Ricardo
bf386e0c41 chore: phase 2 convention alignment — onerror/onclick removal, CSS stacking avatar fallback (v2.8.1)
- Replace inline onerror handlers with CSS stacking + event delegation for avatar fallback
- Replace inline onclick with event delegation for profile link removal
- Replace hardcoded border values with design tokens in reader-links.css
- Add data-avatar-fallback pattern: fallback initials always visible, img layered on top

Confab-Link: http://localhost:8080/sessions/bb4a6ec4-b711-48cd-b3d7-942ec2a9851d
2026-03-13 12:32:14 +01:00
svemagie
2fc85474a5 feat: add ap-dm-thread.njk chat-style conversation partial 2026-03-13 07:27:13 +01:00
svemagie
ea9a9856e9 feat: direct message (DM) receive and reply support
- Detect incoming DM visibility in inbox listener by checking absence of
  the public collection URL in object.toIds/ccIds; store isDirect and
  senderActorUrl on mention notifications
- Add native AP reply path in compose controller: when is-direct=true,
  build Create(Note) addressed only to the sender and deliver via
  ctx.sendActivity() instead of posting a public Micropub blog reply
- Add dedicated "Direct" tab to notifications view (separate from Replies)
  with its own count; update storage query so mention tab filters only
  mention type, reply tab filters only reply type
- Show lock badge (🔒) on direct mention notification cards and add
  ap-notification--direct CSS class
- Compose view: show DM notice banner, hide syndication targets, and
  change submit label when replying to a direct message

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 06:32:50 +01:00
Ricardo
1c2fb321bc feat: image rendering, link preview CSS, lightbox swipe, URL linkification (v2.8.0)
- Gallery photos: 220px → 280px height, 180px on mobile (≤480px)
- Link preview cards: full CSS for horizontal card layout (text left, image right)
- Lightbox: touch/swipe support for mobile (50px threshold)
- URL linkification: bare URLs in content auto-wrapped in <a> tags before AP delivery

Confab-Link: http://localhost:8080/sessions/c5b1471e-b046-44d9-b94f-ab5e68fae7cc
2026-03-06 10:42:39 +01:00
Ricardo
2083741535 fix: use human-readable URLs for reply-to links (v2.7.1)
Reply links were using the AP internal object ID (e.g.
/ap/users/{id}/statuses/{id}) which returns 404 on Mastodon for
browsers. Now uses the human-readable URL (/@username/{id}) for
replyTo params in item cards and notification cards.

- Store url field on reply/mention notifications (inbox-listeners)
- Prefer item.url over item.uid for compose replyTo links
- Falls back to uid for existing notifications without url field

Confab-Link: http://localhost:8080/sessions/d116ad5b-ef8a-424e-9ebe-76c06bef1df6
2026-03-05 08:24:08 +01:00
Ricardo
9332421890 feat: visual polish, focus-point cropping, blurhash placeholders (Release 8)
Card styling: softer 8px radius, subtle box-shadow elevation, hover enhancement.
Action buttons: borderless with color-coded hover states via color-mix().
Typography: tighter line-height (4/3), larger avatars (44px), gallery images (220px).
Focus-point cropping: convert Mastodon focus.x/y to CSS object-position.
Blurhash placeholders: decode DC component to background-color on images.

Confab-Link: http://localhost:8080/sessions/e9d666ac-3c90-4298-9e92-9ac9d142bc06
2026-03-03 19:26:38 +01:00
Ricardo
b9fc98f40c feat: content enhancements — URL shortening, hashtag collapse, bot badge, edit indicator (Release 7)
Shorten long URLs in post content (30 char display limit with tooltip).
Collapse hashtag-heavy paragraphs into expandable <details> toggle.
Show BOT badge for Service/Application actors. Show pencil icon for
edited posts with hover tooltip showing edit timestamp.

Confab-Link: http://localhost:8080/sessions/e9d666ac-3c90-4298-9e92-9ac9d142bc06
2026-03-03 16:40:01 +01:00
Ricardo
fca1738bd3 feat: skeleton loaders replace loading text (Release 6)
Animated card-shaped placeholders with shimmer effect shown during
content loading instead of plain "Loading..." text. Applied to reader,
tag timeline, and explore tabs (both first-load and load-more states).

Confab-Link: http://localhost:8080/sessions/e9d666ac-3c90-4298-9e92-9ac9d142bc06
2026-03-03 15:48:59 +01:00
Ricardo
2d2dcaec7d feat: interaction counts on timeline cards (Release 5)
Extract reply/boost/like counts from AP Collections (getReplies,
getLikes, getShares) and Mastodon API (replies_count, reblogs_count,
favourites_count). Display counts next to interaction buttons with
optimistic updates on like/boost actions.

Confab-Link: http://localhost:8080/sessions/e9d666ac-3c90-4298-9e92-9ac9d142bc06
2026-03-03 14:30:40 +01:00
Ricardo
c243b70629 feat: enriched media model with ALT badges (Release 3+4)
Change photo storage from bare URL strings to objects with url, alt,
width, height (AP) plus blurhash and focus (Mastodon API). Templates
handle both old string and new object format for backward compat.

Add ALT text badges on gallery images — click to expand the full
alt text in an overlay. Renders in both reader and explore views.

Also pass alt text through to lightbox and quote embed photos.

Bump version to 2.5.3.

Confab-Link: http://localhost:8080/sessions/e9d666ac-3c90-4298-9e92-9ac9d142bc06
2026-03-03 13:46:58 +01:00
Ricardo
e34d9c124d feat: relative timestamps in reader (Release 2)
Add Alpine.js directive x-relative-time that converts absolute dates
to human-friendly relative strings: just now, 5m, 3h, 2d, Mar 3.
Updates every 60s for posts less than 24h old. Server-rendered absolute
time stays as no-JS fallback and hover tooltip.

Applied to item cards, quote embeds, and notification cards.

Bump version to 2.5.2.

Confab-Link: http://localhost:8080/sessions/e9d666ac-3c90-4298-9e92-9ac9d142bc06
2026-03-03 13:34:01 +01:00
Ricardo
02d449d03c feat: render custom emoji in reader (Release 1)
Extract custom emoji from ActivityPub objects (Fedify Emoji tags) and
Mastodon API (status.emojis, account.emojis). Replace :shortcode:
patterns with <img> tags in the unified processing pipeline.

Emoji rendering applies to post content, author display names, boost
attribution, and quote embed authors. Uses the shared postProcessItems()
pipeline so both reader and explore views get emoji automatically.

Bump version to 2.5.1.

Confab-Link: http://localhost:8080/sessions/e9d666ac-3c90-4298-9e92-9ac9d142bc06
2026-03-03 13:13:28 +01:00
Ricardo
508ac75363 feat: new posts banner, mark-as-read on scroll, unread filter
- Poll every 30s for new items, show sticky "N new posts — Load" banner
- IntersectionObserver marks cards as read at 50% visibility, batches to
  server every 5s
- Read cards fade to 70% opacity, full opacity on hover
- "Unread" toggle in tab bar filters to unread-only items
- New API: GET /api/timeline/count-new, POST /api/timeline/mark-read

Confab-Link: http://localhost:8080/sessions/e9d666ac-3c90-4298-9e92-9ac9d142bc06
2026-03-02 10:54:11 +01:00
Ricardo
120f2ee00e feat: render quoted posts as embedded cards in reader
Extract quoteUrl from Fedify Note objects (supports Mastodon, Misskey,
Fedibird quote formats). Fetch quoted post data asynchronously on inbox
receive and on-demand in post detail view. Render as rich embed card
with author avatar, handle, content, and timestamp.

Confab-Link: http://localhost:8080/sessions/e9d666ac-3c90-4298-9e92-9ac9d142bc06
2026-03-02 10:33:11 +01:00
Ricardo
611bd3661c feat: add save-for-later button to activitypub reader
Adds a save button to the AP item card action bar that POSTs to
/readlater/save when the readlater plugin is installed. Uses Alpine.js
for optimistic UI update. Button only renders if
application.readlaterEndpoint is set.
2026-02-27 16:02:48 +01:00
Ricardo
a4f72a588d feat: enhance ActivityPub reader with mentions, hashtags, infinite scroll, explore, and tag following
- Fix mentions/hashtags bug: separate Fedify Mention and Hashtag types into
  distinct mentions[] and category[] arrays with proper @ and # rendering
- Add hashtag timeline filtering at /admin/reader/tag with regex-safe queries
- Replace prev/next pagination with AlpineJS infinite scroll (IntersectionObserver)
  with no-JS fallback pagination preserved
- Add public instance timeline explorer at /admin/reader/explore with SSRF
  prevention and XSS sanitization via Mastodon-compatible API
- Add hashtag following with ap_followed_tags collection, inbox listener
  integration for non-followed accounts, and followed tags sidebar display
- Include one-time migration script for legacy timeline data
2026-02-26 18:15:21 +01:00
Ricardo
4e159bfb9d fix: replace nonexistent Nunjucks min filter with inline conditional
The | min filter is Jinja2 syntax, not available in Nunjucks. This caused
"filter not found: min" crashes when posts had photos (never triggered
before the async iteration fix because photo arrays were always empty).
2026-02-24 11:14:55 +01:00
Ricardo
cd7d850b44 fix: use async iteration for Fedify 2.0 attachments/tags, add image lightbox
Fedify 2.0's getAttachments() and getTags() return async iterables, but the
code used synchronous for...of which silently yielded zero results. Changed
to for await...of so media URLs (photo/video/audio) and hashtags are now
properly extracted from incoming posts.

Also replaced the gallery's target=_blank links with an Alpine.js lightbox
modal for full-size image viewing with prev/next navigation and keyboard
support.
2026-02-24 10:25:15 +01:00
Ricardo
23fc8f4614 feat: rewrite moderation UI with filter mode, fix sparse index bug
Moderation page rewritten as single Alpine.js component with inline DOM
updates instead of location.reload(). Added hide/warn filter mode toggle
— warn mode shows muted items behind content warning instead of hiding.

Expanded keyword matching to check content, titles, and summaries.
Fixed MongoDB E11000 duplicate key error by dropping non-sparse indexes
on startup and recreating with sparse:true. Storage layer no longer
stores null url/keyword fields.
2026-02-23 23:11:28 +01:00
Ricardo
743cb6b85b feat: notification tabs, my-profile page, clickable timestamps, quick-reply
- Notification view: tab navigation (Replies, Likes, Boosts, Follows, All)
  with count badges; defaults to Replies tab; type filter in storage layer
  with compound index for efficient queries
- My Profile admin page: profile header with avatar/stats/bio, tabbed
  activity view (Posts, Replies, Likes, Boosts) pulling from posts,
  ap_activities, and ap_interactions collections
- Reader: default tab changed from All to Notes
- Timeline cards: timestamps now link to post detail view
- Notification cards: Reply and View Thread buttons on reply/mention types
2026-02-23 15:55:44 +01:00
Ricardo
31418310d2 fix: pagination, headers, avatars, tab order, and notification UI
- Fix cursor pagination: use string comparison (not Date objects) for
  published field queries in both timeline and notifications
- Fix "Older" cursor to use oldest item's date, not newest
- Remove redundant parent breadcrumb from all AP page headings
- Reorder tabs: Notes first, All last
- Fix avatar loading: non-destructive hide/show with lazy loading
- Add actor avatars with type badge overlay to notification cards
- Add Fediverse navigation group in sidebar
2026-02-21 20:28:40 +01:00
Ricardo
d20dea2dc8 feat: notification management — clear, mark read, dismiss, TTL retention
- Add "Mark all read" and "Clear all" toolbar buttons on notifications page
- Add per-notification dismiss (×) button
- Remove auto-mark-all-as-read on page load (explicit action only)
- Add 30-day TTL index on createdAt for automatic notification cleanup
- New config option: notificationRetentionDays (default 30)
2026-02-21 20:00:05 +01:00
Ricardo
5ff3197493 feat: add internal AP link resolution and OpenGraph card unfurling (v1.1.14)
Reader now resolves ActivityPub links internally instead of navigating
to external instances. Actor links open the profile view, post links
open a new post detail view with thread context (parent chain + replies).

External links in post content get rich preview cards (title, description,
image, favicon) fetched via unfurl.js at ingest time with fire-and-forget
async processing and concurrency limiting.

New files: post-detail controller, og-unfurl module, lookup-cache,
link preview template/CSS, client-side link interception JS.
Includes SSRF protection for OG fetching and GoToSocial URL support.
2026-02-21 18:32:12 +01:00
Ricardo
313d5d414c fix: reader UI fixes and correct Fedify API usage (v1.1.8→1.1.12)
- Fix Unknown authors by adding multi-strategy fallback chain in
  extractObjectData (getAttributedTo → actorFallback → attributionIds)
- Fix empty boosts from Lemmy/PieFed by checking content before storing
- Fix @mention/hashtag styling to stay inline instead of breaking layout
- Fix compose reply to show sanitized HTML blockquote instead of raw text
- Add default-checked syndication targets for AP and Bluesky
- Use authenticated document loader for all lookupObject calls
  (fixes 401 errors on servers requiring Authorized Fetch)
- Fix like handler 404 by using canonical AP uid for interactions
  instead of display URLs; add data-item-uid to card template
- Fix profile bio showing Nunjucks macro source code by renaming
  summary→bio to avoid collision with Indiekit's summary macro
- Fix Fedify API misuse in timeline-store.js: use instanceof Article
  (not string comparison), replyTargetId (not inReplyTo), getTags()
  and getAttachments() async methods (not sync property access)
- Fix inbox-listeners.js: use replyTargetId instead of non-existent
  getInReplyTo(), use instanceof Article for Update handler
- Add error logging to interaction catch blocks
2026-02-21 17:08:28 +01:00
Ricardo
d395a1cc24 fix: resolve Unknown authors, filter empty boosts, style mentions
- Add actorFallback option to extractObjectData() so the activity's
  actor is used when object.getAttributedTo() fails (Authorized Fetch,
  unreachable servers). Falls back to attributionIds for URL-based info.
- Pass create.getActor() as actorFallback in Create inbox listener.
- Skip storing boosts with no content (Lemmy/PieFed activity IDs).
- Add template guard to hide empty cards already in the database.
- Style @mention and hashtag links distinctly from prose content.
- Handle Mastodon's invisible/ellipsis URL span classes.
2026-02-21 14:54:10 +01:00
Ricardo
7e97ab7fbf style: rewrite CSS to use Indiekit theme system
Replace all nonexistent CSS variable references with Indiekit's actual
custom properties. This enables automatic dark mode support (variables
swap via prefers-color-scheme) and visual consistency with the rest of
the admin UI.

Key changes:
- Map --color-text → --color-on-background, --color-text-muted →
  --color-on-offset, --border-radius → --border-radius-small, etc.
- Add post-type differentiation via colored left borders: purple for
  notes, green for articles, yellow for boosts, primary for replies
- Replace hardcoded hex colors (#e11d48, #16a34a) with Indiekit's
  palette variables (--color-red45, --color-green50, etc.)
- Use Indiekit's border-width tokens for consistent border sizing
- Add background/color to form inputs for dark mode compatibility
2026-02-21 14:22:28 +01:00
Ricardo
3ad86ffb39 fix: reader UI — navigation, Alpine.js loading, avatar fallback, Temporal dates
- Return multiple navigation items (ActivityPub, Reader, Notifications, Moderation)
  so all AP sub-pages are accessible from the sidebar
- Fix Alpine.js not loading: `{% block head %}` was silently discarded because
  the parent template chain has no such block — moved script/css into content block
- Pin Alpine.js to exact version 3.14.9 to prevent CDN resolution issues
- Add fallback avatar (first letter) when author photo is missing
- Guard empty author URLs to prevent broken links
- Fix Temporal.Instant TypeError: use String() instead of new Date() for
  Fedify published timestamps in inbox-listeners and timeline-store
- Link author names to remote profile view instead of raw AP URLs
- Bump to 1.1.3
2026-02-21 13:31:52 +01:00
Ricardo
4e514235c2 feat: ActivityPub reader — timeline, notifications, compose, moderation
Add a dedicated fediverse reader view with:
- Timeline view showing posts from followed accounts with threading,
  content warnings, boosts, and media display
- Compose form with dual-path posting (quick AP reply + Micropub blog post)
- Native AP interactions (like, boost, reply, follow/unfollow)
- Notifications view for likes, boosts, follows, mentions, replies
- Moderation tools (mute/block actors, keyword filters)
- Remote actor profile pages with follow state
- Automatic timeline cleanup with configurable retention
- CSRF protection, XSS prevention, input validation throughout

Removes Microsub bridge dependency — AP content now lives in its own
MongoDB collections (ap_timeline, ap_notifications, ap_interactions,
ap_muted, ap_blocked).

Bumps version to 1.1.0.
2026-02-21 12:13:10 +01:00