Skip to content

@gj-kit/expo-media core concepts

An upload with no size limit, or an iCloud download nobody asked for, is a compile error.

Expo media failures rarely look like failures. On iOS 26 FileSystem.uploadAsync ends the process while it is starting an upload, so no promise ever rejects and no retry fires; the localUri MediaLibrary hands back points inside the photo library rather than your app container, so it passes stat and then kills URLSession mid-upload. Android still reports the original fileSize after a quality<1 re-encode, so the presigned size and the bytes storage actually receives disagree.

A selected asset is not always upload-safe

Section titled “A selected asset is not always upload-safe”

Device-library URIs may not outlive the uploader. The adapter boundary makes durable staging and cleanup an explicit application decision.

A network failure can mean uploaded, possibly-uploaded, or never reached storage. Public recovery metadata preserves that distinction without leaking URLs.

  • Unlimited uploads must be spelled out — createMediaKit({ api }) does not compile: limits is required, and Number.POSITIVE_INFINITY is rejected, so unlimited is written 'server-enforced'.
  • duplicate cannot be forgotten — UploadResult.duplicate is required rather than optional, because a missing flag reads as “newly created” and the cancel path then deletes the user’s older photo.
  • Whoever copies owns the cleanup — createDeviceLibrary will not compile without staging, so the factory that materializes cache copies of device photos always carries the StagingCache.cleanup that deletes them.
  • iCloud downloads never default on — adapter.getAssetInfo('id') is a compile error: the second argument is required and carries downloadFromNetwork, so the caller decides on every call and no adapter can quietly inherit the legacy default of true that started cellular transfers.
  • Peer isolation is a CI assertion — The dist-peer-graph guard re-extracts each entry’s external specifiers from the built output across browser/node/native by ESM/CJS; ./core, ./image/pure, ./web and ./testing resolve zero peers.

Never expose presigned URLs or native URI details in public errors. Keep cleanup authorization and attachment transactions in the consuming application.

Continue with the two verified recipes.