feat(preview): consume rustycms live-preview drafts
Deploy / verify (push) Successful in 45s
Deploy / deploy (push) Successful in 1m1s

`?preview_draft=<sid>` on any page/post route forwards the signed
session id to the CMS, which renders the in-memory draft instead of
the persisted entry. Layout listens for `rustycms:reload` postMessages
from the admin iframe parent and re-runs `invalidateAll()` to pick up
fresh draft state. CSP `frame-ancestors` is set per-request when
`PUBLIC_PREVIEW_PARENT_ORIGIN` is configured so the admin iframe can
embed the response.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Peter Meier
2026-05-01 09:24:05 +02:00
parent 3bc7273e71
commit 00d42ebb42
5 changed files with 59 additions and 7 deletions
+4 -1
View File
@@ -24,8 +24,9 @@ export const load: PageServerLoad = async ({ params, locals, url, setHeaders })
const { slug } = params;
const translations = locals.translations ?? {};
const preview = url.searchParams.get('preview') ?? undefined;
const previewDraft = url.searchParams.get('preview_draft') ?? undefined;
if (preview) {
if (preview || previewDraft) {
setHeaders({
'cache-control': 'private, no-store, max-age=0',
'x-robots-tag': 'noindex, nofollow',
@@ -38,6 +39,7 @@ export const load: PageServerLoad = async ({ params, locals, url, setHeaders })
// Hard-cap: post → block → image → img reicht in 3 Levels.
depth: 3,
preview,
previewDraft,
});
if (!post) {
@@ -280,6 +282,7 @@ export const load: PageServerLoad = async ({ params, locals, url, setHeaders })
return {
post,
preview: !!preview,
previewDraft: !!previewDraft,
postImageUrl,
rawPostImageUrl: postImageField?.url ?? null,
postImageFocal: postImageField?.focal ?? null,