@nitida/asset-uploader-expo
v0.2.1
Published
nitida native upload primitives (iOS URLSession + Android WorkManager). The JS API mirrors @nitida/asset-uploader-web's UploadTask, so call sites are identical across web and mobile.
Downloads
348
Maintainers
Readme
@nitida/asset-uploader-expo
Native upload primitives for the nitida asset pipeline.
JS API mirrors @nitida/asset-uploader-web
so call sites are identical:
import { UploadTask } from "@nitida/asset-uploader-expo";
const task = new UploadTask({
file: { uri, mime: "image/jpeg" }, // from expo-image-picker
tenantCode: "epa-cr",
endpoint: "https://your-app.com/api/asset",
});
task.on("progress", ({ ratio }) => console.log(`${(ratio * 100).toFixed(0)}%`));
const { assetId, deduped } = await task.start();Why a native module
| Concern | JS-only fetch | Native (this module) |
|---|---|---|
| Hash a 1 GB file | blocks JS thread | streaming on a background queue |
| Upload survives kill -9 | ❌ | ✅ (URLSession backgroundSessionConfiguration / WorkManager) |
| Upload survives app suspend | unreliable | ✅ |
| Multipart resume after relaunch | manual state in JS | persisted natively, surfaced via listResumableSessions() |
Installation
bun add @nitida/asset-uploader-expoIn app.json:
{
"expo": {
"plugins": ["@nitida/asset-uploader-expo"]
}
}The plugin patches the host AppDelegate to forward iOS background URLSession events.
Then prebuild:
npx expo prebuild --clean
npx expo run:ios # or: npx expo run:androidStatus
- ✅ JS facade (
UploadTask) and types - ✅ iOS native: SHA-256, stat, single-shot PUT via background URLSession, multipart parts, cancel, resume listing, AppDelegate hook
- 🚧 Android native: SHA-256 + stat work; PUT/PUT-part throw
NotImplementedErroruntil the next iteration brings the WorkManager-backed uploader
Architecture notes
The Expo Module is intentionally thin:
- API calls (presign, complete, process) stay in JS — they're short and don't need background survival.
- Only the bytes-on-the-wire path goes native, where it benefits most from OS-level scheduling.
