Uh oh!
There was an error while loading. Please reload this page.
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
waleedlatif1
commented
Aug 6, 2026
waleedlatif1
commented
Aug 6, 2026
@cursor review |
Uh oh!
There was an error while loading. Please reload this page.
…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.
waleedlatif1
commented
Aug 6, 2026
waleedlatif1
commented
Aug 6, 2026
@cursor review |
Uh oh!
There was an error while loading. Please reload this page.
…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.
waleedlatif1
commented
Aug 6, 2026
waleedlatif1
commented
Aug 6, 2026
@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.
Uh oh!
There was an error while loading. Please reload this page.
Three zero-reference exports, found by walking every export in the modules the merge touched and counting non-test references. - `resolveMediaMimeType` + `MEDIA_FALLBACK_MIME` (`lib/uploads/utils/file-utils`). Staging added them in #6341 for `MediaPreview`'s blob path; this branch rewrote that preview to stream from the serve route, so the merge orphaned them. Their tests go too, and the `DUAL_CONTAINER_MIME` doc stops pointing at a function that no longer exists. Worth recording, since deleting the helper deletes the fix: it retagged a dual-container `.webm` to the element the viewer had already chosen. The serve route now declares the type instead, and derives it from the filename, where `webm` maps to `video/webm` — so an audio-only `.webm` reaches an `<audio>` element labelled `video/webm`. Browsers sniff `src=` responses rather than trusting the header, so this is inert in practice, but it is a real narrowing and the public-share route (which uses the stored `file.contentType`) does not share it. - `tableWorkspaceId` (`resources/table-source.ts`, the whole file). Added by this branch's own first commit and never called — `cell-render` takes the workspace id as a plain argument. Its TSDoc claimed to be "the value that decides whether a cell may render a sim-resource chip", which nothing enforced. The table migration will want this helper; it can arrive with a caller and an accurate docstring. - `isMediaFileType` (`lib/uploads/utils/file-utils`). Not ours — dead since #2068, zero references including tests. Removed while the file was open.
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