16 Commits

Author SHA1 Message Date
svemagie
1bb80588fd feat: bookmark flow — tag→channel, notifyBlogroll, update tracking
- bookmark-import: find/create channel from first tag (no more fallback-only)
- bookmark-import: call notifyBlogroll() after creating feed so blogroll gets
  its entries from microsub, not independently
- bookmark-import: store micropubPostUrl on feed for update/delete tracking
- bookmark-import: move feed when tag changes (delete old, create in new channel)
- feeds: add micropubPostUrl field to createFeed()
- feeds: add getFeedByMicropubPostUrl() for update hook lookup
- feeds: add deleteFeedById() for channel-agnostic removal
- index: pass full tags array (not just first) to importBookmarkAsFollow
- index: capture Location header as postUrl for tracking
- index: handle update action — detect tag change or bookmark-of removal
  and call updateBookmarkFollow() accordingly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 09:33:26 +01:00
Ricardo
e48335da2c feat: mark source as read — split button with popover
Add ability to mark all items from a specific feed/source as read at once,
instead of clicking each item individually. The mark-read button becomes a
split button group with a caret that opens a popover offering "Mark [source]
as read". Items without a feedId (AP items) keep the simple button.

Confab-Link: http://localhost:8080/sessions/a477883d-4aef-4013-983c-ce3d3157cfba
2026-03-11 16:08:53 +01:00
Ricardo
5037ff3d8f feat: add feed type indicator and cross-channel duplicate detection
- Store feedType (rss/atom/jsonfeed/hfeed) on feed documents during polling
- Display feed type badge in reader feeds view
- Detect duplicate feeds across all channels using URL normalization
  (trailing slashes, http/https variants)
- Show clear error message when subscribing to a feed that already exists
- Handle duplicates in both reader UI and Microsub API (HTTP 409)
- Bump version to 1.0.44

Confab-Link: http://localhost:8080/sessions/f1d9ff88-e037-4d6e-b595-ed6d9e00898e
2026-03-10 14:27:01 +01:00
Ricardo
a51b554068 feat: delete stale items older than 30 days
Stripped dedup skeletons and unread items older than 30 days are now
hard-deleted on startup. Previously, stripped skeletons accumulated
forever and unread items had no expiry, causing unbounded collection
growth.

Confab-Link: http://localhost:8080/sessions/4d40ef89-a713-48c1-b4ed-0ffafca25677
2026-03-05 22:52:59 +01:00
Ricardo
26225f1f80 feat: add multi-view reader with Channels, Deck, and Timeline views
Three reader views accessible via icon toolbar:
- Channels: existing view (renamed), per-channel timelines
- Deck: TweetDeck-style configurable columns with compact cards
- Timeline: all channels merged chronologically with colored borders

Includes channel color palette, cross-channel query, deck config
storage, session-based view preference, and view switcher partial.
2026-02-26 14:42:00 +01:00
Ricardo
cdd4a58015 fix: extract images from HTML content at read time for existing items
The normalizer fix (1.0.35) only applies to newly ingested items.
Existing items in MongoDB lack photo arrays because dedup prevents
re-processing. Add the same extractImagesFromHtml() fallback in
transformToJf2() so images are extracted from content.html at read
time, making existing xkcd comics and photo posts display immediately.
2026-02-25 17:20:53 +01:00
Ricardo
8868dfcdcb feat: add ActivityPub integration - actor profiles, follow/unfollow, timeline items
- Add actor profile page with outbox fetcher for viewing AP actor posts
- Add follow/unfollow buttons on actor profile (delegates to AP plugin)
- Add AP actor link on item cards for posts from ActivityPub sources
- Add ensureActivityPubChannel() for auto-creating Fediverse channel
- Add AP-aware item storage with dedup, attachments, and categories
- Add CSS styles for actor profile cards and AP-specific UI elements
- Bump version to 1.0.31
2026-02-19 18:11:37 +01:00
Ricardo
3c8a4b2b53 fix: security hardening (SSRF, ReDoS, XSS, open redirect)
- Add SSRF blocklist to media proxy (block private/internal IPs)
- Escape regex in searchItems() to prevent ReDoS
- Sanitize webmention content.html before storage (XSS prevention)
- Return 404 instead of redirect on failed media proxy (open redirect fix)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 14:40:12 +01:00
Ricardo
02bfff7ce9 fix: store dates as ISO strings instead of Date objects
Prevents dateString.split crash when Nunjucks | date filter receives
Date objects from MongoDB. Audit timestamps (createdAt, updatedAt,
lastFetchedAt, etc.) now use .toISOString(). Query-used fields
(published, nextFetchAt) kept as Date objects for MongoDB compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 22:30:40 +01:00
Ricardo
1009a2d6f6 fix: Only count unread items within 30-day retention period
- Add date filter to channel unread counts (UNREAD_RETENTION_DAYS = 30)
- Update getUnreadCount to also filter by date
- Prevents inflated counts from old accumulated items

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-08 13:58:55 +01:00
Ricardo
ab6f81bf72 feat: Phase 1 - Enhanced feed discovery with validation
- Add validator.js: validateFeedUrl with comments feed detection
- Add discovery.js: discoverAndValidateFeeds with type labels
- Add opml.js: OPML 2.0 export of all subscriptions
- Update reader.js: searchFeeds uses validation, subscribe validates
- Update feeds.js: updateFeedStatus for health tracking
- Update search.njk: Show feed types, validation status, error messages
- Add CSS for badges, notices, and invalid feed styling
- Register OPML export route at /reader/opml

Phase 1 of blogroll implementation plan.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-07 01:39:58 +01:00
Ricardo
6caf37a003 feat: add startup cleanup for old read items
Runs cleanupAllReadItems on server startup to clean up accumulated
read items from all channels, keeping only the 30 most recent per
channel per user.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-07 00:52:29 +01:00
Ricardo
61819f1aeb feat: cleanup old read items (keep last 30 per channel)
Prevents database accumulation by automatically deleting older read
items when marking items as read. Keeps the 30 most recent read items
per channel per user to allow revisiting recently read content.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 22:59:46 +01:00
Ricardo
c830ad5df6 feat: add show/hide read items and fix individual mark-read
- Add countReadItems function to storage/items.js
- Update getTimelineItems to filter out read items by default
- Add showRead query param support to channel controller
- Update channel.njk with show/hide read toggle buttons
- Add "All caught up!" state when all items are read
- Add JavaScript handler for individual mark-read buttons
- Mark-read now hides the item with smooth animation
- Add locale strings: showRead, hideRead, allRead

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 21:24:33 +01:00
Ricardo
4819c229cd feat: restore full microsub implementation with reader UI
Restores complete implementation from feat/endpoint-microsub branch:
- Reader UI with views (reader.njk, channel.njk, feeds.njk, etc.)
- Feed polling, parsing, and normalization
- WebSub subscriber
- SSE realtime updates
- Redis caching
- Search indexing
- Media proxy
- Webmention processing
2026-02-06 20:20:25 +01:00
Ricardo
30f9939b3a feat: initial commit - Microsub endpoint for Indiekit
Fork of @indiekit/endpoint-microsub with customizations.
Enables subscribing to feeds and reading content using the Microsub protocol.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 16:32:55 +01:00