Files
site-builder/craft/scripts
shadowdaoandClaude Opus 5.5 8ff0e01c45 preview: inline uploaded assets as data: URLs so they render in the sandboxed Preview
Preview (and version-history Preview) renders the page in an
<iframe sandbox srcdoc> without allow-same-origin, i.e. an opaque origin.
Every site-builder asset response carries Cross-Origin-Resource-Policy:
same-site (whp libs/SiteBuilderAssetServe.php), so each upload requested
from that frame is cross-site and blocked (ERR_BLOCKED_BY_RESPONSE.NotSameSite,
naturalWidth 0). The canvas was fine; Preview images were broken for everyone.

CORP and the sandbox stay as they are. Before the HTML is handed to the
sandboxed frame, the editor (panel origin, same-origin to the proxy) fetches
this site's proxy assets and swaps each URL for a data: URL in the HTML text
(utils/preview-assets.ts): img src/srcset, poster, video src, <link> icon,
inline-style and <style> url(), &quot;/&amp; forms, both proxy URL forms.
<a href>, <meta content>, other sites, other origins are left alone. Per-asset
(8 MiB), total (40 MiB), count (200) and timeout (15 s) caps; any per-asset
failure keeps the original URL. Save/Publish/export are untouched.

blob: was measured and rejected: in Chromium and Firefox a blob: URL made by
the editor window or by the Preview tab does not load inside the null-origin
frame; data: does.

Tests: vitest for the collector/rewriter; new real-browser suite
test:browser:preview-assets (real HTTP stub with the backend's CORP header,
Preview opened by a click through the real openers) reproduces the block with
the old opener and passes with the new one in Chromium and Firefox, measures
blob vs data, and checks the real backend publish holds only assets/<file>.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0185ukXgk6UunFCKyXqLe2Cq
2026-11-02 20:29:36 -08:00
..