Skip to content

fix(endpoint-micropub): don't assume mp-syndicate-to is an array - #874

Merged
paulrobertlloyd merged 1 commit into
getindiekit:mainfrom
rmdes:fix/syndicate-to-non-array
Aug 16, 2026
Merged

fix(endpoint-micropub): don't assume mp-syndicate-to is an array#874
paulrobertlloyd merged 1 commit into
getindiekit:mainfrom
rmdes:fix/syndicate-to-non-array

Conversation

@rmdes

@rmdes rmdes commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Problem

Posting fails with

TypeError: syndicateTo?.includes is not a function

whenever a client sends "mp-syndicate-to": [].

getSyndicateToProperty reads the property straight off the JF2 object and
calls .includes on it, but converting mf2 to JF2 leaves it in one of three
shapes:

client sends after mf2 → JF2 .includes
["a", "b"] ["a", "b"] array — fine
["a"] "a" string — fine
[] {} object — throws

An empty array is what an unticked syndication list produces, so this is
reachable through ordinary use rather than a malformed request. The post type
makes no difference; the only other condition is that the publication has
syndication targets configured, since the function returns early when it has
none. That combination is why it presents as intermittent — selecting a single
target makes the same post succeed.

Found from a browser extension that sent the property unconditionally. The
client has been fixed too, but any client can trip this and the failure takes
down post creation entirely.

Fix

Resolve the value to an array once, before the loop:

const syndicateTo = properties["mp-syndicate-to"];
const requested = Array.isArray(syndicateTo)
  ? syndicateTo
  : typeof syndicateTo === "string"
    ? [syndicateTo]
    : [];

Anything that is neither an array nor a string is treated as no targets.

Behaviour change worth noting

The single-target case is now an exact comparison. It was previously
"https://example.website/".includes(uid) — a substring test — which would
also match a uid that merely appeared inside the configured target string.
Exact matching seems clearly right here, but it is a change.

Testing

  • Two tests added to packages/endpoint-micropub/test/unit/jf2.js, covering
    the non-array shapes and the string shape. I verified the first fails with
    the original expression, reproducing the reported TypeError exactly.
  • 118/118 unit tests pass in endpoint-micropub; eslint and prettier
    clean.
  • The integration tests need MongoDB, which I do not have locally — they fail
    identically on an untouched main, so this changes nothing there.

Converting mf2 to JF2 leaves this property in one of three shapes: an
array when several targets are given, a string when one is, and an empty
object when the client sends an empty array. Calling .includes on it
directly threw

  TypeError: syndicateTo?.includes is not a function

and failed the whole post. Any client that sends "mp-syndicate-to": []
hits it, which is what an unticked syndication list produces, so the post
type made no difference — only whether the publication has syndication
targets configured, since this returns early when it has none.

Resolve the value to an array once before the loop, treating a string as a
single target and anything else as no targets. That also makes the
single-target case an exact comparison: it was previously a substring test
against the string, which could match a uid that merely appeared inside
another.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@rmdes

rmdes commented Aug 15, 2026

Copy link
Copy Markdown
Contributor Author

I can confirm this issue exist on indiekit and my indiekit fork, and impact anyone using a micropub client and NOT selecting a syndication target when publishing a post.

rmdes added a commit to rmdes/indiekit-endpoint-micropub that referenced this pull request Aug 15, 2026
Posting failed with

  TypeError: syndicateTo?.includes is not a function

for any client sending "mp-syndicate-to": [], which is what an unticked
syndication list produces. Converting mf2 to JF2 leaves this property in
one of three shapes: an array when several targets are given, a string
when one is, and an empty object when the array is empty — and an object
has no .includes.

The post type made no difference; the only other condition is that the
publication has syndication targets configured, since this returns early
when it has none. That is why it looked intermittent: selecting a single
target made the same post succeed.

Resolve the value to an array once before the loop, treating a string as a
single target and anything else as none. That also makes the single-target
case an exact comparison rather than a substring test against the string.

Same change proposed upstream in getindiekit/indiekit#874.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
rmdes added a commit to rmdes/indiekit-endpoint-micropub that referenced this pull request Aug 15, 2026
Carries the mp-syndicate-to fix since beta.34: posting failed with
"TypeError: syndicateTo?.includes is not a function" for any client
sending "mp-syndicate-to": [], which is what an unticked syndication list
produces. Converting mf2 to JF2 turns an empty array into an empty object,
which has no .includes. Same change proposed upstream in
getindiekit/indiekit#874.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@paulrobertlloyd
paulrobertlloyd merged commit a7819e7 into getindiekit:main Aug 16, 2026
1 check failed
@paulrobertlloyd

Copy link
Copy Markdown
Collaborator

Good catch – thanks for the fix @rmdes!

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.

2 participants