assets: browser downloads + loud 404s for file-like paths - #735
Open
gtheys wants to merge 1 commit into
Open
Conversation
Server: - GET /api/assets/raw accepts ?download=1, serving the asset with an attachment Content-Disposition (RFC 5987 filename*) so plain browsers and <a href> links save the file under its own name. - The SPA fallback now returns a real 404 for unknown file-looking paths (anything with a non-.html extension, e.g. /files/assets/img.png) instead of index.html with HTTP 200, which made naive download attempts 'succeed' while yielding an HTML file. Unknown app routes still fall through to the SPA shell. Web + Desktop UI (shared app-core Assets view): - New 'Download' context-menu item and a keyboard 'd' on focused asset rows. The shared downloadAsset() helper resolves the asset URL exactly like embedded images do (same-origin HTTP on web, zen-asset:// scheme in the desktop app for local and remote vaults) and saves it via a blob + <a download> click, with no bridge-contract change. Tests: Go coverage for the download flag and the fallback 404; vitest coverage for the download helper (resolve failure, read failure, and anchor naming).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #716 (PR 1 of the suggested split: server + web/desktop UI; CLI/MCP parity can follow).
What this does
1. Server:
?download=1onGET /api/assets/rawWhen the query flag is set, the handler adds an attachment
Content-Disposition(RFC 5987filename*, so unicode filenames survive):This unlocks plain
<a href>downloads in the web app with zero blob plumbing on the server side. Without the flag, embed-serving behavior is byte-for-byte unchanged (no header added).2. Server: the SPA false-200 papercut from the issue
Previously
serveStaticfell back toindex.htmlfor any unknown path — including/files/assets/image.png— with HTTP 200 + text/html. Naive download attempts "succeeded" but yielded an HTML file (reproduced live against a self-hosted pod before the fix). Now unknown paths with a non-.htmlextension get a real404; unknown extension-less app routes still hit the SPA fallback, so client-side routing is untouched.3. Web + Desktop UI (shared
AssetsView)don a focused asset row downloads it (next to the existing Enter/Space open action).downloadAsset()helper resolves the asset URL exactly the way embedded images already do — same-origin HTTP on web, thezen-asset://privileged scheme in the desktop app (which hassupportFetchAPI: true, so it works for local and remote/self-hosted vaults alike) — fetches it as a blob and clicks a hidden<a download>. No bridge-contract change, no new IPC.Verification
go test ./...— all packages pass (incl. newTestAssetDownloadDisposition+TestStaticFallback404sAssetLikePaths);go vetclean.npm run typecheck— all TS workspaces pass.@zennotes/webproduction build passes; new vitest suite covers the helper (anchor naming, unresolvable path, failed fetch).download=1returns200 image/png+ attachment header; inline serving unchanged;/files/assets/nope.png→404instead of200 text/html; unknown app route →200SPA shell.Out of scope (follow-up PR per the issue's suggested split)
Desktop save-dialog,
zn asset list/getCLI, and MCPget_assetparity — happy to take those next.