feat: support string and file-URI attachments for React Native#78
Conversation
Widens BugSplatAttachment.data to also accept:
- string β appended as-is, avoids needlessly wrapping text in a Blob
(which React Native's FormData polyfill can't serialize).
- BugSplatFileRef ({ uri, type? }) β React Native's file-upload shape,
used by expo-image-picker, react-native-view-shot, etc. Lets RN's
fetch stream the file from disk instead of loading it into JS memory.
Refactors the duplicated attachment loop in post()/postFeedback() into
a single appendAttachment() helper that branches on the data shape.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR expands the attachment API to support React Native-friendly attachment shapes and centralizes multipart attachment serialization so that post() and postFeedback() handle each runtimeβs FormData capabilities correctly.
Changes:
- Widen
BugSplatAttachment.datato acceptstringandBugSplatFileRef({ uri, type? }) in addition toBlobandUint8Array. - Refactor attachment appending into a shared
appendAttachment()helper used by bothpost()andpostFeedback(). - Add unit tests covering all
appendAttachment()branches.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/index.ts | Exports the new BugSplatFileRef type from the public entrypoint. |
| src/bugsplat.ts | Adds appendAttachment() and replaces duplicated attachment append loops in post()/postFeedback(). |
| src/bugsplat-options.ts | Extends attachment type definitions and documents the supported attachment data shapes. |
| spec/bugsplat.spec.ts | Adds focused tests for the new appendAttachment() helper behavior. |
π‘ Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Appending a plain string to FormData with a filename arg still produces
a regular form field per spec β the filename is ignored and the server
never sees it as a file upload. That broke componentStack.txt: POSTs
succeeded but BugSplat didn't surface the attachment.
Wrap strings per platform so the multipart part gets a filename header:
- Browser: new Blob([data], { type: 'text/plain' }) + 3-arg append.
- React Native: encode as a base64 data URI inside the { uri, type, name }
shape that RN's fetch uploads as a file. Avoids real Blob objects which
RN's FormData polyfill can't serialize.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Callers that have text to upload (like bugsplat-react's componentStack) should decide how to wrap it for their environment β Blob on web, BugSplatFileRef with a data URI on React Native. Handling that inside the SDK pulled in runtime-detection code for something only one consumer actually cares about. Keeping the union to `Blob | Uint8Array | BugSplatFileRef` leaves the SDK with one straight-line branch per shape and no platform checks. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds React Nativeβfriendly attachment support by allowing attachments to be provided as file URIs, and centralizes multipart attachment appending logic in one helper.
Changes:
- Extends
BugSplatAttachment.datato supportBugSplatFileRef({ uri: string; type?: string }) for React Native file uploads. - Introduces
appendAttachment()to handleBlob,Uint8Array, andBugSplatFileRefattachment shapes and refactorspost()/postFeedback()to use it. - Adds unit tests covering the new attachment-appending behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/index.ts | Re-exports the new BugSplatFileRef type from the public entrypoint. |
| src/bugsplat.ts | Adds appendAttachment() helper and switches both posting methods to use it. |
| src/bugsplat-options.ts | Defines BugSplatFileRef and widens BugSplatAttachment.data union to include it. |
| spec/bugsplat.spec.ts | Adds tests for appendAttachment() across supported attachment shapes. |
π‘ Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Wrapping `data.buffer` uploaded the entire underlying ArrayBuffer even when the Uint8Array was a subarray view (non-zero byteOffset or shorter byteLength), which could corrupt the attachment or leak unrelated bytes from the caller's buffer. Pass the view itself to Blob so it uses the view's byteOffset and byteLength. Adds a regression test that constructs a subarray view into a larger buffer and asserts only the viewed bytes make it into the uploaded Blob. Also renames the file-ref test that said "omits type" but asserted `type: undefined` β it handles a missing type, it doesn't omit the field. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
BugSplatFileRef({ uri: string; type?: string }) to theBugSplatAttachment.dataunion so React Native consumers β@bugsplat/expo, bare RN β can upload files by URI (whatexpo-image-picker,react-native-view-shot,expo-screen-capture, etc. return). RN's fetch streams the file from disk at multipart-assembly time; no need to read it into JS memory.post()andpostFeedback()into a single exportedappendAttachment()helper that branches on the shape ofdata. No platform detection in the SDK β callers provide the shape their runtime expects.Attachment data shapes
Blobbody.append(filename, blob, filename)β multipart file part (browser)Uint8ArrayBlobfirst, then appended the same way (browser)BugSplatFileRef({ uri, type? })body.append(filename, { uri, type, name }, filename)β RN's fetch streams the URIUsage
Text attachments like a component stack are produced by the consumer in whatever shape their runtime needs (e.g.
new Blob([text], { type: 'text/plain' })on web, or adata:text/plain;base64,...URI inside a FileRef on RN). The SDK does not handle text specifically β see the paired change in bugsplat-react#21.Test plan
npm testβ 33 tests pass, including 4 newappendAttachmenttests (Blob, Uint8Array, FileRef, FileRef without type)npm run buildβ clean CJS + ESM@bugsplat/expoexample app on an Android emulator (Pixel 7 API 35): `` catches a render error, client POSTs to BugSplat, server returns 200 with `crash_id`, and `componentStack.txt` shows up as a real file attachment in the BugSplat dashboard.Ship sequence
After this merges + publishes as `9.1.0`:
π€ Generated with Claude Code