Fix(assets): attached files land in assets/, and uploads are no longer corrupted - #15
Open
adibhanna wants to merge 1 commit into
Open
Fix(assets): attached files land in assets/, and uploads are no longer corrupted#15adibhanna wants to merge 1 commit into
adibhanna wants to merge 1 commit into
Conversation
…r corrupted Both bugs were reported against the Android app, which carries the same bridge code; this app had them identically, so it gets the same fix. On a LOCAL vault, attaching a file wrote it to the vault ROOT, next to the notes, and linked it with a hand-built `'../'.repeat(depth)` path, so a note in a folder got ``. Paste already wrote to `assets/`, and so did the cloud vault. Desktop had the same bug and fixed it in ZenNotes#377; the port here was missed. Attach now writes to `assets/` and links by vault-relative path, an image as `![[assets/pic.jpg]]`, matching paste and the cloud vault. On a SELF-HOSTED vault, every uploaded attachment arrived corrupt. The upload hand-built its multipart body as one string and marked the file part `Content-Transfer-Encoding: base64`. That header is a MIME construct: RFC 7578 dropped it from multipart/form-data and Go's mime/multipart ignores it, so the server wrote the base64 TEXT to disk as the file's bytes, a third larger than the original and unreadable by anything. The bytes must stay base64 to cross the native bridge at all, since a CapacitorHttp string body is written out as UTF-8 and mangles anything above 0x7F. `dataType: 'formData'` is the supported way through: CapacitorUrlRequest.getRequestDataFromFormData decodes a `base64File` entry and writes the raw bytes into the part, matching Android. The sibling direct-object upload already used the same mechanism with `dataType: 'file'`. Verified against the real Go server by posting both body shapes: the old one stored 638352 bytes beginning `iVBORw0K`, the base64 text of the PNG, and the new one stored 478762 bytes with the same sha256 as the original. Claude-Session: https://claude.ai/code/session_01AYTRixg5TJmxn2j6FCqfUD
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.
Both bugs were reported against the Android app, which carries the same bridge code. This app had them identically, so it gets the same fix. Android side: ZenNotes/zennotesandroid#41.
Local vault: the file went to the vault root
importDroppedFileasked for a unique name in'', the vault root, wrote the file there, and hand-built the link as'../'.repeat(depth) + filename, so a note in a folder got. Paste already wrote toassets/, and so did the cloud vault.Desktop had this exact bug and fixed it in ZenNotes#377; the port here was missed.
Now:
assets/, linked by vault-relative path, an image as![[assets/pic.jpg]].Self-hosted vault: every upload arrived corrupt
The upload hand-built its multipart body as one string and marked the file part
Content-Transfer-Encoding: base64. RFC 7578 dropped that header frommultipart/form-dataand Go'smime/multipartignores it, so the server wrote the base64 text to disk as the file's bytes: right name, about a third larger, unreadable by anything.The bytes must stay base64 to cross the native bridge, since a CapacitorHttp string body is written out as UTF-8 and mangles anything above 0x7F.
dataType: 'formData'is the supported route:CapacitorUrlRequest.getRequestDataFromFormDatadecodes abase64Fileentry and writes the raw bytes into the part, exactly matching the Android layer. The sibling direct-object upload already used the same mechanism withdataType: 'file'.Proven against the real Go server
iVBORw0K(base64 text)\x89PNGNotes
imported-assets.tsso they can be unit-tested:vault-corecannot be loaded bynode --testbecause it reaches@shared/*through a Vite alias. It re-exports them, so every existing importer is untouched.npm run typecheckclean,npm test25/25,npm run buildsucceeds.