Repository navigation
Files: what each file really is, from its bytes, and viewers in the app for text, code, Markdown, JSON, CSV, PDF and archives - #18
Merged
Conversation
…es, lines, entries, size, length), and text, code, Markdown, JSON, CSV, PDF and archives open in viewers of their own in the app Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
A file in a message now says what it really is, and opens in a viewer in the app. docs/files.md has the whole story.
Hub: what each kept file is, from its bytes
packages/hub/src/fileinfo.tssniffs magic numbers and content, not the network's type. It records:/N, page-tree/Count, also inside compressed object streams);#!, content);text.media_infotable (additive), keyed like the media cache.packages/hub/src/mediainfo.tswalks attachments in the background, one file at a time. It keeps a cursor inmetaand stays behind the archive's cursor.GET /api/attachments/:id/infolooks at a file now, for the viewer.AttachmentView.info?: FileInfois additive and optional. PROTOCOL_VERSION stays 1. Newpackages/protocol/src/files.ts./mediakeepsnosniff, the sandbox CSP and the inline allowlist. One change: a file the network calledapplication/octet-stream(or similar) is now served as the type its bytes say. A PNG then shows inline; an HTML page is still a sandboxed download.Web: viewers, each in a lazy chunk
packages/web/src/ui/files/. They are loaded by the shell added toViewer.tsx:highlight.ts), 3,000 lines at a time.markedparses only, and its tokens become elements. No raw HTML passthrough, http/https/mailto links only (through the existing link path and the desk helper), remote pictures load only on a click, without a referrer.ui/fileopen.tsx, shared with the menus.verify-viewers.ts --probe-pdf). Chromium's built-in viewer does render a/mediaPDF in a frame despite the sandbox CSP. But the Android app's WebView has no PDF viewer, and Chromium's runs a PDF's own script. pdf.js runs no PDF script, works the same everywhere, and its 446 KB chunk and 1.3 MB worker load only when a PDF is opened.@napi-rs/canvas(a native Node binary) as optional. The rootpackage.jsonoverrides it with an empty stub, sobun installdownloads no native code.modulepreloadlinks.Demo world
demo.tsadds these files, several with wrong network types as real networks send them:build-482.txt;insert_get.rs, asapplication/rls-services+xmllike Discord sends it;routing-notes.md, as octet-stream, with a table, a code block, raw<script>and a remote image;bench-483.json, as octet-stream;stretch.csv, with quoted commas;dither-sim-0.4.zip;topology.svg, containing a<script>;rent-split.xlsx, a type with no viewer.Verification
bun run typecheckandbun run testpass (all packages).packages/hub/test/fileinfo.test.ts(31 tests):/mediaserving the sniffed type with the same headers.packages/web/test/files.test.ts(12 tests): CSV parsing, highlighting, card text, the guess before analysis.scripts/verify-viewers.ts(new): 73 checks, all pass, on a fresh demo hub.scripts/verify-desk.ts(updated): 23 checks pass.scripts/verify-history.ts: 22 checks pass.scripts/verify-perf.ts:perf-baseline.jsonfailed on times across the board, includinghub.bootstrap.ms(+135%), code this PR doesn't touch. The machine's load average was 12–14.--runs 1 --pages 5) of origin/main and this branch, three each. At 1×, medians: cold list 750 vs 758 ms, open 175 vs 182 ms, older page 105 vs 101 ms, long reopen 96 vs 106 ms (one 172 ms outlier), relaunch 420 vs 389 ms. At 4× (earlier round): cold 2326 vs 2367 ms, open 703 vs 674 ms. Everything is within noise and far inside the harness's ×1.25 + 50 ms rule.data:media didn't yield between batches; it now filters inline media in SQL and yields.Not verified
packages/chat-protocolneedsbun scripts/accounts-sync.tsafter merge (newfiles.ts,AttachmentView.info).🤖 Generated with Claude Code