feat(preview): consume rustycms live-preview drafts
`?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:
+18
-1
@@ -49,7 +49,10 @@ export const handle: Handle = async ({ event, resolve }) => {
|
||||
},
|
||||
});
|
||||
|
||||
const isPreview = event.url.searchParams.has('preview');
|
||||
const isPreview =
|
||||
event.url.searchParams.has('preview') ||
|
||||
event.url.searchParams.has('preview_draft');
|
||||
const isPreviewDraft = event.url.searchParams.has('preview_draft');
|
||||
|
||||
if (
|
||||
event.request.method === 'GET' &&
|
||||
@@ -73,5 +76,19 @@ export const handle: Handle = async ({ event, resolve }) => {
|
||||
);
|
||||
}
|
||||
|
||||
// Live-preview: allow the admin iframe to embed this response. The admin
|
||||
// origin is configured via PUBLIC_PREVIEW_PARENT_ORIGIN; when unset we fall
|
||||
// back to wildcard (dev only). Outside live-preview we leave existing
|
||||
// headers alone so production hardening (X-Frame-Options / CSP from Caddy)
|
||||
// stays intact.
|
||||
if (isPreviewDraft) {
|
||||
const parent = (process.env.PUBLIC_PREVIEW_PARENT_ORIGIN ?? '').trim();
|
||||
response.headers.set(
|
||||
'content-security-policy',
|
||||
`frame-ancestors 'self' ${parent || '*'}`,
|
||||
);
|
||||
response.headers.delete('x-frame-options');
|
||||
}
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user