ReviewOS

also looking at this

stacks/postline

Mastodon crosspost driver

#26
Merged glennmichael123 wants to merge feat/mastodon-driver into main
11 files +752 -2
11 days ago

Adds Mastodon as a sixth publish target — the first of the "teased in the UI but stubbed" networks to go live.

Why app-owned

The published @stacksjs/socials ships no Mastodon driver, so this is a full app-owned implementation (app/Services/Social/Drivers/MastodonDriver.ts) rather than a re-export wrapper. Keeping it in app code means it survives framework updates (the lesson from the whole vendored-socials saga).

What's added

  • Token-based connect — instance URL + a personal access token (no OAuth dance). verify_credentials validates the token and captures the @user@instance handle. Env fallback via MASTODON_INSTANCE_URL / MASTODON_ACCESS_TOKEN.
  • Driver — statuses publish, v2/media upload (bytes or fetched URL, up to 4), thread reply-chaining via in_reply_to_id, 500-char limit, instance-URL normalization (mastodon.social → https://mastodon.social), typed MastodonApiError.
  • Wiring — crosspost publisher map, providers status (composer toggle appears automatically), routes /postline/mastodon/{status,connect}, and an Accounts connect card (instance + token inline form).

Verification

  • 8 driver unit tests (mocked HTTP): verify, plain publish, media upload + media_ids, thread in_reply_to_id, char-limit guard, MastodonApiError mapping, instance normalization
  • Full end-to-end against a local mock instance through the real stack — connect → single post → 2-segment thread where toot-2 correctly in_reply_to toot-1 → media path, all landing on the mock
  • Browser: composer shows an enabled Mastodon toggle; Accounts card shows connected (@glenn@localhost:3055); 0 console errors
  • 36 tests total; tsc exit 0; pickier clean

Real-instance posting needs the user's instance + token (same as Bluesky), but the full path is proven against the mock.

11 changed files on the files tab, with 0 review threads.

Sign in to comment on this pull request.