Upgrade to React Native 0.86 / Expo SDK 57 (new architecture) - #6064
Upgrade to React Native 0.86 / Expo SDK 57 (new architecture)#6064peachbits wants to merge 37 commits into
Conversation
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
f3dd774 to
0a46981
Compare
|
History cleanup after a review question: commit 2 ("Upgrade to React Native 0.85.3") previously contained a spurious Audited the whole series for more of the same (blob-level revert detection across all commits + exact-line added-then-removed scan, lockfile excluded): this was the only instance. Final tree is bit-identical to the previously validated one, and all 5 commits re-passed the per-commit precommit gate (521/521 tests on commit 1's RN 0.79 base; 517/517 on 0.85). |
0a46981 to
30638ca
Compare
|
🔴→✅ Regression found in review and fixed: the PR was accidentally reverting develop PR #6044 ("Deprecate Botanix to keys-only mode on July 9, 2026") — the Fixed by restoring develop's versions of all 5 files into the upgrade commit — the upgrade legitimately changed zero lines in them, so they now drop out of the PR diff entirely. Verification:
The Botanix July 9 deprecation survives this PR. |
30638ca to
83b07b2
Compare
|
🐛 On-device Android testing found (and fixed) a blocking crash — new commit Symptom: release build on a physical device (OnePlus 5T) crashed the moment the password login scene mounted (tap "Sign in" from the welcome carousel). Root cause: RN 0.85's Android Fabric text measurement throws Fix: clamp animated font sizes to ≥1 (visually identical — the icon containers already collapse to zero width) in the GUI's Verified: rebuilt release APK on the same device — password login scene renders, inputs + eye icon work, zero fatal exceptions. Commit gated: localize/warnings clean, tsc clean, eslint 0 errors, 521/521 tests. Follow-up: edge-login-ui-rn needs the same clamp in its own repo ( |
12195dd to
5a23fed
Compare
|
♻️ Rebased onto current develop (was 67 commits behind and conflicting; now conflict-free). Same 6 commits, same content — mechanical notes:
Also: the edge-login-ui-rn fontSize fix now exists as a proper branch in that repo ( |
5a23fed to
a6c3123
Compare
|
🔁 Retargeted to React Native 0.86.0 / Expo SDK 57 — same 6-commit structure, now a single hop from 0.79.2 to current stable (no intermediate 0.85 in history). What changed in the retarget:
Verification: audits clean (0 develop-window stomps, 0 within-series reverts, coherent prebuilt-free lock); per-commit gates 6/6 at 557/557 (JS surface; post-sweep amendments were iOS-native only, covered by builds); Android release APK builds; iOS builds from source and boots to login on the simulator. On-device Android smoke pending device reconnect. edge-login-ui-rn's clamp branch ( |
a6c3123 to
19a162f
Compare
87373ff to
106f654
Compare
Android ran reanimated 3 via the local `r3-hack` package on the old architecture while iOS ran reanimated 4 on Fabric. Reanimated 4 requires the new architecture, so route both platforms through reanimated 4 / worklets and enable the new architecture on Android: - babel.config.js: always use react-native-worklets/plugin; add api.cache(true) now that the config is static (no platform branch configuring the cache). - metro.config.js: drop the r3-hack Android resolver. - react-native.config.js: drop the reanimated sourceDir override and the worklets Android disable. - package.json: remove the r3-hack dependency; delete scripts/r3-hack. - android/gradle.properties: newArchEnabled=true. - useCarouselGesture: unify the withSpring config to the reanimated-4 algorithm on both platforms (Android previously used the reanimated-3 damping). Also dedupe yaob to ^0.4.0, fixing the nativeIo collision that crashed ZEC/Pirate wallet creation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move the app from React Native 0.79 to 0.86.0 / Expo SDK 57, with both platforms on reanimated v4 and the new architecture. Expo SDK 57 is the release paired with RN 0.86, with React at 19.2. Bumps the RN-ecosystem dependencies together (reanimated 4.5, worklets 0.10, gesture-handler 2.32 per the SDK 57 pin set; TypeScript deliberately held at 5.8.3) and updates the jest preset, worklets resolver, and test snapshots. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Enable newArchEnabled, bump compile/target SDK 35->36, and rewrite settings.gradle for Expo SDK 56 autolinking. Unwrap MainApplication from the ReactNativeHostWrapper removed in SDK 56. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Expo autolinking + new-architecture Podfile (deployment target 16.4 - Expo SDK 57's floor; React Native 0.86 itself only needs 15.1), the ExpoReactNativeFactory AppDelegate, and RCTNewArchEnabled in Info.plist. Includes the build fixes needed under Xcode 26. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
React Native 0.86's Android Fabric text measurement throws IllegalArgumentException ("FontSize should be a positive value") for any Text whose font size is 0 - TextLayoutManager's letterSpacing.isNaN() check unconditionally invokes a getter that validates fontSize > 0. FilledTextInput animates its side-icon sizes to exactly 0 (clear icon on an empty input, left icon when focused), and those sizes feed AnimatedFontIcon's fontSize, so mounting any scene with a text input crashed the app - most visibly the password login scene via edge-login-ui-rn, which shares the same component pattern.
Clamp animated font sizes to a minimum of 1 (visually equivalent: the icon containers already collapse to zero width) in the GUI's AnimatedFontIcon and FilledTextInput, and apply the same one-line clamp to edge-login-ui-rn via patch-package until the fix lands upstream.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
React Native 0.86 ships the equivalent of our old react-native+0.79.2.patch upstream - ShadowTree::commit() now caps optimistic retries at MAX_COMMIT_ATTEMPTS_BEFORE_LOCKING and falls back to an exclusive recursive lock (ReactCommon/react/renderer/mounting/ShadowTree.cpp) - but only behind the preventShadowTreeCommitExhaustion feature flag, which defaults to false. Enable the flag with a 1-line patch so the RN upgrade doesn't silently drop the crash protection. Delete this patch when upstream flips the default. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
These patch releases fix three Android new-architecture regressions found on a physical Android 10 device: send-scene tiles and icon buttons stuck at their initial animation size, a missing address-modal title, and the app viewport staying collapsed after the keyboard was dismissed.
React Native ships this protection default-off. Without it, a runaway ShadowTree commit loop aborts the app in native code with "assertion failed (attempts < 1024)", which reproduced on an Android 10 device while interacting with text inputs. The iOS side of this is a source patch, but Android loads the React Native core from a prebuilt library, so the default cannot be patched there. Override the flag at runtime instead. The override is once-per-process and load() already consumes it, so reset first and re-apply React Native's stable defaults alongside our one change.
The drawer's outside-tap overlay is an Animated.View whose dimming, touchability and stacking are all driven from a reanimated shared value. On Android below 12 under the new architecture those updates never apply, so the overlay never painted its scrim and never captured touches: taps fell through to the scene behind the open drawer and the drawer could not be closed by tapping outside. On those devices only, render a plain View driven by the drawer's discrete open state, sized explicitly because an absolutely positioned view sized only by insets measures 0x0 there. Every other platform keeps the original animated overlay, verified unchanged on an Android 16 emulator. React Navigation 7 makes this same change upstream, so this patch retires when we migrate.
On Android below 12 the blur library falls back to RenderScript, which cannot snapshot content rendered by the new architecture. Instead of the content behind it, it paints a flat gray wash, so modals, the tab bar, scene headers and footers, notification cards and the keyboard-avoiding buttons all rendered washed out or transparent. There is no way to make that blur render correctly, so skip it on those devices and have each host paint a solid background instead. The dark theme's modal color is translucent because it normally sits on top of the blur, so modals get a solid stand-in, and the QR modal gets a plain scrim in place of its blurred underlay. The login-ui patch carries the same fix for its own copies, plus a fix for a development-mode render error where animation worklets captured a Date they cannot serialize.
The auto-login effect runs on mount and disarms itself immediately, but on release builds this scene mounts before the core context reaches the store, so the attempt ran against the placeholder object, threw, and never retried. Bail out until the context is ready and let the effect re-run. Development builds win the race, which is why this only ever showed up in release builds.
View recycling only runs under the new architecture, so enabling it turned this on for the first time. Recycled views arrive still carrying visual properties from their previous use: a button that becomes enabled stays dimmed, and labels render at a stale font size. Both were reproduced on an Android 10 device, on the survey modal's Next button and the wallet name modal's title. Keep recycling off so views render the way they did before the architecture switch. Re-enabling it is a performance follow-up once the property-reset gaps are fixed upstream.
EdgeText asks Android to shrink text to fit its box, with a floor of 65% of the intended size. Under the new architecture that floor is ignored: labels render at a fraction of their size while the text beside them is unaffected, which showed up on the wallet name modal's title and the amount modal's header. Let text truncate rather than shrink on Android, matching what a dozen call sites already opt into individually. Other platforms are unchanged.
Modals deliberately bleed past the bottom of the screen so the sheet never shows a seam above the navigation bar. That overhang sits behind the keyboard, which cut off the bottom of the modal's own content - the text input modal's submit button was only half visible. Drop the overhang while the keyboard is open, the same way SceneWrapper already drops its bottom inset. The drag slop stays, so swipe-to-dismiss is unchanged.
Two problems with how the amount and its currency code were laid out: The input carried a negative margin compensating for extra width that the old architecture added for short values. That extra width is gone, so the compensation pulled the currency code into the digits: '1USD' with one digit, correct spacing from two digits on. The input's width is also measured a render behind its contents, so a value that grows by more than one character at once - 123 becoming 1,234, which also gains a separator - was drawn wider than its box and the leading digits were clipped. Typing past it or deleting back to the same value looked fine, which is what made it look intermittent. Size the field with a matching Text instead, which measures in the same pass as the value it draws, and drop the obsolete margin.
The field echoes a keystroke before it has re-measured, so for one frame the text was wider than its box and slid left, taking the leading digits out of view before settling. A rejected keystroke made it worse: the value never changes, so the box never grows and the echo sat there until it was reverted. Reserve a character of width in the field so a keystroke always has somewhere to land. That reserved space reads as a slightly wider gap before the currency code, which is the trade: the alternative is letting the currency code sit over the reserved space, and then a keystroke briefly draws on top of it.
The Jenkins iOS agents' Xcode upgrade broke expo-modules-jsi 57.0.3 twice over. First, `abs(milliseconds)` in JavaScriptCodable+Date.swift became ambiguous (expo/expo#47957); upstream fixed it in 57.0.5 with `milliseconds.magnitude`, and the existing ~57.0.3 range already allows it, so the lockfile pin moves to 57.0.6 along with the matching pod. Second, the newer Swift rejects SWIFT_RETURNS_RETAINED on the two RuntimeScheduler constructors because the type is not imported as a shared reference. Upstream removed both annotations on their SDK 58 line; the patch mirrors that change exactly and is droppable once a 57.x release picks it up (57.0.6 is currently the newest).
The Jenkins agent's newer Swift rejects EventEmitter's
`nonisolated(unsafe) weak let` captures being sent into the JavaScript
actor ("sending 'emitter' risks causing data races"). Upstream's SDK 58
line already fixed this by boxing the weak reference in the
NonisolatedUnsafeWeakVar wrapper that 57.0.6 ships but does not yet use
here; this patch mirrors that change exactly. No 57.x release carries it
(57.0.14 is byte-identical in this file), so the patch is droppable when
one does.
`deprecated-react-native-prop-types` exists to shim libraries that import PropTypes from react-native; RN 0.86 removed those exports entirely and nothing in the app imports it. `@types/react-native` is stale at 0.71 and obsolete since react-native ships its own types. `react-native-email-link` looks equally unused — it appears in no source file — but it stays: edge-login-ui-rn imports it in PasswordRecoveryActions while declaring it only as a devDependency, so the app has to supply it. Removing it breaks the bundle at password recovery. Fourteen other packages reach us the same way; `react-native-linear-gradient`, `rn-id-blurview`, `react-native-vector-icons` and `react-native-permissions` are the ones that matter for any future dependency cleanup.
react-native-linear-gradient has no codegen spec, so every gradient in the app - cards, buttons, the header, the tab bar, the scene background - was drawn through Fabric's legacy view-manager interop. expo-linear-gradient is a real Fabric component and Expo is already a dependency, so this swap removes a native dependency rather than adding one: edge-login-ui-rn's six gradient scenes migrate through the regenerated patch, which lets react-native-linear-gradient leave package.json entirely (verified on device that removing it beforehand left PinLoginScene throwing "View config not found for component BVLinearGradient"), and the BVLinearGradient pod gives way to ExpoLinearGradient. The props are the same (`colors`, `start`, `end`, `locations`); nothing uses `useAngle`, the one prop Expo lacks. What differs is the typing: Expo wants the color and location arrays to be tuples of two or more, since a gradient with fewer stops has nothing to interpolate. The theme's gradient fields become `GradientColors` to match, and the six scenes that darken the first stop of the asset background build a new tuple instead of mutating a copy. react-native-gifted-charts also reaches for a gradient, but it tries react-native-linear-gradient and falls back to expo-linear-gradient, with both declared optional; the bundle builds and resolves to the Expo one. expo-linear-gradient is mocked in jestSetup because importing it pulls in expo-modules-core, which expects native globals the react-native jest preset doesn't provide. Snapshots move from BVLinearGradient to that mock. Touching these files takes them off the ESLint warnings list, so their pre-existing lint errors are fixed here too.
edge-login-ui-rn asked for react-native-airship ^0.2.9 and patina ^0.1.6 while this app asks for ^0.3.0 and ^0.2.0, so npm installed both — nested copies under edge-login-ui-rn alongside ours. Both packages are UI-layer singletons: airship owns the portal host every modal mounts into, and patina caches themed styles. Two module instances of either is the same class of problem as the duplicate yaob that once cross-wired native IO. edge-login-ui-rn now asks for the same versions, but npm resolves the dependency tree from its published manifest, so that alone won't collapse the duplicates until a release goes out. The overrides make it true today and stay correct afterwards. Both are pure JavaScript, so no native rebuild is involved. Verified the auto-logoff modal still mounts and dismisses through the portal host.
react-native-keyboard-aware-scroll-view has had no release since 2022. It
is pure JavaScript, so it never appeared in a codegen audit, but it drives
its scrolling with findNodeHandle, UIManager.measureInWindow and
UIManager.viewIsDescendantOf - the legacy measurement APIs the new
architecture only serves through a compatibility shim. We already depend on
react-native-keyboard-controller, which ships an equivalent component.
`extraScrollHeight` becomes `bottomOffset`, and the `enableOnAndroid` /
`enableAutomaticScroll` opt-ins go away because the replacement always does
both. Everything else is plain ScrollView props. SendScene2 keeps a ref to
scroll to the end, which is now a plain `ref` rather than `innerRef`, and
takes React Native's `scrollToEnd({ animated })` signature instead of the
old library's positional one.
SurveyModal is the one behavior change: it passed an extraScrollHeight of
-16rem on iOS against +9rem on Android, a hack around the old library
measuring the two platforms differently. bottomOffset means the same thing
on both, so both now pass the 2.75rem every other scene uses.
edge-login-ui-rn makes the same migration in its three keyboard scenes, so
its patch is regenerated here - and renamed to 3.37.2, the version npm
actually resolves, silencing the version-mismatch warning every install
printed. Verified on Android: the address form scrolls a field near the
bottom clear of the keyboard on focus and accepts input. Touching these
files takes them off the ESLint warnings list, so their pre-existing lint
errors are fixed too.
LoginScene has published `global.ReactNativeBlurView` since 2020, when edge-login-ui-rn could not add a native dependency without a breaking release and instead feature-detected a blur component the host snuck to it at runtime (falling back to a dim underlay without one). The reading side was deleted from login-ui in September 2023 (v2.15.0), when its modals started importing rn-id-blurview directly. Nothing in this app, in the installed login-ui lib, or anywhere else in node_modules reads the global today, so the assignment has been write-only for almost three years. The rn-id-blurview import here existed only to feed it.
Under the new architecture the old blur path (rn-id-blurview, Dimezis 2) snapshots the window with a software canvas that renders empty on every Android version - the API < 31 grey wash and a silently transparent sheet on 12+ are the same disease with different symptoms. Modal sheets were see-through over busy scenes, and the chrome tint had been impersonating blur all along. Dimezis 3 fixed the snapshot in hardware but changed the contract: content must be wrapped in an explicit blur target, and whole-window sampling is gone. expo-blur ships that backend as a Fabric-native component, so this adds expo-blur (and its pod) rather than another native dependency. Two targets cover the two kinds of blur surface, shaped by one hard constraint: a blur view must never sit inside its own target, or the renderer recurses computing transforms and overflows the stack (a native libhwui crash). - Modals: the app tree gains one BlurTarget wrapping Main, inside the Airship layer, so ModalBlurBackground (EdgeModal) and the QR modal underlay sample the app content from outside it. login-ui mounts the equivalent target in LoginUiProvider for its own modals, delivered through the regenerated patch. - Chrome: the header, scene footer, tab bar, and notification cards overlay the scene and live inside the app-level target, so each SceneWrapper wraps its content (background dots plus children, excluding the absolutely-positioned footer overlay) in its own target and publishes the ref through a registry while focused. ChromeBlurBackground samples whichever scene is focused, retargeting as navigation changes, and falls back to the long-standing tint when no scene publishes one (login, scenes outside SceneWrapper). The scene footer needs no special casing: with tabs it portals into MenuTabs and without them it is absolutely positioned, so it never sits inside what it samples. Modal backgrounds return to translucent-over-blur on 12+, keeping the solid color below API 31 where no blur implementation can render. iOS keeps its existing whole-window blur, unchanged. Verified on device: the sort modal frosts the wallet list, the security-alerts modal is opaque and legible, the tab bar softly blurs list content scrolling beneath it, and no recursion crash across cold start, tab switches, and stack navigation.
Edge-to-edge draws the window under the status bar, and the Airship layer's safe-area measurement is iOS-only (it measures through React Native's SafeAreaView, a no-op on Android), so dropdown notifications - received transactions, error alerts - slid in underneath the status bar and camera cutout instead of below them. Add the top inset to the dropdown's own padding on Android. iOS already receives it from the Airship layer, so it is excluded there to avoid a doubled gap. login-ui's error dropdown gets the same fix through the regenerated patch.
Two fixes in 6.0.0 target exactly this app's setup: new-architecture detection on React Native 0.77+ and an Android soft exception when the event emitter is touched before initialization (plus Android listener-leak fixes). The breaking changes do not reach us - Flipper support removal (React Native itself dropped Flipper), Flow-to-TypeScript codegen internals, and renames of old-bridge lifecycle APIs the app never calls. Our entire usage is the standard performance mark/measure API in perf.ts.
Both upgrades take the module from bridge interop to codegen under the new architecture. Sound 0.13.0 changes nothing in the API we touch (setCategory, load, play). Haptic-feedback 3.0.0 keeps the default-export trigger() call both this app and edge-login-ui-rn use; its breaking changes are additions (hooks, patterns) and the TurboModule conversion, which is why jest now needs a mock - the import itself demands a native binding. login-ui pins ^1.14.0 until its next release, so an npm override keeps the tree at one copy, the same arrangement airship and patina already use; the login-ui branch bumps its own range in lockstep.
The disable animation's shared value always started at 0 (enabled), and a mount effect then animated it toward the actual disabled prop. An input mounted with disabled=true therefore flashed its enabled look for ~300ms every time its scene appeared - most visibly the spending-limit amount field, whose scene mounts it disabled whenever the limit is switched off. Seed the shared value with the mounted state so the first frame is already correct; later prop changes still animate as before. Fix the same pattern in edge-login-ui-rn's copies of these inputs via the login-ui patch, mirroring an identical commit in that repo.
484672b to
adfaf93
Compare
Regenerate patches/edge-login-ui-rn+3.37.2.patch from the edge-login-ui-rn branch (PR #301) so the app picks up the fixes mirrored there: EdgeText truncating instead of shrinking on Android, EdgeModal dropping its bottom overhang while the keyboard is open (seeded from Keyboard.isVisible), and the animated font-size clamps in both text inputs. This lands as one commit rather than fixups to the matching feature commits because the 3.37.2 patch file postdates them - it was created by the keyboard-controller commit and evolves forward from there. The patch disappears entirely once login-ui releases and the dependency bumps. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
c4e6ae9 to
224c2e7
Compare
A single hop from RN 0.79 / old architecture to RN 0.86 / Expo SDK 57 with the new
architecture enabled on both platforms. SDK 57 is the Expo release paired with RN 0.86,
so the two land together as one upgrade surface.
Android performance (release-build Flashlight benchmarks, OnePlus 5T): scroll jank
7.3% → 2.5%, worst-case scroll FPS 33 → 48, peak scroll CPU −38%, whole-journey CPU −42%
versus the new-arch baseline. Cost: RAM +45% (456 → 662 MB mean) — the expected price of
Fabric plus the modern ecosystem. Raw data and method in
perf/RESULTS.mdon theworkspace, headline numbers in the changelog entry.
iOS: Hermes V1 + React-Core built from source (the prebuilt 0.86 RNCore is compiled
against the non-V1 JSI ABI and dyld-crashes at launch), pinned in the Podfile. ShadowTree
commit-exhaustion protection via a 1-line patch-package flag flip.
Android: new architecture enabled; ShadowTree protection applied at runtime (the
prebuilt core ignores the iOS source patch); Fabric view recycling off (recycled views
arrive with stale visual state); blur dropped below API 31 in favor of solid colors
(RenderScript cannot snapshot Fabric content); drawer outside-tap overlay backported from
react-navigation 7 for devices that cannot animate it.
Fixes along the way: text truncates instead of shrinking illegibly (Fabric ignores
minimumFontScale), modals stay above the keyboard, amount-field clipping/jumping fixed,fontSize-0 crash on animated icons clamped, YOLO auto-login race fixed (dev-only path).
Dependency modernization (same PR)
Replaces legacy-interop UI libraries with Fabric-native equivalents already in the tree,
in lockstep with the matching edge-login-ui-rn PR (the two share these dependencies —
login-ui declares them as devDependencies and relies on the app to install them).
gradient rendered through the legacy view-manager interop). Same props; themes now
declare gradient colors as a tuple of ≥ 2 stops, which the component requires. The old
package is fully removed once login-ui migrates (its six scenes were the last imports).
react-native-keyboard-aware-scroll-view (unmaintained since 2022; positions itself with
findNodeHandle/UIManager measurement APIs that the new architecture only serves through
a shim).
extraScrollHeight→bottomOffset; the Android opt-ins go away. One behaviorchange: SurveyModal's per-platform offset hack collapses to the app-standard 2.75rem —
needs a QA look on both platforms (suppressed in dev builds).
duplicates of two UI singletons (airship owns the modal portal host, patina caches
styles). Aligned versions plus npm
overridesso the dedupe holds until login-ui'snext release.
a way the new architecture renders as empty (gray wash below API 31, fully transparent
above). Modals now blur via expo-blur (Dimezis 3 hardware snapshot, Fabric-native),
sampling an explicit BlurTarget mounted around the app content; below Android 12 the
solid sheet stays, per the accepted decision. Chrome (header, scene footer, tab bar,
notification cards) blurs the focused scene's content via per-scene targets that
SceneWrapper publishes while focused. iOS unchanged.
and an Android event-emitter init race; verified native launch marks still flow
through to JS measures on device.
bridge interop to codegen; haptic 3.x is a TurboModule (login-ui bumps its range in
lockstep, with an npm override holding one copy until its release).
global.ReactNativeBlurViewpublication (login-ui stoppedreading it in v2.15.0),
deprecated-react-native-prop-types,@types/react-native.install).
Deliberately NOT swapped: rn-id-blurview → expo-blur would lose real blur on Android 12+
(expo-blur's Android blur defaults to none; its opt-in method is the one already rejected
for performance and broken-in-modals reasons).
Verified on device (Android): gradients across home/assets/PIN-login, keyboard scroll on
the address form, auto-logoff modal through the portal host. iOS: build + smoke pending
pod install (expo-linear-gradient is a new pod).
Known open (details in the review talking points):
regression; four fixes attempted, likely needs upstream).
useHeaderHeightunderFabric; the v7 migration is the real fix).
in the stacked dependency-modernization PR: real blur on Android 12+ via expo-blur's
Fabric-native backend, solid sheets below. Chrome (header/footer/tab bar/cards)
blurs the focused scene again via per-scene blur targets.
expo-modules-jsi 57.0.3 (type of expression is ambiguous without a type annotation expo/expo#47957); fixed by bumping the lockfile to 57.0.6,
which carries upstream's
milliseconds.magnitudeworkaround.