Skip to content

[pull] main from expo:main - #1171

Merged
pull[bot] merged 12 commits into
code:mainfrom
expo:main
Aug 21, 2026
Merged

[pull] main from expo:main#1171
pull[bot] merged 12 commits into
code:mainfrom
expo:main

Conversation

@pull

@pull pull Bot commented Aug 21, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

jakex7 and others added 12 commits August 21, 2026 12:07
# Why

Expo modules already require iOS 16.4, but SPM configurations declare
iOS 16. It makes easy to miss the code that pass compile tests but fails
during precompilation.

Related discussion:
https://github.com/expo/expo/pull/44876/changes#r3101755826

# How

- Added support for `iOS("16.4")` to the SPM configuration type and
schema.
- Updated all configs to `16.4`. 
- Refactored product-platform mapping to use platform prefixes instead
of enumerating individual versions.
- Removed `iOS(.v15_1)` and `tvOS(.v15_1)` as it's invalid value and
wouldn't work anyway.

# Test Plan

`et prebuild-packages` and tests succeeds.
# Why

Adds TypeScript ESLint configuration file support (`eslint.config.ts`,
`.mts`, `.cts`), following native TypeScript configuration support in
ESLint v9.18.0 (January 2025), fixing "No ESLint config found" output
from `npx expo lint` with `eslint.config.ts`.

# How

Extended configuration file resolution to check for `.ts`, `.mts`, and
`.cts` extensions.

# Test Plan

```
npx create-expo-app@latest test --yes && cd test
npx expo lint # Creates eslint.config.js
mv eslint.config.{js,ts}
npx expo lint # Runs ESLint
```

# Checklist

- [ ] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)

---------

Co-authored-by: Phil Pluckthun <phil@kitten.sh>
…les [step 0] (#49150)

# Why

The task ENG-25370 describes how to move all iOS precompiled metadata
generation from the ruby/cocoapods pipeline and into
`expo-modules-autolinking`.

The plan is to setup CI tests that verifies that the generated data from
the ruby pipeline is consistent with the data we generate in the
auto-linking code in `expo-modules-autolinking`.

When this is verified (over time), we can move the whole ruby code over
to use the output from `expo-modules-autolinking` instead of reading its
own data - and then finally remove the data generation within the Ruby
code.

This PR is the first step in this process - adding support for
generating a metadata file with data from the ruby pipeline. This is for
now checked against a fixture and will fail loud if there are deviations
- making sure we catch any issues with ongoing changes before moving on
to step 1 in the linear task.

# How

- Added ruby methods for generating the metadata json file
- Committed fixture with metadata 
- Added e2e test to catch any changes that would cause the fixture to
need to be updated.

# Test Plan

- Guard test green: `pnpm exec jest
e2e/__tests__/precompiled-derivations-test.ts` passes (334 ms).
- Guard test red: adding a fake `externalDependencies` entry to
`packages/expo-image/spm.config.json` without regenerating fails the
test with the regen command and a structured diff naming the `ExpoImage`
pod.
- Determinism: two consecutive runner invocations produce byte-identical
output.
- `ruby -c` passes on both Ruby files. The `EXPO_PRECOMPILED_DUMP` hook
is a one-line call to the same method exercised by the runner; not
verified via a full `pod install`.

# Checklist

- [x] Documentation is up to date to reflect these changes.
- [x] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
- [x] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
# Why

`npx expo lint` installs ESLint when it is missing and then immediately
loads it within the same process. `await import()` cannot resolve a
module installed mid-process, causing "Cannot find module 'eslint'" on
the first run.

# How

Replace `await import('eslint')` with `require('eslint')`, which can
resolve a module installed mid-process.

Edit by `@kitten`: Replace resolution and loading with
`@expo/require-utils`

# Test Plan

1. Create a new Expo project.
2. Run `npx expo lint` for the first time, without adding ESLint or a
configuration file beforehand.
3. Verify that lint ran successfully on the first run of `npx expo
lint`.

# Checklist

- [ ] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)

---------

Co-authored-by: Phil Pluckthun <phil@kitten.sh>
# Summary

Related to #48670

Upgrades to `metro@0.84.5` via `@expo/metro@~56.0.2`

**Note:**
- `56.0.2` isn't yet marked `latest`, but should be once we're about to
publish or shortly after or before merging.
- `sdk-55` and `sdk-54` need separate releases for different metro
versions and PRs. We may only update 55 and backport it to 54
- `56.0.1` was "burned" and replaced with `56.0.2` to update
`metro-transform-worker` which missed the `0.84.5` bump before (lockfile
flagged this)

# Test Plan

- CI is expected to pass

# Checklist

<!--
Please check the appropriate items below if they apply to your diff.
-->

