You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: toolbar config option with client-side bootstrap mode for shared caches (emdash-cms#1886)
* feat: add toolbar config with client-side bootstrap mode for shared caches
Implements the design agreed in Discussion emdash-cms#1742: a `toolbar` option with
"server" (default, unchanged), "client" (cache-identical public HTML with a
client-rendered Edit pill and an `_edit` query param for fresh editor
renders), and `false` (disabled). The toolbar is now also dismissible in
the browser.
* fix: mark _edit canonical redirect and render as uncacheable
Addresses review: the 302 for non-editors now carries
Cache-Control: private, no-store, and both the redirect and the
editor render opt out of the route cache (a cached redirect would
bounce editors back to the canonical URL).
* test: extract bootstrap script by index instead of regex
CodeQL flags the <script>…</script> regex as a bad HTML-filtering
pattern (case-sensitive tags). Use indexOf/lastIndexOf — we are
slicing our own generated string, not filtering HTML.
Adds a `toolbar` config option for reliable editor-toolbar delivery behind shared caches. `toolbar: "client"` keeps public HTML identical for every visitor and shows a client-side "Edit" pill for logged-in editors that opens a fresh, uncached editor render via an `_edit` query param; `toolbar: false` disables the toolbar entirely. The toolbar can now also be dismissed in the browser via its × button. The default (`"server"`) is unchanged.
Copy file name to clipboardExpand all lines: docs/src/content/docs/reference/configuration.mdx
+27Lines changed: 27 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -367,6 +367,33 @@ emdash({
367
367
368
368
Uploads that exceed the configured limit are rejected with a `413 Payload Too Large` response on the direct upload path, or a `400 Validation Error` on the signed-URL path.
369
369
370
+
### `toolbar`
371
+
372
+
**Optional.** Controls how the editor toolbar (the floating pill on public pages) is delivered. Defaults to `"server"`.
373
+
374
+
| Value | Behavior |
375
+
| ----- | -------- |
376
+
|`"server"` (default) | The toolbar is injected server-side into every HTML response rendered for an authenticated editor. |
377
+
|`"client"`| Public HTML is identical for every visitor. A tiny bootstrap script shows an "Edit" pill in browsers that have logged into the admin; clicking it verifies the session and reloads the page with an `_edit` query param, which is always rendered fresh (never cached) with the full toolbar. |
378
+
|`false`| Never render the toolbar or the bootstrap script. |
379
+
380
+
```js
381
+
emdash({
382
+
toolbar:"client",
383
+
})
384
+
```
385
+
386
+
Use `"client"` when your public HTML is served through a shared cache (Cloudflare Cache Everything / [Workers Cache](https://developers.cloudflare.com/workers/cache/), Fastly, Varnish, …). With server-side injection, an editor browsing the public site receives the cached anonymous variant — without the toolbar — whenever an anonymous visitor primed the cache first, so the toolbar appears and disappears with cache state. In client mode nothing session-specific is injected into shareable HTML, so the cache stays fully effective and the toolbar is reliable.
387
+
388
+
Notes on `"client"` mode:
389
+
390
+
- Logged-out visitors who open a shared `?_edit` URL are redirected to the canonical URL, so the param can't leak drafts or prime extra cache entries with page content.
391
+
- The "logged in" signal is a non-secret `localStorage` flag set by the admin; the pill verifies the real session before entering the edit view.
392
+
- The bootstrap is a small inline `<script>`. If your site sends a strict `Content-Security-Policy` without `'unsafe-inline'`, add a hash for it — the same applies to the server-injected toolbar.
393
+
- EmDash injects nothing session-specific — but if your own templates branch on `Astro.locals.user` (e.g. an "Admin" nav link for logged-in users), that variance is still in your HTML and still fragments the cache.
394
+
395
+
In every mode, the toolbar can be dismissed in the browser via its × button (per-browser, until the next time an editor opens the admin). Preview and edit-mode responses always render server-side with `Cache-Control: private, no-store`.
396
+
370
397
### `experimental`
371
398
372
399
**Optional.** Opt-in features whose behaviour or wire format may change, or be removed, in a minor release. Each field is independently enabled.
0 commit comments