Skip to content

fix(endpoint-posts): use correct template variable for syndicate form source_url#828

Open
rmdes wants to merge 45 commits intogetindiekit:mainfrom
rmdes:fix/syndicate-form-source-url
Open

fix(endpoint-posts): use correct template variable for syndicate form source_url#828
rmdes wants to merge 45 commits intogetindiekit:mainfrom
rmdes:fix/syndicate-form-source-url

Conversation

@rmdes
Copy link

@rmdes rmdes commented Jan 31, 2026

Summary

The syndicate form button in @indiekit-endpoint-posts-syndicate.njk was using data.url for the source_url value, but data is never defined in the template context.

The Bug

When viewing a post in the Indiekit admin UI and clicking the "Syndicate" button:

  1. The form attempts to submit syndication[source_url] with value data.url
  2. But data is undefined - the post controller sets properties via response.locals.properties, not data
  3. So source_url is submitted as undefined
  4. The syndicate endpoint's getPostData() function falls back to finding "the most recently published post awaiting syndication" (see packages/endpoint-syndicate/lib/utils.js:15-34)
  5. Result: A completely different post gets syndicated instead of the one the user was looking at

Reproduction Steps

  1. Have multiple posts, some with mp-syndicate-to set and no syndication yet
  2. View a specific post in the admin UI that already has syndication URLs from previous syndication
  3. Add a new syndication target to that post (e.g., IndieNews)
  4. Click the "Syndicate" button
  5. Expected: The current post gets syndicated
  6. Actual: A different post (the most recent one awaiting syndication) gets syndicated

The Fix

Changed data.url to properties.url in the template to correctly reference the post URL from the template context that was set by the middleware.

Test plan

  • View a post with existing syndication URLs
  • Add a new syndication target
  • Click "Syndicate"
  • Verify the correct post (the one being viewed) is syndicated

🤖 Generated with Claude Code

rmdes and others added 30 commits January 18, 2026 19:56
- Display user profile, commits, starred repos, PRs/issues, repositories
- Support featured repos with recent commits display
- Include private repo activity when authenticated
- Add caching for API responses
- JSON API endpoints for external widgets

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add featured controller for /github/featured page and API
- Add /github/api/featured JSON endpoint for external widgets

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…details

GitHub's Events API no longer includes commit details in PushEvent payloads
for many requests. This adds a fallback that fetches commits directly from
the user's recently pushed repositories when the events API returns empty.

- Try events API first (existing behavior)
- If no commits found, fetch from user's top 5 recently pushed repos
- Parallelize repo commit fetching for performance
- Sort combined results by date

This mirrors the approach used by the featured repos controller which
fetches commits directly from repos.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
This package is maintained separately at rmdes/indiekit-endpoint-github
and published to npm as @rmdes/indiekit-endpoint-github.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…ucture

- Package setup with proper dependencies (feedparser, microformats-parser, ioredis, sanitize-html)
- MongoDB storage layer for channels, feeds, items, notifications, muted, blocked
- Core controllers implementing Microsub API actions
- Endpoint discovery with microsub link in homepage template
- Locale strings for all supported languages

This is the foundation for the full Microsub server plugin. Subsequent
phases will add feed parsing, real-time updates, and the built-in reader UI.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add feed parsing, fetching, and polling infrastructure:

- lib/feeds/parser.js: Feed type detection and parser dispatch
- lib/feeds/rss.js: RSS 1.0/2.0 parser using feedparser
- lib/feeds/atom.js: Atom parser using feedparser
- lib/feeds/jsonfeed.js: JSON Feed parser
- lib/feeds/hfeed.js: Microformats h-feed parser with feed discovery
- lib/feeds/normalizer.js: Converts all feed formats to jf2
- lib/feeds/fetcher.js: HTTP fetcher with ETag/Last-Modified caching
- lib/cache/redis.js: Redis utilities for caching and pub/sub
- lib/polling/tier.js: Adaptive tier-based polling algorithm (Ekster pattern)
- lib/polling/processor.js: Feed processing pipeline with filtering
- lib/polling/scheduler.js: Scheduler with interval-based polling
- lib/controllers/follow.js: Trigger immediate fetch on subscribe
- lib/storage/feeds.js: Extended with tier update methods

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add feed discovery, preview, and full-text search:

