From f5b38831de080a41bfb328539080bc7dcc11daaa Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 5 Oct 2026 17:00:09 +0000 Subject: [PATCH 1/3] pkg: Update react-native and @react-native/jest-preset to 0.87.1 Co-authored-by: Nathaniel Tucker --- package.json | 4 +- packages/react/package.json | 2 +- packages/test/package.json | 2 +- yarn.lock | 441 ++++++++++++++++-------------------- 4 files changed, 198 insertions(+), 251 deletions(-) diff --git a/package.json b/package.json index fa47761f947d..78b7660fb48b 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "@data-client/react": "workspace:*", "@data-client/rest": "workspace:*", "@data-client/test": "workspace:*", - "@react-native/jest-preset": "0.86.2", + "@react-native/jest-preset": "0.87.1", "@react-navigation/native": "^7.0.0", "@react-navigation/native-stack": "^7.0.0", "@testing-library/dom": "^10.4.0", @@ -107,7 +107,7 @@ "prettier": "3.9.5", "react": "19.2.3", "react-dom": "19.2.3", - "react-native": "0.86.2", + "react-native": "0.87.1", "react-native-safe-area-context": "^5.0.0", "react-native-screens": "^4.1.0", "react-test-renderer": "19.2.3", diff --git a/packages/react/package.json b/packages/react/package.json index 64ee600dcb8c..0bf328bcbd59 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -194,7 +194,7 @@ "qs": "^6.14.2", "react": "19.2.3", "react-dom": "^19.0.0", - "react-native": "0.86.2", + "react-native": "0.87.1", "react-native-safe-area-context": "^5.0.0", "react-native-screens": "^4.1.0", "react-test-renderer": "^19.0.0", diff --git a/packages/test/package.json b/packages/test/package.json index f01ae8ac4919..f8be0f1011f7 100644 --- a/packages/test/package.json +++ b/packages/test/package.json @@ -158,7 +158,7 @@ "jest": "^30.0.0", "react": "19.2.3", "react-dom": "19.2.3", - "react-native": "0.86.2", + "react-native": "0.87.1", "react-test-renderer": "*", "rollup-plugins": "workspace:*" } diff --git a/yarn.lock b/yarn.lock index f9f7e9540a7c..16957b0961ae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3295,7 +3295,7 @@ __metadata: qs: "npm:^6.14.2" react: "npm:19.2.3" react-dom: "npm:^19.0.0" - react-native: "npm:0.86.2" + react-native: "npm:0.87.1" react-native-safe-area-context: "npm:^5.0.0" react-native-screens: "npm:^4.1.0" react-test-renderer: "npm:^19.0.0" @@ -3348,7 +3348,7 @@ __metadata: jest: "npm:^30.0.0" react: "npm:19.2.3" react-dom: "npm:19.2.3" - react-native: "npm:0.86.2" + react-native: "npm:0.87.1" react-test-renderer: "npm:*" rollup-plugins: "workspace:*" peerDependencies: @@ -6502,78 +6502,77 @@ __metadata: languageName: node linkType: hard -"@react-native/assets-registry@npm:0.86.2": - version: 0.86.2 - resolution: "@react-native/assets-registry@npm:0.86.2" - checksum: 10c0/e063219dd8548240a278138a595f758a6a140cafe1493631a3d12c3da673aaf6b7d6c2c7115000b13d93c88145ec54b9be509aa683846554273c01bc4a8759c7 +"@react-native/asset-utils@npm:0.87.1": + version: 0.87.1 + resolution: "@react-native/asset-utils@npm:0.87.1" + checksum: 10c0/301be8aa1e3fb834df7ac930db566567b07a3a44e60b5014e2bf8227e36a3b6a274c1f2a0c23b0126ffd4f212fb726622e9d8875f3000ae697d4499c3037aafe languageName: node linkType: hard -"@react-native/codegen@npm:0.86.2": - version: 0.86.2 - resolution: "@react-native/codegen@npm:0.86.2" +"@react-native/codegen@npm:0.87.1": + version: 0.87.1 + resolution: "@react-native/codegen@npm:0.87.1" dependencies: "@babel/core": "npm:^7.25.2" "@babel/parser": "npm:^7.29.0" - hermes-parser: "npm:0.36.0" + hermes-parser: "npm:0.36.1" invariant: "npm:^2.2.4" nullthrows: "npm:^1.1.1" tinyglobby: "npm:^0.2.15" yargs: "npm:^17.6.2" peerDependencies: "@babel/core": "*" - checksum: 10c0/3b36b5d99a525195e61c1197d88118c774654de6e644a677b29461bd2b28718a751f1c45ee25efa6b274f27d36efb096a3ec816c5fba1cda1a5f5843e4239a0a + checksum: 10c0/2aa9cc5b985dad8a1f996783283b83fcbafa0d3755d2bc52d3ecbcd90d1764160c6e083c1e3401243ce4fa30531cca38391c104f4e475a6a33181c0e694b5cde languageName: node linkType: hard -"@react-native/community-cli-plugin@npm:0.86.2": - version: 0.86.2 - resolution: "@react-native/community-cli-plugin@npm:0.86.2" +"@react-native/community-cli-plugin@npm:0.87.1": + version: 0.87.1 + resolution: "@react-native/community-cli-plugin@npm:0.87.1" dependencies: - "@react-native/dev-middleware": "npm:0.86.2" + "@react-native/asset-utils": "npm:0.87.1" + "@react-native/dev-middleware": "npm:0.87.1" debug: "npm:^4.4.0" invariant: "npm:^2.2.4" - metro: "npm:^0.84.3" - metro-config: "npm:^0.84.3" - metro-core: "npm:^0.84.3" + metro: "npm:^0.87.0" semver: "npm:^7.1.3" peerDependencies: "@react-native-community/cli": "*" - "@react-native/metro-config": 0.86.2 + "@react-native/metro-config": 0.87.1 peerDependenciesMeta: "@react-native-community/cli": optional: true "@react-native/metro-config": optional: true - checksum: 10c0/f86e5fbe759b3538538c5534e78bc262d549fcb4a6e5066b71e512c9d326e787ebc8050d977f768c39671a1e995aa9eebab642bc51cbfc96dfcfac1127e329e6 + checksum: 10c0/12c62924578e6f3127d310d720ed88b4541c33f8ad68b81f0d03b93dd492b675254566bb3fd18305f0fbfd0745c9c5c1d4fa86525b967bc9c5f3725e684695d6 languageName: node linkType: hard -"@react-native/debugger-frontend@npm:0.86.2": - version: 0.86.2 - resolution: "@react-native/debugger-frontend@npm:0.86.2" - checksum: 10c0/fa3e9c514f7748cc154455fa699351824bde2098bed6c0772892dbbdb91ed3f5d3bbdfbc7fa8ecb17914fbeac05870b3ca462ab33bc5064ecf0539da7a2ed003 +"@react-native/debugger-frontend@npm:0.87.1": + version: 0.87.1 + resolution: "@react-native/debugger-frontend@npm:0.87.1" + checksum: 10c0/97eab13aa782029dcd26b9a0c8f2b054d15a357648e9ae9564f5061ca903520a3283ab072d9d541a0d9a13c0752ca52bbb0426bc0b8bb98747d0e56dbd95e445 languageName: node linkType: hard -"@react-native/debugger-shell@npm:0.86.2": - version: 0.86.2 - resolution: "@react-native/debugger-shell@npm:0.86.2" +"@react-native/debugger-shell@npm:0.87.1": + version: 0.87.1 + resolution: "@react-native/debugger-shell@npm:0.87.1" dependencies: cross-spawn: "npm:^7.0.6" debug: "npm:^4.4.0" fb-dotslash: "npm:0.5.8" - checksum: 10c0/8aec11d0ccf8c30d968173d5ff024be1b854f600acc48c3f96f1743bfaad708e3da1a49ed672c63fed21c58017dcc4c442b5c456e7e212149295be33bfcf6e9b + checksum: 10c0/f7bda514176e2cd5a772978b4e5cad9657bf62d70aa4492991c1554e5693672540595ae1e20644c9745b14a3adf109e9caece37c04fa2ba2b958fb97f58bb666 languageName: node linkType: hard -"@react-native/dev-middleware@npm:0.86.2": - version: 0.86.2 - resolution: "@react-native/dev-middleware@npm:0.86.2" +"@react-native/dev-middleware@npm:0.87.1": + version: 0.87.1 + resolution: "@react-native/dev-middleware@npm:0.87.1" dependencies: "@isaacs/ttlcache": "npm:^1.4.1" - "@react-native/debugger-frontend": "npm:0.86.2" - "@react-native/debugger-shell": "npm:0.86.2" + "@react-native/debugger-frontend": "npm:0.87.1" + "@react-native/debugger-shell": "npm:0.87.1" chrome-launcher: "npm:^0.15.2" chromium-edge-launcher: "npm:^0.3.0" connect: "npm:^3.6.5" @@ -6583,60 +6582,60 @@ __metadata: open: "npm:^7.0.3" serve-static: "npm:^1.16.2" ws: "npm:^7.5.10" - checksum: 10c0/4e61e17f1cf581b15d570a82401b0c324e6e93ae26661e5dba40579353af122d22dd6d9b4bffefeb5ac4858866bf6a1974b4322f6a560129a6bffb55377bf6c1 + checksum: 10c0/81c6db874e52afaefe8935003f0181fa73d6d80ddc4cc21c315ececf07bdbf8123e5398556f891e5ce482611ae1ca730a2d9670f7dd9a86903d1708ef99de61c languageName: node linkType: hard -"@react-native/gradle-plugin@npm:0.86.2": - version: 0.86.2 - resolution: "@react-native/gradle-plugin@npm:0.86.2" - checksum: 10c0/1c6409d79fddb48d7ff4bc2c59b645e65cfa1a9aa1ecc12861d96af9b4cc5e77b24c6daceb2269461059960617832261761538ab4e3af8b480d29750b2b0fe10 +"@react-native/gradle-plugin@npm:0.87.1": + version: 0.87.1 + resolution: "@react-native/gradle-plugin@npm:0.87.1" + checksum: 10c0/281e6d62b5b4a9cc9043ce31a5628cee4666d415d3b69eedf6fa481437f70d0f85d78622bf9d4a3db3e248b27f16747b8bc02536da8aac609c1d1e450ed835d1 languageName: node linkType: hard -"@react-native/jest-preset@npm:0.86.2": - version: 0.86.2 - resolution: "@react-native/jest-preset@npm:0.86.2" +"@react-native/jest-preset@npm:0.87.1": + version: 0.87.1 + resolution: "@react-native/jest-preset@npm:0.87.1" dependencies: "@jest/create-cache-key-function": "npm:^29.7.0" - "@react-native/js-polyfills": "npm:0.86.2" + "@react-native/js-polyfills": "npm:0.87.1" babel-jest: "npm:^29.7.0" jest-environment-node: "npm:^29.7.0" regenerator-runtime: "npm:^0.13.2" peerDependencies: react: ^19.2.3 - checksum: 10c0/ae6b0665a74f98a86c04eb761360bc854258f98b35f2eb1977cdad7b3e50cee66f6c7c6a9b4486d1eec5102f9c8ac68ba234fcee18ea9ca44ba3737d406ed8ec + checksum: 10c0/68d3e8a082b9e37457c58e5f761327fd52517068b217f609a23f001b38de83065dddf2c51d0ab8f55a16dbee0a6a3d2ce862f6ca56d96daeeafb8656179be380 languageName: node linkType: hard -"@react-native/js-polyfills@npm:0.86.2": - version: 0.86.2 - resolution: "@react-native/js-polyfills@npm:0.86.2" - checksum: 10c0/184c7d2815f79b55bd960f2f76919841a2e4959d9957b159f4d364319e225bf41fdf5eb14c533cafce0cba2e2e47a8ad734e99d82eba7effeca3ccd1282f1f49 +"@react-native/js-polyfills@npm:0.87.1": + version: 0.87.1 + resolution: "@react-native/js-polyfills@npm:0.87.1" + checksum: 10c0/698ae0c675d73833c36412678850bac3e6bb76593ff50d589cc1dffc1ca33bab47c5a451b409c292e1deeef3f40f6b192f1565861bf3336d67f3e5ce2d6a595a languageName: node linkType: hard -"@react-native/normalize-colors@npm:0.86.2": - version: 0.86.2 - resolution: "@react-native/normalize-colors@npm:0.86.2" - checksum: 10c0/40abd68911f0692cfb6548560bacb48c417556df119e98f06e89ccf1ef29e98d2087af5c958cc052dc9a20bf0da69366779b4b626e56f16a945a3bb41a9ccfbe +"@react-native/normalize-colors@npm:0.87.1": + version: 0.87.1 + resolution: "@react-native/normalize-colors@npm:0.87.1" + checksum: 10c0/0ab052554526b886c5ddd92c10a82915f6508bc0a77670d1af256bb0985f829534f2cef7e75ea24b860a910f3562c9ca7ad58007c242205b5966b2f7cd7b2f7b languageName: node linkType: hard -"@react-native/virtualized-lists@npm:0.86.2": - version: 0.86.2 - resolution: "@react-native/virtualized-lists@npm:0.86.2" +"@react-native/virtualized-lists@npm:0.87.1": + version: 0.87.1 + resolution: "@react-native/virtualized-lists@npm:0.87.1" dependencies: invariant: "npm:^2.2.4" nullthrows: "npm:^1.1.1" peerDependencies: "@types/react": ^19.2.0 react: "*" - react-native: 0.86.2 + react-native: 0.87.1 peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/ed5625dae2929c726a8311fb0193d301c78fe4af74697bcbed8b5b6f77a915c36dc56615c482601299c15ff7985c3f892939ee34dd04a361467c6d50c7a4a42f + checksum: 10c0/0062c5555e209e6767b9e7568ad5e4f5716638c4cec1d938412568ad69df7b12ff3cf0cfa6a8bc2c93e70bcd9031b827ef02c7596098263d6e686a61f5bd57a2 languageName: node linkType: hard @@ -10437,12 +10436,12 @@ __metadata: languageName: node linkType: hard -"babel-plugin-syntax-hermes-parser@npm:0.36.0": - version: 0.36.0 - resolution: "babel-plugin-syntax-hermes-parser@npm:0.36.0" +"babel-plugin-syntax-hermes-parser@npm:0.36.1": + version: 0.36.1 + resolution: "babel-plugin-syntax-hermes-parser@npm:0.36.1" dependencies: - hermes-parser: "npm:0.36.0" - checksum: 10c0/3c20d2b2595e890bf7bf14b48a1dc6eb2ad2625e04f942254f3676440e20489eb8266fba8f8077194d294dfb67552b6b969bb40b93c873b88fdc319528dc2606 + hermes-parser: "npm:0.36.1" + checksum: 10c0/d6343ef16032253408cc8f4585c7acc275101f3194c312606e0f0d65ccf768db36b74e907296a93f3844c108ed19776052d5e844cbd21ec18c43a23ce7c2055e languageName: node linkType: hard @@ -11323,13 +11322,6 @@ __metadata: languageName: node linkType: hard -"ci-info@npm:^2.0.0": - version: 2.0.0 - resolution: "ci-info@npm:2.0.0" - checksum: 10c0/8c5fa3830a2bcee2b53c2e5018226f0141db9ec9f7b1e27a5c57db5512332cde8a0beb769bcbaf0d8775a78afbf2bb841928feca4ea6219638a5b088f9884b46 - languageName: node - linkType: hard - "ci-info@npm:^3.2.0": version: 3.9.0 resolution: "ci-info@npm:3.9.0" @@ -15187,10 +15179,19 @@ __metadata: languageName: node linkType: hard -"flow-parser@npm:0.*": - version: 0.312.0 - resolution: "flow-parser@npm:0.312.0" - checksum: 10c0/7351b7e2c895a14569c594be3f12453fd99b956ee8e50bc229f398ee4c73174f87eda805235c247d8cd822df8dc26e8d544bceef516af07221d2ee5ff9101512 +"flow-estree@npm:0.331.0": + version: 0.331.0 + resolution: "flow-estree@npm:0.331.0" + checksum: 10c0/3e967611d5e4f83a4fde886d90cffe48078702b51258eddcc2f6c2e5d8bca37986df5d890b9f787b0760bb35886bcc3aecd7db6f7db1fff0f9f2ef7b216cd281 + languageName: node + linkType: hard + +"flow-parser@npm:0.*, flow-parser@npm:0.331.0": + version: 0.331.0 + resolution: "flow-parser@npm:0.331.0" + dependencies: + flow-estree: "npm:0.331.0" + checksum: 10c0/bfeb7652a3f82c6689b7290ec2e40973c0a665990a199fd160e16854f6f163449e348c296df218cebe303f5e547665a32131e4598a4eeba821ac72fd415e7134 languageName: node linkType: hard @@ -16146,24 +16147,17 @@ __metadata: languageName: node linkType: hard -"hermes-compiler@npm:250829098.0.16": - version: 250829098.0.16 - resolution: "hermes-compiler@npm:250829098.0.16" - checksum: 10c0/4ea360bb1ce0830346a432a4c3d32faf8fb6e23455659b97f7ac90ba4c8e7ee43d95088d3ab11e8b03bf492b24f9243a05050b04954edba9f9c0d6d552c48527 +"hermes-compiler@npm:250829098.0.17": + version: 250829098.0.17 + resolution: "hermes-compiler@npm:250829098.0.17" + checksum: 10c0/1bcfcb9268b18593e19e7d4e071dd644cbcff380535a74ea0318b417e30ba190b33e70086f8576c3b28deb2572ba01f57b1a9e5ae10f6841dedaff281b037200 languageName: node linkType: hard -"hermes-estree@npm:0.35.0": - version: 0.35.0 - resolution: "hermes-estree@npm:0.35.0" - checksum: 10c0/a88c9dc63b8b3679b1aeb43e72e977597096c1bd7d59978c952f1d6df6d1a517c4a817c70b1b701854996b485adfa66c2fc7f80871029a7f0c04306f6717b59a - languageName: node - linkType: hard - -"hermes-estree@npm:0.36.0": - version: 0.36.0 - resolution: "hermes-estree@npm:0.36.0" - checksum: 10c0/fe27f57b0f8c3921e9dc48c517e25f4399609ca386353f90e04d3f859bacbee93184af80a6b930db5e981e8953a5c4083147556b21b19519917e131e7533b27c +"hermes-estree@npm:0.36.1": + version: 0.36.1 + resolution: "hermes-estree@npm:0.36.1" + checksum: 10c0/9f552e1f809e05a4ddc5dcc10c5d1d5e375eade985026c3f8876a227db76c33059d25f93f92628a0e43d29a6da6977fbb643fafc8830babad62c1b88b2b56739 languageName: node linkType: hard @@ -16174,21 +16168,12 @@ __metadata: languageName: node linkType: hard -"hermes-parser@npm:0.35.0": - version: 0.35.0 - resolution: "hermes-parser@npm:0.35.0" - dependencies: - hermes-estree: "npm:0.35.0" - checksum: 10c0/49d98093a2094758db5b536627c6cf5146b140f66e63143acf471c62f1d3fd8bd6ae10a33f2372f72e3653deda5d4615c6dae89d01248849440916209901fc4a - languageName: node - linkType: hard - -"hermes-parser@npm:0.36.0": - version: 0.36.0 - resolution: "hermes-parser@npm:0.36.0" +"hermes-parser@npm:0.36.1": + version: 0.36.1 + resolution: "hermes-parser@npm:0.36.1" dependencies: - hermes-estree: "npm:0.36.0" - checksum: 10c0/76e726366ac2ea91e9464853f439d582ddee9c07ccb84cac35297ce1a5d197bf96b84ab030423a22940b55a0fa5bb191bc0ebeebd95f8e34116900decdccdb86 + hermes-estree: "npm:0.36.1" + checksum: 10c0/31f2b0a383e15a3cdd8f34bc11498a35504771b58f24db5694ea5013faf6dbe6b27a47f7825bae5494dd57afac4de54c05f750d4ad646ff6787bbba97dfbd8eb languageName: node linkType: hard @@ -16703,17 +16688,6 @@ __metadata: languageName: node linkType: hard -"image-size@npm:^1.0.2": - version: 1.2.1 - resolution: "image-size@npm:1.2.1" - dependencies: - queue: "npm:6.0.2" - bin: - image-size: bin/image-size.js - checksum: 10c0/f8b3c19d4476513f1d7e55c3e6db80997b315444743e2040d545cbcaee59be03d2eb40c46be949a8372697b7003fdb0c04925d704390a7f606bc8181e25c0ed4 - languageName: node - linkType: hard - "image-size@npm:^2.0.2": version: 2.0.4 resolution: "image-size@npm:2.0.4" @@ -19591,70 +19565,69 @@ __metadata: languageName: node linkType: hard -"metro-babel-transformer@npm:0.84.4": - version: 0.84.4 - resolution: "metro-babel-transformer@npm:0.84.4" +"metro-babel-transformer@npm:0.87.1": + version: 0.87.1 + resolution: "metro-babel-transformer@npm:0.87.1" dependencies: "@babel/core": "npm:^7.25.2" flow-enums-runtime: "npm:^0.0.6" - hermes-parser: "npm:0.35.0" - metro-cache-key: "npm:0.84.4" + flow-parser: "npm:0.331.0" + metro-cache-key: "npm:0.87.1" nullthrows: "npm:^1.1.1" - checksum: 10c0/d1ac996666334bc1cfe9d399cbf4cd747b675f6f8f758c2317eebcc52bd76046ed864ddb7b270efeb8cf337940a61fb03912e5c859b7cbc54687c2f5c41a9d2a + checksum: 10c0/9ec68353af175188b642cd4f1101e020cfbb355d308ab4b5f0fded44918e186506f260b87cf41db88caea4b7d31b7e58ed27770f7063d0ddd40c41ad11626984 languageName: node linkType: hard -"metro-cache-key@npm:0.84.4": - version: 0.84.4 - resolution: "metro-cache-key@npm:0.84.4" +"metro-cache-key@npm:0.87.1": + version: 0.87.1 + resolution: "metro-cache-key@npm:0.87.1" dependencies: flow-enums-runtime: "npm:^0.0.6" - checksum: 10c0/a82ab6367f11886d960cc8fa1f3aa54f6529fe30c16059c141c3e789084c50838fdd7e1a5528534cd9c11a74c63aa5c6a7461dbfa50e8c449b6141eaf2fd05e0 + checksum: 10c0/2da75b15e9242fb3faebfc72574d5bd73c6873f80d3da0bece2fe1d4082d7d1977d59ad3a8c4f67627e85e93ea2a82edb2f53acae6c14d5791ad69d34e4c1742 languageName: node linkType: hard -"metro-cache@npm:0.84.4": - version: 0.84.4 - resolution: "metro-cache@npm:0.84.4" +"metro-cache@npm:0.87.1": + version: 0.87.1 + resolution: "metro-cache@npm:0.87.1" dependencies: exponential-backoff: "npm:^3.1.1" flow-enums-runtime: "npm:^0.0.6" https-proxy-agent: "npm:^7.0.5" - metro-core: "npm:0.84.4" - checksum: 10c0/3bf7f3a1f85b4f1af05f4b2c71c78e56fd3262d967ee43f02e9ff6820254063af33a70b6549e3dc5e993a6a0b9df92e9279632ad9a8b1cde2577342f93df45eb + metro-core: "npm:0.87.1" + checksum: 10c0/f3fdb422c8512f9454d4eb672873814ea814d92b8d7ae8ffc16f2543f57631c87a09c8fbda54835a56e26a1e092bfec24a685e9b980480b6a89378911c3a338b languageName: node linkType: hard -"metro-config@npm:0.84.4, metro-config@npm:^0.84.3": - version: 0.84.4 - resolution: "metro-config@npm:0.84.4" +"metro-config@npm:0.87.1": + version: 0.87.1 + resolution: "metro-config@npm:0.87.1" dependencies: connect: "npm:^3.6.5" flow-enums-runtime: "npm:^0.0.6" jest-validate: "npm:^29.7.0" - metro: "npm:0.84.4" - metro-cache: "npm:0.84.4" - metro-core: "npm:0.84.4" - metro-runtime: "npm:0.84.4" - yaml: "npm:^2.6.1" - checksum: 10c0/f8aaf7d8cff9b486353b62f4746b0a70f99749bd4061f5ae847524aaedcd9c5a34bf176cbbe12fb33e771e8ed3c1496654b2578fa5ba8b9e4f856f0589744d98 + metro: "npm:0.87.1" + metro-cache: "npm:0.87.1" + metro-core: "npm:0.87.1" + metro-runtime: "npm:0.87.1" + checksum: 10c0/2c6a10d5581197d467569a590a19b9f493b2691fd5bd9c29291fba7bf8f8c7e4f8dd7099f99d7c29aa56a5198b72ae3d3eefc1e94465d4abb40911c572469fe6 languageName: node linkType: hard -"metro-core@npm:0.84.4, metro-core@npm:^0.84.3": - version: 0.84.4 - resolution: "metro-core@npm:0.84.4" +"metro-core@npm:0.87.1": + version: 0.87.1 + resolution: "metro-core@npm:0.87.1" dependencies: flow-enums-runtime: "npm:^0.0.6" lodash.throttle: "npm:^4.1.1" - metro-resolver: "npm:0.84.4" - checksum: 10c0/19d859de16b5e082c9c31bed981c579a4e6d31a626c7829b725df9ae0ffb755d0ef7809ba9f8adf22d3921f5ffdd931ed77b21b95ca2ea17895f0c99b3cab831 + metro-resolver: "npm:0.87.1" + checksum: 10c0/d945f4ddb9594c27c0c8bb21f819530ddbb9d83f3bdffbc6ef68161d195aa2385ab1cd1b21d1524dfd6fccda409404dd3e6237f065edc1bf1fa8f7a6868012d6 languageName: node linkType: hard -"metro-file-map@npm:0.84.4": - version: 0.84.4 - resolution: "metro-file-map@npm:0.84.4" +"metro-file-map@npm:0.87.1": + version: 0.87.1 + resolution: "metro-file-map@npm:0.87.1" dependencies: debug: "npm:^4.4.0" fb-watchman: "npm:^2.0.0" @@ -19664,76 +19637,75 @@ __metadata: jest-worker: "npm:^29.7.0" micromatch: "npm:^4.0.4" nullthrows: "npm:^1.1.1" - walker: "npm:^1.0.7" - checksum: 10c0/09ca829570d1d6dc5beb0534da8a7f2bfcae5415b0974fd5f58b4a05da95dbafdd47f7dc8dedeb11b6562ee9a92c4d918466d02a05cda6e1eaf2c400cbbe6fb4 + checksum: 10c0/2adfe190819ce68ea96e92238bdbf3f5a4b544c1c89a74199c44411226f6088d8d8a06d425b2922046c20a4ba3548e7fd22c9650a842bbefebe5c2eb11b7419a languageName: node linkType: hard -"metro-minify-terser@npm:0.84.4": - version: 0.84.4 - resolution: "metro-minify-terser@npm:0.84.4" +"metro-minify-terser@npm:0.87.1": + version: 0.87.1 + resolution: "metro-minify-terser@npm:0.87.1" dependencies: flow-enums-runtime: "npm:^0.0.6" terser: "npm:^5.15.0" - checksum: 10c0/c9b36c2adb8254c38bdedad9da8bf2b7fae7f45cbd883e590430a5fc9cad808af24dd08a9420925e15733dab886528ad553e3eeb3faffc53d3ad80e7e03e5f6d + checksum: 10c0/8789263ce8767ab3b389423f974dbc88b57da7ebd3b5bfabb6e6334210c781a8e23802ec417f5140db3dca5509ef83cba0dc570544c9ab774e0c91c38ccff635 languageName: node linkType: hard -"metro-resolver@npm:0.84.4": - version: 0.84.4 - resolution: "metro-resolver@npm:0.84.4" +"metro-resolver@npm:0.87.1": + version: 0.87.1 + resolution: "metro-resolver@npm:0.87.1" dependencies: flow-enums-runtime: "npm:^0.0.6" - checksum: 10c0/468334270598222e15cbee32af51a3b5e1f4fa6869794955b95d1134b28a58594e8e3879e841ccf00bbb5cd86c689a4481714d6c6a464931987d5333d2c55f80 + checksum: 10c0/1218f9a3a2b94d00bf256dd8963460900dad6570f5b4859ac03bf966570c500303576ad47d4616ae9226ce438abb285fcd5cd282862b16d7c2c2b8a22ab7dc44 languageName: node linkType: hard -"metro-runtime@npm:0.84.4, metro-runtime@npm:^0.84.3": - version: 0.84.4 - resolution: "metro-runtime@npm:0.84.4" +"metro-runtime@npm:0.87.1, metro-runtime@npm:^0.87.0": + version: 0.87.1 + resolution: "metro-runtime@npm:0.87.1" dependencies: "@babel/runtime": "npm:^7.25.0" flow-enums-runtime: "npm:^0.0.6" - checksum: 10c0/e2b2e819027940c6bbd081e5650238d52b6c6d78561cd486b8c10cd1e7fce0213c66fa7f885e37ad5377fcd5726b1c9e473fba6de13938cdf2c966e82968c05f + checksum: 10c0/47ccc9aa8205475d11ea25c2f047fb0f870b8c81072adcd38d5e3fdaf8206f3828823e8720bcb7e5f8f7b940d757a127d18d7f48f0c2375a9094247946a8591d languageName: node linkType: hard -"metro-source-map@npm:0.84.4, metro-source-map@npm:^0.84.3": - version: 0.84.4 - resolution: "metro-source-map@npm:0.84.4" +"metro-source-map@npm:0.87.1, metro-source-map@npm:^0.87.0": + version: 0.87.1 + resolution: "metro-source-map@npm:0.87.1" dependencies: "@babel/traverse": "npm:^7.29.0" "@babel/types": "npm:^7.29.0" flow-enums-runtime: "npm:^0.0.6" invariant: "npm:^2.2.4" - metro-symbolicate: "npm:0.84.4" + metro-symbolicate: "npm:0.87.1" nullthrows: "npm:^1.1.1" - ob1: "npm:0.84.4" + ob1: "npm:0.87.1" source-map: "npm:^0.5.6" vlq: "npm:^1.0.0" - checksum: 10c0/39df4524022e07aa4b4d09dd874a9509eb9e2e1e491e80a35099020347ab6be2407851b026452296aad314b0eb7ecf14f9b6bab96bd7c31d47d8b1eb30279aaf + checksum: 10c0/0344446175ea907cd075b6a6d47e31673b14c414fe16a3fd9005c969c9003ace86cfc4a7f73a75c4156da721a8246bbdb7ee5f7d0aa9c6081c80b1f01b0a766a languageName: node linkType: hard -"metro-symbolicate@npm:0.84.4": - version: 0.84.4 - resolution: "metro-symbolicate@npm:0.84.4" +"metro-symbolicate@npm:0.87.1": + version: 0.87.1 + resolution: "metro-symbolicate@npm:0.87.1" dependencies: flow-enums-runtime: "npm:^0.0.6" invariant: "npm:^2.2.4" - metro-source-map: "npm:0.84.4" + metro-source-map: "npm:0.87.1" nullthrows: "npm:^1.1.1" source-map: "npm:^0.5.6" vlq: "npm:^1.0.0" bin: metro-symbolicate: src/index.js - checksum: 10c0/416a9ef694150a8ec708187743b74ab67e0b4fec39c64610b3771b584830117670a62acb9aa824f84a44efbb1cfec07aaf943d1aaf349d977eecf7c72bd8c0bf + checksum: 10c0/4c1b8bab66118bb82bd57b74875ad619b63846340799866b22b394a5f4056bde558c1ec880c8060d55484d0abc96d73bcd6f509bb9d73cc76349a711b5cc3895 languageName: node linkType: hard -"metro-transform-plugins@npm:0.84.4": - version: 0.84.4 - resolution: "metro-transform-plugins@npm:0.84.4" +"metro-transform-plugins@npm:0.87.1": + version: 0.87.1 + resolution: "metro-transform-plugins@npm:0.87.1" dependencies: "@babel/core": "npm:^7.25.2" "@babel/generator": "npm:^7.29.1" @@ -19741,34 +19713,34 @@ __metadata: "@babel/traverse": "npm:^7.29.0" flow-enums-runtime: "npm:^0.0.6" nullthrows: "npm:^1.1.1" - checksum: 10c0/7edb0c0d3655e9f5f5fb8bd8221ec297394b8730c959a3245ea81e50da8177ad7782f21696201a0dcb922281efd919e9548d5b819d8338e52d4b130f06333123 + checksum: 10c0/6ffc825d59fb4af9198114063b27627522de5f6ec20a4c840fbae8b99b6a3896e45f4e53800435e824cac9b708c10af270a90aee98714fbfb2105d4724e5800a languageName: node linkType: hard -"metro-transform-worker@npm:0.84.4": - version: 0.84.4 - resolution: "metro-transform-worker@npm:0.84.4" +"metro-transform-worker@npm:0.87.1": + version: 0.87.1 + resolution: "metro-transform-worker@npm:0.87.1" dependencies: "@babel/core": "npm:^7.25.2" "@babel/generator": "npm:^7.29.1" "@babel/parser": "npm:^7.29.0" "@babel/types": "npm:^7.29.0" flow-enums-runtime: "npm:^0.0.6" - metro: "npm:0.84.4" - metro-babel-transformer: "npm:0.84.4" - metro-cache: "npm:0.84.4" - metro-cache-key: "npm:0.84.4" - metro-minify-terser: "npm:0.84.4" - metro-source-map: "npm:0.84.4" - metro-transform-plugins: "npm:0.84.4" + metro: "npm:0.87.1" + metro-babel-transformer: "npm:0.87.1" + metro-cache: "npm:0.87.1" + metro-cache-key: "npm:0.87.1" + metro-minify-terser: "npm:0.87.1" + metro-source-map: "npm:0.87.1" + metro-transform-plugins: "npm:0.87.1" nullthrows: "npm:^1.1.1" - checksum: 10c0/95924f9bcaf6df931bba2783f440d8fab29909bdde8cecdcc3bc7603e7de71e51728a34288f045694b616c94216d1fc683493b8a470e074c9c8a7f220aa9f9b5 + checksum: 10c0/50401e5aa9249591d940140465c81c7c2088e8e925993a589f6e99a03c8b1cb3cd3ced8e0c5e528f9041a2d15b1904e5a972a1a2945298277d5ed6f9a0558440 languageName: node linkType: hard -"metro@npm:0.84.4, metro@npm:^0.84.3": - version: 0.84.4 - resolution: "metro@npm:0.84.4" +"metro@npm:0.87.1, metro@npm:^0.87.0": + version: 0.87.1 + resolution: "metro@npm:0.87.1" dependencies: "@babel/code-frame": "npm:^7.29.0" "@babel/core": "npm:^7.25.2" @@ -19778,30 +19750,28 @@ __metadata: "@babel/traverse": "npm:^7.29.0" "@babel/types": "npm:^7.29.0" accepts: "npm:^2.0.0" - ci-info: "npm:^2.0.0" connect: "npm:^3.6.5" debug: "npm:^4.4.0" error-stack-parser: "npm:^2.0.6" flow-enums-runtime: "npm:^0.0.6" + flow-parser: "npm:0.331.0" graceful-fs: "npm:^4.2.4" - hermes-parser: "npm:0.35.0" - image-size: "npm:^1.0.2" invariant: "npm:^2.2.4" jest-worker: "npm:^29.7.0" jsc-safe-url: "npm:^0.2.2" lodash.throttle: "npm:^4.1.1" - metro-babel-transformer: "npm:0.84.4" - metro-cache: "npm:0.84.4" - metro-cache-key: "npm:0.84.4" - metro-config: "npm:0.84.4" - metro-core: "npm:0.84.4" - metro-file-map: "npm:0.84.4" - metro-resolver: "npm:0.84.4" - metro-runtime: "npm:0.84.4" - metro-source-map: "npm:0.84.4" - metro-symbolicate: "npm:0.84.4" - metro-transform-plugins: "npm:0.84.4" - metro-transform-worker: "npm:0.84.4" + metro-babel-transformer: "npm:0.87.1" + metro-cache: "npm:0.87.1" + metro-cache-key: "npm:0.87.1" + metro-config: "npm:0.87.1" + metro-core: "npm:0.87.1" + metro-file-map: "npm:0.87.1" + metro-resolver: "npm:0.87.1" + metro-runtime: "npm:0.87.1" + metro-source-map: "npm:0.87.1" + metro-symbolicate: "npm:0.87.1" + metro-transform-plugins: "npm:0.87.1" + metro-transform-worker: "npm:0.87.1" mime-types: "npm:^3.0.1" nullthrows: "npm:^1.1.1" serialize-error: "npm:^2.1.0" @@ -19811,7 +19781,7 @@ __metadata: yargs: "npm:^17.6.2" bin: metro: src/cli.js - checksum: 10c0/ff92915119db29cd855274f3789d391cba83c50cb92e22d1e9b8c729e7f6d39495e32540a22ca4c6591eea6a847ade49fcfa5faab01b2300227e3f1fc7df359c + checksum: 10c0/874637fb0eea6d7b2d970c2dd5c8e3b8dbcae92371b21b231d7bb95037e661db80a1a2f90ec2510d864e0abfe3d88947d256e60845b13436df6cf704a61ec4d1 languageName: node linkType: hard @@ -21280,12 +21250,12 @@ __metadata: languageName: node linkType: hard -"ob1@npm:0.84.4": - version: 0.84.4 - resolution: "ob1@npm:0.84.4" +"ob1@npm:0.87.1": + version: 0.87.1 + resolution: "ob1@npm:0.87.1" dependencies: flow-enums-runtime: "npm:^0.0.6" - checksum: 10c0/8bf3a3bdc2b27f1b1b60569c31ff2d9d829025f9a1ce7388b5e810242e48672c8d6b24e5972d6e30aef4d84f6894d12b13d0c6c418460d031da1972b96920bba + checksum: 10c0/e75cfd9508668aefd23420f167f7305646f8515d71a8fa8d571f77f7c2b5b5862dd6171bf53d05be6061c32424306092bb8aeb359fa49e633d7d9fe40e6155da languageName: node linkType: hard @@ -23794,15 +23764,6 @@ __metadata: languageName: node linkType: hard -"queue@npm:6.0.2": - version: 6.0.2 - resolution: "queue@npm:6.0.2" - dependencies: - inherits: "npm:~2.0.3" - checksum: 10c0/cf987476cc72e7d3aaabe23ccefaab1cd757a2b5e0c8d80b67c9575a6b5e1198807ffd4f0948a3f118b149d1111d810ee773473530b77a5c606673cac2c9c996 - languageName: node - linkType: hard - "quick-lru@npm:^5.1.1": version: 5.1.1 resolution: "quick-lru@npm:5.1.1" @@ -24201,29 +24162,27 @@ __metadata: languageName: node linkType: hard -"react-native@npm:0.86.2": - version: 0.86.2 - resolution: "react-native@npm:0.86.2" +"react-native@npm:0.87.1": + version: 0.87.1 + resolution: "react-native@npm:0.87.1" dependencies: - "@react-native/assets-registry": "npm:0.86.2" - "@react-native/codegen": "npm:0.86.2" - "@react-native/community-cli-plugin": "npm:0.86.2" - "@react-native/gradle-plugin": "npm:0.86.2" - "@react-native/js-polyfills": "npm:0.86.2" - "@react-native/normalize-colors": "npm:0.86.2" - "@react-native/virtualized-lists": "npm:0.86.2" - abort-controller: "npm:^3.0.0" + "@react-native/asset-utils": "npm:0.87.1" + "@react-native/codegen": "npm:0.87.1" + "@react-native/community-cli-plugin": "npm:0.87.1" + "@react-native/gradle-plugin": "npm:0.87.1" + "@react-native/normalize-colors": "npm:0.87.1" + "@react-native/virtualized-lists": "npm:0.87.1" anser: "npm:^1.4.9" ansi-regex: "npm:^5.0.0" - babel-plugin-syntax-hermes-parser: "npm:0.36.0" + babel-plugin-syntax-hermes-parser: "npm:0.36.1" base64-js: "npm:^1.5.1" commander: "npm:^12.0.0" flow-enums-runtime: "npm:^0.0.6" - hermes-compiler: "npm:250829098.0.16" + hermes-compiler: "npm:250829098.0.17" invariant: "npm:^2.2.4" memoize-one: "npm:^5.0.0" - metro-runtime: "npm:^0.84.3" - metro-source-map: "npm:^0.84.3" + metro-runtime: "npm:^0.87.0" + metro-source-map: "npm:^0.87.0" nullthrows: "npm:^1.1.1" pretty-format: "npm:^29.7.0" promise: "npm:^8.3.0" @@ -24238,17 +24197,14 @@ __metadata: ws: "npm:^7.5.10" yargs: "npm:^17.6.2" peerDependencies: - "@react-native/jest-preset": 0.86.2 "@types/react": ^19.1.1 react: ^19.2.3 peerDependenciesMeta: - "@react-native/jest-preset": - optional: true "@types/react": optional: true bin: react-native: cli.js - checksum: 10c0/cb2d91c52f0d1ab18b46c239f801ba86b173126eb53e71aff1e6f22068b58cbfe909f222ff53bdcbfc0d286ddb7448f9c5607b7d6ba0e269a877d014331df337 + checksum: 10c0/c005f48153263c9a81433d2e15e485f740c608220c04ac506a5ffe9eb4263dce1bab9bbc98491b443793c9346dfddc67c577e5e986c05c4972d5a436e9ca2e35 languageName: node linkType: hard @@ -25237,7 +25193,7 @@ __metadata: "@data-client/react": "workspace:*" "@data-client/rest": "workspace:*" "@data-client/test": "workspace:*" - "@react-native/jest-preset": "npm:0.86.2" + "@react-native/jest-preset": "npm:0.87.1" "@react-navigation/native": "npm:^7.0.0" "@react-navigation/native-stack": "npm:^7.0.0" "@testing-library/dom": "npm:^10.4.0" @@ -25267,7 +25223,7 @@ __metadata: prettier: "npm:3.9.5" react: "npm:19.2.3" react-dom: "npm:19.2.3" - react-native: "npm:0.86.2" + react-native: "npm:0.87.1" react-native-safe-area-context: "npm:^5.0.0" react-native-screens: "npm:^4.1.0" react-test-renderer: "npm:19.2.3" @@ -28343,7 +28299,7 @@ __metadata: languageName: node linkType: hard -"walker@npm:^1.0.7, walker@npm:^1.0.8": +"walker@npm:^1.0.8": version: 1.0.8 resolution: "walker@npm:1.0.8" dependencies: @@ -29071,15 +29027,6 @@ __metadata: languageName: node linkType: hard -"yaml@npm:^2.6.1": - version: 2.9.0 - resolution: "yaml@npm:2.9.0" - bin: - yaml: bin.mjs - checksum: 10c0/f340718df45e97a9551b9bf9dac61c80050bc464513b710debfb5067c380c8472e3b67809cffacb4ab5ffb5e66ef9310816c88b05f371cec60abfedd8c88e0a2 - languageName: node - linkType: hard - "yargs-parser@npm:^20.2.2": version: 20.2.9 resolution: "yargs-parser@npm:20.2.9" From fe85a38872b76a2773582a09f6b53827a7acf9a7 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 5 Oct 2026 14:40:11 +0000 Subject: [PATCH 2/3] test: Map react-native/setup-env for @react-native/jest-preset 0.87 The 0.87 jest setup mocks react-native/setup-env; our ReactNative project mirrors the preset's moduleNameMapper so it needs the same alias. Co-authored-by: Nathaniel Tucker --- jest.config.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jest.config.js b/jest.config.js index 1dab51d128b7..38b0dc5e07a3 100644 --- a/jest.config.js +++ b/jest.config.js @@ -114,6 +114,9 @@ const projects = [ resolver: require.resolve('@react-native/jest-preset/jest/resolver.js'), moduleNameMapper: { ...baseConfig.moduleNameMapper, + '^react-native/setup-env$': `${path.dirname( + require.resolve('react-native/package.json'), + )}/src/setup-env.js`, '^react-native($|/.*)': `${path.dirname( require.resolve('react-native/package.json'), )}$1`, From aef625d3e50bc19cac91b4163bf15db17602c20d Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 5 Oct 2026 14:40:11 +0000 Subject: [PATCH 3/3] fix(react): Use requestIdleCallback instead of InteractionManager on React Native React Native 0.87 removed InteractionManager (accessing it throws in DEV). Native GCPolicy and IdlingNetworkManager now share the web implementations, which already schedule via requestIdleCallback with a timeout. Focus revalidation in native useSuspense/useFetch/useDLE uses a cancellable runWhenIdle helper. Co-authored-by: Nathaniel Tucker --- .../references/getDefaultManagers.md | 2 +- .../references/getDefaultManagers.md | 2 +- .changeset/react-native-087-idle-callback.md | 13 +++++ docs/core/api/getDefaultManagers.md | 2 +- .../integration-garbage-collection.native.tsx | 11 +--- .../src/hooks/__tests__/runWhenIdle.native.ts | 57 +++++++++++++++++++ .../src/hooks/__tests__/useDLE.native.tsx | 14 +---- .../src/hooks/__tests__/useFetch.native.tsx | 14 +---- .../hooks/__tests__/useSuspense.native.tsx | 13 +---- .../react/src/hooks/runWhenIdle.native.ts | 13 +++++ packages/react/src/hooks/useDLE.native.ts | 6 +- packages/react/src/hooks/useFetch.native.ts | 6 +- .../react/src/hooks/useSuspense.native.ts | 6 +- .../managers/IdlingNetworkManager.native.ts | 19 ------- .../src/managers/__tests__/RIC.native.ts | 31 +++++----- packages/react/src/state/GCPolicy.native.ts | 19 ------- 16 files changed, 119 insertions(+), 109 deletions(-) create mode 100644 .changeset/react-native-087-idle-callback.md create mode 100644 packages/react/src/hooks/__tests__/runWhenIdle.native.ts create mode 100644 packages/react/src/hooks/runWhenIdle.native.ts delete mode 100644 packages/react/src/managers/IdlingNetworkManager.native.ts delete mode 100644 packages/react/src/state/GCPolicy.native.ts diff --git a/.agents/skills/data-client-manager/references/getDefaultManagers.md b/.agents/skills/data-client-manager/references/getDefaultManagers.md index f4ff0422869f..82799d0188fb 100644 --- a/.agents/skills/data-client-manager/references/getDefaultManagers.md +++ b/.agents/skills/data-client-manager/references/getDefaultManagers.md @@ -91,7 +91,7 @@ const managers = getDefaultManagers({ ``` `IdlingNetworkManager` can prevent stuttering by delaying [sideEffect](https://dataclient.io/rest/api/Endpoint#sideeffect)-free (read-only/GET) fetches -until animations are complete. This works in web using [requestIdleCallback](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback), and react native using InteractionManager.runAfterInteractions. +until animations are complete. This works in both web and React Native using [requestIdleCallback](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback). ### Disabling diff --git a/.agents/skills/data-client-setup/references/getDefaultManagers.md b/.agents/skills/data-client-setup/references/getDefaultManagers.md index 8e5f01cb6919..1166b2309cf3 100644 --- a/.agents/skills/data-client-setup/references/getDefaultManagers.md +++ b/.agents/skills/data-client-setup/references/getDefaultManagers.md @@ -91,7 +91,7 @@ const managers = getDefaultManagers({ ``` `IdlingNetworkManager` can prevent stuttering by delaying [sideEffect](https://dataclient.io/rest/api/Endpoint#sideeffect)-free (read-only/GET) fetches -until animations are complete. This works in web using [requestIdleCallback](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback), and react native using InteractionManager.runAfterInteractions. +until animations are complete. This works in both web and React Native using [requestIdleCallback](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback). ### Disabling diff --git a/.changeset/react-native-087-idle-callback.md b/.changeset/react-native-087-idle-callback.md new file mode 100644 index 000000000000..c137b8502e17 --- /dev/null +++ b/.changeset/react-native-087-idle-callback.md @@ -0,0 +1,13 @@ +--- +'@data-client/react': patch +--- + +Fix React Native 0.87 support + +React Native 0.87 removed `InteractionManager`, so using `@data-client/react` there threw +"InteractionManager has been removed from react-native core" in development. Low-priority work now runs through +`requestIdleCallback`: refetches when a screen regains focus in [useSuspense()](https://dataclient.io/docs/api/useSuspense), +[useFetch()](https://dataclient.io/docs/api/useFetch) and [useDLE()](https://dataclient.io/docs/api/useDLE), +sweeps by `GCPolicy`, and fetches by +[IdlingNetworkManager](https://dataclient.io/docs/api/getDefaultManagers#manager-inheritance). This works on every +supported React Native version. diff --git a/docs/core/api/getDefaultManagers.md b/docs/core/api/getDefaultManagers.md index dbd18870a33c..683f2daa9fff 100644 --- a/docs/core/api/getDefaultManagers.md +++ b/docs/core/api/getDefaultManagers.md @@ -133,7 +133,7 @@ const managers = getDefaultManagers({ ``` `IdlingNetworkManager` can prevent stuttering by delaying [sideEffect](/rest/api/Endpoint#sideeffect)-free (read-only/GET) fetches -until animations are complete. This works in web using [requestIdleCallback](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback), and react native using InteractionManager.runAfterInteractions. +until animations are complete. This works in both web and React Native using [requestIdleCallback](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback). ::: diff --git a/packages/react/src/__tests__/integration-garbage-collection.native.tsx b/packages/react/src/__tests__/integration-garbage-collection.native.tsx index 9d66d2c16416..5657d812b694 100644 --- a/packages/react/src/__tests__/integration-garbage-collection.native.tsx +++ b/packages/react/src/__tests__/integration-garbage-collection.native.tsx @@ -8,13 +8,7 @@ import { MockResolver } from '@data-client/test'; import { render, screen, act, fireEvent } from '@testing-library/react-native'; import { ArticleResource } from '__tests__/new'; import { useState } from 'react'; -import { - View, - Text, - Button, - TouchableOpacity, - InteractionManager, -} from 'react-native'; +import { View, Text, Button, TouchableOpacity } from 'react-native'; const mockGetList = jest.fn(); const mockGet = jest.fn(); @@ -114,7 +108,6 @@ describe('Integration Garbage Collection React Native', () => { await act(async () => { jest.advanceTimersByTime(1000); - InteractionManager.setDeadline(0); await jest.runOnlyPendingTimersAsync(); }); @@ -132,7 +125,6 @@ describe('Integration Garbage Collection React Native', () => { // Jest time pass to trigger sweep but not expired act(() => { jest.advanceTimersByTime(GC_INTERVAL); - InteractionManager.setDeadline(0); }); // Switch back to list view @@ -156,7 +148,6 @@ describe('Integration Garbage Collection React Native', () => { GC_INTERVAL, ), ); - InteractionManager.setDeadline(0); await jest.runOnlyPendingTimersAsync(); }); diff --git a/packages/react/src/hooks/__tests__/runWhenIdle.native.ts b/packages/react/src/hooks/__tests__/runWhenIdle.native.ts new file mode 100644 index 000000000000..23b281e78f2f --- /dev/null +++ b/packages/react/src/hooks/__tests__/runWhenIdle.native.ts @@ -0,0 +1,57 @@ +import runWhenIdle from '../runWhenIdle.native'; + +describe('runWhenIdle', () => { + beforeEach(() => { + jest.useFakeTimers(); + }); + afterEach(() => { + delete (global as any).requestIdleCallback; + delete (global as any).cancelIdleCallback; + jest.useRealTimers(); + }); + + describe('with requestIdleCallback', () => { + beforeEach(() => { + (global as any).requestIdleCallback = jest.fn((cb: () => void) => + setTimeout(cb, 0), + ); + (global as any).cancelIdleCallback = jest.fn(clearTimeout); + }); + + it('should defer callback until idle', () => { + const fn = jest.fn(); + runWhenIdle(fn); + expect((global as any).requestIdleCallback).toHaveBeenCalledWith(fn); + expect(fn).not.toHaveBeenCalled(); + jest.runAllTimers(); + expect(fn).toHaveBeenCalledTimes(1); + }); + + it('should cancel with cancelIdleCallback', () => { + const fn = jest.fn(); + const cancel = runWhenIdle(fn); + cancel(); + expect((global as any).cancelIdleCallback).toHaveBeenCalled(); + jest.runAllTimers(); + expect(fn).not.toHaveBeenCalled(); + }); + }); + + describe('without requestIdleCallback', () => { + it('should defer callback to a timeout', () => { + const fn = jest.fn(); + runWhenIdle(fn); + expect(fn).not.toHaveBeenCalled(); + jest.runAllTimers(); + expect(fn).toHaveBeenCalledTimes(1); + }); + + it('should cancel pending timeout', () => { + const fn = jest.fn(); + const cancel = runWhenIdle(fn); + cancel(); + jest.runAllTimers(); + expect(fn).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/packages/react/src/hooks/__tests__/useDLE.native.tsx b/packages/react/src/hooks/__tests__/useDLE.native.tsx index 0797e964f543..fc26fdf3cb07 100644 --- a/packages/react/src/hooks/__tests__/useDLE.native.tsx +++ b/packages/react/src/hooks/__tests__/useDLE.native.tsx @@ -20,7 +20,7 @@ import { createEntityMeta } from '__tests__/utils'; import nock from 'nock'; import React, { Suspense } from 'react'; // relative imports to avoid circular dependency in tsconfig references -import { InteractionManager, Text, View } from 'react-native'; +import { Text, View } from 'react-native'; import { AsyncBoundary } from '../..'; import { StateContext, ControllerContext } from '../../context'; @@ -276,22 +276,14 @@ describe('useDLE', () => { const { getByText, getByTestId } = render(tree); expect(fbmock).not.toHaveBeenCalled(); - await new Promise(resolve => - InteractionManager.runAfterInteractions(() => { - resolve(null); - }), - ); + await new Promise(resolve => setTimeout(resolve, 0)); // still should revalidate expect(dispatch.mock.calls.length).toBe(1); act(() => thenavigation.navigate('Home')); expect(getByText('Home')).toBeDefined(); act(() => thenavigation.goBack()); - await new Promise(resolve => - InteractionManager.runAfterInteractions(() => { - resolve(null); - }), - ); + await new Promise(resolve => setTimeout(resolve, 0)); expect(getByTestId('article')).toBeDefined(); // since we got focus back we should have called again expect(dispatch.mock.calls.length).toBe(2); diff --git a/packages/react/src/hooks/__tests__/useFetch.native.tsx b/packages/react/src/hooks/__tests__/useFetch.native.tsx index 7c1c7b46c621..e89c11f3f483 100644 --- a/packages/react/src/hooks/__tests__/useFetch.native.tsx +++ b/packages/react/src/hooks/__tests__/useFetch.native.tsx @@ -19,7 +19,7 @@ import { createEntityMeta } from '__tests__/utils'; import nock from 'nock'; import React, { Suspense } from 'react'; // relative imports to avoid circular dependency in tsconfig references -import { InteractionManager, Text, View } from 'react-native'; +import { Text, View } from 'react-native'; import { AsyncBoundary } from '../..'; import { StateContext, ControllerContext } from '../../context'; @@ -309,22 +309,14 @@ describe('useFetch', () => { const { getByText, getByTestId } = render(tree); expect(fbmock).not.toHaveBeenCalled(); - await new Promise(resolve => - InteractionManager.runAfterInteractions(() => { - resolve(null); - }), - ); + await new Promise(resolve => setTimeout(resolve, 0)); // still should revalidate expect(dispatch.mock.calls.length).toBe(1); act(() => thenavigation.navigate('Home')); expect(getByText('Home')).toBeDefined(); act(() => thenavigation.goBack()); - await new Promise(resolve => - InteractionManager.runAfterInteractions(() => { - resolve(null); - }), - ); + await new Promise(resolve => setTimeout(resolve, 0)); // since we got focus back we should have called again expect(dispatch.mock.calls.length).toBe(2); diff --git a/packages/react/src/hooks/__tests__/useSuspense.native.tsx b/packages/react/src/hooks/__tests__/useSuspense.native.tsx index 7631c4ee97df..27926cb3869f 100644 --- a/packages/react/src/hooks/__tests__/useSuspense.native.tsx +++ b/packages/react/src/hooks/__tests__/useSuspense.native.tsx @@ -36,7 +36,6 @@ import { createEntityMeta } from '__tests__/utils'; import nock from 'nock'; import React, { Suspense } from 'react'; import { Text, View } from 'react-native'; -import { InteractionManager } from 'react-native'; import { Temporal } from 'temporal-polyfill'; // relative imports to avoid circular dependency in tsconfig references @@ -287,22 +286,14 @@ describe('useSuspense()', () => { const { getByText, getByTestId } = render(tree); expect(fbmock).not.toHaveBeenCalled(); - await new Promise(resolve => - InteractionManager.runAfterInteractions(() => { - resolve(null); - }), - ); + await new Promise(resolve => setTimeout(resolve, 0)); // still should revalidate expect(dispatch.mock.calls.length).toBe(1); act(() => thenavigation.navigate('Home')); expect(getByText('Home')).toBeDefined(); act(() => thenavigation.goBack()); - await new Promise(resolve => - InteractionManager.runAfterInteractions(() => { - resolve(null); - }), - ); + await new Promise(resolve => setTimeout(resolve, 0)); expect(getByTestId('article')).toBeDefined(); // since we got focus back we should have called again expect(dispatch.mock.calls.length).toBe(2); diff --git a/packages/react/src/hooks/runWhenIdle.native.ts b/packages/react/src/hooks/runWhenIdle.native.ts new file mode 100644 index 000000000000..9d5796187f69 --- /dev/null +++ b/packages/react/src/hooks/runWhenIdle.native.ts @@ -0,0 +1,13 @@ +/** Defers low-priority work until the JS thread is idle + * + * @returns cancels the callback if it has not yet run + */ +export default function runWhenIdle(callback: () => void): () => void { + // @react-native/jest-preset runs in a plain Node environment without requestIdleCallback + if (typeof requestIdleCallback === 'function') { + const handle = requestIdleCallback(callback); + return () => cancelIdleCallback(handle); + } + const handle = setTimeout(callback, 0); + return () => clearTimeout(handle); +} diff --git a/packages/react/src/hooks/useDLE.native.ts b/packages/react/src/hooks/useDLE.native.ts index 70c2e1a456c1..1a99e25fdca8 100644 --- a/packages/react/src/hooks/useDLE.native.ts +++ b/packages/react/src/hooks/useDLE.native.ts @@ -9,8 +9,8 @@ import type { } from '@data-client/core'; import { ExpiryStatus } from '@data-client/core'; import { useEffect, useMemo } from 'react'; -import { InteractionManager } from 'react-native'; +import runWhenIdle from './runWhenIdle.native.js'; import useCacheState from './useCacheState.js'; import useController from './useController.js'; import useFocusEffect from './useFocusEffect.native.js'; @@ -119,13 +119,11 @@ export default function useDLE< useFocusEffect(() => { // revalidating non-suspending data is low priority, so make sure it doesn't stutter animations - const task = InteractionManager.runAfterInteractions(() => { + return runWhenIdle(() => { if (Date.now() > expiresAt && key) { controller.fetch(endpoint, ...(args as Parameters)); } }); - - return () => task.cancel(); }, []); const data = useMemo(() => { diff --git a/packages/react/src/hooks/useFetch.native.ts b/packages/react/src/hooks/useFetch.native.ts index 3af19e10c4fa..d4fea45fdc23 100644 --- a/packages/react/src/hooks/useFetch.native.ts +++ b/packages/react/src/hooks/useFetch.native.ts @@ -8,8 +8,8 @@ import type { ResolveType, } from '@data-client/core'; import { useEffect, useMemo } from 'react'; -import { InteractionManager } from 'react-native'; +import runWhenIdle from './runWhenIdle.native.js'; import { UsablePromise, createFulfilled, @@ -109,13 +109,11 @@ export default function useFetch< useFocusEffect(() => { // revalidating non-suspending data is low priority, so make sure it doesn't stutter animations - const task = InteractionManager.runAfterInteractions(() => { + return runWhenIdle(() => { if (Date.now() > expiresAt && key) { controller.fetch(endpoint, ...(args as Parameters)); } }); - - return () => task.cancel(); }, []); if (!key) return undefined; diff --git a/packages/react/src/hooks/useSuspense.native.ts b/packages/react/src/hooks/useSuspense.native.ts index b607ea43915b..7dd27f1a3755 100644 --- a/packages/react/src/hooks/useSuspense.native.ts +++ b/packages/react/src/hooks/useSuspense.native.ts @@ -9,8 +9,8 @@ import type { NI, } from '@data-client/core'; import { useEffect, useMemo } from 'react'; -import { InteractionManager } from 'react-native'; +import runWhenIdle from './runWhenIdle.native.js'; import useCacheState from './useCacheState.js'; import useController from './useController.js'; import useFocusEffect from './useFocusEffect.native.js'; @@ -106,13 +106,11 @@ export default function useSuspense< useFocusEffect(() => { // revalidating non-suspending data is low priority, so make sure it doesn't stutter animations - const task = InteractionManager.runAfterInteractions(() => { + return runWhenIdle(() => { if (Date.now() > expiresAt && key) { controller.fetch(endpoint, ...(args as Parameters)); } }); - - return () => task.cancel(); }, []); // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/packages/react/src/managers/IdlingNetworkManager.native.ts b/packages/react/src/managers/IdlingNetworkManager.native.ts deleted file mode 100644 index 1d2f830321df..000000000000 --- a/packages/react/src/managers/IdlingNetworkManager.native.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { NetworkManager } from '@data-client/core'; -import { InteractionManager } from 'react-native'; - -/** Can help prevent stuttering by waiting for idle for sideEffect free fetches */ -export default class NativeIdlingNetworkManager extends NetworkManager { - /** Calls the callback when client is not 'busy' with high priority interaction tasks - * - * Override for platform-specific implementations - */ - protected idleCallback( - callback: (...args: any[]) => void, - options?: IdleRequestOptions, - ) { - InteractionManager.runAfterInteractions(callback); - if (options?.timeout) { - InteractionManager.setDeadline(options.timeout); - } - } -} diff --git a/packages/react/src/managers/__tests__/RIC.native.ts b/packages/react/src/managers/__tests__/RIC.native.ts index d6445544429e..6b338d356793 100644 --- a/packages/react/src/managers/__tests__/RIC.native.ts +++ b/packages/react/src/managers/__tests__/RIC.native.ts @@ -1,29 +1,34 @@ -import { IdlingNetworkManager } from '..'; describe('RequestIdleCallback', () => { - let warnSpy: jest.SpyInstance; - beforeEach(() => { - warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); - }); afterEach(() => { - warnSpy.mockRestore(); + delete (global as any).requestIdleCallback; + jest.useRealTimers(); }); - it('should run using InteractionManager', async () => { + it('should still run when requestIdleCallback is not available', async () => { + jest.resetModules(); + const { IdlingNetworkManager } = await import('..'); const fn = jest.fn(); - jest.useFakeTimers(); // @ts-expect-error this is protected member new IdlingNetworkManager().idleCallback(fn, {}); - jest.runAllTimers(); expect(fn).toHaveBeenCalled(); - jest.useRealTimers(); }); - it('should run with timeout using InteractionManager', async () => { - const fn = jest.fn(); + + it('should run through requestIdleCallback with timeout', async () => { jest.useFakeTimers(); + (global as any).requestIdleCallback = jest.fn( + (cb: () => void, options?: IdleRequestOptions) => + setTimeout(cb, options?.timeout ?? 0), + ); + jest.resetModules(); + const { IdlingNetworkManager } = await import('..'); + const fn = jest.fn(); // @ts-expect-error this is protected member new IdlingNetworkManager().idleCallback(fn, { timeout: 500 }); + expect(fn).not.toHaveBeenCalled(); + expect((global as any).requestIdleCallback).toHaveBeenCalledWith(fn, { + timeout: 500, + }); jest.runAllTimers(); expect(fn).toHaveBeenCalled(); - jest.useRealTimers(); }); }); diff --git a/packages/react/src/state/GCPolicy.native.ts b/packages/react/src/state/GCPolicy.native.ts deleted file mode 100644 index ef657929d5d5..000000000000 --- a/packages/react/src/state/GCPolicy.native.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { GCPolicy } from '@data-client/core'; -import { InteractionManager } from 'react-native'; - -/** Can help prevent stuttering by waiting for idle before performing GC sweeps */ -export default class NativeGCPolicy extends GCPolicy { - /** Calls the callback when client is not 'busy' with high priority interaction tasks - * - * Override for platform-specific implementations - */ - protected idleCallback( - callback: (...args: any[]) => void, - options?: IdleRequestOptions, - ) { - InteractionManager.runAfterInteractions(callback); - if (options?.timeout) { - InteractionManager.setDeadline(options.timeout); - } - } -}