Skip to content

chore: migrate from react-native-fs to expo-file-system#7428

Draft
janicduplessis wants to merge 2 commits into
developfrom
@janic/expo-fs-dev-screen
Draft

chore: migrate from react-native-fs to expo-file-system#7428
janicduplessis wants to merge 2 commits into
developfrom
@janic/expo-fs-dev-screen

Conversation

@janicduplessis
Copy link
Copy Markdown
Contributor

@janicduplessis janicduplessis commented May 3, 2026

Fixes APP-####

What changed (plus any additional context for devs)

Removes react-native-fs from the app and routes every caller through expo-file-system, which is already pulled in transitively via the expo SDK and is now promoted to a direct dependency. The motivation was twofold: react-native-fs is unmaintained and needed a local patch to survive RN 0.81 (PromiseImpl.reject now rejects null code), and the API surface we use is small and maps cleanly to expo-file-system.

Changes by call site:

  • src/components/DappBrowser/screenshots.ts β€” copyFile/unlink/readDir β†’ copyAsync/deleteAsync({ idempotent: true })/readDirectoryAsync. The orphan-prune path was reshaped slightly: readDirectoryAsync returns plain filename strings, where RNFS returned ReadDirItem objects with a path field, so the file URIs are now built explicitly from documentDirectory + name.
  • src/handlers/cloudBackup.ts β€” writeFile/unlink β†’ writeAsStringAsync/deleteAsync. RNCloudFs's sourcePath.path still expects a POSIX path, so the file:// URI is stripped before the cloud copy.
  • src/model/migrations.ts (migration v16) β€” unlink(path.join(...)) β†’ deleteAsync(URI, { idempotent: true }). cacheDirectory already ends with a trailing slash, so path is no longer needed.
  • src/handlers/pinata.ts β€” RNFS.uploadFiles({...}).promise β†’ FileSystem.uploadAsync(url, fileUri, { uploadType: MULTIPART, ... }). expo-file-system derives the multipart filename from the URI's basename and has no override; to preserve the caller-supplied filename, it's passed through pinataMetadata.name in the form parameters, which Pinata uses for the pin name.
  • src/screens/Diagnostics/helpers/createAndShareStateDumpFile.ts β€” same documentDirectory/writeAsStringAsync/deleteAsync swap. The Android-only RNFS.DownloadDirectoryPath write was redundant with the share sheet that follows and is dropped β€” expo-file-system has no equivalent for the public Downloads folder, but the cross-platform share sheet ("Save to Files", Drive, AirDrop, etc.) already covers the developer-export use case on both platforms.

react-native-fs is removed from package.json; base-64 (its sub-dep) drops out of the lockfile too.

Screen recordings / screenshots

n/a β€” equivalent behaviour, no UI surface change.

What to test

  • DappBrowser screenshots: open and close several browser tabs over a session; verify tab thumbnails appear correctly when switching between tabs and that orphan cleanup still runs (no leftover screenshot files in the document directory after a tab is closed).
  • Cloud backup: trigger an iCloud / Google Drive backup of the wallet and verify the file lands in the cloud and the local document copy is deleted afterwards.
  • Migration v16: install an older build that still writes rainbow-token-list.json / rainbow-token-list-etag.json into the cache dir, then upgrade to this build; verify those files are gone after first launch (or simply that the migration runs without error in a fresh install).
  • Pinata avatar upload: through the ENS profile flow, pick an image and upload it as the avatar; verify the upload succeeds, the IPFS URL resolves to the image, and (if you have access to the Pinata dashboard) the pin's name matches the original filename.
  • Diagnostics state dump: open the Diagnostics screen and trigger "Share state dump"; verify the share sheet opens with the JSON file and that triggering it twice in a row works (no leftover-file errors).

`createAndShareStateDumpFile` is the only caller of `react-native-fs`
that touches the public Android Downloads folder, which has no
expo-file-system equivalent. The Android-only Downloads copy was
redundant β€” the share sheet handles cross-platform export of the
dump JSON via the document directory, which works the same on iOS
and Android.

Swap the four `RNFS` calls for their `expo-file-system` equivalents
(`documentDirectory`, `writeAsStringAsync`, `deleteAsync`) and drop
the `RNFS.DownloadDirectoryPath` branch. The `getInfoAsync`
existence check is also gone β€” `deleteAsync({ idempotent: true })`
already no-ops when the file is missing.

`expo-file-system` is added as a direct dependency at the version
already pulled in transitively through `expo`.
Migrates the four remaining `react-native-fs` callers to the
equivalent `expo-file-system` APIs and removes the package from the
dependency list. `expo-file-system` is already pulled in transitively
via the `expo` SDK and was promoted to a direct dependency in the
preceding commit.

- DappBrowser screenshot store (`screenshots.ts`): `copyFile` β†’
  `copyAsync`, `unlink` β†’ `deleteAsync({ idempotent: true })`,
  `readDir` β†’ `readDirectoryAsync`. The orphan-prune path was
  restructured around filename strings since `readDirectoryAsync`
  returns plain names rather than `ReadDirItem` objects.
- Cloud backup (`cloudBackup.ts`): `writeFile`/`unlink` β†’
  `writeAsStringAsync`/`deleteAsync`. RNCloudFs still wants a POSIX
  path for `sourcePath.path`, so the `file://` URI is stripped
  before handing off.
- Migrations v16 (`migrations.ts`): `unlink(path.join(...))` β†’
  `deleteAsync(URI, { idempotent: true })`. `cacheDirectory` already
  ends with a trailing slash, so `path.join` is no longer needed.
- Pinata upload (`pinata.ts`): `RNFS.uploadFiles({...}).promise` β†’
  `FileSystem.uploadAsync(url, fileUri, { uploadType: MULTIPART, ...})`.
  The caller-supplied `filename` is preserved via
  `pinataMetadata.name` since expo-file-system's multipart Content-
  Disposition derives the filename from the URI's basename and there
  is no override option.

Also renames a stale `screenshotWithRNFSPath` local in the dapp
browser hook to `screenshotWithFullPath`.
@janicduplessis janicduplessis changed the title feat(diagnostics): migrate state-dump helper to expo-file-system chore: migrate from react-native-fs to expo-file-system May 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant