From a8009888a2c8fd12d137824bacbbab4bc7be0e48 Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Tue, 19 May 2026 16:54:13 +0200 Subject: [PATCH 1/2] Pin react-native-onyx to PR #787 head for cache-first mergeCollectionWithPatches Bumps react-native-onyx to the head of Expensify/react-native-onyx#787, which makes mergeCollectionWithPatches cache-first (matches every other Onyx write method): cache + subscribers are updated synchronously before the storage write is issued, so subscribers still reflect the merged data when the storage write fails (e.g. IDB corruption). Fixes #90634 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index a3bb84bbe7db..9aeadf749683 100644 --- a/package-lock.json +++ b/package-lock.json @@ -115,7 +115,7 @@ "react-native-localize": "^3.5.4", "react-native-nitro-modules": "0.35.0", "react-native-nitro-sqlite": "9.6.0", - "react-native-onyx": "3.0.71", + "react-native-onyx": "git+https://github.com/Expensify/react-native-onyx.git#42b796d64f92b8122c1e545adb6aac587df7a787", "react-native-pager-view": "8.0.0", "react-native-pdf": "7.0.2", "react-native-permissions": "^5.4.0", @@ -34993,9 +34993,9 @@ } }, "node_modules/react-native-onyx": { - "version": "3.0.71", - "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-3.0.71.tgz", - "integrity": "sha512-q84y7aULjoRtQMjLP7fXYtI0nDROyfCgSKHEgZNHBwSvSogOEbGbsHw9qGm6jFIjIoOJf6Hzd3+FnIrFu+WVEQ==", + "version": "3.0.75", + "resolved": "git+ssh://git@github.com/Expensify/react-native-onyx.git#42b796d64f92b8122c1e545adb6aac587df7a787", + "integrity": "sha512-JkbO9379kCM8OluhHM58lhtm299wCsAQmOUJG1WZMe3/6Vxe2Q5JKnIdj3Sk2+mWwx0bv40ocdBYpBOUoGK6qQ==", "license": "MIT", "dependencies": { "ascii-table": "0.0.9", diff --git a/package.json b/package.json index 5f30885c1c47..3508c4c6d23b 100644 --- a/package.json +++ b/package.json @@ -179,7 +179,7 @@ "react-native-localize": "^3.5.4", "react-native-nitro-modules": "0.35.0", "react-native-nitro-sqlite": "9.6.0", - "react-native-onyx": "3.0.71", + "react-native-onyx": "git+https://github.com/Expensify/react-native-onyx.git#42b796d64f92b8122c1e545adb6aac587df7a787", "react-native-pager-view": "8.0.0", "react-native-pdf": "7.0.2", "react-native-permissions": "^5.4.0", From 9fd1811bbfc52a25949b0efab5341b0ee4efce23 Mon Sep 17 00:00:00 2001 From: eliran goshen Date: Wed, 20 May 2026 14:34:01 +0200 Subject: [PATCH 2/2] Remove obsolete react-native-onyx patch reverting Onyx #770 The patch reverted Onyx PR #770 locally. Onyx PR #785 merged the canonical upstream revert, and the SHA bump in this PR (42b796d64f92b8122c1e545adb6aac587df7a787) is branched off Onyx main after #785 -- so the lines the patch tries to delete are already gone, causing patch-package to fail on apply. Deletes the patch file and clears its details.md entry. Behavior is unchanged: the same revert is now in upstream Onyx. Related: https://github.com/Expensify/App/issues/86181 --- patches/react-native-onyx/details.md | 10 +-- .../react-native-onyx+3.0.71.patch | 67 ------------------- 2 files changed, 1 insertion(+), 76 deletions(-) delete mode 100644 patches/react-native-onyx/react-native-onyx+3.0.71.patch diff --git a/patches/react-native-onyx/details.md b/patches/react-native-onyx/details.md index 765902c6dd6c..839eda61743e 100644 --- a/patches/react-native-onyx/details.md +++ b/patches/react-native-onyx/details.md @@ -1,11 +1,3 @@ # `react-native-onyx` patches -### [react-native-onyx+3.0.71.patch](react-native-onyx+3.0.71.patch) - -- Reason: - - > Reverts [Onyx PR #770 (the subscription-side skip for skippable collection member ids in subscribeToKey)](https://github.com/Expensify/react-native-onyx/pull/770) and the line [PR #779](https://github.com/Expensify/react-native-onyx/pull/779) added to work around [PR #770](https://github.com/Expensify/react-native-onyx/pull/770)'s silent-no-callback contract. - -- Upstream PR/issue: https://github.com/Expensify/react-native-onyx/pull/785 -- E/App issue: https://github.com/Expensify/App/issues/86181 -- PR Introducing Patch: https://github.com/Expensify/App/pull/90764 \ No newline at end of file +_No active patches._ \ No newline at end of file diff --git a/patches/react-native-onyx/react-native-onyx+3.0.71.patch b/patches/react-native-onyx/react-native-onyx+3.0.71.patch deleted file mode 100644 index 90666509eba5..000000000000 --- a/patches/react-native-onyx/react-native-onyx+3.0.71.patch +++ /dev/null @@ -1,67 +0,0 @@ -diff --git a/node_modules/react-native-onyx/dist/OnyxUtils.js b/node_modules/react-native-onyx/dist/OnyxUtils.js -index de56f94..495d378 100644 ---- a/node_modules/react-native-onyx/dist/OnyxUtils.js -+++ b/node_modules/react-native-onyx/dist/OnyxUtils.js -@@ -868,24 +868,6 @@ function subscribeToKey(connectOptions) { - const subscriptionID = lastSubscriptionID++; - callbackToStateMapping[subscriptionID] = mapping; - callbackToStateMapping[subscriptionID].subscriptionID = subscriptionID; -- // If the subscriber is attempting to connect to a collection member whose ID is skippable (e.g. "undefined", "null", etc.) -- // we suppress wiring the subscription fully to avoid unnecessary callback emissions such as for "report_undefined". -- // We still return a valid subscriptionID so callers can disconnect safely. -- try { -- const skippableIDs = getSkippableCollectionMemberIDs(); -- if (skippableIDs.size) { -- const [, collectionMemberID] = OnyxKeys_1.default.splitCollectionMemberKey(mapping.key); -- if (skippableIDs.has(collectionMemberID)) { -- // Clean up the provisional mapping to avoid retaining unused subscribers. -- OnyxCache_1.default.addNullishStorageKey(mapping.key); -- delete callbackToStateMapping[subscriptionID]; -- return subscriptionID; -- } -- } -- } -- catch (e) { -- // Not a collection member key, proceed as usual. -- } - // When keyChanged is called, a key is passed and the method looks through all the Subscribers in callbackToStateMapping for the matching key to get the subscriptionID - // to avoid having to loop through all the Subscribers all the time (even when just one connection belongs to one key), - // We create a mapping from key to lists of subscriptionIDs to access the specific list of subscriptionIDs. -@@ -1394,12 +1376,6 @@ function logKeyChanged(onyxMethod, key, value, hasChanged) { - function logKeyRemoved(onyxMethod, key) { - Logger.logInfo(`${onyxMethod} called for key: ${key} => null passed, so key was removed`); - } --/** -- * Getter - returns the callback to state mapping, useful in test environments. -- */ --function getCallbackToStateMapping() { -- return callbackToStateMapping; --} - /** - * Clear internal variables used in this file, useful in test environments. - */ -@@ -1458,6 +1434,5 @@ const OnyxUtils = { - setWithRetry, - multiSetWithRetry, - setCollectionWithRetry, -- getCallbackToStateMapping, - }; - exports.default = OnyxUtils; -diff --git a/node_modules/react-native-onyx/dist/useOnyx.js b/node_modules/react-native-onyx/dist/useOnyx.js -index 9213cff..2e48c73 100644 ---- a/node_modules/react-native-onyx/dist/useOnyx.js -+++ b/node_modules/react-native-onyx/dist/useOnyx.js -@@ -220,12 +220,8 @@ function useOnyx(key, options, dependencies = []) { - newValueRef.current = null; - sourceValueRef.current = undefined; - resultRef.current = [undefined, { status: (options === null || options === void 0 ? void 0 : options.initWithStoredValues) === false ? 'loaded' : 'loading' }]; -+ shouldGetCachedValueRef.current = true; - } -- // Force a cache re-read on every (re)subscription so any side effects from -- // subscribeToKey (e.g. addNullishStorageKey for skippable collection member ids) -- // are reflected in the next getSnapshot. Resetting this flag does not change -- // resultRef by itself, so it doesn't cause an extra mount render. -- shouldGetCachedValueRef.current = true; - hasMountedRef.current = true; - isConnectingRef.current = true; - onStoreChangeFnRef.current = onStoreChange;