Repository navigation
id(web): mimeToExtension returns Object.prototype members for prototype-named MIME types — 'constructor' yields the Object constructor instead of 'bin', corrupting paste filenames #2920
Description
id(web): mimeToExtension returns Object.prototype members for prototype-named MIME types — 'constructor' yields the Object constructor instead of 'bin', corrupting paste filenames
Evidence (verified this run, main 321dc21)
pkgs/id/web/src/image-upload.ts:43-54 — the extension table is a plain object literal and the fallback relies on nullish coalescing:
export function mimeToExtension(mime: string): string {
const map: Record<string, string> = { "image/png": "png", /* … */ };
return map[mime] ?? "bin";
}?? "bin" only fires for null/undefined. For a key that exists on Object.prototype, the lookup returns the inherited member — never nullish — so the fallback never runs and the function returns a function or object despite its declared string return type.
Probe (the function's verbatim lines 43-54 extracted from this HEAD; laptop ~/git/fleet/probe-2026-10-30-laneA-mimext/, bun run probe.ts):
| mime | result (runtime type) |
|---|---|
image/png |
"png" (string, correct) |
application/octet-stream |
"bin" (correct) |
"" |
"bin" (correct) |
constructor |
function Object() { [native code] } (function) |
toString |
function toString() { [native code] } (function) |
hasOwnProperty |
function hasOwnProperty() { [native code] } (function) |
__proto__ |
[object Object] (object) |
Downstream, generatePasteFilename (image-upload.ts:76-79) interpolates the result into a filename, so mimeToExtension("constructor") yields paste-<ts>.function Object() { [native code] } — a filename containing spaces, braces and parentheses — instead of paste-<ts>.bin. That name is used for pasted images whose File.type is empty/unrecognized (handleImageUpload, :237), a value ultimately supplied by the clipboard/drag source.
Why it matters
Same plain-object-lookup class fixed for detectLanguage in #2787 and for LANG_IMPORTS in highlight.ts:284-286 (own-key check, with an explanatory comment) — image-upload.ts was missed, and its ?? fallback makes the failure silent: no error, just a non-string "extension" flowing into a generated filename and upload metadata. The existing tests (image-upload.test.ts:109-143) pin the seven real types plus two unknown-string cases, but no prototype-name case.
Acceptance criteria
mimeToExtensionreturns"bin"for everyObject.prototypemember name (constructor,toString,hasOwnProperty,valueOf,__proto__, …) and for any other unlisted MIME string.- The seven listed types still map exactly as before; existing
image-upload.test.tscases unchanged and green. - New tests pin the prototype-name cases.
- Fix uses an own-key check (
Object.hasOwn) or an equivalent prototype-free table (Object.create(null)/Map), consistent with the id(web): detectLanguage returns Object.prototype members as languages — plain-object lookups on EXT_TO_LANG/FILENAME_TO_LANG trust arbitrary filenames ('notes.constructor' returns the Object constructor, '__proto__' returns a prototype object) #2787 precedent in the same package; the declaredstringreturn type holds at runtime for all inputs.
Dedup: searched open + closed issues for mimeToExtension / image-upload prototype this run — no hits. #2787 covers highlight.ts only. Sibling filed the same run: #2919 (terminalBytesForKey in world-keyboard.ts, same class, different file/function/caller — independently fixable).
Activity
dezren39 commentedon Oct 31, 2026
🤖 Agent note · filed
mimeToExtensioninpkgs/id/web/src/image-upload.tslooks up a plain-object table with no own-key check, so prototype-named MIME types return Object.prototype members (functions/objects) instead of the documented"bin"fallback, corrupting generated paste filenames; reproduced with the verbatim function on the laptop at main 321dc21."bin", the seven listed types map as before, new tests pin the cases.world-keyboard.ts).dezren39 commentedon Oct 31, 2026
Cross-link from the filing run: #2792 is the open design issue for one own-key rule across dynamic lookups; this filing is a concrete verified instance in
image-upload.ts(mimeToExtension) for its tracker. Sibling instance: #2919.5 remaining items
dezren39 commentedon Nov 1, 2026
🤖 Agent note · handed off
dezren39 commentedon Nov 1, 2026
🤖 Agent note · picked up
mimeToExtension.dezren39 commentedon Nov 1, 2026
🤖 Agent note · done
mimeToExtensionown-key fix PR.9771ddb1f