Repository navigation
feat: expose the response's Content-Type on FileData - #198
Conversation
`parseFileData` read one header and dropped the rest, so a caller that needed the media type of a download had to re-derive it from the filename extension — lossy for anything not in its table, and wrong for a file saved under the wrong extension. Backlog does send a correct `Content-Type`; it was being thrown away. Added to both halves of the union, so `FileData.contentType` is reachable without narrowing first. The browser half could have gone without it — `blob()` carries the same value in its `type` — but a field only one branch has is a field callers have to guard. `""` when the header is absent, matching how `filename` already behaves. Closes #197 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Two things from re-reading this, one measured and one I should have put in the description.
|
| uploaded as | Content-Type |
|---|---|
note.txt |
text/plain |
page.html |
text/html |
d.json |
application/json |
blob.bin |
application/octet-stream |
Bare media types, no charset even on text/*. Nothing to change — recording it because the field is only useful as-is if that holds.
This is a type-level breaking change, which the description does not say
contentType is required on both interfaces, so anything that constructs a FileData — a test double, a fake, a hand-built fixture — stops compiling until it adds the field. Reading is unaffected.
I argued for putting it on both halves of the union so callers do not have to narrow before reading it, and I still think that is right, but the cost is this, and I left it out. The alternative is contentType?: string, which avoids the break and hands every caller a guard for a value the library always produces — worse, I think, for a 0.x library where this is the moment to get the shape right. Happy to switch if you would rather not take the break.
|
Closing a gap in how I verified this, prompted by the question of whether the header is really there. The earlier measurement did not test the code path this PR changes. I read the header with Checked, and it does not redirect — Then ran this branch against a live space, which is the check I should have run first:
|
mmktomato
left a comment
There was a problem hiding this comment.
@katayama8000
I added a comment 🙏
| expect(data).toHaveProperty("filename", expected); | ||
| }); | ||
|
|
||
| // Backlog does send a correct Content-Type; before this it was read off the |
There was a problem hiding this comment.
This comment doesn't make sense after merge.
(Same here: #196 (comment) )
There was a problem hiding this comment.
You are right, and it is the same mistake you already caught on #196 — I fixed it there and then wrote it again here. Fixed in the head commit.
Replaced with what the tests actually pin: Backlog sends a bare media type with no charset parameter, so the value compares directly. That holds whenever someone reads it, rather than only while this PR is open.
I also swept both branches for anything else phrased against the previous behaviour. The remaining "before"s are positional — "sanitise it before using it as a path", "before the unquoted form" — not temporal.
62 tests, lint, format and tsc still pass.
"before this it was read off the response and thrown away" is the same mistake already corrected in #196: it describes the change, and after the merge there is no before for a reader to compare against. Replaced with the fact the tests are actually pinning — Backlog sends a bare media type, no charset parameter, so the value compares directly. That is worth knowing whenever it is read, not just while reviewing this. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
@mmktomato fixed |
Closes #197.
Based on #196, not
master— both changeparseFileData, and stacking keeps this diff to the three lines that are actually aboutContent-Type. Retarget tomasteronce #196 lands.The problem
FileDatacarriedbody,urlandfilename. The response'sContent-Typewas read past and discarded, so a caller that needed the media type of a download had to re-derive it from the filename extension.Backlog does send a correct one. Measured against a live space:
Content-Typeshot.pngimage/png図面.pngimage/pngdata.csvtext/csvshot.jpg(bytes are a PNG)image/jpegnulab/backlog-mcp-server#187 carries a hand-written
MIME_TYPEStable for exactly this, returningapplication/octet-streamfor any extension not in it — while the server's own answer was on the response.The change
added to both halves of the union. The browser half could have gone without it, since
blob()carries the same value in itstype, but a field only one branch has is a field callers have to guard before reading.""when the header is absent, matchingfilename.Not solved, worth knowing
Backlog derives
Content-Typefrom the extension too — theshot.jpgrow above is a PNG that Backlog labelsimage/jpeg. So this is the server's claim, not a sniff. It is still a better source than a caller repeating the same guess with a smaller table, but a consumer that must be right about the format still has to check the bytes.Verified
Three tests, all failing without the change: the two content types above, and
""when the header is absent. 62 tests,oxlint,oxfmt --check,tsc --noEmitandnpm run buildall clean.🤖 Generated with Claude Code