Skip to content

Pantry Host 0.6.0 — Publish to Bluesky from any self-hosted origin

Choose a tag to compare

@jpdevries jpdevries released this 13 Jul 01:35
· 29 commits to main since this release

The round trip is now open to every tier. 0.5.0 let you publish recipes and menus to your PDS — but only from origins that could complete AT Protocol OAuth. 0.6.0 removes that constraint and closes the loop on cross-device identity.

Publish broker (#38)

Self-hosted instances (LAN, Tailscale, plain HTTP — any origin that can't do AT OAuth itself) now publish through a popup on the hosted origin, my.pantryhost.app/publish-broker:

  • The popup shows which origin is asking, the exact record JSON, and a dry-run badge when applicable; nothing is written without your confirm click inside the popup (real URL bar — no clickjacking).
  • OAuth tokens and DPoP keys never leave the broker origin — only record payloads go in, only receipts come out, with targetOrigin-locked replies.
  • One request per popup lifetime; the payload can't be swapped after the review renders.
  • Records still travel browser → PDS. Pantry Host infrastructure stores nothing.
  • Sign-in inside the broker runs in a nested popup (signInPopup + BroadcastChannel) because PDS auth pages send COOP headers that would sever the popup's link to your app on a redirect.

Adopt-own-records (#40)

Importing your own published recipe used to disconnect it from its record — re-publishing minted a duplicate. Now, when a recipe or menu's sourceUrl is an at:// record owned by the signed-in DID:

  • Publish targets the original's rkey — putRecord updates it in place. The broker review screen says so explicitly: "Updates your existing record <rkey> in place."
  • On OAuth-capable origins, the CTA reflects it immediately: import your own record and it shows "View on Bluesky" without ever publishing from that device.
  • Menu children you own get the same treatment — local edits land on the originals instead of freezing as strongRefs.
  • Re-publish also preserves photos: when a fresh photo fetch fails (CORS-blocked CDNs), the existing record's embed is carried forward — a re-publish never loses a photo.

Fixes

  • Hosted-origin sign-in worked for the first time (#41): client-metadata.json was served without CORS headers, so my.pantryhost.app could never fetch it and sign-in died before OAuth started. All prior sign-ins had been on loopback.
  • Stale localStorage cache seeds no longer white-screen detail pages (#39): a cached recipe/menu shape missing its load-bearing arrays is discarded instead of trusted, at both the cache layer and the render layer.
  • Deterministic rkeys + PDS reconcile (#36): publish state is derived from the PDS, not localStorage — a second device or a cleared cache resolves the same record. (Merged pre-0.6.0, ships here.)
  • #stage scroll restored on Tier 1 navigation (#35).
  • Leftover dry-run receipts no longer render a published CTA in real mode; shared Modal panel no longer transparent on the web tier.

Known gaps

  • First publish of a CORS-blocked external photo (including cdn.bsky.app) is still photoless — com.atproto.sync.getBlob fallback tracked as follow-up.
  • Fully sovereign alternatives to the broker (own-domain OAuth, app passwords) tracked in #37.

🤖 Generated with Claude Code