Commit Graph
41612 Commits
Author SHA1 Message Date
Fabrizio Cucci 993be7d6c6 Bump Hermes to 260318099.0.4
Picks up two fixes released in hermes-v260318099.0.4:

- Avoid reserve() in ConsecutiveStringStorage. Lazy compilation appends to
  the string storage on every newly compiled function, and reserve() on
  libc++ sizes to exactly the requested capacity rather than growing
  geometrically, so repeated appends were quadratic.
- Re-land of the VariableScope rescan optimization.

See https://github.com/reactwg/react-native-releases/issues/1430
2026-09-27 12:28:32 +01:00
Fabrizio Cucci 13d30b643c Regenerate C++ API snapshots after the ObjC ArrayBuffer reverts
The revert of the NSData argument path moved codegen back to NSMutableData
but did not refresh the recorded snapshots, leaving Validate C++ API
Snapshots red on the release branch.

Changelog: [Internal]
2026-09-24 15:31:31 +01:00
Christian Falch 7fdfc4ebf3 Repair stale staged headers in the iOS prebuild (#58596)
Summary:
The iOS prebuild (`node scripts/ios-prebuild`) stages React Native's headers into `packages/react-native/.build/headers` as hard links, and skipped any target that already existed.

When changing the original source files, these hard links can become stale and errors like this can occur:

```
Libraries/LinkingIOS/RCTLinkingManager.mm:91:7: error: use of undeclared identifier 'RCTIsSceneDelegateApp'
```

This is a problem that contributors will see - not regular users, but the fix helps with strange error messages.

## Changelog:

[INTERNAL] [FIXED] - Repair stale staged headers in the iOS prebuild instead of compiling against a previous checkout's copies

Pull Request resolved: https://github.com/react/react-native/pull/58596

Test Plan:
✅ New unit tests, 16 cases in `packages/react-native/scripts/ios-prebuild/__tests__/setup-test.js`, using real temporary directories rather than an `fs` mock, since the defect is about inodes.

End to end on an Xcode 27 checkout:

- Replaced a staged header with a copy, so it kept the same contents but a different inode. `node scripts/ios-prebuild -s -f Debug` restored it to the source inode and logged `Linked React/Base → .build/headers/React`. The previous code skipped it.
- Ran setup a second time with nothing changed: no file was relinked, and nothing was logged.
- Confirmed the three colliding targets still resolve to the same source as before the change, by inode.
- `node scripts/ios-prebuild -b -f Debug -p ios-simulator` → `** BUILD SUCCEEDED **`.

Reviewed By: cipolleschi

Differential Revision: D120740409

Pulled By: shwanton

fbshipit-source-id: 41c1eb112c3395d6c7158d7151be7fdd92a21cef
(cherry picked from commit b935e74ad5)
2026-09-24 15:23:36 +01:00
Christian Falch 9465ef76f7 Stop re-creating library package roots on every sync (#58597)
Summary:
Building an app in Xcode fails when it autolinks a library that ships its own `Package.swift`, with one error per such library:

```
Missing package product 'reactnativeskia_ReactNativeSkia.ReactNativeSkia'
Missing package product 'reactnativesafeareacontext_ReactNativeSafeAreaContext.ReactNativeSafeAreaContext'
```

The same project builds fine from the command line. Two problems combine.

**The sync destroys package roots Xcode has already loaded.** Autolinking writes one symlink per self-managed library into `build/generated/autolinking/libs/<Name>`, and Xcode treats each as a local Swift package root. The generator deleted that whole directory and recreated it on every run, even when the generated output was byte-for-byte identical. Measured on a real app, across one no-op sync: the `libs/` inode changed from 1913513750 to 1913930645, `libs/ReactNativeSkia` from 1913513937 to 1913930649, while the generated `Package.swift` kept the same MD5. Recreating a package root that Xcode has already resolved is what produces the error above.

**Xcode's own bookkeeping made the sync run every time.** The "Sync SPM Autolinking" build phase re-syncs when a watched input looks newer than its stamp, and it checked each library's whole directory with `find <dir> -newer <stamp>`. Xcode writes its per-user scheme state inside that directory, at `<lib>/.swiftpm/xcode/xcuserdata/<user>.xcuserdatad/xcschemes/xcschememanagement.plist`. So Xcode's own write marked the next build stale, which triggered the destructive re-sync, which broke that build. `xcodebuild` does not write that file, which is why command-line builds were never affected.

This change makes the `libs/` tree idempotent — unchanged entries keep their inode, and entries that are no longer autolinked are pruned instead of wiped — and makes the staleness check skip `.swiftpm`.

### How to verify

In an app that autolinks a library shipping its own `Package.swift`, build in Xcode twice in a row. Both builds should succeed. Before this change the second build fails with `Missing package product`.

## Changelog:
[IOS][FIXED] - Stop SwiftPM autolinking from recreating library package roots on every sync, which broke Xcode builds of apps using libraries that ship their own Package.swift

Pull Request resolved: https://github.com/react/react-native/pull/58597

Test Plan:
**Unit tests.** `yarn test packages/react-native/scripts/spm` — 21 suites, 1009 tests pass.

New tests, written and seen failing before the fix:

- Two consecutive generation runs over an unchanged self-managed dependency keep both the `libs/` inode and each entry's inode. Failed before the fix with the same inode churn measured on the real app.
- A dependency removed between two runs leaves no symlink under `libs/`.
- The emitted staleness snippet is extracted from the generated script and executed under `/bin/bash -c` with `set -euo pipefail` against a temporary tree. A write under `.swiftpm/` is ignored; a real source change is still detected.

**Real app.** A React Native 0.87.1 app on Xcode 27 autolinking `shopify/react-native-skia` and `react-native-safe-area-context`, both self-managed. Before: `xcodebuild` succeeded, Xcode failed in about 5 seconds with the two errors above, on nearly every build.

**Not run:** the full CI matrix, and no Android-side check — this touches iOS SwiftPM tooling only.

## Scope

Deliberately minimal.

One case still re-syncs: the first time Xcode creates `.swiftpm` inside a library, that bumps the library directory's own mtime, so the build after a fresh checkout reports stale once per library. That is harmless now that the sync is idempotent.

One related item is left alone: the aggregate `Package.swift` is still rewritten on every sync even when its content is unchanged, which bumps its mtime and can make Xcode re-resolve. That is wasteful but not destructive, and it is no longer reached on an ordinary IDE build now that `.swiftpm` writes do not mark the sync stale.

Reviewed By: cipolleschi

Differential Revision: D120740029

Pulled By: shwanton

fbshipit-source-id: 3783d4cee4791ab13517d8f0dcac71f752cb7c1b
(cherry picked from commit 97cc934dc7)
2026-09-24 15:23:27 +01:00
Bao Nguyen 6532c25d24 Expose ReactNativeFeatureFlags through react-private-interface (#57940)
Summary:
Fixes https://github.com/react/react-native/issues/57933.

`react-native/virtualized-lists` is published separately and imported `ReactNativeFeatureFlags` through `react-native/src/private/featureflags/ReactNativeFeatureFlags`, which is not listed in `react-native`'s `"exports"`. Metro therefore warned and fell back to file-based resolution whenever an app rendered a virtualized list.

Thanks huntie for the patch and the direction — this PR now applies it instead of the original approach:

- `ReactNativeFeatureFlags` is exposed on the existing private package boundary, `react-native/react-private-interface` (both the runtime getter and the `.js.flow` re-export);
- `VirtualizedList.js` and `VirtualizeUtils.js` import it from there.

No new `src/private/*` subpath is exported, and the feature-flag singleton is unchanged.

Per your review, the `scripts/monorepo-tests/__tests__/check-packages-test.js` and `scripts/shared/monorepoUtils.js` changes have been dropped — the PR is now just the patch above. Happy to look at enabling `react-native/no-deep-imports` on `virtualized-lists` as a follow-up if that's wanted.

`VirtualizeUtils.js` is included alongside `VirtualizedList.js` because it carried the same runtime deep import. The remaining occurrences are out of scope: the four in `react-native/jest-preset` are all `import type` and are erased before resolution, and the one in `VirtualizeUtils-test.js` is not shipped (`virtualized-lists` excludes `**/__tests__/**` from `files`).

## Changelog:

[GENERAL] [FIXED] - Fix the Metro package-exports warning caused by `react-native/virtualized-lists` importing an unexported React Native subpath.

Pull Request resolved: https://github.com/react/react-native/pull/57940

Test Plan:
No new test is added. The existing `virtualized-lists` suites already cover this route, because `VirtualizeUtils`/`VirtualizedList` read the flags at runtime through the new boundary.

Counterfactual — dropping only the `ReactNativeFeatureFlags` getter and its `import typeof` from `react-private-interface.js`, keeping the two `virtualized-lists` imports:

```text
TypeError: Cannot read properties of undefined (reading 'fixVirtualizeListCollapseWindowSize')

      182 |     let lastWillAddMore;
      183 |
    > 184 |     if (ReactNativeFeatureFlags.fixVirtualizeListCollapseWindowSize()) {
          |                                ^

      at computeWindowedRenderLimits (packages/virtualized-lists/Lists/VirtualizeUtils.js:184:32)
      at Object.<anonymous> (packages/virtualized-lists/Lists/__tests__/VirtualizeUtils-test.js:261:47)

Test Suites: 2 failed, 6 passed, 8 total
Tests:       20 failed, 1 skipped, 151 passed, 172 total
```

Restoring the getter makes it green again.

```text
$ yarn jest packages/virtualized-lists scripts/monorepo-tests packages/react-native/Libraries/ReactPrivate --runInBand
Test Suites: 9 passed, 9 total
Tests:       1 skipped, 176 passed, 177 total
Snapshots:   69 passed, 69 total

$ yarn flow-check
Found 0 errors

$ yarn lint
$ eslint --max-warnings 0 .
Done in 10.23s.
```

Reviewed By: javache

Differential Revision: D119164284

Pulled By: cortinico

fbshipit-source-id: 1e8ae3b85ae7fb28c55f207f887a97aad85b563c
(cherry picked from commit a506ed66cc)
2026-09-24 15:23:18 +01:00
Oskar Pawica e1988679c7 fix(android): bump androidx.collection to 1.4.4 to avoid MutableIntObjectMap corruption in SurfaceMountingManager (#58389)
Summary:
since https://github.com/react/react-native/issues/56646 the view registry is a `MutableIntObjectMap`; `androidx.collection` 1.4.0 to 1.4.2 corrupt `ScatterMap` and its primitive variants after remove-heavy sequences, fixed in 1.4.3 (https://issuetracker.google.com/issues/352560465). Apps resolve 1.4.0 or 1.4.2 and lose registry entries; RN then drops mount instructions and can leave stale views.

Fixes https://github.com/react/react-native/issues/58388.

## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->

`[ANDROID] [FIXED] - Bump androidx.collection to 1.4.4 to fix view registry entries getting lost in SurfaceMountingManager`

Pull Request resolved: https://github.com/react/react-native/pull/58389

Test Plan:
Reproducer: https://github.com/pawicao/rn-android-view-registry-corruption
- RN 0.87.1 app resolving androidx.collection 1.4.2: 91 `Unable to find viewState` soft exceptions on 45 tags over two 40-round runs on a Pixel 9a, and a stale view left on screen.
- Same screen with androidx.collection pinned to 1.4.4: none over 120 rounds.

Reviewed By: cortinico

Differential Revision: D119149754

Pulled By: javache

fbshipit-source-id: afb13330bac575218a07a030bb1bcd5bf7e00824
(cherry picked from commit d6a5f159c6)
2026-09-24 15:23:08 +01:00
React Native Bot 62f0e0b54a [LOCAL] Bump Podfile.lock 2026-09-21 18:05:20 +00:00
React Native Bot 215169c51b Release 0.88.0-rc.2
#publish-packages-to-npm&next
v0.88.0-rc.2
2026-09-21 16:15:27 +00:00
Fabrizio Cucci 070af03ab3 Revert "Align TurboModule EventEmitter payload types across platforms (#58063)"
This reverts commit ab2ea649e6.
2026-09-21 14:42:15 +01:00
Fabrizio Cucci 19a3184981 Revert "Use NSData for the JS->ObjC ArrayBuffer argument path (#57596)"
This reverts commit 5e86c323ce.

# Conflicts:
#	packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleHObjCpp-test.js.snap
#	packages/react-native/ReactCommon/react/nativemodule/core/iostests/RCTTurboModuleTests.mm
2026-09-21 12:17:17 +01:00
Fabrizio Cucci 639cdedb50 Revert "RCTArrayBuffer zero-copy class for ObjC TM (#57879)"
This reverts commit 11f9a7f449.

# Conflicts:
#	packages/react-native/ReactCommon/react/nativemodule/core/iostests/RCTTurboModuleTests.mm
#	packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm
2026-09-21 12:15:49 +01:00
Rob Hogan f2439a83cf [0.88][LOCAL] Bump Metro minimum to 0.87.1
## Summary:

Bump minimum Metro version to 0.87.1, within the same semver range, to ensure upgraders get the same version as fresh projects would.

Mostly fixes, including a couple of `Platform` inlining corrections. It also replaces the `image-size` dependency to clear CVE alerts.

Metro release notes: https://github.com/react/metro/releases/tag/v0.87.1

## Changelog:

[General] [Changed] - Bump Metro minimum to 0.87.1

## Test Plan:

```
yarn install --frozen-lockfile --ignore-scripts
yarn flow-check
yarn test packages/metro-config packages/community-cli-plugin packages/dev-middleware
```

(cherry picked from commit 18a22b1d59)
2026-09-21 10:24:24 +01:00
Fabrizio Cucci 579212e15c Restore .js fallback for legacy deep imports of untyped modules
Relocating the hand-written declarations under types_DEPRECATED/ (#57513)
changed where the react-native-legacy-deep-imports export condition points
for ./Libraries/*. It used to resolve to ./Libraries/*.d.ts, beside the real
.js, so TypeScript's extension substitution still found modules with no
hand-written declaration. It now resolves into types_DEPRECATED/, which
contains no .js files, so those specifiers stop resolving.

Reported against 0.88.0-rc.0 with react-native/Libraries/Core/InitializeCore.

Add the old location as a second entry so the condition falls back to it.
Modules that do have a declaration keep resolving to types_DEPRECATED/
because that entry is still first.

This is applied to 0.88-stable only. 0.88 is a non-breaking release, so the
regression must not ship in it. main intentionally keeps the current
behaviour pending a deliberate decision on retiring deep imports.
2026-09-16 13:36:44 +01:00
React Native Bot 74760de04c [LOCAL] Bump Podfile.lock 2026-09-15 23:46:34 +00:00
React Native Bot 05a41cdc67 Release 0.88.0-rc.1
#publish-packages-to-npm&next
v0.88.0-rc.1
2026-09-15 22:16:48 +00:00
Fabrizio Cucci ad7b17d8ee Fix cache-key test on release branches
getCacheKey only hashes package contents when the version ends in -main;
published releases short-circuit to the version string. The test asserted
only the main-build property, so it failed on every release branch.
Assert the correct property for each case.
2026-09-15 20:26:15 +01:00
Christian Falch 6069149f25 Derive the generated manifests' iOS platform floor from the app (#58379)
Summary:
The SwiftPM manifests React Native generates — the `Autolinked` aggregate, the per-dependency synth packages, and the scaffolded community packages — hardcoded `platforms: [.iOS(.v15)]`. SwiftPM refuses to link a product whose minimum platform is above the depending target's, so any self-managed package with a higher floor could not be autolinked. Every Expo package declares iOS 16.4, so a stock Expo app on 0.87.1 fails at build time with:

```
error: The package product 'Expo' requires minimum platform version 16.4 for the iOS platform,
       but this target supports 15.0 (in target 'AutolinkedAggregate' from project 'Autolinked')
```

The app itself is correct (`IPHONEOS_DEPLOYMENT_TARGET = 16.4`); the only disagreement was the generated manifests.

The floor is now the app's own `IPHONEOS_DEPLOYMENT_TARGET`, read from the injected `.xcodeproj`:

- Target selection: the injection marker's `targetUuid`, else the application target named by `--product-name`, else every application target.
- Per configuration: the target's own value, else the project-level configuration of the same name. The lowest value wins, since one manifest floor has to hold for every configuration.
- Clamped to React Native's minimum (15.1, `min_ios_version_supported`) and emitted in string form (`.iOS("16.4")`), because the `.vNN` enum form cannot express a minor version.

`setup-apple-spm.js` resolves the value once per `add`/`update`/`sync`/`scaffold` run, logs it (`iOS deployment target: 16.4 (from MyApp.xcodeproj)`), and passes it to the generator, the sync script, and the scaffolder via a new `--ios-deployment-target` flag. The flag value is sanitized at the generator boundary as well. `SCAFFOLDER_VERSION` is bumped to 20 so existing scaffolds regenerate with the new floor.

A floor set in an `.xcconfig` the configuration is based on is honored, including `#include` chains (target literal → target xcconfig → project literal → project xcconfig). A floor supplied through a build-setting variable (`$(MY_FLOOR)`) is not resolved and falls back to the minimum; the log line says so. `spm add` and `spm update` also refresh the `platforms:` element of existing scaffolded manifests (those carrying the scaffolder marker, including the pre-v20 `.iOS(.v15)` form, over the same expanded dependency set the scaffolder uses, transitive SwiftPM dependencies included) without creating new scaffolds or touching anything else in them.

Known limitation, documented in `scripts/spm/__docs__/spm-scripts.md`: the project file is not one of the auto-sync build phase's staleness inputs, so a deployment target changed after `spm add` takes effect on the next `spm update`.

The default floor moves from 15.0 to 15.1 for apps without a readable project setting; React Native already requires 15.1 for the app target, so this is not observable.

## Changelog:

[IOS] [FIXED] - SwiftPM: generated manifests derive their iOS platform floor from the app's `IPHONEOS_DEPLOYMENT_TARGET` instead of hardcoding iOS 15, so dependencies with a higher minimum (e.g. Expo, 16.4) can be autolinked

Pull Request resolved: https://github.com/react/react-native/pull/58379

Test Plan:
Unit tests were written first and seen failing, then made green:

```
yarn jest --no-cache -i packages/react-native/scripts/spm
Test Suites: 37 passed, 37 total
Tests:       1733 passed, 1733 total
```

New/updated coverage: `ios-deployment-target-test.js` (pbxproj reading: target-level, project-level fallback, xcconfig chain with `#include` and `<group>` anchoring, minimum across configurations, marker/`--product-name`/all-targets selection, invalid values, clamping, unreadable project), `scaffold-package-swift-test.js` (emitted floor, refresh of existing scaffolded manifests), `generate-spm-autolinking-test.js` (aggregate and synth templates, `--ios-deployment-target` through `main()`), `scaffold-package-swift-test.js`, `sync-spm-autolinking-test.js` (flag forwarding), `setup-apple-spm-test.js` (resolution and log line).

ESLint (`--max-warnings 0`), Prettier, and Flow are clean on the touched files.

Not run here: an end-to-end Xcode build of an Expo app on this branch. The failing scenario and the fix were verified by the Expo team against 0.87.1 with the same manifest change patched in locally (build proceeds past SwiftPM resolution into compiling `Expo`).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed By: cortinico

Differential Revision: D119653699

Pulled By: cipolleschi

fbshipit-source-id: 7c69dd4d97bed719f7bbd28fb0832cdf2f151f55
(cherry picked from commit 92564f33fd)
2026-09-15 16:53:25 +01:00
Lazizbek Ergashev 903c4ab763 Run SPM-generated shell scripts under bash, not /bin/sh (#58362)
Summary:
SPM setup scripts start with `set -euo pipefail`, but every one of them runs under `/bin/sh`. On a machine where `/bin/sh` isn't bash (e.g. dash), that fails immediately with `set: Illegal option -o pipefail`, so no SwiftPM build gets past the first build phase.

Two spots in `generate-spm-xcodeproj.js`:

- `shellScriptPhase` hardcodes `shellPath: '/bin/sh'` for every `PBXShellScriptBuildPhase` it builds (Sync SPM Autolinking, Embed React Native Flavored Frameworks, plugin-contributed phases), while their bodies are bash-only. Now sets `shellPath: '/bin/bash'`, and refreshes it on an already-injected project too.
- The "Sync SPM Autolinking" scheme pre-action runs the same kind of script, but a scheme pre-action ignores a build phase's `shellPath` entirely — Xcode reads the shell from the `ActionContent`'s own `shellToInvoke` attribute instead (default `/bin/sh`). Now sets `shellToInvoke = "/bin/bash"` on both scheme creation and when adding/refreshing the pre-action on an existing scheme.

Fixes https://github.com/react/react-native/issues/58359

## Changelog:

[IOS] [FIXED] - SwiftPM: run generated build scripts under bash instead of /bin/sh, so they don't break on a host where /bin/sh isn't bash

Pull Request resolved: https://github.com/react/react-native/pull/58362

Test Plan: `yarn test packages/react-native/scripts/spm` — 838 passed, including new cases for the refreshed `shellPath`/`shellToInvoke` on a project injected before this fix, and a scheme injected before the attribute existed.

Reviewed By: cortinico

Differential Revision: D119328611

Pulled By: cipolleschi

fbshipit-source-id: 2039a5c3c0224ca17d096f4837380b0977f4b539
(cherry picked from commit 25f48bd72f)
2026-09-15 16:53:25 +01:00
Christian Falch 38302c9534 Derive an SPM library's Swift name from its podspec (#58290)
Summary:
An autolinked library's SwiftPM target name is also its header import prefix, so deriving it from the npm package name was wrong for most of the ecosystem (`react-native-svg` publishes `RNSVG`, not `ReactNativeSvg`) and wrong silently — no error, just headers nobody can import under the expected name.

## How:

This PR reads the podspec file on scaffolding, and will use the name from the podspec if available. In addition it deprecates the react-native.config.js `spm` section in favor of the library's `package.json` file.

### Configuration

A package's SwiftPM settings now live in `swiftpmConfig` in its `package.json`, following `codegenConfig`'s conventions: `name`, `dependencies`, `autolinkingPlugin` and `scaffold` for a library, `modules` and `denyPlugins` for an app. The `spm` block in react-native.config.js is deprecated — still read, so nothing breaks, but it warns once per file and package.json wins field by field.

### Resolving

A name resolves from `swiftpmConfig.name`, then the deprecated `spm.name`, then the podspec's `header_dir` or name, then the npm name. The podspec is thereby transitional rather than permanent: `spm scaffold` records the name it derived as `swiftpmConfig.name` in the library's package.json, so the next run needs no podspec to name it. It never overwrites a name the library already declares, never records a name guessed from the npm name, and reports what it did.

### Failsafety

A prefix Swift cannot spell is normalized to the identifier SwiftPM would compile it as, with a warning. A reserved name or two deps landing on one name is a hard error naming swiftpmConfig.name as the fix; the scope-borrowing that auto-corrected collisions is removed, since a name the build invents is a name no #import can predict. Collision checks key on SwiftPM's c99 name, so react-native-svg and react_native_svg no longer pass and then compile as one module.

### Implementation

Name resolution reads the two podspec fields it needs with the regex parser, so it adds no `pod ipc spec` spawn, and the full read is memoized on the resolved path so one run reads a podspec once across name resolution, header search paths and scaffolding.

`rn-tester` and the Apple test library move to the new location.

## Changelog:

[IOS] [FIXED] - Read SwiftPM name from podspec and store in package.json when scaffolding

Pull Request resolved: https://github.com/react/react-native/pull/58290

Test Plan: ✅ Unit tests

Reviewed By: cortinico

Differential Revision: D119159904

Pulled By: cipolleschi

fbshipit-source-id: 59a7c62ecb601498060a5721f362dae8c5cc92de
(cherry picked from commit 1cfc5f29a0)
2026-09-15 16:53:11 +01:00
Gabriel Donadel a07219cbcc fix(codegen): skip node_modules and symlinks when crawling for components (#58518)
Summary:
`findFilesWithExtension` walks a library's directory looking for `.mm` files that declare a Fabric component. The walk descends into every subdirectory, `node_modules` included, resolves symlinks through `statSync`, and keeps no visited set.

This got broken after https://github.com/react/react-native/issues/57790 because `parseiOSAnnotations` now enters every library that declares a `codegenConfig` without an `ios` key into its map with an empty `components` object, so nothing removes it from `librariesToCrawl`. Previously such libraries were filtered before crawling.

An app that declares `codegenConfig` with `"type": "all"` and no `ios` key now gets treated as a component library, so the walk covers the entire project.

What we notice in the [expo repo](https://github.com/expo/expo/pull/50134) is that under pnpm, the traversal never terminates. Workspace packages link into each other's `node_modules` and form cycles. Because symlinks are followed, the walk only stops once paths hit the 1023 byte limit. CocoaPods progress stops right after the "Using React Native Core and React Native Dependencies prebuilt versions" line while a `generate-codegen-artifacts.js` child sits at 100% CPU.

Under npm and yarn, the walk completes but with the wrong result. In those cases, `node_modules` holds real directories, but the walk covers the whole dependency tree. Crawling one app of roughly 1100 packages turned up 382 `.mm` files, 43 of which declare a component, among them React core views such as `RCTImageComponentView` and `RCTScrollViewComponentView` from `react-native-macos`. Each one is written into the app's entry in `RCTThirdPartyComponentsProvider.mm`. The existing `/react-native/` path filter does not exclude them, since it requires a trailing separator and `react-native-macos` has none.

## Changelog:

[IOS] [FIXED] - Codegen no longer crawls `node_modules` or follows symlinks when discovering components

Pull Request resolved: https://github.com/react/react-native/pull/58518

Test Plan:
Two cases added to `packages/react-native/scripts/codegen/__tests__/generate-artifacts-executor-test.js`. The three existing `findFilesWithExtension` mocks move from `statSync` to `lstatSync`.

The symlink case builds a link pointing back at its own parent, so the pre-fix walk never terminates.

**Negative control:** with the `generateRCTThirdPartyComponents.js` change reverted and the tests left in place, both new cases fail. All 24 existing snapshots pass unchanged, so the change is additive for projects that already declare an `ios` config.

Measured by crawling the app directory of two real projects:

| Project | Before | After |
| --- | --- | --- |
| `apps/bare-expo`, pnpm | 116,800 reads in 30s, still running | 34 files, 1.1s |
| yarn app, ~1100 packages | 382 files, 5.8s | 8 files, 0.3s |

Reviewed By: fabriziocucci

Differential Revision: D120122552

Pulled By: vzaidman

fbshipit-source-id: 233b8dc338b92372a34a0855f12a549e52513200
(cherry picked from commit 39751d864d)
2026-09-15 15:02:03 +01:00
Fabrizio Cucci 79024f7c59 Bump Hermes to 260318099.0.3 2026-09-15 15:01:55 +01:00
Rubén Norte a855c0431f Enable the imperative EventTarget API in canary (#58479)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58479

`enableImperativeEvents` was defined as a JS-only feature flag, but OSS release stages are only applied to common flags: `ossReleaseStage` is consumed exclusively by the generators that produce the native override classes, so setting it on a JS-only flag is silently a no-op. The feature could therefore never be shipped through the canary channel.

This defines `enableImperativeEvents` as a common flag at release stage `canary`, and renames the JS-only flag to `enableImperativeEvents_DEPRECATED`. The deprecated flag is kept because the common flag is read through the native module: a JS bundle delivered to a native build that predates this change finds no such method and falls back to the default, which would silently turn the feature off. The gate in `ReactNativeElement` and `ReadOnlyText` now keeps the public EventTarget methods when either flag is enabled.

Changelog:
[General][Added] - Enable the imperative EventTarget API (`addEventListener`, `removeEventListener`, `dispatchEvent`) on native view refs in canary

Reviewed By: javache

Differential Revision: D119645412

fbshipit-source-id: 4fd33dfaff1640fd5d40b5bc9c3f657ea7b3bb86
(cherry picked from commit 8480b86820)
2026-09-14 10:15:31 +01:00
Rubén Norte 760b5daf5f Ship enableNativeEventTargetEventDispatching by default (#58450)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58450

The renderer can dispatch events either through the legacy plugin-based system or through the W3C EventTarget API (addEventListener/dispatchEvent), gated behind the enableNativeEventTargetEventDispatching feature flag. Enabling it by default was previously blocked on the renderer, which did not carry the necessary changes until React 19.3.0. That sync has now landed, so flip the flag's default value to true and drop the TODO that tracked the blocker.

Fully removing the flag and the legacy dispatch path is left for a follow-up.

Changelog:
[General][Changed] - Enabled Web-based event dispatching refactor

Reviewed By: javache

Differential Revision: D119495069

fbshipit-source-id: 53ad5b88c8b5cdd11c3fd1ee27d0f147b83c41a9
(cherry picked from commit 31d33ce91b)
2026-09-14 10:15:15 +01:00
Rubén Norte 0b0ce740cb React 19.3.0 sync int React Native OSS (#58446)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58446

Sync of React 19.3.0 into React Native

Changelog: [General][Changed] - Sync React 19.3.0 into React Native

jest_e2e[run_all_tests] bypass-github-export-checks

Reviewed By: fabriziocucci

Differential Revision: D119490598

fbshipit-source-id: 4a00bd01fd1a4b1c48ffcae182f1b88cd0cf9e06
(cherry picked from commit b0b71421c1)
2026-09-14 10:15:02 +01:00
Rubén Norte b4e7d025c0 Export the native Fabric UI manager for React (#58398)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58398

Expose the native Fabric UI manager through `react-native/react-private-interface` so the React renderer can consume it without reading the global directly.

Changelog: [Internal]

Reviewed By: cortinico

Differential Revision: D119165837

fbshipit-source-id: a41860ef4962c9a71b8052db29f7ff86529db18e
(cherry picked from commit 73a76ddced)
2026-09-14 10:12:59 +01:00
React Native Bot ab7dde8242 [LOCAL] Bump Podfile.lock 2026-09-08 15:46:26 +00:00
React Native Bot f065722abe Release 0.88.0-rc.0
#publish-packages-to-npm&next
v0.88.0-rc.0
2026-09-08 13:53:53 +00:00
Fabrizio Cucci 981724d016 Bump hermes version 2026-09-08 13:36:43 +01:00
Fabrizio Cucci b113cf5864 [LOCAL] Bump hermes-v1 to 260318099.0.1 2026-09-07 17:37:38 +01:00
Cole Huntley 8cfde6d083 Fix Image.getSize failing for data: URIs on Android (#58353)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58353

Fixes https://github.com/react/react-native/issues/57787.
Supersedes https://github.com/react/react-native/pull/57788.

## Context
On Android, `Image.getSize()` and `Image.getSizeWithHeaders()` reject for every `data:` URI.
Both resolve dimensions through Fresco's encoded-image pipeline. That pipeline has producer
sequences only for network, local-file and local-content URIs; every other scheme falls through to
a throw:
    Unsupported uri scheme for encoded image fetch! Uri is: data:image/jpg;base64,...
Fresco's decoded-image pipeline does handle the scheme (`SOURCE_TYPE_DATA -> dataFetchSequence`), so
the capability exists — the encoded entry point simply does not expose it. A previous change added a
fast path for `res://` URIs for exactly this reason; `data:` was never given one.
Any app that gates rendering on `getSize` therefore cannot display an inline base64 image on
Android at all, while iOS is unaffected.
## This Diff
- Adds a `data:` fast path to `getSize` and `getSizeWithHeaders`, mirroring the existing
  resource-drawable fast path, routed through `fetchDecodedImage` rather than `fetchEncodedImage`.
- Pins the request to auto-rotate so it produces the same Fresco bitmap cache key that
  `ReactImageView` builds for the same URI. Rotation options are part of that key, so a mismatch
  here would decode into a key nothing reads and force a second decode at render time.
- Sets `DownsampleMode.NEVER` so the reported dimensions stay intrinsic rather than
  post-downsample, preserving the behaviour the encoded path was originally adopted for. That
  option is absent from the bitmap cache key, so it does not disturb the parity above.
- Reads the visible dimensions straight off the decoded image, which has already had its EXIF
  rotation applied, rather than repeating the axis swap the encoded subscriber performs by hand.
  `BaseCloseableStaticBitmap` applies that same predicate internally, so repeating it here would
  double-apply it.
- Adds unit coverage for the `data:` scheme, which had none: decoded-pipeline routing, cache-key
  parity with `ReactImageView`, intrinsic dimensions, the headers variant, and both failure paths.
- Adds two `data:` rows to the RNTester `Image.getSize` platform test — one plain, one tagged EXIF
  orientation 6 — so a real decode, rather than a mocked pipeline, proves the reported dimensions
  are the visible ones. Both are inline base64, so they need no network.
Because the decode now warms the bitmap memory cache under the key the `<Image>` subsequently
reads, a caller that sets its image source from the `getSize` success callback paints from cache
instead of decoding at render time.
## Alternatives Considered
**Parse the dimensions out of the base64 header.** Satisfies the `getSize` contract and is cheaper,
but warms nothing. Callers that relied on the decode side effect for smooth playback would keep
re-decoding every frame at render time — it fixes the rejection without fixing the regression that
accompanied it.
**Add a `data:` arm to Fresco's encoded producer sequence.** Pushes a behavioural change into shared
image infrastructure used by every app, to serve a caller that wants a decoded result anyway. The
narrower fix belongs on this side.
**Have callers stop gating rendering on `getSize`.** Makes the image appear, but permanently
discards the decode-then-render ordering, leaving the surface visibly flickering.
Changelog:
[Android][Fixed] - Fix `Image.getSize()` and `Image.getSizeWithHeaders()` rejecting `data:` URIs

Reviewed By: Abbondanzo, javache, cortinico

Differential Revision: D118657320

fbshipit-source-id: 576ce8458c921b199d717161c2113a7d4f99221b
2026-09-04 20:56:05 -07:00
Maximilian Krause 08c7781e5a fix(image): preserve source headers with crossOrigin and referrerPolicy (#58319)
Summary:
When `crossOrigin="use-credentials"` or `referrerPolicy` is used on an `Image`, `getImageSourcesFromImageProps` currently fully replaces `source.headers`, removing custom headers such as `Authorization`.

This fix merges the generated headers with the user-provided source headers instead (user-provided headers take precedence).

## Changelog:

[GENERAL] [FIXED] - Preserve Image source headers when using crossOrigin or referrerPolicy

Pull Request resolved: https://github.com/react/react-native/pull/58319

Test Plan: Confirmed existing tests are unchanged & added a regression test

Reviewed By: christophpurrer

Differential Revision: D118797893

Pulled By: javache

fbshipit-source-id: 8018846647232f97cb9e12d6095774826999c89b
2026-09-04 14:19:29 -07:00
Pieter De Baets 3ca6ea3eca Buffer async CallInvoker work with module calls (#58313)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58313

In bridgeless, native reaches JS by two routes that end in the same
`RuntimeScheduler` queue but get there differently. `callFunctionOnModule` goes
through the instance's `BufferedRuntimeExecutor`; the `CallInvoker` goes
straight to `scheduleTask`. The CallInvoker therefore skips the buffer entirely
and can reach the runtime while a module call issued earlier is still parked,
unflushed, because the bundle is mid-evaluation. Native code that issues both
cannot rely on the order it issued them in, and `Task` is a min-heap on
`now() + timeout(priority)` with no insertion tiebreak, so equal priorities do
not settle it either.

Gives the two channels the same buffering. `BufferedRuntimeExecutor` gains a
priority-carrying `execute`, so work routed through it keeps the scheduler
priority it was submitted with instead of collapsing to the executor default,
and buffered work from both overloads stays in one submission-ordered stream.
`BufferedCallInvoker` sits on that executor and becomes the bridgeless
`jsCallInvoker` on Android, iOS and macOS.

`invokeSync` deliberately keeps going straight to the scheduler: a synchronous
call cannot wait for a flush that only happens once the bundle has run.

Behind `enableBufferedCallInvoker`, default true. `ReactInstance` picks between
the buffered invoker and the existing `RuntimeSchedulerCallInvoker` in one
place, so the platform call sites are identical either way and the change is
revertible at runtime — it moves when native-issued async work first reaches JS
during startup, which is the intended contract but affects every native module.

One lifetime hazard this surfaces, worth knowing about beyond this diff:
`BufferedRuntimeExecutor` reaches the scheduler through a raw pointer captured
at construction, which is safe only while the owning instance is alive. A
CallInvoker is routinely held across instance teardown, so `BufferedCallInvoker`
guards every async dispatch on a weak reference to the scheduler and drops the
work when it has expired — the same contract `RuntimeSchedulerCallInvoker` has.
Without that guard this reliably segfaults on a reload.

Changelog:
[General][Changed] - Async `CallInvoker` work is now buffered alongside callable module calls, so it no longer runs before the JS bundle has finished evaluating

Reviewed By: rubennorte

Differential Revision: D118456662

fbshipit-source-id: 7c6ccb595d69595721092eeb84b4724809140496
2026-09-04 12:39:12 -07:00
Sam Zhou f072ddb17c Deploy 0.331.0 to xplat (#58332)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58332

[changelog](https://github.com/facebook/flow/blob/main/Changelog.md)
Changelog: [Internal]

Reviewed By: panagosg7

Differential Revision: D118823256

fbshipit-source-id: 11d1e53dad7985686fd97a2aa771cd5c5ece7e09
2026-09-04 12:16:47 -07:00
Pieter De Baets d5dcd2f999 Fix require cycle (#58330)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58330

`AbortController` requires `AbortSignal` which requires `AbortController`

Changelog: [Internal]

___

Differential Revision: D118818763

fbshipit-source-id: fed51bc3c59bde1464b2cee5c0a65bccc4e7574a
2026-09-04 12:13:49 -07:00
Maximilian Krause c300f84f2c fix(text): avoid mutating accessibilityState (#58318)
Summary:
When `accessibilityState.disabled` conflicts with an explicit `disabled` prop, the `Text` component currently updates `accessibilityState` in place. This mutates an object owned by the caller, which can cause issues when other code uses that same object.

This fix creates a new object instead, while retaining existing behavior (giving priority to the explicit prop).

## Changelog:

[GENERAL] [FIXED] - Prevent Text from mutating the accessibilityState prop

Pull Request resolved: https://github.com/react/react-native/pull/58318

Test Plan: Unchanged tests pass + added a regression test

Reviewed By: Abbondanzo

Differential Revision: D118788803

Pulled By: javache

fbshipit-source-id: 77f69e851d06250aa27e20912a2c2fc91394b81d
2026-09-04 09:38:32 -07:00
Jakub Piasecki d44efb09c1 Cover react/renderer/imagemanager with Stable API guards (#58307)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58307

Classifies `react/renderer/imagemanager:imagemanager` as a "for frameworks" target under the three-tier C++ stable API visibility model. Consumers that opt into `RN_STRICT_API` now get a warning if they include its headers directly, which they can acknowledge with `RN_ALLOW_FRAMEWORKS`; without that flag the guards are inert, so no existing build changes behaviour.

`React-Fabric` already depended on `React-cxxstableapi` from an earlier migration in the same pod, so the module's subspec needs no change.

Changelog: [Internal]

Reviewed By: rubennorte

Differential Revision: D118621752

fbshipit-source-id: ecf701cc3377904088a7bd56bf39b2b924850ca2
2026-09-04 08:43:18 -07:00
Christoph Purrer 38fd9d57df Restore paperComponentName: 'RCTSwitch' to fix @testing-library/react-native queries (#58323)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58323

Restore `paperComponentName: 'RCTSwitch'` in `SwitchNativeComponent.js` and regenerate affected snapshots to fix test breakages introduced by D117877024.

`testing-library/react-native` 13.3.3 hardcodes `HOST_SWITCH_NAMES = ['RCTSwitch']`, so renaming the component to `Switch` broke `getByRole('switch')` queries and `toBeChecked()` assertions. This was the only xplat/js-wide breakage from that diff—only bare `<Switch>` renders without explicit `accessible` props failed, and only in `TWInternBoolSettingComponent-test.js`.

Add an inline comment documenting the `testing-library/react-native` constraint to prevent future regressions. The four other component renames in D117877024 have no RNTL special-casing and remain as landed.

Changelog: [iOS][Fixed] Restore `paperComponentName: 'RCTSwitch'` to fix `testing-library/react-native` queries

Reviewed By: javache

Differential Revision: D118743290

fbshipit-source-id: 0fbd5e99fb1dfd7f0b1a307b0ed058f0d2082b77
2026-09-04 08:16:43 -07:00
Rubén Norte 50a7d464fb Make assorted Libraries modules Flow strict-local (#57733)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57733

Upgrade several remaining Libraries modules (WebSocket, PanResponder, RCTEventEmitter, and Flow type tests) from `flow` to `flow strict-local` with accurate types. WebSocket exposes spec-mandated getters/setters and opts out of the `unsafe-getters-setters` lint with a scoped directive. Behavior is unchanged.

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D113763779

fbshipit-source-id: 86827a975e996a4c85dd92344d36746e61887dde
2026-09-04 06:40:51 -07:00
Rubén Norte a9dc32ce58 Make element inspector dev support modules Flow strict-local (#57741)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57741

Upgrade the element inspector dev support modules from `flow` to `flow strict-local`, replacing loose `Object`/`Function` types with the accurate types already used by their callers and dependencies.

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D113763787

fbshipit-source-id: 114d12cb02e244431d59b18e3b3c6cfa363bd25f
2026-09-04 06:40:51 -07:00
Rubén Norte 5211157ab7 Make AppRegistry and Core timers Flow strict-local (#57735)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57735

Upgrade `AppRegistry` (and its Flow type companion) and several Core timer modules from `flow` to `flow strict-local` with accurate types. Behavior is unchanged.

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D113763781

fbshipit-source-id: 48936dbc898c9d409818fb23794711e7bb6c66ed
2026-09-04 06:40:51 -07:00
Rubén Norte 2920b6e8e0 Make assorted Components Flow strict-local (#57732)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57732

Upgrade assorted components from `flow` to `flow strict-local` with accurate types. `Button` replaces implicit truthiness checks with explicit comparisons that preserve the exact previous runtime behavior (no logic change).

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D113763782

fbshipit-source-id: 74e0ab2501b25d84cf501dce24d729e3cf790965
2026-09-04 06:40:51 -07:00
Rubén Norte a593f1a527 Make Utilities modules Flow strict-local (#57729)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57729

Upgrade assorted Utilities modules from `flow` to `flow strict-local` with accurate types. `insetsDiffer` uses local variables instead of reassigning its function parameters. Behavior is unchanged.

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D113763792

fbshipit-source-id: 4c7672439ae5af27f4298c04dc5606ced5509888
2026-09-04 06:40:51 -07:00
Rubén Norte 590ca972e0 Make StyleSheet modules Flow strict-local (#57731)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57731

Upgrade the StyleSheet modules from `flow` to `flow strict-local`. `processFilter` and `setNormalizedColorAlpha` required small, behavior-preserving refactors (local variables instead of reassigning function parameters, and explicit null/empty checks) to satisfy the stricter lints.

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D113763790

fbshipit-source-id: 9861d496dde2c16d8e2fc20fd7173a88789ff3d0
2026-09-04 06:40:51 -07:00
Rubén Norte c72e8c7c65 Make Blob/File/URL modules Flow strict-local (#57728)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57728

Upgrade the Blob-related modules (`File`, `FileReader`, `URL`, `URLSearchParams`) from `flow` to `flow strict-local`. These expose spec-mandated getters/setters, so they opt out of the `unsafe-getters-setters` lint with a scoped `// flowlint unsafe-getters-setters:off` directive. `URL` also received small behavior-preserving refactors (local variables instead of parameter reassignment, explicit null/empty checks).

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D113763778

fbshipit-source-id: 1e0ceb02270d458fae6b89886ae41d9893ae7329
2026-09-04 06:40:51 -07:00
Rubén Norte 1a7c318ffc Make deprecated native module specs Flow strict-local (#57724)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57724

Upgrade the legacy native module spec files from `flow` to `flow strict-local` to enforce stricter local type checking. Loose `Object` types were replaced with the codegen-equivalent `UnsafeObject`, and `Array<any>` parameters with `Array<unknown>`, both of which are codegen-identical so the generated native interfaces are unchanged.

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D113763785

fbshipit-source-id: 085a0a570246eeda27b3c22a56a2696b04821fd5
2026-09-04 06:40:51 -07:00
Oskar Eichler 0d64c9a13a Run codegen for formatted native component calls (#58257)
Summary:
The source-optimized preset enables native component codegen only when `codegenNativeComponent` is immediately followed by `<`. Valid Flow syntax permits comments or whitespace before the type arguments, so `codegenNativeComponent /* comment */ <NativeProps>(...)` bypasses codegen and emits an ordinary runtime call instead of the generated `__INTERNAL_VIEW_CONFIG` produced by the full preset path.

Use the stable `codegenNativeComponent` identifier token as the cheap source prefilter while retaining the existing null/undefined full-scan path. Formatting no longer changes build output; false-positive tokens only enable the codegen visitor, which remains a no-op without a matching call.

## Changelog:

[GENERAL] [FIXED] - Run native component codegen when Flow type arguments are separated by trivia.

Pull Request resolved: https://github.com/react/react-native/pull/58257

Test Plan:
- Added a valid Flow native-component spec containing a comment before `<NativeProps>`.
- Exact optimized baseline emits the ordinary call without `__INTERNAL_VIEW_CONFIG`; the fixed transform generates the static view config.
- Full preset Jest passes: 4/4 suites, 111/111 tests, 16 snapshots.
- Fresh Flow check reports 0 errors.
- Targeted no-ignore ESLint, Prettier, and `git diff --check` pass.

No public API or breaking behavior change; optimized and full preset paths now agree for valid formatting.

Reviewed By: GijsWeterings

Differential Revision: D118266389

Pulled By: javache

fbshipit-source-id: 0b4279eed9f831e1e8f4669bd522645023dfdeac
2026-09-04 06:09:06 -07:00
nishan (o^▽^o) 63d118af72 Fix per-node memory regression caused by Grid styles (#58311)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58311

# Why

Currently, grid style properties are stored in yoga style (`gridTemplateRows_`, `gridAutoColumns_` etc). These properties increase the size of style object from `152` bytes to `280` bytes (84% increase). The cost is added even when a node is not a grid container or a grid item.

# How

Move grid style properties behind a pointer that is lazily allocated, on the first grid property set. A node that doesn't use grid only adds the cost of this pointer (8 bytes). So style now costs 160 bytes (5% increase). The public API remains unchanged.

# Tests

A test is added to catch the style size regression and `tests/GridStyleTest.cpp` includes additional cases to assert unset style, copy and move behaviour.

Changelog: [Internal]

X-link: https://github.com/react/yoga/pull/2018

Reviewed By: rubennorte

Differential Revision: D118628661

Pulled By: javache

fbshipit-source-id: 185370e93bcf5b277b48c436ba3d06dada5a66fe
2026-09-04 05:54:27 -07:00
Jakub Piasecki 5e9cce8b12 Cover react/renderer/animationbackend with Stable API guards (#58304)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58304

Classifies `react/renderer/animationbackend:animationbackend` as a "for frameworks" target under the three-tier C++ stable API visibility model. Consumers that opt into `RN_STRICT_API` now get a warning if they include its headers directly, which they can acknowledge with `RN_ALLOW_FRAMEWORKS`; without that flag the guards are inert, so no existing build changes behaviour.

`React-Fabric` already depended on `React-cxxstableapi` from an earlier migration in the same pod, so the module's subspec needs no change.

Changelog: [Internal]

Reviewed By: rubennorte

Differential Revision: D118616103

fbshipit-source-id: dbe574a524c8a29e204792ca2193c4c8238d1c20
2026-09-04 05:26:06 -07:00
Christian Falch fcbeda1109 stop baking an absolute HERMES_CLI_PATH into the app pbxproj (#58292)
Summary:
`npx react-native spm add` writes `HERMES_CLI_PATH` into the app's committed `project.pbxproj` — the absolute path of `hermesc` in the `hermes-compiler` npm package, as resolved on whichever machine ran the command. So every SwiftPM-converted app commits one developer's disk layout.

Nothing needs it: `react-native-xcode.sh` already resolves `hermesc` at build time through react-native's own dependency graph when the current value is not a file. A relative setting can't replace it either — `$(REACT_NATIVE_PATH)/../hermes-compiler` breaks on a symlinked `react-native`, and `$(SRCROOT)/../node_modules/…` breaks on hoisted monorepos.

So this deletes `resolveHermesCliPathSetting()`, along with the `hermesCliPath` parameter it fed on `injectSpmIntoPbxproj` and `mergeReactBuildSettings`. Already-injected projects self-clean on the next `spm add`/`update`, which strips every scalar recorded in `.spm-injected.json` before re-injecting.

### Scope: SwiftPM only

Both pieces involved arrived with SwiftPM in https://github.com/react/react-native/issues/57332 and first shipped in 0.87.0 — `scripts/spm/generate-spm-xcodeproj.js` (the whole file, including the write) and the `NODE_HERMESC` build-time fallback in `react-native-xcode.sh`.

Everything CocoaPods relies on is older and untouched, all present in 0.86.0: the pod-derived `HERMES_CLI_PATH` default, the "hermesc could not be found" error, and the `hermesc -emit-binary` call. **A CocoaPods build cannot be affected by this change.**

That parameter shipped in 0.87.0 and 0.87.1, but SwiftPM is Preview-labelled, so removing it is in scope. Nothing in the repo passed it except the deleted resolver.

## Known limitation

The fallback is gated on `PODS_ROOT` being absent, so a SwiftPM app that keeps side-by-side non-RN pods skips it and needs an explicit `HERMES_CLI_PATH`. Evaluating that gate verbatim out of the unchanged script:

| app | gate | hermesc |
| --- | --- | --- |
| no `Pods/` (normal SwiftPM app) | fires | from `node_modules` |
| `Pods/`, non-RN pods only | skipped | pod path — absent |
| `Pods/` with `hermes-engine` | skipped | the pod's, unchanged |

Set it in an xcconfig, not the pbxproj: `createdScalars` cleanup removes by key, so it would drop a hand-edited value too. Keying the gate on the `hermes-engine` directory would close this — left as a follow-up so this PR doesn't touch the bundling script.

## Changelog:

[IOS] [FIXED] - SwiftPM: stop baking an absolute, machine-specific HERMES_CLI_PATH into the app's pbxproj; resolve hermesc at build time instead

Pull Request resolved: https://github.com/react/react-native/pull/58292

Test Plan:
Red first — with the source reverted, the new entry-point test fails on a seeded `hermes-compiler` fixture: `✕ writes no HERMES_CLI_PATH, in any configuration or the marker` (1 failed, 76 passed).

```
yarn jest packages/react-native/scripts/spm --no-cache -i
Test Suites: 18 passed, 18 total
Tests:       835 passed, 835 total
```

`yarn flow-check` (0 errors), plus `yarn eslint --max-warnings 0` and `yarn prettier --check` on the four changed files.

End to end: a 0.87.1 SwiftPM app (`shopify/react-native-skia` example, no Pods) with the `HERMES_CLI_PATH` lines removed from its pbxproj builds in Release, the fallback resolving `hermesc` from `node_modules/hermes-compiler`. That build ran against an earlier revision of this branch which also widened the shell gate; with no `Pods/` it is row 1, where both conditions behave identically. There is no shell test harness, and the script is unchanged here.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed By: cortinico

Differential Revision: D118624244

Pulled By: cipolleschi

fbshipit-source-id: 5784a2de69af0c50c82129d96423801b0f5b0eba
2026-09-04 05:14:30 -07:00
Pieter De Baets bf0e377c0a Reduce JNI allocations when importing native maps (#58274)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58274

`ReadableNativeMap` materialization copied keys and created temporary JNI references for every imported type. Cache pointers to the stable native values and reuse global `ReadableType` references so importing maps and arrays does less allocation and lookup work.

Writable maps can continue mutating after materialization because `folly::dynamic` stores object entries in reference-stable `F14NodeMap` nodes.

Changelog: [Internal]

Reviewed By: christophpurrer, rubennorte

Differential Revision: D118277119

fbshipit-source-id: 955a60ef7f1eb4cb7549d64caa1238416e90b223
2026-09-04 05:02:48 -07:00