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
+6 -2
View File
@@ -235,6 +235,8 @@ export type ContentGetOptions = {
fields?: string[];
/** Signierter Preview-Token (HMAC), entsperrt Drafts für genau diesen Eintrag. Bypass Cache. */
preview?: string;
/** Signierte Live-Preview-Session-ID — Server rendert In-Memory-Draft statt persistierten Eintrag. Bypass Cache. */
previewDraft?: string;
};
// ---------------------------------------------------------------------------
@@ -325,6 +327,7 @@ export async function getPageBySlug(
if (options?.fields?.length)
u.searchParams.set("_fields", options.fields.join(","));
if (options?.preview) u.searchParams.set("preview", options.preview);
if (options?.previewDraft) u.searchParams.set("preview_draft", options.previewDraft);
return fetch(u.toString());
};
const normSlug = normalizePageSlug(slug);
@@ -351,7 +354,7 @@ export async function getPageBySlug(
}
return (await res.json()) as PageEntry;
};
if (options?.preview) return fetchFn();
if (options?.preview || options?.previewDraft) return fetchFn();
return cached("page", key, fetchFn);
}
@@ -573,6 +576,7 @@ export async function getPostBySlug(
if (options?.fields?.length)
u.searchParams.set("_fields", options.fields.join(","));
if (options?.preview) u.searchParams.set("preview", options.preview);
if (options?.previewDraft) u.searchParams.set("preview_draft", options.previewDraft);
return fetch(u.toString());
};
const normSlug = normalizePostSlug(slug);
@@ -599,7 +603,7 @@ export async function getPostBySlug(
}
return (await res.json()) as PostEntry;
};
if (options?.preview) return fetchFn();
if (options?.preview || options?.previewDraft) return fetchFn();
return cached("post", key, fetchFn);
}