fix(files): render audio and video stored as application/octet-stream - #6341
Conversation
The file viewer built the blob backing <audio>/<video> from the record's stored content type with a truthiness fallback, so a stored application/octet-stream was passed straight through and the element could not determine the format. Downloading the same file worked because the download path derives its content type from the filename. - Add resolveEffectiveMimeType, which resolves a generic stored type against the filename, and use it for the media blob, the type column, and the type filter (an octet-stream video was also invisible to the Audio/Video/Image filters) - Map .webm to video/webm rather than audio/webm: a <video> element plays an audio-only stream, an <audio> element drops the picture - Preview .bmp, .avif and .ico, which upload accepts but the viewer sent to the download-only path; serve them with their real content type so nosniff does not block them. .tiff and .heic stay unsupported - no browser renders them - Open .jsonl in the text editor, and fill the extension-to-mime gaps for .mmd, .diff, .patch and .fish
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview MIME resolution: Adds Viewer & files UI: Audio/video blob URLs, the Type column, and audio/video/image filters use effective MIME instead of raw Images: Serve utils: Extends extension/MIME maps and safe inline types for more image, audio, and video formats. Reviewed by Cursor Bugbot for commit 0a62147. Configure here. |
Greptile SummaryThe PR improves previews for files whose stored MIME type is generic by deriving an effective type from the filename.
Confidence Score: 5/5The PR appears safe to merge because no blocking failure remains within the eligible follow-up review scope. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| apps/sim/lib/uploads/utils/file-utils.ts | Adds presentation-oriented MIME resolution, media-element retagging, and extension mappings while retaining legacy persisted WebM typing. |
| apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/file-viewer.tsx | Uses the resolved media MIME type when constructing blob URLs for audio and video previews. |
| apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/file-category.ts | Expands native image preview categories for AVIF, BMP, and ICO files. |
| apps/sim/app/workspace/[workspaceId]/files/files.tsx | Applies effective MIME resolution consistently to displayed type labels and media/image filters. |
| apps/sim/app/api/files/public/[token]/content/route.ts | Derives passthrough public-share response types from filenames to support inline rendering under nosniff. |
| apps/sim/app/api/files/utils.ts | Adds MIME mappings and safe-inline entries for the newly previewable media and image formats. |
Reviews (4): Last reviewed commit: "fix(files): keep the dual-container vide..." | Re-trigger Greptile
Follow-up to the review pass on this branch. - Revert the global .webm -> video/webm remap. EXTENSION_TO_MIME is shared with non-viewer callers, and a .webm with an empty stored type would have started taking the STT route's video branch (stt/route.ts:211 -> extractAudioFromVideo), which 500s where no ffmpeg binary is on PATH. The ambiguity is now settled in resolveMediaMimeType, which knows which element the caller is rendering - Resolve the public share route's Content-Type from the filename via getContentType, matching the workspace serve route, instead of echoing the client-declared stored type into a public unauthenticated response. Add the audio/video entries contentTypeMap was missing so a shared media file keeps a real Content-Type (disposition is unchanged - none are inline-safe) - Make resolveEffectiveMimeType total (string, not string | null); the null contract only bought one label edge case and cost a ?? at every call site, one of which was dead - Drop .jsonl from the text-editable set. The editor loads the whole file and only CSV has a byte cap, so a large .jsonl would trade a download-only fallback for a crashed tab. Needs the size guard generalized first - Trim two comments that restated their code
|
@cursor review |
…resents The viewer routes .webm to the video player, but the Type column and the audio/video filters resolved it through EXTENSION_TO_MIME and read audio/webm, so one file showed as Audio and opened in a <video>. resolveEffectiveMimeType now consults a DUAL_CONTAINER_MIME map first. It stays out of EXTENSION_TO_MIME because the speech-to-text and ElevenLabs routes read that table directly, where a video/* label pushes a .webm into ffmpeg audio extraction it does not need.
|
@cursor review |
…d type resolveFileType writes user_file.content_type, and it delegated to resolveEffectiveMimeType, so DUAL_CONTAINER_MIME could persist video/webm. The speech-to-text route reads that back as file.type, which sends the upload into the ffmpeg extraction path the previous commit set out to avoid. resolveFileType now resolves through EXTENSION_TO_MIME alone; the video default stays on the presentation path. Both share an identifiesFormat predicate.
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 0a62147. Configure here.
Summary
<audio>/<video>from the record's stored content type with a truthiness fallback (file.type || fallback), so a storedapplication/octet-streamwas passed straight through and the element could not determine the format. Downloading the same file worked because the download path derives its content type from the filename.resolveEffectiveMimeType, which resolves a generic stored type against the filename, and routed the media blob, the Type column, and the type filter through it — an octet-stream video was also invisible to the Audio/Video/Image filters..webmnow maps tovideo/webmrather thanaudio/webm: a<video>element plays an audio-only stream, an<audio>element drops the picture..bmp,.avifand.iconow preview — upload accepts them but the viewer sent them to the download-only path. They're also served with their real content type sonosniffdoesn't block the<img>..tiffand.heicstay unsupported since no browser renders them..jsonlopens in the text editor, and filled the extension-to-mime gaps for.mmd,.diff,.patchand.fish.Type of Change
Testing
Unit tests added for
resolveEffectiveMimeTypeand the new preview categories; verified they fail against the old behavior.bun run check:api-validation, typecheck, and lint pass.Checklist