diff --git a/package-lock.json b/package-lock.json index 3c4336da1fc..fd713735351 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3854,6 +3854,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -75614,6 +75615,7 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/react-native-collapsible-tab-view/-/react-native-collapsible-tab-view-8.0.1.tgz", "integrity": "sha512-/MRimYn4FB4Dzmypy0J976FVZeX9OEOyFR3fogO68YDHyleSEEgVI2ecrcbtJ4jC8LPT0weDhJPtUQtWtzlQ8A==", + "license": "MIT", "dependencies": { "use-deep-compare": "^1.1.0" }, @@ -75891,34 +75893,6 @@ "version": "1.0.0", "license": "MIT" }, - "node_modules/react-native-reanimated": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.1.6.tgz", - "integrity": "sha512-F+ZJBYiok/6Jzp1re75F/9aLzkgoQCOh4yxrnwATa8392RvM3kx+fiXXFvwcgE59v48lMwd9q0nzF1oJLXpfxQ==", - "license": "MIT", - "dependencies": { - "react-native-is-edge-to-edge": "^1.2.1", - "semver": "7.7.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0", - "react": "*", - "react-native": "*", - "react-native-worklets": ">=0.5.0" - } - }, - "node_modules/react-native-reanimated/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/react-native-safe-area-context": { "version": "5.6.2", "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.6.2.tgz", @@ -76028,48 +76002,6 @@ "react-native": "*" } }, - "node_modules/react-native-worklets": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.6.1.tgz", - "integrity": "sha512-URca8l7c7Uog7gv4mcg9KILdJlnbvwdS5yfXQYf5TDkD2W1VY1sduEKrD+sA3lUPXH/TG1vmXAvNxCNwPMYgGg==", - "license": "MIT", - "dependencies": { - "@babel/plugin-transform-arrow-functions": "^7.0.0-0", - "@babel/plugin-transform-class-properties": "^7.0.0-0", - "@babel/plugin-transform-classes": "^7.0.0-0", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.0.0-0", - "@babel/plugin-transform-optional-chaining": "^7.0.0-0", - "@babel/plugin-transform-shorthand-properties": "^7.0.0-0", - "@babel/plugin-transform-template-literals": "^7.0.0-0", - "@babel/plugin-transform-unicode-regex": "^7.0.0-0", - "@babel/preset-typescript": "^7.16.7", - "convert-source-map": "^2.0.0", - "semver": "7.7.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0", - "react": "*", - "react-native": "*" - } - }, - "node_modules/react-native-worklets/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "license": "MIT" - }, - "node_modules/react-native-worklets/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/react-native-zip-archive": { "version": "7.0.1", "license": "MIT", @@ -122989,7 +122921,7 @@ "react-native-qrcode-svg": "6.2.0", "react-native-radial-gradient": "1.1.4", "react-native-randombytes": "3.6.1", - "react-native-reanimated": "4.1.6", + "react-native-reanimated": "~3.19.5", "react-native-restart": "0.0.27", "react-native-safe-area-context": "^5.2.0", "react-native-screens": "^4.10.0", @@ -123003,7 +122935,6 @@ "react-native-video": "6.18.0", "react-native-view-shot": "3.8.0", "react-native-webview": "^13.14.1", - "react-native-worklets": "0.6.1", "react-native-zip-archive": "7.0.1", "react-qr-code": "2.0.18", "react-redux": "8.0.5", @@ -123493,7 +123424,6 @@ "version": "7.26.8", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.26.8.tgz", "integrity": "sha512-OmGDL5/J0CJPJZTHZbi2XpO0tyT2Ia7fzpW5GURwdtp2X3fMmN8au/ej6peC/T33/+CRiIpA8Krse8hFGVmT5Q==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.26.5" }, @@ -125523,6 +125453,16 @@ "version": "4.3.3", "license": "MIT" }, + "packages/mobile/node_modules/react-native-is-edge-to-edge": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.1.7.tgz", + "integrity": "sha512-EH6i7E8epJGIcu7KpfXYXiV2JFIYITtq+rVS8uEb+92naMRBdxhTuS8Wn2Q7j9sqyO0B+Xbaaf9VdipIAmGW4w==", + "license": "MIT", + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "packages/mobile/node_modules/react-native-linear-gradient": { "version": "2.8.3", "license": "MIT", @@ -125589,6 +125529,37 @@ "react-native-svg": "^13.2.0" } }, + "packages/mobile/node_modules/react-native-reanimated": { + "version": "3.19.5", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.19.5.tgz", + "integrity": "sha512-bd4AwIkBAaY4BjrgpSoKjEaRG/tXD756F5nGuiH5IMBSKN8tRdUEA8hWZCyIo/R6/kha/tVSoCqodVUACh7ZWw==", + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-arrow-functions": "^7.0.0-0", + "@babel/plugin-transform-class-properties": "^7.0.0-0", + "@babel/plugin-transform-classes": "^7.0.0-0", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.0.0-0", + "@babel/plugin-transform-optional-chaining": "^7.0.0-0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0-0", + "@babel/plugin-transform-template-literals": "^7.0.0-0", + "@babel/plugin-transform-unicode-regex": "^7.0.0-0", + "@babel/preset-typescript": "^7.16.7", + "convert-source-map": "^2.0.0", + "invariant": "^2.2.4", + "react-native-is-edge-to-edge": "1.1.7" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0", + "react": "*", + "react-native": "*" + } + }, + "packages/mobile/node_modules/react-native-reanimated/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, "packages/mobile/node_modules/react-native-restart": { "version": "0.0.27", "license": "MIT", diff --git a/packages/mobile/ios/Podfile.lock b/packages/mobile/ios/Podfile.lock index 4d10400ee3c..2f699902536 100644 --- a/packages/mobile/ios/Podfile.lock +++ b/packages/mobile/ios/Podfile.lock @@ -2140,7 +2140,7 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - RNReanimated (4.1.6): + - RNReanimated (3.19.5): - DoubleConversion - glog - hermes-engine @@ -2162,10 +2162,10 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNReanimated/reanimated (= 4.1.6) - - RNWorklets + - RNReanimated/reanimated (= 3.19.5) + - RNReanimated/worklets (= 3.19.5) - Yoga - - RNReanimated/reanimated (4.1.6): + - RNReanimated/reanimated (3.19.5): - DoubleConversion - glog - hermes-engine @@ -2187,10 +2187,9 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNReanimated/reanimated/apple (= 4.1.6) - - RNWorklets + - RNReanimated/reanimated/apple (= 3.19.5) - Yoga - - RNReanimated/reanimated/apple (4.1.6): + - RNReanimated/reanimated/apple (3.19.5): - DoubleConversion - glog - hermes-engine @@ -2212,32 +2211,8 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNWorklets - Yoga - - RNScreens (4.18.0): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2024.11.18.00) - - RCTRequired - - RCTTypeSafety - - React-Core - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-ImageManager - - React-NativeModulesApple - - React-RCTFabric - - React-RCTImage - - React-rendererdebug - - React-utils - - ReactCodegen - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - RNScreens/common (= 4.18.0) - - Yoga - - RNScreens/common (4.18.0): + - RNReanimated/worklets (3.19.5): - DoubleConversion - glog - hermes-engine @@ -2249,17 +2224,19 @@ PODS: - React-Fabric - React-featureflags - React-graphics + - React-hermes - React-ImageManager + - React-jsi - React-NativeModulesApple - React-RCTFabric - - React-RCTImage - React-rendererdebug - React-utils - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core + - RNReanimated/worklets/apple (= 3.19.5) - Yoga - - RNShare (12.2.1): + - RNReanimated/worklets/apple (3.19.5): - DoubleConversion - glog - hermes-engine @@ -2271,7 +2248,9 @@ PODS: - React-Fabric - React-featureflags - React-graphics + - React-hermes - React-ImageManager + - React-jsi - React-NativeModulesApple - React-RCTFabric - React-rendererdebug @@ -2280,7 +2259,7 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - RNSVG (15.15.0): + - RNScreens (4.18.0): - DoubleConversion - glog - hermes-engine @@ -2295,14 +2274,15 @@ PODS: - React-ImageManager - React-NativeModulesApple - React-RCTFabric + - React-RCTImage - React-rendererdebug - React-utils - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNSVG/common (= 15.15.0) + - RNScreens/common (= 4.18.0) - Yoga - - RNSVG/common (15.15.0): + - RNScreens/common (4.18.0): - DoubleConversion - glog - hermes-engine @@ -2317,13 +2297,14 @@ PODS: - React-ImageManager - React-NativeModulesApple - React-RCTFabric + - React-RCTImage - React-rendererdebug - React-utils - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - RNWorklets (0.6.1): + - RNShare (12.2.1): - DoubleConversion - glog - hermes-engine @@ -2335,9 +2316,7 @@ PODS: - React-Fabric - React-featureflags - React-graphics - - React-hermes - React-ImageManager - - React-jsi - React-NativeModulesApple - React-RCTFabric - React-rendererdebug @@ -2345,9 +2324,8 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNWorklets/worklets (= 0.6.1) - Yoga - - RNWorklets/worklets (0.6.1): + - RNSVG (15.15.0): - DoubleConversion - glog - hermes-engine @@ -2359,9 +2337,7 @@ PODS: - React-Fabric - React-featureflags - React-graphics - - React-hermes - React-ImageManager - - React-jsi - React-NativeModulesApple - React-RCTFabric - React-rendererdebug @@ -2369,9 +2345,9 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNWorklets/worklets/apple (= 0.6.1) + - RNSVG/common (= 15.15.0) - Yoga - - RNWorklets/worklets/apple (0.6.1): + - RNSVG/common (15.15.0): - DoubleConversion - glog - hermes-engine @@ -2383,9 +2359,7 @@ PODS: - React-Fabric - React-featureflags - React-graphics - - React-hermes - React-ImageManager - - React-jsi - React-NativeModulesApple - React-RCTFabric - React-rendererdebug @@ -2558,11 +2532,10 @@ DEPENDENCIES: - RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`) - RNPermissions (from `../../../node_modules/react-native-permissions`) - RNReactNativeHapticFeedback (from `../../../node_modules/react-native-haptic-feedback`) - - RNReanimated (from `../../../node_modules/react-native-reanimated`) + - RNReanimated (from `../node_modules/react-native-reanimated`) - RNScreens (from `../../../node_modules/react-native-screens`) - RNShare (from `../../../node_modules/react-native-share`) - RNSVG (from `../node_modules/react-native-svg`) - - RNWorklets (from `../../../node_modules/react-native-worklets`) - RNZipArchive (from `../../../node_modules/react-native-zip-archive`) - "snap-kit-react-native (from `../../../node_modules/@snapchat/snap-kit-react-native`)" - SRSRadialGradient (from `../../../node_modules/react-native-radial-gradient/ios`) @@ -2797,15 +2770,13 @@ EXTERNAL SOURCES: RNReactNativeHapticFeedback: :path: "../../../node_modules/react-native-haptic-feedback" RNReanimated: - :path: "../../../node_modules/react-native-reanimated" + :path: "../node_modules/react-native-reanimated" RNScreens: :path: "../../../node_modules/react-native-screens" RNShare: :path: "../../../node_modules/react-native-share" RNSVG: :path: "../node_modules/react-native-svg" - RNWorklets: - :path: "../../../node_modules/react-native-worklets" RNZipArchive: :path: "../../../node_modules/react-native-zip-archive" snap-kit-react-native: @@ -2928,11 +2899,10 @@ SPEC CHECKSUMS: RNImageCropPicker: 64b6bec9ec185ee59b71a93d7058816bd0e1916e RNPermissions: f9a0f92115d3e67ebc7fc202ce21c8133ce562f0 RNReactNativeHapticFeedback: 5fdbbaedabc1698dc3bb2a72105fadf63136a451 - RNReanimated: ba8383d1962c876d6b25be62454bef13ff0f5dd9 + RNReanimated: 8a31823e0237f8acc67449779473bb5b4b7cf856 RNScreens: 3bd1e11f556f1ac51ea88223cadc9f6a95cd33fa RNShare: 714e53dc317f27540d137783b544d79a0dbef410 RNSVG: 17ecf94f01f36124607b239fa7c025b052d1d382 - RNWorklets: 44160e261e329771dd8ab00528221c5d0f78088e RNZipArchive: 7bb4c70d6aa2dd235212c0a4a3de0a4e237e2569 snap-kit-react-native: 751006199818fccb38c8a01196495167bc25e9fb SnapSDK: 1e68aad748e080f49e3802559b3b76026666ef62 diff --git a/packages/mobile/package.json b/packages/mobile/package.json index 1eb988857f6..4822086beaf 100644 --- a/packages/mobile/package.json +++ b/packages/mobile/package.json @@ -135,7 +135,7 @@ "react-native-qrcode-svg": "6.2.0", "react-native-radial-gradient": "1.1.4", "react-native-randombytes": "3.6.1", - "react-native-reanimated": "4.1.6", + "react-native-reanimated": "~3.19.5", "react-native-restart": "0.0.27", "react-native-safe-area-context": "^5.2.0", "react-native-screens": "^4.10.0", @@ -149,7 +149,6 @@ "react-native-video": "6.18.0", "react-native-view-shot": "3.8.0", "react-native-webview": "^13.14.1", - "react-native-worklets": "0.6.1", "react-native-zip-archive": "7.0.1", "react-qr-code": "2.0.18", "react-redux": "8.0.5", diff --git a/packages/mobile/patches/react-native-collapsible-tab-view+8.0.1.patch b/packages/mobile/patches/react-native-collapsible-tab-view+8.0.1.patch deleted file mode 100644 index 591682b1192..00000000000 --- a/packages/mobile/patches/react-native-collapsible-tab-view+8.0.1.patch +++ /dev/null @@ -1,123 +0,0 @@ -diff --git a/node_modules/react-native-collapsible-tab-view/lib/commonjs/Container.js b/node_modules/react-native-collapsible-tab-view/lib/commonjs/Container.js -index 4c383f7..bd1b671 100644 ---- a/node_modules/react-native-collapsible-tab-view/lib/commonjs/Container.js -+++ b/node_modules/react-native-collapsible-tab-view/lib/commonjs/Container.js -@@ -96,7 +96,9 @@ const Container = exports.Container = /*#__PURE__*/_react.default.memo(/*#__PURE - const headerScrollDistance = (0, _reactNativeReanimated.useDerivedValue)(() => { - return headerHeight !== undefined ? headerHeight - minHeaderHeight : 0; - }, [headerHeight, minHeaderHeight]); -- const indexDecimal = (0, _reactNativeReanimated.useSharedValue)(index.value); -+ // Avoid reading from a shared value during React render (Reanimated strict mode). -+ // `index` is initialized from `initialIndex`, so we can seed `indexDecimal` directly. -+ const indexDecimal = (0, _reactNativeReanimated.useSharedValue)(initialIndex); - const afterRender = (0, _reactNativeReanimated.useSharedValue)(0); - _react.default.useEffect(() => { - afterRender.value = (0, _reactNativeReanimated.withDelay)(_helpers.ONE_FRAME_MS * 5, (0, _reactNativeReanimated.withTiming)(1, { -diff --git a/node_modules/react-native-collapsible-tab-view/lib/commonjs/MaterialTabBar/TabBar.js b/node_modules/react-native-collapsible-tab-view/lib/commonjs/MaterialTabBar/TabBar.js -index 3322cb0..d4634f8 100644 ---- a/node_modules/react-native-collapsible-tab-view/lib/commonjs/MaterialTabBar/TabBar.js -+++ b/node_modules/react-native-collapsible-tab-view/lib/commonjs/MaterialTabBar/TabBar.js -@@ -102,7 +102,8 @@ const MaterialTabBar = ({ - } - } - }, [scrollEnabled, tabNames]); -- const cancelNextScrollSync = (0, _reactNativeReanimated.useSharedValue)(index.value); -+ // Avoid reading from a shared value during React render (Reanimated strict mode). -+ const cancelNextScrollSync = (0, _reactNativeReanimated.useSharedValue)(0); - const onScroll = (0, _reactNativeReanimated.useAnimatedScrollHandler)({ - onScroll: event => { - tabsOffset.value = event.contentOffset.x; -@@ -115,8 +116,9 @@ const MaterialTabBar = ({ - isScrolling.value = false; - } - }, []); -- const currentIndexToSync = (0, _reactNativeReanimated.useSharedValue)(index.value); -- const targetIndexToSync = (0, _reactNativeReanimated.useSharedValue)(index.value); -+ // Avoid reading from a shared value during React render (Reanimated strict mode). -+ const currentIndexToSync = (0, _reactNativeReanimated.useSharedValue)(0); -+ const targetIndexToSync = (0, _reactNativeReanimated.useSharedValue)(0); - (0, _reactNativeReanimated.useAnimatedReaction)(() => { - return index.value; - }, nextIndex => { -diff --git a/node_modules/react-native-collapsible-tab-view/lib/module/Container.js b/node_modules/react-native-collapsible-tab-view/lib/module/Container.js -index 50c3da7..3e26590 100644 ---- a/node_modules/react-native-collapsible-tab-view/lib/module/Container.js -+++ b/node_modules/react-native-collapsible-tab-view/lib/module/Container.js -@@ -89,7 +89,9 @@ export const Container = /*#__PURE__*/React.memo(/*#__PURE__*/React.forwardRef(( - const headerScrollDistance = useDerivedValue(() => { - return headerHeight !== undefined ? headerHeight - minHeaderHeight : 0; - }, [headerHeight, minHeaderHeight]); -- const indexDecimal = useSharedValue(index.value); -+ // Avoid reading from a shared value during React render (Reanimated strict mode). -+ // `index` is initialized from `initialIndex`, so we can seed `indexDecimal` directly. -+ const indexDecimal = useSharedValue(initialIndex); - const afterRender = useSharedValue(0); - React.useEffect(() => { - afterRender.value = withDelay(ONE_FRAME_MS * 5, withTiming(1, { -diff --git a/node_modules/react-native-collapsible-tab-view/lib/module/MaterialTabBar/TabBar.js b/node_modules/react-native-collapsible-tab-view/lib/module/MaterialTabBar/TabBar.js -index 39d4211..553c706 100644 ---- a/node_modules/react-native-collapsible-tab-view/lib/module/MaterialTabBar/TabBar.js -+++ b/node_modules/react-native-collapsible-tab-view/lib/module/MaterialTabBar/TabBar.js -@@ -95,7 +95,8 @@ const MaterialTabBar = ({ - } - } - }, [scrollEnabled, tabNames]); -- const cancelNextScrollSync = useSharedValue(index.value); -+ // Avoid reading from a shared value during React render (Reanimated strict mode). -+ const cancelNextScrollSync = useSharedValue(0); - const onScroll = useAnimatedScrollHandler({ - onScroll: event => { - tabsOffset.value = event.contentOffset.x; -@@ -108,8 +109,9 @@ const MaterialTabBar = ({ - isScrolling.value = false; - } - }, []); -- const currentIndexToSync = useSharedValue(index.value); -- const targetIndexToSync = useSharedValue(index.value); -+ // Avoid reading from a shared value during React render (Reanimated strict mode). -+ const currentIndexToSync = useSharedValue(0); -+ const targetIndexToSync = useSharedValue(0); - useAnimatedReaction(() => { - return index.value; - }, nextIndex => { -diff --git a/node_modules/react-native-collapsible-tab-view/src/Container.tsx b/node_modules/react-native-collapsible-tab-view/src/Container.tsx -index e782b90..e181be8 100644 ---- a/node_modules/react-native-collapsible-tab-view/src/Container.tsx -+++ b/node_modules/react-native-collapsible-tab-view/src/Container.tsx -@@ -145,7 +145,9 @@ export const Container = React.memo( - }, [headerHeight, minHeaderHeight]) - - const indexDecimal: ContextType['indexDecimal'] = useSharedValue( -- index.value -+ // Avoid reading from a shared value during React render (Reanimated strict mode). -+ // `index` is initialized from `initialIndex`, so we can seed `indexDecimal` directly. -+ initialIndex - ) - - const afterRender = useSharedValue(0) -diff --git a/node_modules/react-native-collapsible-tab-view/src/MaterialTabBar/TabBar.tsx b/node_modules/react-native-collapsible-tab-view/src/MaterialTabBar/TabBar.tsx -index 60de38e..4e2dbbf 100644 ---- a/node_modules/react-native-collapsible-tab-view/src/MaterialTabBar/TabBar.tsx -+++ b/node_modules/react-native-collapsible-tab-view/src/MaterialTabBar/TabBar.tsx -@@ -119,7 +119,8 @@ const MaterialTabBar = ({ - [scrollEnabled, tabNames] - ) - -- const cancelNextScrollSync = useSharedValue(index.value) -+ // Avoid reading from a shared value during React render (Reanimated strict mode). -+ const cancelNextScrollSync = useSharedValue(0) - - const onScroll = useAnimatedScrollHandler( - { -@@ -137,8 +138,9 @@ const MaterialTabBar = ({ - [] - ) - -- const currentIndexToSync = useSharedValue(index.value) -- const targetIndexToSync = useSharedValue(index.value) -+ // Avoid reading from a shared value during React render (Reanimated strict mode). -+ const currentIndexToSync = useSharedValue(0) -+ const targetIndexToSync = useSharedValue(0) - - useAnimatedReaction( - () => { diff --git a/packages/mobile/scripts/patch-react-native-exceptions.js b/packages/mobile/scripts/patch-react-native-exceptions.js new file mode 100644 index 00000000000..a64f588fe65 --- /dev/null +++ b/packages/mobile/scripts/patch-react-native-exceptions.js @@ -0,0 +1,67 @@ +#!/usr/bin/env node +/** + * Applies a fix to React Native's ExceptionsManager to avoid "Error.stack getter + * called with an invalid receiver" on Hermes when .stack is accessed on + * non-Error values (e.g. legacy custom errors, thrown strings). + * @see https://github.com/facebook/react-native/issues/43636 + * @see https://github.com/facebook/hermes/issues/1496 + * + * Run after npm install to re-apply (node_modules can be overwritten on install). + */ + +const fs = require('fs') +const path = require('path') + +const target = path.join( + __dirname, + '../node_modules/react-native/Libraries/Core/ExceptionsManager.js' +) + +if (!fs.existsSync(target)) { + process.exit(0) +} + +let content = fs.readFileSync(target, 'utf8') + +if (content.includes('getErrorStackSafe')) { + process.exit(0) +} + +const helper = `/** + * Safely reads the .stack property from an error-like value. + * Hermes can throw "Error.stack getter called with an invalid receiver" when + * .stack is accessed on objects that inherit from Error using legacy patterns + * (e.g. MyError.prototype = new Error) or other non-Error values. This helper + * prevents that from crashing the app. + * @see https://github.com/facebook/react-native/issues/43636 + * @see https://github.com/facebook/hermes/issues/1496 + */ +function getErrorStackSafe(e: mixed): string | void { + if (e == null) return undefined; + try { + return typeof e.stack === 'string' ? e.stack : undefined; + } catch { + return undefined; + } +} + +` + +content = content.replace( + 'function preprocessException(data: ExceptionData): ExceptionData {', + helper + 'function preprocessException(data: ExceptionData): ExceptionData {' +) +content = content.replace( + 'const stack = parseErrorStack(e?.stack);', + 'const stack = parseErrorStack(getErrorStackSafe(e));' +) +content = content.replace( + 'rawStack: e.stack,', + 'rawStack: getErrorStackSafe(e),' +) +content = content.replace( + 'if (firstArg?.stack) {', + 'if (getErrorStackSafe(firstArg)) {' +) + +fs.writeFileSync(target, content) diff --git a/packages/mobile/src/components/audio/AudioPlayer.tsx b/packages/mobile/src/components/audio/AudioPlayer.tsx index 7c6e21841fc..4754a516a00 100644 --- a/packages/mobile/src/components/audio/AudioPlayer.tsx +++ b/packages/mobile/src/components/audio/AudioPlayer.tsx @@ -153,10 +153,6 @@ type QueueableTrack = { export const AudioPlayer = () => { const track = useCurrentTrack() const playing = useSelector(getPlaying) - const playingRef = useRef(playing) - useEffect(() => { - playingRef.current = playing - }, [playing]) const seek = useSelector(getSeek) const counter = useSelector(getCounter) const repeatMode = useSelector(getRepeat) @@ -777,14 +773,11 @@ export const AudioPlayer = () => { uid: queueTrackUids[queueIndex] }) - // Respect the current desired play/pause state. - // Previously we called `TrackPlayer.play()` immediately after reset, which could briefly - // autoplay and then get paused by later state sync (especially on slow/buffering starts). - if (playingRef.current) { - await TrackPlayer.play() - } else { - await TrackPlayer.pause() - } + // Always play when starting a new queue (reset + add). This path is only hit when + // the user explicitly requests playback (e.g. tap tile). Checking playingRef here + // caused "pause after buffer": during async makeTrackData/add, Redux playing could + // lag, so we'd call pause() and playback would never start or would stop after buffer. + await TrackPlayer.play() enqueueTracksJobRef.current = enqueueTracks(newQueueTracks, queueIndex) await enqueueTracksJobRef.current diff --git a/packages/mobile/src/harmony-native/components/Image/Image.tsx b/packages/mobile/src/harmony-native/components/Image/Image.tsx index 241b85d2a1c..c0c77cdb478 100644 --- a/packages/mobile/src/harmony-native/components/Image/Image.tsx +++ b/packages/mobile/src/harmony-native/components/Image/Image.tsx @@ -24,7 +24,25 @@ export const Image = (props: ImageProps) => { return null } - return + // Wrap onError to prevent Error objects from being passed as props + // This fixes "Error.stack getter called with an invalid receiver" in Hermes + const handleError = onError + ? (error: { nativeEvent: ImageErrorEventData } | Error) => { + // Ensure we always pass the expected event structure, not a raw Error object + if (error instanceof Error) { + // If we receive an Error object, wrap it in the expected structure + onError({ + nativeEvent: { + error: error.message || 'Image load error' + } + }) + } else { + onError(error) + } + } + : undefined + + return } export const preload = ( diff --git a/packages/mobile/src/screens/profile-screen/routes.ts b/packages/mobile/src/screens/profile-screen/routes.ts index 377941a1b62..bd4cf6a99d4 100644 --- a/packages/mobile/src/screens/profile-screen/routes.ts +++ b/packages/mobile/src/screens/profile-screen/routes.ts @@ -1,9 +1,10 @@ import type { RouteProp } from '@react-navigation/native' type ProfileTabParamList = { - Reposts: { lazy: boolean } + Reposts: { lazy?: boolean } Albums: {} Playlists: {} + Tracks: {} } export type ProfileTabRoutes = diff --git a/packages/web/src/common/store/lineup/sagas.ts b/packages/web/src/common/store/lineup/sagas.ts index 39dadf90ac7..4302d778c37 100644 --- a/packages/web/src/common/store/lineup/sagas.ts +++ b/packages/web/src/common/store/lineup/sagas.ts @@ -204,7 +204,9 @@ function* fetchLineupMetadatasAsync( lineupSelector(state, action.handle?.toLowerCase()) ) const source = sourceSelector - ? yield* select(sourceSelector) + ? yield* select((state) => + sourceSelector(state, action.handle?.toLowerCase()) + ) : lineup.prefix const queueUids = Object.keys(yield* select(getPositions)).map((uid) => diff --git a/packages/web/src/common/store/pages/profile/lineups/tracks/sagas.js b/packages/web/src/common/store/pages/profile/lineups/tracks/sagas.js index c11dd70ab29..2f5373dc1f8 100644 --- a/packages/web/src/common/store/pages/profile/lineups/tracks/sagas.js +++ b/packages/web/src/common/store/pages/profile/lineups/tracks/sagas.js @@ -27,6 +27,9 @@ const PREFIX = tracksActions.prefix function* getTracks({ offset, limit, payload, handle }) { yield waitForRead() + if (!handle) { + return [] + } const currentUserId = yield call(queryCurrentUserId) const profileHandle = handle.toLowerCase() diff --git a/scripts/patch-package.sh b/scripts/patch-package.sh index c5ae6cb9ef8..0d35e39341f 100755 --- a/scripts/patch-package.sh +++ b/scripts/patch-package.sh @@ -5,9 +5,3 @@ npx patch-package --error-on-fail npx patch-package --patch-dir=packages/mobile/patches --error-on-fail npx patch-package --patch-dir=packages/web/patches --error-on-fail npx patch-package --patch-dir=packages/identity-service/patches --error-on-fail - -if [ -d "packages/mobile" ]; then - cd packages/mobile - npx patch-package --patch-dir=mobile-patches --error-on-fail - cd ../.. -fi \ No newline at end of file diff --git a/scripts/postinstall.sh b/scripts/postinstall.sh index c4759a1b222..94eb097214e 100755 --- a/scripts/postinstall.sh +++ b/scripts/postinstall.sh @@ -19,6 +19,9 @@ fi printf "${GREEN}Applying patches...\n${NC}" npm run patch-package > /dev/null +printf "${GREEN}Patching React Native ExceptionsManager (Hermes fix)...\n${NC}" +node ./packages/mobile/scripts/patch-react-native-exceptions.js + # xcodebuild may exist (e.g. if xcode-select is installed via homebrew) but won't work alone if [[ -z "${SKIP_POD_INSTALL}" ]]; then if ! xcodebuild --help &>/dev/null; then