- lib/controllers/search.js: Feed discovery from URLs via autodiscovery
  links, h-feed parsing, and channel item search
- lib/controllers/preview.js: Fetch and preview feeds without storing,
  returns sample items
- lib/search/indexer.js: MongoDB text index creation for full-text search
- lib/search/query.js: Full-text search with fallback to regex matching,
  includes search suggestions

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add mute, block, and content filtering:

- lib/storage/filters.js: Comprehensive filter operations including
  muted/blocked URL checks, type filtering, regex filtering, and
  channel filter settings
- lib/storage/items.js: Add deleteItemsByAuthorUrl for blocking
- lib/controllers/block.js: Remove past items when blocking a URL
- lib/polling/processor.js: Use filters module for channel filtering

Supports:
- Muting URLs per-channel or globally
- Blocking author URLs with retroactive item removal
- ExcludeTypes: filter out likes, reposts, bookmarks, replies, etc.
- ExcludeRegex: pattern matching for content filtering

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add SSE broker and WebSub integration:

- lib/realtime/broker.js: SSE connection management with ping
  keepalive, channel subscriptions, Redis pub/sub integration
- lib/controllers/events.js: Updated to use broker for real-time
  event streaming
- lib/websub/discovery.js: WebSub hub discovery from Link headers
  and content (Atom, RSS, HTML)
- lib/websub/subscriber.js: Subscribe/unsubscribe to hubs with
  HMAC signature verification, subscription renewal detection
- lib/websub/handler.js: WebSub callback handler with signature
  verification, subscription confirmation, and content processing

Supports:
- GET ?action=events for SSE stream with channel subscriptions
- 10-second ping keepalive
- Redis pub/sub for multi-instance broadcasting
- WebSub subscription with automatic signature verification
- WebSub content push handling with background processing

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add webmention verification and processing for notifications channel:
- verifier.js: Fetch source URL, verify link to target, parse microformats
  to extract author, content, and mention type (like, reply, repost, etc.)
- processor.js: Store notifications in MongoDB, publish real-time events
  via Redis pub/sub, support read/unread tracking per user
- receiver.js: Accept webmentions async (202 Accepted), process in background

Implements IndieWeb webmention receiving spec for social reader notifications.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add full social reading experience in Indiekit admin:
- views/reader.njk: Channel list with unread counts
- views/channel.njk: Timeline view with pagination
- views/channel-new.njk: Create new channel form
- views/item.njk: Single item detail view with actions
- views/settings.njk: Channel filtering settings (ExcludeType/Regex)
- views/compose.njk: Compose reply/like/repost form
- views/partials/: Reusable item-card, timeline, author, actions

Updated index.js to mount reader routes as sub-router for correct
baseUrl handling. Navigation links to /microsub/reader.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Change package name to @rmdes/indiekit-endpoint-microsub
- Update repository URLs to rmdes/indiekit fork
- Ready for npm publish

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…B cursors

.toSorted() is a JavaScript array method (ES2023), but MongoDB cursors
require .sort() method. This was causing 'toSorted is not a function'
errors when accessing /microsub routes.

Added eslint-disable comments since the unicorn/no-array-sort rule
doesn't distinguish between Array#sort and MongoDB cursor's sort().

Co-Authored-By: Claude Opus 4.5 <[email protected]>
The templates were using `request.baseUrl` directly in Nunjucks,
but the request object isn't available in the template context.
Updated all controllers to pass `baseUrl` as a render variable
and updated all templates to use `{{ baseUrl }}` instead.

