CL-6560: Recover previewable content for stored file uploads - #273
Merged
Conversation
Covers resolving a file upload's out-of-band bytes back into an artifact's content when they decode as text, an oversized upload never landing as a stored-but-empty row, and the Library preview distinguishing a genuinely empty artifact from one whose stored file just can't be rendered.
A browser upload's bytes were always intact in the artifacts content store, but the Library detail pane and its GET /:artifactId read the artifact row's own content column, which createFileArtifact leaves empty by design for every out-of-band upload — a real 10 KB Markdown file read back as "This document has no content yet," implying nothing had been uploaded. createArtifactDbStore.get now resolves that out-of-band blob and inlines it into content whenever it decodes as text, the same thing the HTML preview route already did, generalized to every text-decodable MIME type. A non-text blob (an image, a real PDF, a legacy .docx/.xlsx) is left empty, but the Library preview now tells those two empty cases apart: source.upload.mimeType marks a real stored file, so the doc, sheet, and pdf renderers say "We couldn't read this file's contents for preview" instead of implying the upload never happened.
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.
Summary
A real file uploaded through the Library's Files page (e.g. a ~10 KB
SKILL.md) read back with an honest-looking row (Kind: File,Updated: 15s ago) but the detail pane said "This document has no content yet." — implying nothing had been uploaded.This was stored-but-unreadable, not silently dropped. Verified directly against Postgres:
createFileArtifact(@corbits/artifacts) is the one path a browser upload goes through, and it writes real bytes into theartifacts.uploadside table while deliberately leaving the artifact row's owncontentcolumn empty (source.upload.idis the reference). The reported artifact'suploadrow held all 15998 bytes, byte-identical to the original file. No data was lost — every previously-uploaded file with asource.uploadreference is fully recoverable.The bug was in the read path:
GET /:artifactIdreturned the row's raw (empty)contentcolumn untouched, and the Library detail pane's doc/sheet/pdf renderers treat empty content as "nothing was ever stored" — correct for a blank co-edited doc, false for a real upload whose bytes just live out-of-band.Fix
createArtifactDbStore().get()(packages/artifacts-hub/src/routes.ts) now resolves the out-of-band blob viaresolveDownload(already used by the HTML preview route) and inlines it intocontentwhenever it decodes as text — generalizing what/previewalready did fortext/htmlalone to every text-decodable MIME type (Markdown, plain text, CSV, JSON, ...)..docx/.xlsx),contentstays empty — but the Library preview (apps/web/src/pages/library-page.tsx,packages/artifact-ui/src/artifact-renderer.tsx) now tells that apart from a truly-empty artifact viasource.upload.mimeType, and shows an honest "We couldn't read this file's contents for preview" instead of "no content yet."./renderer-kindserver-safe subpath to@corbits/artifact-uiso the hub-side route can reuseisTextDecodableMediaTypeinstead of duplicating the check.Verification
resolvePreviewableContentcovering: text-decodable blob inlined, non-text blob left empty (no garbage decode), inline content never re-fetched, missing blob reference handled.ArtifactRenderertests asserting the honest "couldn't read this file's contents" message replaces "no content yet" only when a real upload is known to back the empty content.SKILL.mdartifact:resolvePreviewableContentrecovers all 15998 stored bytes as readable text where the rawcontentcolumn was empty.bun testgreen inpackages/artifacts-hub(66 tests) andpackages/artifact-ui(80 tests);bun run typecheckclean inpackages/artifacts-hub,packages/artifact-ui, andapps/web;eslintclean on all changed files.Fixes CL-6560.
Test plan
packages/artifacts-hub:bun test— 66 passpackages/artifact-ui:bun test— 80 passapps/web:bun run typecheckclean; targetedbun teston touched files green