fix: delegate HEIC media to configured image services#2175
Conversation
🦋 Changeset detectedLatest commit: 7ef2d0e The changes in this PR will be included in the next version bump. This PR includes changesets to release 17 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/auth-atproto
@emdash-cms/blocks
@emdash-cms/cloudflare
@emdash-cms/contentful-to-portable-text
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/plugin-cli
@emdash-cms/plugin-types
@emdash-cms/registry-client
@emdash-cms/registry-lexicons
@emdash-cms/registry-verification
@emdash-cms/sandbox-workerd
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-field-kit
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
There was a problem hiding this comment.
This is a sensible, well-scoped bug fix: HEIC/HEIF files are undisplayable in browsers, so converting them client-side before they hit the existing local-media upload flow is the right layer to solve it. The change is additive (no break), the CSP-compatible heic-to/csp import is appropriate, the changeset is user-facing, and no user-visible strings were added. Tests cover conversion behavior, browser renderability, and end-to-end flow through the media API.
I read the changed files and traced the two call-sites (MediaLibrary and MediaPickerModal). The only meaningful gap is that the same HEIC fix is not applied to uploadToProvider, so external-provider uploads can still store an undisplayable original. The rest of the code looks solid.
|
I'm a bit reluctant to add a big new WASM dependency for this. It seems like something the image server should be handling. |
Overlapping PRsThis PR modifies files that are also changed by other open PRs:
This may cause merge conflicts or duplicated work. A maintainer will coordinate. |
What does this PR do?
Removes the browser-side HEIC/WASM conversion and makes the storage-backed
/_imageendpoint use the configured image infrastructure instead.On Node, local Astro image services continue transforming storage bytes directly, while external Astro services receive the storage adapter's public URL through their
validateOptions/getURLcontract. External services opt into HEIC input by listingheicorheifinimage.service.config.supportedInputFormats; EmDash also requires a rewritten transform URL and a genuinely public storage source. On Cloudflare Workers, the existing Images binding remains the transformer and is detected automatically.When no capable path is configured, direct, signed, and MCP HEIC uploads return
415 UNSUPPORTED_IMAGE_FORMATbefore a broken library item is stored. Signed uploads that become unsupported before confirmation are deleted on a best-effort basis and marked failed. Existing storage-backed media with public R2/S3 URLs now builds admin thumbnails through/_imageusing its storage key.Related issue/discussion: none; this follows the maintainer review on this PR.
Type of change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runAI-generated code disclosure
Screenshots / test output
Production verification on
masonjames.com(Astro Node + S3-compatible R2 storage + Cloudflare image resizing):/_imageredirects the existing HEIC storage object to the configured external service and returns a 400×300 WebP (44,796 bytes).Cache-Control: public, max-age=31536000, immutable.Repository validation:
pnpm format:checkpnpm lint:json | jq '.diagnostics | length'—0pnpm lintpnpm typecheck— 31 package projectsTMPDIR=/private/tmp pnpm --filter emdash test— 386 files passed, 1 skipped; 4,996 tests passed, 3 skippedpnpm --filter @emdash-cms/cloudflare test— 17 files, 232 tests passedpnpm --filter @emdash-cms/admin exec vitest run tests/lib/media-thumbnail.test.ts— 8 tests passedpnpm --filter emdash buildpnpm --filter @emdash-cms/cloudflare buildpnpm --filter @emdash-cms/admin buildThe canonical
TMPDIRis used because the repository's sandbox watcher assertion otherwise compares macOS's/var/foldersspelling with its/private/var/foldersrealpath; no product test fails under the canonical path.