Skip to content

Syndication slice 3: Hashnode adapter + operator-config docs - #3

Merged
DanMat merged 1 commit into
mainfrom
feat/syndication-slice-3
Sep 7, 2026
Merged

DanMat merged 1 commit into
mainfrom
feat/syndication-slice-3

Conversation

@DanMat

@DanMat DanMat commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Third syndication slice: a Hashnode target, so a published post can be cross-posted to Dev.to and Hashnode from the same admin page and the same MCP tool.

What's here

  • HashnodeTarget — a new adapter behind the existing SyndicationTarget interface (a new implementation, not a redesign):
    • publishPost GraphQL mutation to create, updatePost to update (by the stored external id — re-posting updates, never duplicates).
    • Canonical sent as originalArticleURL; tags sent as Hashnode's required {name, slug} objects (slug lowercase-hyphenated, at most five).
    • GraphQL returns 200 even on failure, so the adapter fails on a non-2xx or an errors payload — surfacing e.g. "requires Hashnode Pro" verbatim.
    • Credentials are operator env only (HASHNODE_TOKEN, HASHNODE_PUBLICATION_ID); missing either → "Not configured", never called.
  • Wiring — registered in the plugin's target map alongside Dev.to. No core change, no new capability, no new table: it reuses the slice-1/2 Syndicator, blog_syndication, the nimbuscms.blog:syndicate capability, the admin page, and the MCP tool.
  • Docs — README gains a Syndication section (both surfaces, the wildcard-immune capability, and a per-target env table including the Hashnode Pro caveat), and the stale "declares no capability — every surface is public read" line is corrected.

Tests

HashnodeTargetTest covers the create/update request shape, the tag-object formatting, the GraphQL-200-with-errors path, a non-2xx, and the not-configured refusal. Local: phpstan level 6 clean, cs-fixer clean, phpunit green (the two MySQL repository tests run against the DB in CI).

Next

Slice 4 — Hacker News / Reddit prefilled share links (human clicks, no auto-post), plus the Reddit auto-submit conversation to have there.
🤖 Generated with Claude Code

Adds Hashnode as a second syndication target behind the existing
SyndicationTarget interface — a new adapter, not a redesign. It publishes
with the `publishPost` GraphQL mutation and updates with `updatePost`
against gql.hashnode.com, sends the canonical as `originalArticleURL`, and
formats tags as Hashnode's `{name, slug}` objects. GraphQL replies 200 even
on failure, so the adapter treats a non-2xx *or* an `errors` payload as an
error (with a clear "requires Hashnode Pro" message surfaced through).

Credentials stay server-side env (HASHNODE_TOKEN, HASHNODE_PUBLICATION_ID);
a target missing either shows as "Not configured" and is never called. No
core change, no new capability — it reuses the slice-1/2 Syndicator, table,
capability, admin page and MCP tool.

README gains a Syndication section (both surfaces, the wildcard-immune
capability, and the per-target env table incl. the Hashnode Pro caveat), and
the stale "declares no capability" line is corrected.

Tests: the adapter's create/update request shape, tag objects, the
GraphQL-200-with-errors path, non-2xx, and the not-configured refusal.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@DanMat
DanMat merged commit f69062e into main Sep 7, 2026
2 checks passed
@DanMat
DanMat deleted the feat/syndication-slice-3 branch September 7, 2026 00:42
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