- [x] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
…le (#49196)

# Why

On web, `Crypto.AES` reads the wrong bytes whenever a caller passes a
`Uint8Array` that is a window onto a larger buffer.

Two places reach past a view to its backing buffer and drop `byteOffset`
/ `byteLength`:

```ts
// SealedData.fromCombined
const buffer = binaryInputBytes(combined).buffer as ArrayBuffer;

// binaryInputBytes
if (ArrayBuffer.isView(input)) {
  return new Uint8Array(input.buffer);
}
```

`BinaryInput` is `string | Uint8Array | ArrayBuffer`, and a `Uint8Array`
is very often a window onto something bigger — `subarray()` of a read
buffer, a slice of a pooled allocation, a record framed inside a larger
payload. Reading `.buffer` off one of those yields the whole allocation,
not the 48 bytes the caller meant.

The result is a `SealedData` describing the wrong region entirely. With
a 42-byte sealed blob sitting at offset 100 of a 512-byte buffer:

```
combinedSize=512 (expected 42)
decrypt FAILED -> DOMException: The operation failed for an operation-specific reason
```

`combinedSize` reports the backing length, so `iv()` reads offset 0 of
the backing buffer instead of the blob's IV, and `tag()` — which is
positioned as `combinedSize - tagSize` — lands at the end of the backing
buffer. Decryption fails with `OperationError`.

This is silent and input-dependent: the same sealed bytes work when they
happen to own their buffer and fail when they are a view, which makes it
look like data corruption rather than a library bug.

# How

Keep the view rather than its buffer.

`SealedData` now holds the `Uint8Array` and slices it with `subarray`,
so every offset is relative to the sealed data instead of to whatever
allocation happens to be underneath. `binaryInputBytes` passes
`byteOffset` and `byteLength` through when it wraps a view.

Storing the view rather than normalizing with a copy in `fromCombined`
keeps the existing zero-copy behaviour and fixes the getters as a class,
instead of patching the one call site that happened to reach `.buffer`.

Data built by `fromParts` and `encryptAsync` is unaffected — both
allocate exact-size arrays, where the view and its buffer coincide — so
the only behaviour that changes is the cases that were reading the wrong
bytes.

`subarray` clamps where `new Uint8Array(buffer, offset, length)` threw,
so on its own this change would have made truncated input fail later and
less clearly — `decryptAsync` would report a generic AES-GCM
`OperationError`, and `tag()` would hand back a short slice instead of
raising. `fromCombined` therefore now rejects data that cannot hold its
own IV and tag.

That check is not new behaviour for the API, it is the behaviour the
other platforms already have. Android throws
`InvalidSealedDataConfigException` from [`SealedData`'s
`init`](https://github.com/expo/expo/blob/main/packages/expo-crypto/android/src/main/java/expo/modules/crypto/aes/objects/SealedData.kt),
and iOS throws out of `AES.GCM.SealedBox(combined:)`. Web was the only
platform that accepted a too-short blob, and it failed later with a raw
`RangeError: Invalid typed array length: -18`. It now fails at the same
point as the other two, with the code Android uses:

```
CodedError [ERR_INVALID_SEALED_DATA_CONFIG]: Sealed data is 10 bytes, which is too short to
hold a 12-byte IV and a 16-byte authentication tag. Pass the whole combined output of
encryptAsync, or set ivLength and tagLength in the config to match how the data was sealed.
```

The `ArrayBuffer.isView` branch is only reachable for views outside the
declared `BinaryInput` union (`DataView`, `Int8Array`, …), since
`Uint8Array` returns earlier. It is fixed for the same reason: the
branch exists precisely to accept those, and it was mishandling every
one of them.

# Test Plan

Added `src/aes/__tests__/`, which had no coverage before. Every test
below fails on `main` and passes with this change.

`web-utils-test.web.ts` covers `binaryInputBytes` (6 tests),
`SealedData-test.web.ts` covers `fromCombined` (4 tests).

Before — 5 distinct assertions fail, reported as 10 because each
`.web.ts` file is picked up by both the Node and the Web jest project:

```
● binaryInputBytes › keeps the region of a DataView
    Expected: 3
    Received: 64
● binaryInputBytes › keeps the region of a non-Uint8Array typed view
    Expected: 3
    Received: 64
● SealedData.fromCombined › reads a Uint8Array that views part of a larger buffer
    Expected: 48
    Received: 200
● SealedData.fromCombined › rejects data too short to hold an IV and a tag
● SealedData.fromCombined › rejects data too short for a custom config

Test Suites: 4 failed, 4 total
Tests:       10 failed, 10 passed, 20 total
```

After, with the pre-existing 28 tests still green:

```
Test Suites: 10 passed, 10 total
Tests:       48 passed, 48 total
```

The unit tests stop at the `SealedData` boundary because `crypto.subtle`
is present in the Node jest project but not in the jsdom one, so a round
trip cannot run in both. To confirm the user-visible effect I ran one
directly against Node's WebCrypto, encrypting, framing the sealed bytes
at offset 100 of a 512-byte buffer, and decrypting through
`fromCombined(view)`:

```
──────── BEFORE the fix ────────
MODE=old  combinedSize=512 (expected 42)
  decrypt FAILED -> DOMException: The operation failed for an operation-specific reason
──────── AFTER the fix ────────
MODE=fixed  combinedSize=42 (expected 42)
  decrypt OK -> "attack at dawn"
```

`et check-packages expo-crypto`:

```
Tasks:    2 successful, 2 total
🏁 All checks passed.
```

`tsc -p tsconfig.json --noEmit` exits 0.

# Checklist

- [x] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [x] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
# Why

`NavigationIndependentTree` was never recommended solution in
expo-router -
https://docs.expo.dev/router/migrate/from-react-navigation/#independent

For a very rare cases when someone needs a mini-app or different
navigation within our system, they can just use
`@react-navigation/native` and construct the whole nested navigation
themselves.

# How

Remove `NavigationIndependentTree`

# Test Plan

CI

# Checklist

<!--
Please check the appropriate items below if they apply to your diff.
-->

- [ ] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)

---------

Co-authored-by: expo-tuft[bot] <288127324+expo-tuft[bot]@users.noreply.github.com>
Co-authored-by: Expo Bot <34669131+expo-bot@users.noreply.github.com>
# Why

<!--
Please describe the motivation for this PR, and link to relevant GitHub
issues, forums posts, or feature requests.
-->
Fix ENG-25941

# How

<!--
How did you build this feature or fix this bug and why?
-->

Fix four incomplete SDK examples.

# Test Plan

<!--
Please describe how you tested this change and how a reviewer could
reproduce your test, especially if this PR does not include automated
tests! If possible, please also provide terminal output and/or
screenshots demonstrating your test/reproduction.
-->

Proofread.

# Checklist

<!--
Please check the appropriate items below if they apply to your diff.
-->

- [ ] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [x] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
…49183)

# Why

<!--
Please describe the motivation for this PR, and link to relevant GitHub
issues, forums posts, or feature requests.
-->

Fix ENG-26079

# How

<!--
How did you build this feature or fix this bug and why?
-->

- Add example screenshots to Expo UI universal component pages
- Add available components screenshots in the Universal and Expo UI
overview pages in card form

# Test Plan

<!--
Please describe how you tested this change and how a reviewer could
reproduce your test, especially if this PR does not include automated
tests! If possible, please also provide terminal output and/or
screenshots demonstrating your test/reproduction.
-->

See preview:
https://pr-49183.expo-docs.pages.dev/versions/unversioned/sdk/ui/#universal
&
https://pr-49183.expo-docs.pages.dev/versions/unversioned/sdk/ui/universal/

<img width="2370" height="2060" alt="CleanShot 2026-08-21 at 00 47
17@2x"
src="https://github.com/user-attachments/assets/9cadbcf7-3a2f-46b8-91c2-72fad5a1f46e"
/>


<img width="2446" height="2046" alt="CleanShot 2026-08-21 at 00 47
13@2x"
src="https://github.com/user-attachments/assets/d1b46d7b-20c7-4581-b340-f50d2005aab6"
/>

# Checklist

<!--
Please check the appropriate items below if they apply to your diff.
-->

- [ ] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)

---------

Co-authored-by: Kadi Kraman <hellokadi@gmail.com>
# Why

Since Vaul is a heavy library and not-maintained anymore, we want to
remove it and the whole web modal stack from expo-router.

# How

1. Remove web modal stack
2. Export `NativeStackView`, so that people can create their own modal
stacks
3. Add guide for how to create custom modal stack -
docs/pages/router/advanced/web-modals.mdx

# Test Plan

CI

# Checklist

<!--
Please check the appropriate items below if they apply to your diff.
-->

- [ ] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)

---------

Co-authored-by: expo-tuft[bot] <288127324+expo-tuft[bot]@users.noreply.github.com>
Co-authored-by: Aman Mittal <amandeepmittal@live.com>
…-announce

Reverses yesterday's opt-in default: the "started - watch the run"
comment posts on every comment-path command unless --no-announce is
given. Dispatch runs remain quiet always.
@pull pull Bot locked and limited conversation to collaborators Aug 21, 2026
@pull pull Bot added the ⤵️ pull label Aug 21, 2026
@pull
pull Bot merged commit ea694b1 into code:main Aug 21, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants