Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57628
NOTE: Patches over a `flow-api-translator` bug, which I'll fix upstream later. We need to pick this to `0.87-stable` to resolve user integration issues.
**Context**
TypeScript's `exactOptionalPropertyTypes` flag (strict mode) creates a distinction between `foo?: T` and `foo?: T | undefined`.
```js
// Flow's semantics
interface Props {
onRefresh?: () => void;
}
const a: Props = { onRefresh: undefined }; // ✅ ok
```
```ts
// TypeScript with exactOptionalPropertyTypes: true (i.e. strict mode)
interface Props {
onRefresh?: () => void;
}
const a: Props = { onRefresh: undefined }; // ❌ error
interface PropsFixed {
onRefresh?: (() => void) | undefined;
}
const b: PropsFixed = { onRefresh: undefined }; // ✅ ok
```
With this added strictness in TypeScript, our generated types via `flow-api-translator` could create downstream type incompatibility in apps.
**This diff**
Patches the above issue in React Native's Flow → TS `types_generated/` pipeline. We transform all instances to the wider `foo?: T | undefined` format, for maximum compatibility.
**Notes**
`foo?: T [| undefined]` **remains stripped** in the API snapshot (existing transform with the aim of a concise format). There is a net, nonfunctional snapshot diff around function members, which (as a positive result) are re-ordered.
Changelog:
[General][Fixed] - **Strict TypeScript API**: Optional property types are now widened to explicitly include `| undefined` for `exactOptionalPropertyTypes` compatibility
Reviewed By: cipolleschi
Differential Revision: D113030161
fbshipit-source-id: 3ab005edab6b80b18fbb9ae7125ba56e3bd94195
Co-authored-by: Alex Hunt <huntie@meta.com>
Summary:
The nightly-tests job `[ios] react-native-unistyles` fails on Xcode 26.3 with:
```
error: no matching function for call to '__construct_at'
note: in instantiation of member function 'std::vector<...RuntimeSamplingProfile>::vector' requested here
note: in implicit copy constructor for 'facebook::react::jsinspector_modern::tracing::TraceRecordingState' first required here
```
while compiling the **Swift** files of the Unistyles pod. The same failure hits any library built with Swift C++ interop (`-cxx-interoperability-mode=default`) — in practice, every Nitro-based library — against the prebuilt React Native core.
### The error
`TraceRecordingState` and `HostTracingProfile` hold `std::vector`s of move-only types (`RuntimeSamplingProfile` and `FrameTimingSequence` explicitly delete their copy constructors). Here's the C++ subtlety: `std::vector<T>`'s copy constructor is **declared for every `T`** — it only becomes ill-formed when *instantiated*. So the implicit copy constructors of these two structs are not implicitly deleted; they exist as declared-but-broken constructors that hard-error the moment anything asks for a copy.
### Why React Native compiles fine today
Nothing in RN ever asks. Every usage passes these types by reference; the single constructions move. A pure C++ (or ObjC++) build never instantiates the implicit copy constructors, so this code has always compiled — and always would, no matter how much C++ CI you throw at it. The defect is unobservable from within C++.
### What fails, and why now
The prebuilt-core headers now ship as real clang modules. A Swift target with C++ interop imports them (directly or transitively — e.g. via a module member whose `#ifdef __cplusplus` body opens because interop builds modules with C++ enabled), and Swift's ClangImporter surfaces the C++ value types to Swift as copyable. When the consumer's generated interop code then uses such a type as a Swift value — for a Nitro-based library, the nitrogen-generated `*_cxx.swift` bridging does exactly this — the compiler **synthesizes a copy of the type, instantiating the ill-formed implicit copy constructor**. That is the "ask" that plain C++ never makes; on Xcode 26.3 it hard-errors the entire module import, killing every Swift file in the consumer. (Newer Swift toolchains treat such types as non-copyable instead of failing.)
Before the prebuilt-modules work there was no Swift-visible module containing these headers, so no interop consumer ever imported these types — which is why this surfaces now despite the C++ being unchanged.
We deliberately did **not** fix this by removing headers from the module maps: the guarded-C++-in-modules pattern is shared by ~30 legitimately modular headers and is benign in all but this one shape, and experiments showed the type is reachable through multiple independent module surfaces (removing one member just moved the error to the next path).
### The fix
Declare the truth: make both types explicitly move-only.
```cpp
TraceRecordingState(const TraceRecordingState &) = delete;
TraceRecordingState &operator=(const TraceRecordingState &) = delete;
TraceRecordingState(TraceRecordingState &&) = default;
TraceRecordingState &operator=(TraceRecordingState &&) = default;
```
With the copy constructor explicitly deleted, Swift's importer sees a non-copyable type and imports it as such instead of instantiating a broken copy. It is also simply more correct C++: these types were never copyable in practice, and the explicit deletion turns any future accidental copy into a clear compile error at the call site instead of a template backtrace.
Declaring special members makes `HostTracingProfile` a non-aggregate, so its one designated-initializer construction site (`HostTargetTraceRecording.cpp`) is converted to member-wise assignment.
A sweep of the affected header surface (`std::vector`/`std::map`/`std::deque` of move-only element types) found exactly these two types; a follow-up adds a `headers-verify.js` gate that imports the shipped modules under Swift C++ interop at prebuild time, so the next type with this shape fails RN's own CI instead of community nightlies.
## Changelog:
[IOS] [FIXED] - Fix Swift C++-interop build failure (implicit copy constructor of TraceRecordingState/HostTracingProfile) for libraries using cxx interop with prebuilt React Native core
Pull Request resolved: https://github.com/react/react-native/pull/57605
Test Plan:
On a fresh RN-nightly app with stock `react-native-unistyles@3.3.0` + `react-native-nitro-modules`, prebuilt core (`RCT_USE_RN_DEP=1 RCT_USE_PREBUILT_RNCORE=1`), Xcode 26.3:
- **Red**: stock headers reproduce the CI failure exactly (`__construct_at` → `TraceRecordingState`). Fixing only `TraceRecordingState` then surfaces the identical failure on `HostTracingProfile` — confirming the shape, not the type, is the bug.
- **Green**: with both headers fixed (stock module maps, nothing else changed): BUILD SUCCEEDED — zero `__construct_at`, zero `shadowNodeFromValue`, zero module errors.
- All RN-internal usages audited: references and moves only; no behavior change. Plain C++/ObjC++ compilation unaffected by construction.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Reviewed By: fabriziocucci
Differential Revision: D112802806
Pulled By: cipolleschi
fbshipit-source-id: d2ae201c1fbb4de040f51ebc88263c7347b5979b
Summary:
Fixes the three post-release failures from the [0.87.0-rc.2 publish run](https://github.com/react/react-native/actions/runs/29775529785/):
- Keep Flow annotations in `verifyArtifactsAreOnMaven.js` as comments so `actions/github-script` can load the file with plain Node.
- Pin the Podfile lock workflow to `macos-15`, which provides the configured Xcode 16.4 version.
- Use the canonical `react/react-native` owner for release asset API operations so upload POST requests are not redirected from the former owner.
## Changelog:
[INTERNAL] [FIXED] - Fix post-release Maven verification, Podfile lock, and release asset jobs
Pull Request resolved: https://github.com/react/react-native/pull/57627
Test Plan:
```sh
node --check .github/workflow-scripts/verifyArtifactsAreOnMaven.js
node --check scripts/releases/upload-release-assets-for-dotslash.js
yarn jest .github/workflow-scripts/__tests__/verifyArtifactsAreOnMaven-test.js scripts/releases/__tests__/upload-release-assets-for-dotslash-test.js --runInBand
```
13 tests and 15 snapshots pass.
Reviewed By: zeyap
Differential Revision: D113032768
Pulled By: cipolleschi
fbshipit-source-id: df5f493603e6c25157fd7660b54aa409dcb742e7
Summary:
Step 1 of making the prebuilt `ReactNativeDependencies` pod the **single header authority** for the third-party C/C++ deps (RCT-Folly, glog, boost, DoubleConversion, fmt, fast_float, SocketRocket) in prebuilt-deps mode.
Today the deps **binary** replaces the source pods' code, but the pod still `s.dependency`'s the real source pods and borrows their headers via `$(PODS_ROOT)/<pod>` search paths. That split header authority is the dual-copy bug class behind the 2026-07-03 SocketRocket regression (`duplicate interface` under `use_frameworks!` — SocketRocket's ObjC headers have no include guards).
Three commits:
1. **fix(cocoapods): harden prebuilt-deps header search paths and artifact handling** — `rndependencies.rb`'s `||= [] << path` only added the deps header search path when `HEADER_SEARCH_PATHS` was unset (silently dropped otherwise); normalize and always append, and point at the pod-local flattened `Headers/`. `ReactNativeDependencies.podspec` `prepare_command` now fails closed (`exit 1`) instead of silently producing a no-link pod. `reactNativeDependencies.js` no longer deletes + re-downloads a locally staged artifact that lacks a version marker.
2. **feat(cocoapods): dependency-only facades for third-party pods in prebuilt-deps mode** — in prebuilt-deps mode the real source pods are not declared, so a community podspec's hardcoded `s.dependency "RCT-Folly"` would resolve from trunk and compile from source next to the prebuilt binary. `RNDepsFacades` generates dependency-only local facade podspecs (no sources, no headers, a single dependency on `ReactNativeDependencies`); versions/subspecs are derived from the real podspecs in `third-party-podspecs/` (SocketRocket synthesized fail-closed from `socket_rocket_config`). Full contract documented in `scripts/cocoapods/__docs__/prebuilt-deps.md`.
3. **feat(ios-prebuild): SocketRocket privacy manifest + Xcode 26 header layout** — embed an RN-authored, accurate-empty `PrivacyInfo.xcprivacy` for SocketRocket (upstream ships none), and stage flat public headers into `include/` so Xcode 26's SwiftPM accepts the header layout.
Stacked on https://github.com/react/react-native/issues/57305 (base: `chrfalch/prebuilt-resources`); the SwiftPM preview (https://github.com/react/react-native/issues/57332) rebases on top of this. Follow-up (separate PR): headers-only `ReactNativeDependenciesHeaders.xcframework` sidecar so SPM auto-serves the deps namespaces and `ReactNativeHeaders` goes pure-RN.
## Changelog:
[IOS][CHANGED] - Prebuilt-deps mode: serve third-party headers from the ReactNativeDependencies pod itself and resolve community `s.dependency` on RCT-Folly/glog/boost/etc. via dependency-only facade pods
Pull Request resolved: https://github.com/react/react-native/pull/57440
Test Plan:
E2E matrix (2026-07-06, locally built deps artifact via `prepare-ios-prebuilds.js`):
- rn-tester, prebuilt core + prebuilt deps, static linkage — builds
- rn-tester, prebuilt core + prebuilt deps, `USE_FRAMEWORKS=dynamic` — builds (the SocketRocket-regression config)
- helloworld (private), prebuilt core + prebuilt deps, static — builds
- source-mode control: no facades generated, `Podfile.lock` identical to baseline
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Reviewed By: fabriziocucci
Differential Revision: D111449257
Pulled By: cipolleschi
fbshipit-source-id: ace5716868d126a08721200efd640e903b191658
Summary:
`scripts/e2e/init-project-e2e.js` publishes in-repo packages to the local Verdaccio proxy with `npm publish`, but omits `--tag`. **npm ≥ 11** (bundled with Node 24+) refuses to publish a prerelease version (e.g. `0.87.0-rc.0`) without an explicit tag:
```
npm error You must specify a tag using --tag when publishing a prerelease version.
```
This breaks `yarn test-release-local` immediately at the publish step on any machine using npm ≥ 11.
## Fix
Pass an explicit `--tag react-native-e2e`. This is a throwaway local registry and the install step pins the **exact** version, so the dist-tag value is not significant for resolution.
## Changelog
[Internal] - Fix `test-release-local` publishing on npm ≥ 11
Pull Request resolved: https://github.com/react/react-native/pull/57552
Test Plan: `yarn test-release-local -t RNTestProject -p iOS` now gets past the publish step on npm 11 (previously failed immediately at `npm publish`).
Reviewed By: christophpurrer
Differential Revision: D111995913
Pulled By: zeyap
fbshipit-source-id: 107a96d5c4317129228f783ad52bffe1578d1138
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57490
See [**RFC0894: Removing deep imports from react-native**](https://github.com/react-native-community/discussions-and-proposals/pull/894)
This is the **big switch** to enable the Strict TypeScript API (generated types + single index entry point) by default in React Native.
**Opt-in → opt-out**
After this change, the main `react-native` package resolves its `"types"` entry points only to `types_generated/index.d.ts` — with no other subpaths available.
The new `"react-native-legacy-deep-imports"` condition maps to legacy `types/` and `Libraries/*.d.ts` sources.
**Impact limitation**: For this stage of rollout, the `"default"` condition continues to resolve to source files. Only TypeScript is affected.
**How to opt out**
Opposite of today's opt-in, which we will update in [the docs](https://reactnative.dev/docs/strict-typescript-api). Again, the only impact area today is **TypeScript**.
```json5
// tsconfig.json
{
"extends": "react-native/typescript-config",
"compilerOptions": {
...
"customConditions": ["react-native-legacy-deep-imports"]
}
}
```
**Other changes**
- Drop `react-native/typescript-config/strict` entry point, update README.
- Update `__typetests__`.
**Rollout plan**
**Target release: 0.87**. This and the contributing stack will be cherry picked for RC1.
- We've conducted testing against 100+ real Expo codebases, giving us the confidence that we've reduced breaking changes enough that the vast majority of RN codebases can migrate.
- The Strict API includes a number of **intentional breaking changes**, and docs have been kept up to date.
- We're shipping a `/migrate-to-strict-api` skill to migrate via agents, see https://github.com/react-native-community/skills/pull/3.
**What's improved since 0.80?**
Since the initial opt-in launch of the Strict API in 0.80, we've been making continuous improvements over the last year to get our generated types into a widely launchable state.
Most notably:
- 21+ new/updated root APIs and fixes due to community feedback ([discussion](https://github.com/react-native-community/discussions-and-proposals/discussions/893), [PRs](https://github.com/react/react-native/pulls?q=is%3Apr%20label%3A%22JS%20API%20stabilization%20(1.0)%22%20is%3Aclosed)).
- Upstream encapsulation blocker in TypeScript, fixed in 6.0 (https://github.com/react/react-native/issues/53565).
- Tailwind/Uniwind compatibility (`interface` types for props).
- `*Instance` ref type exports for all built-in components (https://github.com/react-native-community/discussions-and-proposals/pull/1003).
- Fixes to previously mistyped, high impact APIs, such as `Appearance`.
- New subpath entry points for `asset-registry`, `setup-env`, and others.
- Refinements to doc comments/type translation build.
**Rollback plan**
Revert this diff.
IMPORTANT: We'll adopt a policy of **super-eager rollback**, if there are any unsolvable issues during the RC phase.
Changelog:
[General][Breaking] - React Native's default JavaScript API is now the [Strict TypeScript API](https://reactnative.dev/docs/strict-typescript-api). Use `customConditions: ["react-native-legacy-deep-imports"]` to opt out.
Reviewed By: cortinico
Differential Revision: D110458670
fbshipit-source-id: 4b0e0b458a5f895f783d6d936e7b11ccff2df076
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57369
**Problem**
The separate `react-native/assets-registry` package includes a longstanding ecosystem footgun.
`registry.js` holds asset state in a module-scoped variable, which makes the package a stateful singleton: exactly one instance must exist per JS runtime, or registration and lookup diverge.
We provide no guarantee that this singleton requirement holds:
- The install layout — how the package manager dedupes packages in `node_modules` — decides how many copies exist, and `react-native`'s exact-version pin means third-party ranges never dedupe against it.
Effects:
- **Consumers silently break**: `expo-asset` and `expo-image` can land on a second copy: assets register in one, resolve as `undefined` from the other. Expo neutralizes this with a shim in `expo/cli` that redirects every registry import to a single virtual module — bare React Native + Metro has no such protection.
- **This blocks 1.0**: The ecosystem can't move from exact-version lockstep to semver ranges until stateful packages like the asset registry are safe to duplicate. Today, relaxing the pin would turn a latent footgun into a common one.
**To solve this**, move towards (but not quite yet) deleting `react-native/assets-registry`, in favour of a replacement `AssetRegistry` API offered directly by `react-native`.
**Key changes**
NOTE: **Reviewer note**: Browsing file changes on GitHub may be more focused — https://github.com/react/react-native/pull/57369/changes
NOTE: Squash of https://github.com/react/react-native/pull/57233 (D108750302) and https://github.com/react/react-native/pull/57232 (D108750303)
`'react-native'`:
- Add new `AssetRegistry` API, along with the `PackagerAsset` and `AssetDestPathResolver` root type exports in `react-native`.
- Add a new `'react-native/asset-registry'` secondary entry point — intended for Metro's `transformer.assetRegistryPath` config contract.
`react-native/assets-registry`:
- Update to source from this relocated implementation — fixing the duplicate install layout bug (where apps/frameworks enforce a single copy of `react-native`).
**Impact**
- **✅ Fixed**: Imports from either `react-native` or `react-native/assets-registry` in RN 0.87+ will be durable to duplicate package installs — Expo can remove their virtual module shim.
- **✅ Fixed**: Deep import `'react-native/Libraries/Image/AssetRegistry'` dependency removed (migrated in `react-native/metro-config`).
Changelog:
- [General][Fixed] - **assets-registry**: `react-native/assets-registry` now shares state across duplicate installs, sourcing from a relocated implementation in the `react-native` package
- [General][Added] - Add `AssetRegistry` API (replaces `react-native/assets-registry/registry`)
- [General][Breaking] - `react-native/Libraries/Image/AssetRegistry` is removed. Please use the `AssetRegistry` API (apps/library code) and/or the `react-native/asset-registry` entrypoint (Metro/build configs).
Reviewed By: robhogan
Differential Revision: D109019622
fbshipit-source-id: 75599a94a9aba084a1266f2128c448379d1596cd
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57236
Move `handleJSError` from `cxxreact/ErrorUtils.h` (header-inline) to `jserrorhandler/ErrorUtils.{h,cpp}` (declared + linked). Inverts the cyclic dep so `jserrorhandler` becomes a standalone leaf and `cxxreact:bridge` can be narrowed out of more consumers in follow-ups.
The old `<cxxreact/ErrorUtils.h>` include path continues to work via a deprecated `#warning` forwarder header that includes the new location. `cxxreact:bridge` now depends on `jserrorhandler:jserrorhandler` so existing consumers of the deprecated path still link cleanly. `jserrorhandler/BUCK` drops its `cxxreact:bridge` dep (and the matching `React-cxxreact` podspec entry).
Changelog:
[Internal]
Reviewed By: christophpurrer
Differential Revision: D108786498
fbshipit-source-id: 6a34ec47665558ac9c91343253e027ed1df70e93
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57328
Today the iterator-setter path in `ConcreteComponentDescriptor::cloneProps` runs three sequential walks over the input — `RawProps::parse(parser)` (builds `keyIndexToValueIndex_` for `convertRawProp`), `static_cast<folly::dynamic>(rawProps)` (materializes a `folly::dynamic` via `jsi::dynamicFromValue` in JSI mode), and then `dynamic.items()` to dispatch `setProp`. Only the third is actually used: `convertRawProp` is never called on the iterator-setter branch, and the `folly::dynamic` materialization exists only as iteration scaffolding.
Restructure so the runtime flag picks one of two construction paths up front:
- **Iterator-setter** — copy-construct from `sourceProps` via the (re-enabled) `Props` copy ctor, then walk `rawProps` in-place via the new `RawProps::forEachItem` helper and route each entry through `setProp`. `parse()` is skipped entirely; the `folly::dynamic` materialization is skipped in `Mode::JSI`.
- **Classic** — unchanged: `parse()` + 3-arg `convertRawProp`-driven ctor.
`forEachItem` switches on `RawProps::Mode`:
- `Mode::JSI` — walks `value_.asObject(*runtime_).getPropertyNames(...)` and constructs `RawValue` from each `jsi::Value` directly, no `folly::dynamic` in between.
- `Mode::Dynamic` — iterates `dynamic_.items()` (same as today).
- `Mode::Empty` — no-op.
A new `HasIteratorSetterCtor<T>` concept (`std::copy_constructible<T>`) documents the contract and feeds a `static_assert` in `cloneProps`, so a future Props type that deletes its copy ctor fails at compile time rather than silently diverging at runtime between the two flag states.
The `RN_SERIALIZABLE_STATE` Props 2.0 accumulation branch keeps its existing dynamic-iteration shape — when `fallbackToDynamicRawPropsAccumulation` is true, `initializeDynamicProps` has already merged the source's rawProps with the input onto `shadowNodeProps->rawProps`, so we iterate that merged dynamic rather than the raw input.
The per-field `flag ? sourceProps.X : convertRawProp(...)` ternaries across every Props .cpp file become dead in the flag-on path (the copy ctor handles those fields) but are still functional in the flag-off path. They get removed in a follow-up cleanup; this diff is structurally non-breaking on either flag state.
Changelog:
[Internal]
Reviewed By: zeyap
Differential Revision: D109568749
fbshipit-source-id: eae20478418a7dbf7364c73d85d7694d99f1e8f1
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57361
Broadens the former header-shrink change into a single representation-optimization commit for MapBuffer. It bundles three layout optimizations that were previously split: (1) the header is reduced to a single 2-byte `count` field; (2) multi-byte values are read via `memcpy` so unaligned access is well-defined on all platforms; (3) every dynamic-data entry (`String`, `Map`, `MapBufferList`, `IntBuffer`, `DoubleBuffer`) packs its `[offset][byteLength]` into the bucket's 8-byte value instead of writing an in-band length prefix into the dynamic data section.
Net effect: 4 fewer bytes per dynamic entry, one fewer indirection on read (the length is already in the bucket), and every dynamic entry becomes self-delimiting from its bucket alone. No public API change — only the internal serialized representation.
Changelog: [Internal]
landed-with-radar-review
Reviewed By: lenaic, zeyap
Differential Revision: D109848478
fbshipit-source-id: 30749aaa1c2d9fc9b1f8684a3b67815ef44632e8
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57360
Introduces a dedicated `MapBufferList` `DataType` for an ordered array of nested MapBuffers, instead of overloading the `Map` type for lists. This makes a list of MapBuffers self-describing and distinguishable from a single nested `Map` (they were byte-distinct in payload but previously shared the `Map` type tag). Updates the C++ builder (`putMapBufferList`), the Kotlin `MapBuffer` interface, `ReadableMapBuffer`, and `WritableMapBuffer`, and adds cross-language JNI round-trip coverage in the serialization instrumentation test.
Changelog:
[Android][Added] - Add a dedicated `MapBufferList` type to `MapBuffer` for ordered lists of nested `MapBuffer`s
landed-with-radar-review
Reviewed By: zeyap
Differential Revision: D109848477
fbshipit-source-id: 7f590d5999d0cc4ee2d9d28cc34ae9220e442e18
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57359
Adds two new MapBuffer entry types, `IntBuffer` and `DoubleBuffer`, for storing homogeneous arrays of ints and doubles compactly in the dynamic data section. Unlike `Map` / map lists, these carry no per-element key/type overhead: a batch of N values costs ~N*elementSize bytes plus a single 4-byte count prefix instead of N 12-byte buckets. The bucket value holds the offset of the array within the dynamic data section.
Covers the full surface: the C++ reader (`MapBuffer::getIntBuffer` / `getDoubleBuffer`), the C++ builder (`MapBufferBuilder::putIntBuffer` / `putDoubleBuffer`), and the Kotlin reader API (`MapBuffer.getIntBuffer` / `getDoubleBuffer`, `Entry.intBufferValue` / `doubleBufferValue`). The `DataType` enum gains `IntBuffer = 6` and `DoubleBuffer = 7`, kept in sync across C++ and Kotlin.
Changelog:
[General][Added] - Add `IntBuffer` and `DoubleBuffer` entry types to MapBuffer for compact homogeneous int/double arrays
landed-with-radar-review
Reviewed By: zeyap
Differential Revision: D109848476
fbshipit-source-id: f9e86b7c094dea796d9a8b725e53eb948c1390ca
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57389
**Context**
Strict TypeScript API readiness: High quality inline docs should reach users via TypeScript in their IDEs.
**This diff**
Prior iterations of our Flow → TS translation stack dropped doc comments for default-exported values, and/or identifiers which change shape after type transformation (e.g. Flow `component` syntax), meaning many root APIs (`View`, `ScrollView`, `Pressable`, and others) showed no documentation on hover.
This diff extends the existing `reattachDocComments` transform to handle doc comment repositioning (suitable for the TS lang server) from a greater set of source positions:
- the exported declaration
- a `.displayName` assignment
- a HOC-wrapped inner component
- a renamed wrapper's public-named component
- a `declare const` / `declare export default typeof X` stub
**Impact**
(With the source code JSDoc improvements earlier in this stack.)
| Before (legacy types) | After (Strict API) |
| -- |
| {F1991869487} | {F1991869472} |
| ⚠️ No inline docs for many symbols | ✅ New, detailed inline docs reach the TS server 🎉 |
Changelog:
[General][Fixed] - Preserve doc comments on root API symbols in the generated TypeScript types
Reviewed By: rubennorte
Differential Revision: D109316361
fbshipit-source-id: 8a83455fcf317f355bd7c5a67712d322248d8b00
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57403
Make `RuntimeScheduler` implement `IEventLoopControl`.
Wire `ReactInstance` to register that scheduler on Hermes
runtimes that expose `ISetEventLoopControl`.
Clear the pointer during teardown before `RuntimeScheduler`
is destroyed.
Regenerate React Native C++ API snapshots for the public
header change.
Only the modern scheduler have the actual implementation, it's no-op
in the legacy scheduler.
Changelog: [Internal]
Reviewed By: javache
Differential Revision: D106744175
fbshipit-source-id: 90eb17ce8dbc929b5f2474e019de07ad28d9c21d
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57400
In this diff we drop the custom choreographer for the backend on Android and instead plug into the one in `FabricUIManager`. This reduces the area for possible mistakes, makes it clearer how Fabric interacts with animation on a per-frame basis, and simplifies the flow around invalidation and cleanup of the React instance.
The crash this is meant to avoid comes from having two separate frame callback lifecycles. The old `AnimationBackendChoreographer` owned a self-reposting callback that could keep driving `FabricUIManagerBinding.driveAnimationBackend` independently from Fabric's own lifecycle. During React instance teardown, `FabricUIManager.invalidate()` pauses Fabric's frame callback and then unregisters the native binding. If a separate backend callback survives that sequence, it can invoke the binding after the native side has been uninstalled.
The shared animation backend is now driven from Fabric's existing `DISPATCH_UI` frame callback after mount items are dispatched. The Android `AnimationChoreographer` implementation only owns backend pause/resume state and conditionally forwards active frames to the shared backend.
Threading-wise:
- If invalidation happens before a frame starts, `mDestroyed` makes the frame no-op.
- If invalidation races with an already-running frame, `ReactChoreographer.removeFrameCallback` is serialized with callback execution via the `callbackQueues` monitor, so `onHostPause()` waits for the current `DISPATCH_UI` callback to finish before `unregister()` tears down the native binding.
- If the frame reposts itself in `schedule()`, the blocked removal observes and removes that callback before teardown continues.
Changelog:
[Android][Fixed] - Drive the shared animation backend from Fabric's frame callback during React instance teardown
Reviewed By: javache, zeyap
Differential Revision: D110321362
fbshipit-source-id: 77c462ee30aeec2d3af0dcd48b8eed15846ae5da
Summary:
Some third-party libraries, like react-native-reanimated, can clone nodes in a different thread while react-native is calling `setNativeProps_DEPRECATED`. This results in a race condition, where a stale pointer to `nativeProps_DEPRECATED` can be accessed, resulting in a crash. This usually manifests as a `EXC_BAD_ACCESS` crash on iOS. On Android it seems more rare. We've added a lock around accesses to nativeProps_DEPRECATED, but alternative options of fixing this can be considered too.
For more information see https://github.com/software-mansion/react-native-reanimated/issues/7666
## Changelog:
[INTERNAL] [FIXED] - Fixed crashes caused by race conditions when third-party libraries clone the shadow dom from a different thread
Pull Request resolved: https://github.com/react/react-native/pull/52646
Test Plan:
Due to this being a race condition that only manifests in rare circumstances, it's very difficult to create a reliable reproduction case. The issue mentioned above contains ThreadSanitizer logs that demonstrate this issue. TSan no longer complains with this patch applied, and we've not seen any additional issues from it after deploying it in production over the past week.
Added unit test covering the `nativeProps_DEPRECATED` merge logic in `UIManager::cloneNode` and `ShadowNode::clone`:
```
buck2 test //xplat/js/react-native-github/packages/react-native/ReactCommon/react/renderer/uimanager:tests -- --regex FabricUIManagerTest
```
Reviewed By: zeyap
Differential Revision: D110169424
Pulled By: javache
fbshipit-source-id: 6139253dcc2c33348a0c1a3bd01e695d15aa83bc
Summary:
The C++ native animated backend (`cxxNativeAnimatedEnabled`) prevents the `useNativeDriver` first-frame flash by having `AnimatedMountingOverrideDelegate` re-merge a view's live animated props (`getManagedProps`) onto mount `Update` mutations, so a stale JS re-render can't reach the screen. There is a residual at connect time: `connectAnimatedNodeToView` registers the view (the override starts overriding it) but never runs the props node, so `getManagedProps()` returns an empty object until the next animation frame. If a Fabric mount transaction is pulled in that window the override has nothing to merge and the un-driven default value flashes for one frame, most visibly when a brand-new view is connected to an already mid-flight shared `Animated.Value`.
This seeds the props node with `node->update()` at the end of `connectAnimatedNodeToView` so `getManagedProps()` is live the instant the view becomes managed. No manager mutex is held at that point and `update()` takes only the node-local props mutex, so it is lock-safe; it is idempotent with the per-frame update and adds no extra Fabric commit because it only stages. It closes the connect-while-`Update`-in-flight case and mitigates the brand-new-view (`Insert`) first-paint case; the override only rewrites `Update`/`Delete` mutations today, so fully closing `Insert` is a follow-up. It also adds the missing unit coverage for the `getManagedProps` / `hasManagedProps` seam the override depends on.
## Changelog:
[INTERNAL] [FIXED] - Seed managed props when a view connects to the native animated backend so they are live before the first frame, shrinking the useNativeDriver mount flash
Pull Request resolved: https://github.com/react/react-native/pull/57391
Test Plan: Adds `ManagedPropsMountingOverrideTests.cpp` to the ReactCommon animated unit tests. `getManagedPropsReflectsLiveValueAcrossFrames`, `getManagedPropsNullForUnconnectedView`, `hasManagedPropsTracksConnectAndDisconnect` and `getManagedPropsIsolatedPerView` pin the seam and pass regardless of the change. `getManagedPropsLiveImmediatelyOnConnect` and `getManagedPropsLiveOnConnectWhileValueMidFlight` are the regression cases: they fail without the seed (empty props at connect) and pass with it. Run via the animated C++ unit test target. On-device verification (iOS and Android with `cxxNativeAnimatedEnabled` on, frame-stepped capture of a popover/menu open) is still recommended for the user-visible flash.
Reviewed By: sammy-SC
Differential Revision: D110323404
Pulled By: zeyap
fbshipit-source-id: 485e31e1c874548da1ee7339481164faa763b2d9
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57387
Adds `yarn fantom-cli`, an interactive REPL that evaluates JavaScript against the same native tester binary and Hermes runtime that Fantom tests run in. State persists across lines, input goes through Metro/Babel (so `import`, JSX and Flow all work), and the environment is set up the same way tests set it up — `React`, `ReactNative` and the `Fantom` API are available globally, so you can render surfaces and drive them interactively from the prompt.
The native tester gains an `--interactive` mode that loads a warm-up bundle without running tests and then evaluates length-prefixed snippets read from stdin, reporting results, console output and errors back as newline-delimited JSON. A Node driver hosts a Metro server, builds the warm-up bundle, spawns the binary, and bridges each line of input into the live runtime (top-level declarations persist across evaluations).
Features:
- Console-style output: results are printed with an inspector similar to the Chrome DevTools / Node.js consoles (nested objects/arrays up to a depth limit, quoted strings, functions/classes, `Map`/`Set`/`RegExp`/`Date`/`Error`, class instances, circular references, multi-line wrapping), colorized by type when stdout is a terminal. Inspecting a property never aborts the result or leaks into later evaluations: a property whose getter fails renders as `[Thrown: <error>]`, including getters that fail asynchronously through the runtime's global error handler (e.g. accessing a `react-native` export backed by a TurboModule that isn't registered).
- Autocompletion: pressing Tab completes global identifiers, in-scope bindings and object properties (property names are listed without invoking getters).
- Node-like CLI: with no arguments it starts the REPL; `-e <code>` evaluates a snippet and exits; a filename runs that script and exits. In the non-interactive modes the value of a trailing expression is not printed (use `console.log`) and a thrown error exits with a non-zero status code.
Also documents the REPL in the Fantom README.
Changelog: [Internal]
Reviewed By: javache, sammy-SC
Differential Revision: D110187712
fbshipit-source-id: 3e76c498ae04b8b1ce9e0e27e5ce6b6a0cd11e09
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57376
AnimatedPropsRegistry::update() runs on the UI thread every animation frame and
created a surface's entry via operator[]. clearOnSurfaceStop() (run on the JS
thread when a surface stops) erases that entry, but an in-flight animation frame
landing after the stop re-created it via operator[] -- and since the surface is
gone, nothing ever cleans it up again. The resurrected entry leaks its
PropsSnapshot and ShadowNodeFamily for the lifetime of the registry.
A surface's entry is legitimately created by getMap(), which
AnimationBackendCommitHook calls on every React commit. stopSurface drains
in-flight commits before unregistering the ShadowTree
(ShadowTreeRegistry::remove takes the registry's unique lock, which excludes the
shared-locked commit visits), so getMap() can never run for a stopped surface.
That leaves update()'s operator[] as the only thing that can resurrect one.
Fix: update() now only refines surfaces that already exist (find instead of
operator[]) and never creates an entry; getMap() remains the sole creator. A
stopped surface can no longer be resurrected, and there is no extra bookkeeping
that could grow over time.
Changelog: [General][Fixed] - Fix a surface-stop race in the C++ Animated shared backend that could permanently leak per-surface animated state
Reviewed By: javache
Differential Revision: D109156094
fbshipit-source-id: 4684ca51d372023e3b082427a225de7d84d14889
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57377
ViewShadowNodeProps was a thin subclass of ViewProps that only forwarded its constructor. After the feature flag propagation logic was removed, the subclass serves no purpose.
Changelog:
[Internal]
Reviewed By: lenaic
Differential Revision: D110095190
fbshipit-source-id: a2555c4ba455e51116c73be3b5c9a71788895ffd
Summary:
Closes https://github.com/react/react-native/issues/45255.
Adds `textAlign: 'start' | 'end'` support for Text and TextInput across the JS types, Android, iOS, and Fabric text conversion paths.
- Android legacy Text and TextInput now accept logical `start`/`end` alignment values.
- Fabric preserves `start`/`end` as distinct `TextAlignment` values and resolves them against layout direction for iOS paragraph layout.
- Existing `left`/`right` behavior is left unchanged to avoid changing current RTL semantics.
This replaces https://github.com/react/react-native/issues/57007 because the original fork became locked and could not be updated after the upstream conflict.
## Changelog:
[GENERAL] [ADDED] - Add support for `textAlign: 'start'` and `textAlign: 'end'`.
Pull Request resolved: https://github.com/react/react-native/pull/57201
Test Plan:
- `yarn build-types`
- `yarn test-typescript`
- `yarn flow-check`
- `./node_modules/.bin/prettier --check packages/react-native/Libraries/Components/TextInput/TextInput.d.ts packages/react-native/Libraries/Components/TextInput/TextInput.flow.js packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js packages/react-native/types/__typetests__/index.tsx packages/react-native/ReactNativeApi.d.ts`
- `./gradlew ktfmtCheck -Preact.internal.useHermesStable=true --no-daemon`
- `./gradlew :packages:react-native:ReactAndroid:testDebugUnitTest --tests com.facebook.react.views.textinput.ReactTextInputPropertyTest.testTextAlign --tests com.facebook.react.views.text.TextAttributePropsTest -Preact.internal.useHermesStable=true --no-daemon`
- `./gradlew ':packages:react-native:ReactAndroid:buildCMakeDebug[arm64-v8a][hermestooling,jsi,etc]' -Preact.internal.useHermesStable=true --no-daemon`
- `git diff --check`
The Android unit test and CMake checks were run from an ASCII-only temporary worktree because Kotlin unit test compilation in my main checkout fails before running these tests when the workspace path contains non-ASCII characters.
Reviewed By: christophpurrer
Differential Revision: D108628602
Pulled By: javache
fbshipit-source-id: 28111d0553451d7de0424a07e956f71bda8787ca
Summary:
Removes the deprecated `animated` prop from `Modal`. It was a no-op everywhere. Use `animationType` instead.
See https://github.com/react/react-native/issues/57384
## Changelog:
[GENERAL] [REMOVED] - Remove deprecated `Modal` `animated` prop
Pull Request resolved: https://github.com/react/react-native/pull/57385
Test Plan:
- `yarn jest packages/react-native/Libraries/Modal`
- `yarn flow` and `tsc` pass with the prop removed from `Modal.js` / `Modal.d.ts`.
Reviewed By: huntie
Differential Revision: D110205204
Pulled By: cortinico
fbshipit-source-id: 8e5b4d7dc8811d7270de3776476e7f868eafddd5
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57367
Places this one folder up, in a location that will be preserved when we later delete the manual `types/` dir. These tests already apply to both the `types/Libraries` dirs and the generated `types_generated/`.
Changelog: [Internal]
___
Differential Revision: D110055787
fbshipit-source-id: 5ff190d301628877c9bda57c92b1af1a2917f1ca
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57346
Restores a deprecated three-argument overload of `RawProps::at()` for backwards compatibility with existing callers (like Nitro modules) that pass prefix/suffix separately.
The new overload concatenates `prefix + name + suffix` when needed and delegates to the parser's `at(string_view)` method. When both prefix and suffix are null, it forwards directly to the single-argument version.
Changelog: [Internal]
Reviewed By: cortinico
Differential Revision: D109837388
fbshipit-source-id: c16188cee163ca786f4530d07475f561a53c51b6
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57310
Add `AppIcon.icon` file (Icon Composer) for macOS 26 Tahoe. Also rename previous `.icns` file for consistency.
`electron/packager` is updated to `^20.0.0` (`.icon` support was added in `18.4.0`).
**Notes**
- This change ensures the Icon Composer source is part of the codebase (following above Electron packager support which came in March).
Changelog:
[General][Changed] - **React Native DevTools**: Add macOS 26/27 app icon
Reviewed By: robhogan
Differential Revision: D97292364
fbshipit-source-id: ba1c34175a95da8c2860142d9db0c4d98d3f6de0
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57348
Follow-up to the `js1 build-cxx-api` rename. Move `build-geo-screenshot-tests`, `build-js-api`, and `build-twui-screenshot-tests` under the `build` group so they sit next to their siblings (`js1 build assets`, `js1 build turbomodule`, etc.) instead of being top-level hyphenated outliers.
Each old top-level command stays as a hidden alias that prints a deprecation notice and delegates to the new module, so existing muscle memory and any out-of-tree scripts keep working.
Also updates the two places that emit the old command names into user-visible output: the TWUI template comment headers, and the JS API snapshot failure message.
Changelog:
[Internal]
Reviewed By: zeyap
Differential Revision: D109844649
fbshipit-source-id: 00623fa8b4d724e16a2dc62d196182c32a9fed64
Summary:
Adds ArrayBuffer support to ObjC TurboModules, following the C++ ArrayBuffer PR ([`226ef2e`](https://github.com/facebook/react-native/commit/226ef2e7c5d1928d5696dc23efc1b8950ba00e37)).
- Codegen support for `ArrayBufferTypeAnnotation` in ObjC module specs (`NSMutableData *` params/returns, new `ArrayBufferKind`)
- JSI↔ObjC conversion wraps native-backed buffers zero-copy via `-[NSMutableData initWithBytesNoCopy:length:deallocator:]`; the deallocator retains the backing store so the bytes stay valid even if the `NSMutableData` escapes the call or the source ArrayBuffer is garbage-collected
- JS-backed buffers are copied, which is safe on both the synchronous and asynchronous paths
This PR is iOS-only; Android support follows in a separate PR.
## Changelog:
[IOS] [ADDED] - Add ArrayBuffer support to ObjC TurboModules
X-link: https://github.com/facebook/react-native/pull/56986
Reviewed By: javache
Differential Revision: D106846249
Pulled By: christophpurrer
fbshipit-source-id: 3393d5d6f31a1412f5d52328c90e51205aa6b153
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57339
Every Props subclass parses its fields in its 3-arg ctor's initializer list, but `Props` was the odd one out — its 3-arg ctor had an empty initializer list and a body that called a separate `Props::initialize` method, which then assigned `nativeId` and (on Android) ran `initializeDynamicProps`.
Fold the `nativeId` parse back into the initializer list and inline the Android `initializeDynamicProps` call into the ctor body, matching the subclass pattern.
This removes the only remaining external caller of `Props::initialize`: `YogaStylableProps`'s ctor was constructing its `Props` subobject via `Props()` and then calling `initialize(...)` from its body. Replace with the standard `Props(ctx, sourceProps, rawProps, filterObjectKeys)` initializer-list chain. With both call sites gone, delete `Props::initialize` outright.
Behaviour is unchanged: the work that `initialize` did still runs on the same construction path, just via the ctor itself.
Changelog:
[Internal]
Reviewed By: christophpurrer
Differential Revision: D109691981
fbshipit-source-id: 835615191332239e90353da2e66fecc429365529
Summary:
X-link: https://github.com/facebook/react-native/pull/55763
RawPropsKey previously stored three `const char*` fields
(prefix, name, suffix) that were concatenated at runtime to form
property names.
This is pretty niche, used to make a few patterns simpler, but also can lead to confusing conflicts when the same property name can be represented in different ways (e.g. T174300106). Iterator style props parsing also completely avoids it.
Lets change the API to a flat name instead.
This change is breaking, but could only find a single user (Nitro module) effected, searching through `react-native-libraries`.
Changelog:
[General][Breaking] - Remove RawPropsKey prefix and suffix
Reviewed By: christophpurrer
Differential Revision: D94367880
fbshipit-source-id: d865725c7be6f880760b6e8d1a567a1b12ac469a
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57308
`private/helloworld` depends on `react-native/core-cli-utils` (it imports `android`, `app`, and `apple` from it to build the app), but that package is no longer published to npm nor to the local Verdaccio proxy that the e2e build installs against. Since `private/helloworld` is excluded from the workspace, it installs standalone, so its `"*"` dependency on `react-native/core-cli-utils` could not resolve and `npm install` failed with `E404`.
Resolve `"*"`-pinned in-repo `react-native/*` dependencies to a local `file:` path in `_prepareHelloWorld()`, so helloworld consumes `core-cli-utils` directly from its in-repo reference implementation regardless of whether it is published. This mirrors how the `react-native` package itself is already wired up for the e2e build.
Changelog: [Internal]
Reviewed By: javache
Differential Revision: D109374920
fbshipit-source-id: b6668785387511fa54580ee75e81f13168782797
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57286
We currently have a mix of quote styles in `.yml` files (AI summary below). This applies prettier and reformats everything to single quotes to align with defaults.
Also fixes a couple of cases of over-indentation.
```
Single-quotes only (0 double-quoted scalars):
analyze-pr.yml
— 12 single, 0 double
api-changes.yml
— 3 single, 0 double
check-for-reproducer.yml
— 4 single, 0 double
retry-workflow.yml
— 1 single, 0 double
Single-quote predominant > double:
autorebase.yml 2 vs 1
create-draft-release.yml 8 vs 2
generate-changelog.yml 3 vs 2
on-issue-labeled.yml 7 vs 2
prebuild-ios-core.yml 59 vs 17
prebuild-ios-dependencies.yml 39 vs 1
stale-bot.yml 18 vs 15
test-all.yml 70 vs 27
Double-quote predominant > single:
bump-podfile-lock.yml 1 vs 10
create-release.yml 3 vs 12
e2e-android-rntester.yml 2 vs 6
e2e-android-templateapp.yml 6 vs 13
e2e-ios-rntester.yml 2 vs 7
e2e-ios-templateapp.yml 2 vs 18
fantom-tests.yml 2 vs 7
monitor-new-issues.yml 3 vs 12
publish-npm.yml 42 vs 50
validate-cxx-api-snapshots.yml 2 vs 23
validate-dotslash-artifacts.yml 2 vs 5
Tie / 1-1:
cache-reaper.yml 1 vs 1
close-pr.yml 1 vs 1
needs-attention.yml 2 vs 2
All files contain single quotes somewhere, but only those 4 are single-quote-exclusive. Most CI-heavy workflows — bump, create-release, e2e-, fantom, monitor, publish-npm, validate- — lean double-quoted, while the pr/issue automation, prebuild ios, test-all, and stale-bot lean single-quoted.
```
Changelog: [Internal]
___
Differential Revision: D109151683
fbshipit-source-id: 24391e906c0dd92fe402224089dce8bb2068b4d9
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57274
Fantom could not deterministically fire delayed JS timers: the timer registry it used scheduled timers on a real background thread with real wall-clock delays, so `setTimeout(fn, 100)`/`setInterval` callbacks never fired within a synchronous test. This adds a mockable timer registry and a public Fantom API to control it from JS, similar to `installHighResTimeStampMock`.
- New `Fantom.installTimerMock()` returns a controller with `advanceTimersByTime(ms)`, `runAllTimers()`, `getPendingTimerCount()`, and `uninstall()` (jest fake-timer style). While installed, `setTimeout`/`setInterval` callbacks only fire when the virtual clock is advanced.
- New deterministic `FantomTimerRegistry` (no background thread) keyed off a virtual clock, injected via a new optional `platformTimerRegistryFactory` seam on `ReactInstanceConfig` (the default registry is unchanged for all other consumers).
- `PlatformTimerRegistry` gains a virtual `setTimerManager` (default no-op) so the registry can be wired polymorphically.
- Control flows from JS through new `NativeFantom` methods, the same way the high-res timestamp mock works.
Default (non-mock) behavior is preserved: zero-delay `setTimeout` still fires on the next work loop, and existing tests are unaffected.
Changelog: [Internal]
Reviewed By: christophpurrer
Differential Revision: D109017304
fbshipit-source-id: 8afe6fb2a39f470ae293038f6592c46535442dc2
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57248
Implement the CDP `Page.addScriptToEvaluateOnNewDocument` and `Page.removeScriptToEvaluateOnNewDocument` methods in the modern JS inspector (`jsinspector-modern`). `Page.addScriptToEvaluateOnNewDocument` registers a JavaScript snippet that is evaluated in every new JS runtime created for the Host (for example, after a reload), before the application's main bundle runs, matching the standard Chrome DevTools Protocol semantics. This is useful for debugger frontends and tooling that need to install instrumentation ahead of application code.
The registered scripts are stored as session state (alongside `Runtime.addBinding` subscriptions in `SessionState`) and replayed onto each new runtime by `RuntimeAgent` via the runtime executor, so they run before any user code and survive reloads. Per CDP semantics the script does not run in the runtime that is current when it is registered; the client triggers `Page.reload` to apply it. `HostAgent` handles both methods, returning the generated script `identifier` from add and removing by `identifier` on remove.
Changelog:
[General][Added] - Implement the `Page.addScriptToEvaluateOnNewDocument` and `Page.removeScriptToEvaluateOnNewDocument` CDP methods in the modern inspector
Reviewed By: hoxyq
Differential Revision: D107084044
fbshipit-source-id: 7951028f81f89fbf36418cf8da8a03a7191d228a
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57226
This removes the experimental `enableImageRequestDowngradingForNonVisibleImages` feature flag and backs out the behavior it gated. When enabled, `ImageShadowNode` downgraded image requests to prefetch priority for images that layout determined did not intersect the viewport — threading an `ImageRequestPriority` through `ImageRequestParams` and the Apple image managers, and propagating per-node viewport frames during Yoga layout via `experimental_layoutOrigin`/`experimental_layoutFrame` on `LayoutContext`.
The flag defaulted to off and was never enabled in a release, and the gated behavior did not deliver the expected improvement, so the feature is removed entirely: `<Image>` once again always requests at immediate priority. This deletes the feature flag, the `ImageRequestPriority` enum and the `ImageRequestParams::priority` field, the priority parameter on `RCTImageManager`/`RCTSyncImageManager`/`RCTImageManagerProtocol`, the `experimental_layout*` `LayoutContext` fields and their Yoga propagation, the iOS request-priority debug overlay, and the associated Fantom test scaffolding. The generated feature-flag sources and the C++ API snapshots are regenerated accordingly.
Changelog: [Internal]
Reviewed By: javache
Differential Revision: D108411690
fbshipit-source-id: 1538ec699ed2857f3d3154d666fac43a1dc64cd1
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57213
`StateData` is the placeholder data type for shadow nodes that have no state. It declared `getMapBuffer()` but never defined it, which breaks the build under clang-22.
`ConcreteState<DataT>::getMapBuffer()` calls `getData().getMapBuffer()` only when the `StateDataWithMapBuffer` concept is satisfied, and otherwise returns `MapBufferBuilder::EMPTY()`. Because `StateData` declared `getMapBuffer()`, it satisfied the concept, so `ConcreteState<StateData>::getMapBuffer()` referenced the undefined `StateData::getMapBuffer()`. Whether a class template's virtual members are implicitly instantiated is unspecified ([temp.inst]/11); clang-22 instantiates this override, turning the missing definition into an undefined-symbol link error.
Remove `getMapBuffer()` from `StateData` so the concept is no longer satisfied and the `EMPTY()` fallback is used — the same way `getJNIReference()` is already handled for this placeholder type. `getDynamic()` stays, since `ConcreteState` calls it unconditionally.
Changelog:
[Internal]
Reviewed By: javache
Differential Revision: D95506209
fbshipit-source-id: 71e767bb19dce5b6097d49654b3701896a783f5b
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57205
## Changelog:
[Internal][Fixed] - Fix EXC_BAD_ACCESS / KERN_INVALID_ADDRESS in C++ Animated when `useSharedAnimatedBackend()` flips across a reused runtime
C++ Animated chose between the legacy and shared-`AnimationBackend` code paths by reading `ReactNativeFeatureFlags::useSharedAnimatedBackend()` live, in many places. That flag is a process-global singleton (`ReactNativeFeatureFlags::accessor_`). On some app the global is reset and re-applied on every user switch (`FBReactModule setUpReactNativeFeatureFlags` -> `dangerouslyReset()`/`override()`), and the previous user's runtime is kept alive and reused. The shared `AnimationBackend` is attached only once, when an instance's `Scheduler` is constructed, gated on the flag at that moment. On a multi-account device the global flag could therefore read true on a reused instance whose backend was never attached, so `getOrCreate` took the shared path and dereferenced a null backend. It also let JS and C++ disagree, since JS caches the flag per runtime while C++ followed the mutated global.
Fix: make the per-instance decision once and use it everywhere instead of the live flag.
- `NativeAnimatedNodesManagerProvider::getOrCreate` selects the path by whether the shared `AnimationBackend` actually exists for this instance (`unstable_getAnimationBackend().lock() != nullptr`).
- `NativeAnimatedNodesManager` stores a `const bool useSharedAnimatedBackend_`, latched in its constructor (true for the shared-backend ctor, false for the legacy ctor), and exposes it via `useSharedAnimatedBackend()`. All internal reads now use the member.
- `PropsAnimatedNode` reads the decision through `manager_->useSharedAnimatedBackend()`.
The attach side (`Scheduler`) is intentionally unchanged: it remains the single construction-time read that latches the per-instance decision the rest of the code now follows. This keeps JS and C++ consistent across global flag flips and removes the null dereference.
Reviewed By: sbuggay
Differential Revision: D108428720
fbshipit-source-id: dff283cd3671866395d1b07b6c9c72e504aecea2
Summary:
X-link: https://github.com/facebook/react-native/pull/57140
`StartupLogger::getInitReactRuntimeEndTime()` was a public getter returning the `initReactRuntimeEndTime` member, but it had no callers. `NativePerformance` (the only consumer of `StartupLogger`) never reads it. This removes the dead getter; the backing member `initReactRuntimeEndTime` is kept because `logStartupEvent`/`reset` still write it.
Changelog: [Internal]
Reviewed By: mdvacca
Differential Revision: D108012904
fbshipit-source-id: 56a6710c485a926caf82ecb1cc08e845571b2dd8
Summary:
X-link: https://github.com/facebook/react-native/pull/57142
`StartupLogger::getRunJSBundleEndTime()` was a public getter that returned the `runJSBundleEndTime` member, but it had no callers. `NativePerformance` is the only consumer of `StartupLogger` and reads the start-time getters plus `getAppStartupEndTime`, never this end-time getter. This removes the dead getter. The backing member `runJSBundleEndTime` is kept because `logStartupEvent`/`reset` still write it.
Changelog: [Internal]
Reviewed By: mdvacca
Differential Revision: D108012912
fbshipit-source-id: ac6348b8223fba8695843340e99d7e277bf4f60a
Summary:
X-link: https://github.com/facebook/react-native/pull/57137
`RAMBundleRegistry::multipleBundlesRegistry` was a static factory wrapping the public `RAMBundleRegistry` constructor (the one taking a main bundle plus a factory callback), but it had no callers anywhere. Registries are constructed via the public constructor directly. With the sibling `singleBundleRegistry` already removed, this deletes the last orphaned static factory; the constructor and the rest of the class remain intact.
Changelog: [Internal]
Reviewed By: mdvacca
Differential Revision: D108012906
fbshipit-source-id: 7bb403ff7660317f0f5b422dca140ac69e048dac
Summary:
X-link: https://github.com/facebook/react-native/pull/57143
`RAMBundleRegistry::singleBundleRegistry` was a static factory that wrapped the public `RAMBundleRegistry` constructor, but it had no callers anywhere. Objects are constructed via the public constructor directly. This removes the orphaned factory; the sibling `multipleBundlesRegistry`, the constructor, `MAIN_BUNDLE_ID`, `registerBundle`, `getModule`, and `getBundle` are all left intact.
Changelog: [Internal]
Reviewed By: mdvacca
Differential Revision: D108012903
fbshipit-source-id: 5d8f18ebce2bb19abd124dbb7c9eda60baa0f272
Summary:
X-link: https://github.com/facebook/react-native/pull/57145
`HostTargetController::installPerfIssuesBinding()` was declared in `jsinspector-modern/HostTarget.h` but had no definition anywhere and no callers. (`HostTargetController` is `final`, so the method is not an override.) A declared-but-never-defined non-virtual member cannot be invoked — any call would be a link error — so this is unreachable dead code. The unrelated, live `HostTarget::installPerfIssuesBinding` (a different class) is left intact.
Changelog: [Internal]
Reviewed By: mdvacca
Differential Revision: D108012907
fbshipit-source-id: 5c7f14a7956f67e3e884a32f95aa2e50fd0f3ea6
Summary:
X-link: https://github.com/facebook/react-native/pull/57133
`JSIndexedRAMBundle` was a deprecated legacy-architecture class (annotated `[[deprecated("This API will be removed along with the legacy architecture.")]]` and guarded by `#ifndef RCT_REMOVE_LEGACY_ARCH`) for parsing indexed RAM bundles. It was only ever instantiated by `Instance::loadRAMBundleFromString` and `Instance::loadRAMBundleFromFile`, and those two `Instance` methods have no callers anywhere in fbsource: the old Android entry point `CatalystInstanceImpl` that used to call them has been deleted, and the new architecture (`ReactInstance` / bridgeless) routes `loadScriptFromFile` through `loadJSBundleFromFile` in the new runtime, never touching the legacy `Instance`. The only remaining user was its own unit test.
This removes `JSIndexedRAMBundle` and the two dead `Instance` RAM-bundle loaders that referenced it:
- Delete `JSIndexedRAMBundle.cpp`, `JSIndexedRAMBundle.h`, and `JSIndexedRAMBundleTest.cpp`.
- Remove `loadRAMBundleFromString` / `loadRAMBundleFromFile` from `Instance.cpp` / `Instance.h` and drop the now-unused include.
- Drop `JSIndexedRAMBundle.h` from `CXXREACT_PUBLIC_HEADERS` in `cxxreact/BUCK`.
- Update the committed C++ API snapshots accordingly.
The broader legacy RAM-bundle machinery (`RAMBundleRegistry`, `JSModulesUnbundle`, `Instance::loadRAMBundle`, `JSIExecutor::setBundleRegistry`) is left in place; it belongs to the same `RCT_REMOVE_LEGACY_ARCH` legacy bridge and can be removed as a follow-up.
Changelog: [Internal]
Reviewed By: javache, mdvacca
Differential Revision: D108001933
fbshipit-source-id: 4b0f12258e8caff1991847a4bb211e94fbecefa8
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/57116
## Changelog:
[General][Breaking] Compile out RuntimeScheduler_Legacy under RCT_REMOVE_LEGACY_ARCH
Guard the legacy RuntimeScheduler implementation behind the `RCT_REMOVE_LEGACY_ARCH` macro instead of deleting it. `RuntimeScheduler_Legacy.h`/`.cpp` remain in the tree, but their contents — along with the feature-flag-based selection between the legacy and modern schedulers in `RuntimeScheduler.cpp`, `NativeMutationObserver.cpp`, and `Task.h` — are wrapped in `#ifndef RCT_REMOVE_LEGACY_ARCH`. When the macro is defined, the legacy code is compiled out and `RuntimeScheduler` unconditionally instantiates `RuntimeScheduler_Modern`; when it is not defined, behavior is unchanged.
The C++ API snapshots are updated to drop the `RuntimeScheduler_Legacy` symbols from the new-arch surface, and the parameterized scheduler test (`RuntimeSchedulerTest`) only runs the modern configuration when the legacy arch is compiled out.
Reviewed By: rubennorte
Differential Revision: D107777881
fbshipit-source-id: 2b50711ab3af182edc45a87fd232d96a0f879837
Summary:
This makes the shell to use escape interpretation by setting `echo -e "..."`. For zsh shell, this often works out of the box. For other shells like bash, we may need to set it explicitly.
## 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
-->
[INTERNAL] [FIXED] - allow escape interpretation for shells
Pull Request resolved: https://github.com/facebook/react-native/pull/57114
Test Plan:
- CI Passes
- Verified Locally on template app
https://github.com/user-attachments/assets/4c8c6bf7-1cf2-4bd8-b094-651c44578ae0
Reviewed By: cipolleschi
Differential Revision: D107904889
Pulled By: cortinico
fbshipit-source-id: 2222f589ecc149a82d5067e0a2198b9c1a17ffcb
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/57103
Changelog: [General][Fixed] Fixed `display: contents` nodes having `hasNewLayout` set incorrectly
`cleanupContentsNodesRecursively` unconditionally sets `hasNewLayout=true` on `display: contents` children, including on code paths where their parent's layout was not actually performed in this pass. The stale flag can survive across layout passes and, in clone-on-write renderers (e.g. React Native Fabric), be observed by a subsequent pass whose parent was cloned but whose layout was served from cache, leaving the contents child's owner pointing at the previous parent revision.
There are two paths through which the cleanup could stamp a contents child whose parent's `hasNewLayout` would end up false:
1. Measure-phase visit. Inside `calculateLayoutImpl`, the cleanup ran with no knowledge of `performLayout`. When the parent's `calculateLayoutImpl` was invoked only with `performLayout=false` (cache miss on measure, cache hit on layout), the cleanup stamped contents children even though the parent itself never had its `hasNewLayout` set.
2. Absolute-layout walk. `layoutAbsoluteDescendants` walks every static layout descendant of the containing block - including ones whose own `calculateLayoutImpl` was skipped via the layout-phase cache. The cleanup invoked along that walk unconditionally stamped contents children, but the parent's `hasNewLayout` was only updated when the recursion actually found new layout downstream.
In both cases, the result is the same invariant violation: a contents node with `hasNewLayout=true` whose parent has `hasNewLayout=false`. A consumer iterating the tree via `hasNewLayout` skips the parent and never clears the stale flag.
X-link: https://github.com/facebook/yoga/pull/1970
Test Plan:
Added `YGContentsNodeHasNewLayoutTest.cpp` with regression tests:
- `contents_child_hasNewLayout_not_stamped_on_measure_only_visit` - pins the measure-phase fix
- `absolute_descendant_through_contents_is_reachable_via_hasNewLayout` - pins the positive case for absolute-layout path
- `absolute_phase_cleanup_does_not_stamp_when_parent_layout_skipped` - pins the negative case for absolute-layout path
Reviewed By: javache
Differential Revision: D107854528
Pulled By: j-piasecki
fbshipit-source-id: cae5e889622296e8b6380a6428509b5ffea3e9ae
Summary:
This fixes the failing CI jobs on main for `template` testing. The job fails as they echo `react.internal.mavenLocalRepo=...` to the `gradle.properties` of template test project. As a result of which the `gradle.properties` look like below:
```properties
android.builtInKotlin=false
android.newDsl=falsereact.internal.mavenLocalRepo=...
```
To fix it we add a line break in the `echo` command.
## 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
-->
[INTERNAL] [FIXED] - add line break to gradle.properties for template testing
Pull Request resolved: https://github.com/facebook/react-native/pull/57107
Test Plan:
- CI Passing
- Verified Locally
Reviewed By: cortinico
Differential Revision: D107880136
Pulled By: cipolleschi
fbshipit-source-id: 81cf2fe53c1c2285f79db538aa5aa3cb745f796d