Fixes 404 errors when navigating within the reader UI.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Replace `field` macro with `input` (field isn't exported globally)
- Replace `fieldset` + checkboxes filter with `checkboxes` macro
- Fix textarea label to use string not object
- Add attributes for autofocus support
- Add missing locale key for channel name

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…e macros

- Replace non-existent icons with valid Indiekit icons:
  - arrow-left/arrow-right → previous/next
  - heart → like
  - settings → updatePost
  - bell → mention
  - plus → createPost
  - external → public
  - dot → Unicode bullet ●
- Fix textarea macro to use string label instead of object
- Fix checkboxes macro usage
- Bump version to beta.6

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…polation

- Fix locale interpolation: change %{channel} to {{channel}} syntax
- Add /channels/:uid/feeds route for viewing and managing feeds
- Add form to subscribe to new feeds with immediate background fetch
- Add button to unfollow feeds
- Add "Feeds" button to channel view header
- Add locale strings for feed URL label and placeholder
- Add JSDoc @returns annotations
- Bump version to beta.7

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add /reader/search page to discover feeds from any URL
- Add feed discovery using auto-detect for RSS, Atom, JSON Feed, h-feed
- Add subscribe form with channel selection dropdown
- Add "Follow" button to main reader view for easy access
- Bump version to beta.8

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add console.info/warn messages during init to track startup
- Log whether database is available when scheduler starts
- Helps diagnose why scheduler might not be running
- Bump version to beta.9

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Initialize Redis connection from application.redisUrl config
- Use ioredis with lazy connect and error handling
- Log connection status for debugging

Co-Authored-By: Claude Opus 4.5 <[email protected]>
When a feed is unfollowed/deleted, also delete all items that were
fetched from that feed. Previously items remained orphaned in the
database.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Prevents "name.replace is not a function" error when code passed to
IndiekitError is not a string (e.g., when response.statusText is
undefined in some edge cases)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…iance

Features:
- Micropub compose integration (reply, like, repost, bookmark)
- WebSub auto-subscription when hub discovered in feeds
- Media proxy with Redis caching (4h TTL, 2MB max)
- Enhanced full-text search with weighted indexes
- Basic test suite (auth, validation, media-proxy, jf2, feeds, pagination, tier, filters)

Fixes:
- Entry matching now works with URLs (Microsub spec compliance)
- getUserId helper for proper auth in API token requests
- All controllers use consistent user identification

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Fixes two feed processing issues:

1. Invalid time value for non-standard date formats:
   - Added parseDate() helper that handles formats like "2026-01-28 08:40"
   - Gracefully falls back to undefined instead of throwing

2. Unable to detect feed type for ActivityPub sites:
   - WordPress sites with ActivityPub plugin return JSON instead of HTML
   - Now detects ActivityPub JSON and tries common feed paths (/feed/, etc.)
   - Added tryCommonFeedPaths() as fallback for feed discovery

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Fixes multiple issues with the reader UI:

1. Author photos showing [object Object]:
   - Added extractPhotoUrl() to handle photo objects in h-card normalization
   - Added normalizeAuthor() in transformToJf2 for robust photo extraction

2. Empty photo galleries:
   - Added normalizeMediaArray() to ensure all media URLs are strings
   - Handles legacy data that may have stored photo objects

3. Empty source spans:
   - Added url field to _source alongside feedUrl
   - Processor now adds feed name to item._source.name

4. Item links returning 404:
   - Fixed item-card.njk to use item._id instead of item.uid
   - Updated getItemById to try both _id and uid lookups
   - Added 404.njk template for graceful error handling

5. Item context links (replies, likes, reposts):
   - Fixed property names to use hyphenated jf2 format (in-reply-to, etc.)

Bumps version to 1.0.2

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Wrap cache.put() in try-catch to handle network error responses
- Return valid Response objects in all error paths
- Add fallback responses for offline/network failure scenarios
- Better error logging with request URLs

Prevents "Cache.put() encountered a network error" and
"Failed to convert value to Response" errors

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…terns

- Add dedicated CSS file with comprehensive reader styling
- Add yellow glow effect for unread items
- Add multi-photo grid layouts (2/3/4 photos)
- Add context bars for interaction types (like, repost, reply, bookmark)
- Add inline action buttons on item cards
- Add keyboard navigation (j/k for items, o/Enter to open)
- Add character counter to compose view
- Create custom reader layout for CSS inclusion
- Update all views to use new reader layout
- Bump version to 1.0.3

Co-Authored-By: Claude Opus 4.5 <[email protected]>
rmdes and others added 14 commits January 28, 2026 15:58
Nunjucks doesn't have a built-in 'min' filter. Use conditional
expression instead for photo count.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
The item-card action links use short params (reply, like, repost, bookmark)
but the controller only extracted long-form params (replyTo, likeOf, etc).
Now supports both forms.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Temporary debug logging to diagnose why interactions are being
created as empty notes instead of likes/replies/reposts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Enable the profile scope in IndieAuth to return user profile information
(name, url, photo) parsed from the h-card on the user's site.

- Add profile.js module to fetch and parse h-card microformats
- Enable profile scope in scope.js
- Include profile data in authorization and token responses
- Add unit test for profile module

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Normalize interaction URLs (like-of, repost-of, in-reply-to, bookmark-of)
  to strings in the normalizer
- Update item-card template to extract URL from object values
- Add ensureString helper in compose controller
- Fix template crashes when interaction properties contain objects

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…ssion

- Use 'content' instead of 'error.message' for error template
- Ensure statusText is a string with fallback
- Parse JSON error response for better error messages
- Fixes "Input data should be a String" error on repost/compose

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add POST /api/mark-read route to handle the "Mark all as read" button
in the channel view. The route uses the existing markItemsRead function
with the special "last-read-entry" value to mark all items as read.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…ggle

- Filter out read items from timeline by default
- Add "Show read (N)" button when there are read items
- Add "Hide read items" button when viewing read items
- Show "All caught up!" message when all items are read
- Only show "Mark all as read" when there are unread items

Co-Authored-By: Claude Opus 4.5 <[email protected]>
The preset was deleting the url property from frontmatter, leaving
Eleventy to generate URLs from file paths. This caused a mismatch
between Indiekit's stored URL and Eleventy's generated URL.

Now the url is converted to a permalink property (with trailing slash)
so Eleventy generates the URL that Indiekit expects.

Fixes URL mismatch issues with syndication and other features that
rely on the post URL being consistent.

Fork published as @rmdes/indiekit-preset-eleventy for testing.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add optional comment field for likes/reposts/bookmarks
- Fetch syndication targets from Micropub config
- Display syndication target checkboxes in compose form
- Include mp-syndicate-to in Micropub requests
- Add CSS styling for syndication fieldset

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Handle full URLs by extracting pathname
- Custom URL paths for content collection
- Bump version to 1.0.0-beta.28

Co-Authored-By: Claude Opus 4.5 <[email protected]>
… source_url

The syndicate form button was using `data.url` for the source_url value,
but `data` is never set in the template context. The post controller and
middleware set `properties` (via response.locals.properties), not `data`.

This caused the syndicate form to submit with an undefined source_url,
which made the syndicate endpoint fall back to finding "the most recently
published post awaiting syndication" instead of syndicating the post
the user was actually viewing.

The fix changes `data.url` to `properties.url` to correctly reference
the post URL from the template context.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
rmdes added a commit to rmdes/indiekit-endpoint-posts that referenced this pull request Jan 31, 2026
Fork of @indiekit/endpoint-posts to fix a critical bug where the
syndicate form was using undefined `data.url` instead of `properties.url`,
causing the wrong post to be syndicated.

PR submitted upstream: getindiekit/indiekit#828

Co-Authored-By: Claude Opus 4.5 <[email protected]>
rmdes added a commit to rmdes/indiekit-cloudron that referenced this pull request Jan 31, 2026
Adds npm override for @indiekit/endpoint-posts to use
@rmdes/indiekit-endpoint-posts which fixes a critical bug
where clicking "Syndicate" would syndicate the wrong post.

The upstream bug: the syndicate form used `data.url` but
`data` is undefined - the template context has `properties`.

PR submitted upstream: getindiekit/indiekit#828

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Handle 'page' post type specially with root-level URLs
- Pages go to /{slug}/ instead of /content/pages/{date}-{slug}/
- Bump version to 1.0.0-beta.29

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant