Skip to content

Data Liberation: Negotiate browser image formats when downloading media - #4674

Merged
chubes4 merged 1 commit into
feat/site-artifact-import-clifrom
fix/dla-media-format-negotiation
Aug 26, 2026
Merged

Data Liberation: Negotiate browser image formats when downloading media#4674
chubes4 merged 1 commit into
feat/site-artifact-import-clifrom
fix/dla-media-format-negotiation

Conversation

@aagam-shah

Copy link
Copy Markdown
Contributor

What

The Data Liberation media downloader now sends the same image Accept header a browser sends, and names the saved file by the content type that actually arrives when it differs from the URL extension.

Why

downloadMedia fetched with no Accept header. CDNs that negotiate image formats (Wix, Squarespace, Cloudinary f_auto, imgix auto=format, Photon) then return the legacy or original encoding.

On a 28-page Wix store, retina variants came back as 1 to 7 MB PNGs instead of the ~10 KB AVIFs a visitor gets. The portable media set filled its 160 MiB budget and the export failed with "Portable capture exceeds compiler limits" after a three-minute capture.

Same URL, measured with curl: no Acceptimage/png, 1,409,778 bytes. Browser Acceptimage/avif, 8,759 bytes.

With this change the same capture exports at 128 MB and the generated theme carries 162 AVIF assets.

How to test

  • cd packages/data-liberation-agent && npx vitest run src/lib/media-fetch
  • studio create --from https://<a-wix-site> and check capture-receipt.jsonportableMedia.selected_bytes and the website/media/*.avif files.

Bundles were rebuilt from this source (npm run build in the package leaves the tree clean).

Part of the studio create --from work in #3952.

AI assistance: Claude Code (Claude Fable 5) traced the size failure to the missing Accept header and drafted the change. Aagam Shah directed the work and is responsible for it.

🤖 Generated with Claude Code

The media downloader fetched with no Accept header, so format-negotiating
CDNs (Wix, Squarespace, Cloudinary f_auto, imgix auto=format, Photon)
returned the legacy/original encoding. On a small Wix store the retina
variants came back as 1-7 MB PNGs instead of the ~10 KB AVIFs a visitor's
browser receives, the portable media set filled its 160 MiB budget, and
the artifact export failed against the 192 MiB compiler limit.

Send Chromium's image Accept header and name the downloaded file by the
negotiated content type when it differs from the URL extension, so an AVIF
body is not stored as `.png`. Same-format aliases (`.jpeg`/`.jpg`,
`.tif`/`.tiff`) keep the URL extension.

On the same site the export now completes at 128 MB, with 162 AVIF assets
in the generated theme instead of 82 multi-megabyte PNGs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@aagam-shah

Copy link
Copy Markdown
Contributor Author

Note on CI: the red "Unit Tests" job is inherited from the base branch. PR #3952's own build (buildkite 21303) fails the same job, and the failing suites are all in apps/studio and packages/ui (15 files, 104 tests locally on the untouched base). "Data Liberation" and "Lint" pass here.

@chubes4
chubes4 merged commit 289c6d7 into feat/site-artifact-import-cli Aug 26, 2026
8 of 9 checks passed
@chubes4
chubes4 deleted the fix/dla-media-format-negotiation branch August 26, 2026 02:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants