`fileTypes` in the manifest, and two GET routes behind it: /v1/thumb and
/v1/render. the platform calls them when it meets a `.heic` and nothing in the
platform knows which plugin answered.
THIS IS THE REASON TO INSTALL av-club FOR SOMEBODY WHO NEVER CONVERTS ANYTHING.
sharp's libheif has no HEVC decoder, so without this a folder of iPhone photographs
is a wall of file icons and opening one offers a download. with it, they thumbnail
and they open.
only heic and heif are claimed. everything else the browser shows — jpeg, png,
webp, avif, svg, and every video ffmpeg reads — core already handles, and claiming
those would take work off a path that is faster and needs no plugin.
size and width are CLAMPED here rather than trusted. the caller is the platform
rather than a browser, but a route that resizes to whatever number arrives is one
query string from an allocation the size of the machine, and "the only caller is
trusted" stops being true the first time somebody adds a second caller.
THE DERIVED ASSET IS DELETED AFTER THE BYTES ARE READ. runSharp without an
outputPath stores its result — right for the API, wrong here: this is a view of a
file that already exists, asked for on every folder listing, and keeping them would
fill the asset store with thumbnails nothing owns and nothing expires. read fully
rather than streamed, because a streamed Bun.file would still be reading when the
delete lands.
jpeg for the thumbnail (small, universal), webp for the render (the viewer wants
the quality back).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>