Skip to content

[pull] main from tinacms:main#213

Merged
pull[bot] merged 1 commit into
code:mainfrom
tinacms:main
May 11, 2026
Merged

[pull] main from tinacms:main#213
pull[bot] merged 1 commit into
code:mainfrom
tinacms:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented May 11, 2026

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

## Summary

Closes #6503.

This PR makes media operations branch-aware end-to-end:

1. **Forward the branch on every cloud media call.** `TinaMediaStore`'s
`upload_url`, `list`, and `delete` requests now carry
`?branch=<encodedBranch>`, so once an app opts into branch-aware media
those operations are scoped to the editor's current branch instead of
always hitting production.
2. **Fix staging URL handling for multi-segment branches.**
`@tinacms/graphql`'s media URL resolver now formats staging URLs as
`/__staging/<branch>/__file/<path>` instead of
`/__staging/<encoded-branch>/<path>`. The previous form broke for
branches containing `/` (e.g. `feat/my-branch`) because CloudFront
decodes paths before downstream components see them — the S3 write key
(with a literal `%2F`) wouldn't match the decoded read path. The
`__file` delimiter lets the branch contribute its natural `/` segments
while still marking where the file path begins.
3. **Refresh from the server after upload.** The media manager now drops
its locally-constructed entries and re-fetches the list, since the
server is the source of truth for the canonical `src` URL (including the
staging-branch path when applicable). Constructing it on the client
would mean mirroring the server's branch-aware path logic plus the
per-stage CDN host, which is fragile to keep in sync.

### Branch-forwarding details

- `persist_cloud()` — appends `?branch=<encodedBranch>` to the
`upload_url` request, then returns `[]` so the media manager's refresh
path runs (see point 3 above)
- `list()` cloud branch — appends `&branch=<encodedBranch>` to the list
URL
- `delete()` cloud branch — appends `?branch=<encodedBranch>` to the
delete URL

`this.api.branch` is already URL-encoded by
[`Client.setBranch()`](https://github.com/tinacms/tinacms/blob/main/packages/tinacms/src/internalClient/index.ts#L167).
A new private `encodedBranchParam()` helper decodes then re-encodes at
the use site so the value is always single-encoded, even if the URL
containing it is later re-processed.

The local-mode code paths (`persist_local`, the local-mode list branch,
the local-mode delete branch) are untouched.

Also reserves an optional `rename?(from: string, to: string):
Promise<Media>` hook on the `MediaStore` interface as a future extension
point — no implementation in `TinaMediaStore`, no surfacing in
`MediaManager`.

## Backward compatibility

Older assets-api versions ignore unknown query parameters, so this can
ship before
[tinacms/tinacloud#3330](tinacms/tinacloud#3330)
lands. When the flag isn't enabled on an app, the server's
[`isBranchRequest()`](https://github.com/tinacms/tinacloud/blob/main/js/assets-api/src/api/koa-admin.ts#L16)
helper falls through to production behaviour — and that fall-through is
regression-tested for all three endpoints by
[tinacms/tinacloud#3472](tinacms/tinacloud#3472).

## Test plan

- [x] `pnpm --filter tinacms build` — clean
- [x] `pnpm --filter tinacms test` — 321 passed, 5 skipped (no
regressions)
- [x] Manual diff inspection: each of the three cloud URLs now ends with
`?branch=…` or `&branch=…` exactly once; local-mode branches are
untouched
- [x] Encoding round-trip: `feat/my-branch` (stored as
`feat%2Fmy-branch`) decodes to `feat/my-branch` and re-encodes back to
`feat%2Fmy-branch`

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Jack Pettit [SSW] <57518417+JackDevAU@users.noreply.github.com>
@pull pull Bot locked and limited conversation to collaborators May 11, 2026
@pull pull Bot added the ⤵️ pull label May 11, 2026
@pull pull Bot merged commit 9e7eba9 into code:main May 11, 2026
5 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant