mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
* feat(files): preview HEIC photos in the file viewer The agent can read HEIC since #6346, but the Files page still showed 'Preview not available' — an <img> pointed at the serve route got the stored HEIF under nosniff, which no browser outside Safari renders. The serve route now resolves a JPEG derivative for HEIF bytes, cached in the artifact store and keyed by the source's storage key. Workspace keys are regenerated on every content replacement, so the key is already a content version and using it avoids streaming the original just to hash it. Caching matters here in a way it did not for the vision path: a preview is re-fetched on every view and the WASM decode costs roughly a second for a phone photo. The original stays the stored object — downloads and raw=1 serve it untouched, so this never changes what a user gets back. compileDocumentIfNeeded becomes resolveServableBytes, since it now resolves images as well as generated documents. .tif/.tiff stay download-only: nothing decodes those on either side. * fix(files): make the preview derivative opt-in and never show a broken image Five issues from review, all interlocking around one decision. The derivative is now requested with preview=1 rather than suppressed with raw=1. raw=1 would have corrupted generated-document downloads: every non-markdown workspace download routes through the serve route and relies on resolveServableDocBytes compiling stored source into the real binary. Opt-in separates the three consumers cleanly — previews get the JPEG, downloads get untouched stored bytes, and doc compilation stays unconditional. - Public shares resolve the derivative too, with the same preview/download split; the viewer requests it, the download button does not. - Split the brand predicate. isHeifContainer stays broad for the vision path, where it only runs after sharp has already failed. The serve path runs first, so it uses isHevcHeifContainer — an AVIF was costing a storage round-trip, a WASM load and a misleading warn per request. - A derivative that cannot be produced (past the 20MB ceiling, or a decode failure) now falls back to 'Preview not available' instead of a broken image. UnsupportedPreview moved to preview-shared to avoid a module cycle. - The chat composer chip requests the derivative, so HEIC attachments stop rendering as broken thumbnails. * fix(files): reset the image preview when the file is overwritten An overwrite preserves the storage key, which is what the parent keys this component on, so only the URL version changes and it never remounts. The previous bytes' outcome therefore stuck, leaving a replaced image parked on 'Preview not available' until something else forced a remount. Reset on URL change during render rather than in an effect — this is derived state, and an effect would render the stale outcome first. * improvement(files): drop the dead preview reset and cap the ftyp brand scan - Content writes mint a new storage key, so the parent's key={file.key} already remounts ImagePreview; the render-phase reset was unreachable and made renames flash a loading overlay. - Clamp the ftyp compatible-brand scan to a real box size. The declared size is attacker-controlled and this now runs on every preview request. - UnsupportedPreview takes a primitive name so memo is load-bearing. - Fix the hardcoded ? in the public preview URL builder. * improvement(copilot): only ask for a preview derivative on image thumbnails A video has no derivative path, so preview=1 there only spent a brand sniff per request. Adds the missing test coverage for the helper.