fix(react-native): make expo-file-system a peer dependency - #1795
fix(react-native): make expo-file-system a peer dependency#1795workflowhub26 wants to merge 1 commit into
Conversation
The hard pin "expo-file-system": "18.*.*" forces npm to install a
second, nested copy of expo-file-system in apps on Expo SDK 54+,
where the app itself uses 19.x or newer. Expo autolinking then mixes
the two versions' native code and the app crashes at launch
(NoClassDefFoundError: expo.modules.filesystem.FilePermissionModule).
Moving the dependency to peerDependencies (">=18.0.0") lets the host
app own the version, so only one copy is ever installed.
The new ambient shim (same pattern as react-native-shim.d.ts) keeps
the generated SDK compiling under "npm ci --omit=peer", where peer
packages are not installed.
Fixes appwrite/sdk-for-react-native#114
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Greptile SummaryThe PR moves expo-file-system from a pinned React Native dependency to a host-owned peer and adds a build-only ambient declaration for peer-omitted validation. The widened range, however, accepts versions whose root module no longer provides the generated SDK’s legacy filesystem API.
Confidence Score: 4/5This PR should not merge until the peer compatibility range or generated filesystem import is aligned with expo-file-system 19+, otherwise uploads fail for the Expo versions this change targets. The host-provided 19+ package satisfies the new peer range, but generated upload code still invokes APIs that newer releases expose only through the legacy entrypoint, with the ambient shim hiding the mismatch during compilation. Files Needing Attention: templates/react-native/package.json.twig, templates/react-native/src/expo-file-system-shim.d.ts.twig Important Files Changed
Prompt To Fix All With AI### Issue 1
templates/react-native/package.json.twig:48
**Peer range exposes legacy API break**
When an Expo SDK 54+ application supplies `expo-file-system` 19+, the new peer range accepts that implementation while generated services still import legacy filesystem APIs from the package root, causing multipart file uploads to fail at runtime.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "fix(react-native): make expo-file-system..." | Re-trigger Greptile |
| }, | ||
| "peerDependencies": { | ||
| "expo": "*", | ||
| "expo-file-system": ">=18.0.0", |
There was a problem hiding this comment.
Peer range exposes legacy API break
When an Expo SDK 54+ application supplies expo-file-system 19+, the new peer range accepts that implementation while generated services still import legacy filesystem APIs from the package root, causing multipart file uploads to fail at runtime.
Knowledge Base Used: Templates
Prompt To Fix With AI
This is a comment left during a code review.
Path: templates/react-native/package.json.twig
Line: 48
Comment:
**Peer range exposes legacy API break**
When an Expo SDK 54+ application supplies `expo-file-system` 19+, the new peer range accepts that implementation while generated services still import legacy filesystem APIs from the package root, causing multipart file uploads to fail at runtime.
**Knowledge Base Used:** [Templates](https://app.greptile.com/appwrite/-/custom-context/knowledge-base/appwrite/sdk-generator/-/docs/templates.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.|
Author here. The automated review is right that the peer range and the import path have to move together, and I'd rather fix that than argue it. Adding the specific evidence, because most of it is already committed in this repo. 1.
|
| root import | /legacy import |
|
|---|---|---|
| 18.x | works | subpath does not exist yet |
| 19+ / 5x | throws at runtime | works |
expo-file-system/legacy was created by the same change that made the modern API the default, so it is not available in the 18.x half of the proposed range. That means #1691 (switch the import to /legacy) and this PR (widen the peer) are each half a fix, and even applied together they don't produce a consistent state across >=18.0.0.
Options
Happy to implement whichever you prefer:
- (a) peer floor at the SDK-54-aligned version +
/legacyimport, dropping 18.x. Simplest, and matches what Expo 54+ users actually have installed. - (b) keep
>=18.0.0and resolve at runtime — tryexpo-file-system/legacy, fall back to the root. Covers both, at the cost of a try/catch in generated code. - (c) peer
>=18.0.0 <19.0.0+ root import. Consistent, but leaves Expo 54+ users where they are today.
I'd drop the .d.ts shim in all three — it only exists to make the current inconsistency compile.
For what it's worth, I've been running (a) against react-native-appwrite@0.34.0 via patch-package in an Expo SDK 57 app, together with an overrides pin, and both pieces are needed today. Glad to reshape this PR toward whichever option you'd take, or to close it if you'd rather solve it differently.
What does this PR do?
Moves the React Native SDK's
expo-file-systemdependency from a hard pin ("18.*.*") to a peer dependency (">=18.0.0"), and adds an ambient type shim so the generated SDK still builds when peers are omitted.Fixes appwrite/sdk-for-react-native#114.
Why
react-native-appwritecurrently declares:Apps on Expo SDK 54+ ship
expo-file-system19.x or newer, so npm installs a second, nested copy of 18.x undernode_modules/react-native-appwrite/. Expo autolinking then mixes the two versions' native code and the app crashes at launch:With a peer dependency, the host app owns the version and only one copy is ever installed.
">=18.0.0"deliberately has no upper bound — an upper bound would recreate this exact problem on the next Expo SDK release. Apps on older Expo SDKs are unaffected (their 18.x satisfies the range), and npm 7+ auto-installs missing peers for apps that do not listexpo-file-systemthemselves.Changes
templates/react-native/package.json.twig—expo-file-systemmoved fromdependenciestopeerDependenciesas">=18.0.0".templates/react-native/src/expo-file-system-shim.d.ts.twig(new) — ambient module declaration covering exactly the API surface the SDK uses (readAsStringAsync,writeAsStringAsync,EncodingType,cacheDirectory). Same pattern as the existingreact-native-shim.d.ts.twig: without it,npm ci --omit=peer && npm run build(as run invalidation.yml) could no longer resolve the import. Like the react-native shim it is not part of the publishedfiles, so consumers keep getting real types from their ownexpo-file-systeminstall.src/SDK/Language/ReactNative.php— registers the new template file.templates/react-native/package-lock.json.twig— regenerated withnpm install --package-lock-only; the diff is exactly the moved dependency plus the"peer": truemarker on the existing entry.Verification
FileSystemusage (mirroringservices/template.ts.twiglines 200–208) typechecks against the shim alone withtsc --strict5.9.3 and noexpo-file-systeminstalled — the situationnpm ci --omit=peerproduces.overridesentry to force a singleexpo-file-systemcopy; without it,expo-doctorflags the duplicate and a native Android build crashes at launch exactly as described in Added automated deployment to NPM #114.Related
appwrite/sdk-for-react-native#112 is adjacent but separate: the SDK calls the legacy FileSystem API, which newer
expo-file-systemversions expose viaexpo-file-system/legacy. This PR does not change runtime behavior — it only stops the forced second native copy.🤖 Generated with Claude Code