diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml
new file mode 100644
index 0000000000..e71792358f
--- /dev/null
+++ b/.github/workflows/e2e-test.yml
@@ -0,0 +1,339 @@
+name: E2E Tests
+
+on:
+ pull_request:
+
+ workflow_dispatch:
+ inputs:
+ ios:
+ description: "Run iOS e2e tests"
+ type: boolean
+ default: false
+ android:
+ description: "Run Android e2e tests"
+ type: boolean
+ default: true
+ mock_server_branch:
+ description: "stream-chat-test-mock-server branch"
+ type: string
+ default: "main"
+
+permissions:
+ contents: read
+ pull-requests: read
+ checks: read
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+env:
+ MOCK_SERVER_BRANCH: ${{ inputs.mock_server_branch || 'main' }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_PR_NUM: ${{ github.event.pull_request.number }}
+ GITHUB_EVENT_ACTION: ${{ github.event.action }}
+ GITHUB_EVENT_BEFORE: ${{ github.event.before }}
+ GITHUB_EVENT_AFTER: ${{ github.event.after }}
+ # node_modules of the e2e app and the workspaces it depends on (nmHoistingLimits: workspaces
+ # keeps them apart); `yarn workspaces focus` installs nothing else.
+ NODE_MODULES_PATHS: |
+ node_modules
+ configs/*/node_modules
+ package/node_modules
+ package/native-package/node_modules
+ examples/E2ETestApp/node_modules
+ .yarn/install-state.gz
+
+jobs:
+ check:
+ name: Check E2E Required
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ outputs:
+ required: ${{ steps.check.outputs.required }}
+ steps:
+ - uses: actions/checkout@v6
+ - uses: ./.github/actions/ruby-cache
+ - name: Check if e2e tests are required
+ id: check
+ working-directory: examples/SampleApp
+ run: bundle exec fastlane e2e_check_required
+
+ ios:
+ needs: check
+ if: needs.check.outputs.required == 'true' && github.event_name == 'workflow_dispatch' && inputs.ios
+ runs-on: macos-15
+ timeout-minutes: 60
+ env:
+ DETOX_IOS_DEVICE: "iPhone 17 Pro"
+ IOS_VERSION: "26.2"
+ XCODE_VERSION: "26.2"
+ APP_PATH: examples/E2ETestApp/ios/build/detox/Build/Products/Release-iphonesimulator/E2ETestApp.app
+ MOCK_SERVER_BUNDLE_PATH: ${{ github.workspace }}/../mock-server-gems
+ steps:
+ - uses: actions/checkout@v6
+ - uses: actions/setup-node@v6
+ with:
+ node-version: 24.x
+ cache: "yarn"
+ cache-dependency-path: "yarn.lock"
+ - uses: maxim-lobanov/setup-xcode@v1
+ with:
+ xcode-version: ${{ env.XCODE_VERSION }}
+ # A fresh simulator takes minutes to boot on CI; boot it now so that overlaps with setup.
+ - name: Boot simulator
+ run: |
+ runtime="com.apple.CoreSimulator.SimRuntime.iOS-${IOS_VERSION//./-}"
+ udid=$(xcrun simctl list devices available -j |
+ jq -r --arg rt "$runtime" --arg name "$DETOX_IOS_DEVICE" '.devices[$rt][]? | select(.name == $name) | .udid' | head -1)
+ if [ -z "$udid" ]; then
+ echo "::warning::No $DETOX_IOS_DEVICE on iOS $IOS_VERSION; Detox will pick and boot a simulator itself"
+ exit 0
+ fi
+ echo "DETOX_IOS_UDID=$udid" >> "$GITHUB_ENV"
+ nohup xcrun simctl boot "$udid" > /dev/null 2>&1 &
+ - uses: ./.github/actions/ruby-cache
+
+ # --- JS dependencies ---
+ - name: Restore node_modules
+ id: node-modules
+ uses: actions/cache/restore@v5
+ with:
+ path: ${{ env.NODE_MODULES_PATHS }}
+ key: ${{ runner.os }}-e2e-node-modules-${{ hashFiles('yarn.lock') }}
+ # Only the e2e app's dependency tree, not every example app.
+ - name: Install dependencies
+ run: yarn workspaces focus e2etestapp
+ - name: Save node_modules
+ if: steps.node-modules.outputs.cache-hit != 'true'
+ uses: actions/cache/save@v5
+ with:
+ path: ${{ env.NODE_MODULES_PATHS }}
+ key: ${{ steps.node-modules.outputs.cache-primary-key }}
+
+ # --- App binary: rebuilt only when the app or SDK sources change, not for test-only changes ---
+ - name: Restore app
+ id: app
+ uses: actions/cache/restore@v5
+ with:
+ path: ${{ env.APP_PATH }}
+ key: e2e-ios-app-xcode${{ env.XCODE_VERSION }}-${{ hashFiles('yarn.lock', 'package/package.json', 'package/src/**', 'package/shared-native/**', 'package/native-package/package.json', 'package/native-package/src/**', 'package/native-package/ios/**', 'package/native-package/*.podspec', 'examples/SampleApp/Gemfile.lock', 'examples/E2ETestApp/*.js', '!examples/E2ETestApp/.detoxrc.js', 'examples/E2ETestApp/*.json', 'examples/E2ETestApp/*.tsx', 'examples/E2ETestApp/src/**', 'examples/E2ETestApp/ios/**', '!examples/E2ETestApp/ios/build/**', '!examples/E2ETestApp/ios/Pods/**') }}
+ - name: Set up ccache
+ if: steps.app.outputs.cache-hit != 'true'
+ uses: hendrikmuhs/ccache-action@v1.2
+ with:
+ key: e2e-ios-xcode${{ env.XCODE_VERSION }}
+ max-size: 1500M
+ - name: Point the RN ccache wrappers at ccache
+ if: steps.app.outputs.cache-hit != 'true'
+ # RN's ccache-clang.sh runs `$CCACHE_BINARY clang`, but Xcode doesn't export that build
+ # setting to the compiler, so without this every compile silently skips ccache.
+ run: echo "CCACHE_BINARY=$(which ccache)" >> "$GITHUB_ENV"
+ - name: Cache pods
+ if: steps.app.outputs.cache-hit != 'true'
+ uses: actions/cache@v5
+ with:
+ path: examples/E2ETestApp/ios/Pods
+ key: ${{ runner.os }}-e2e-pods-${{ hashFiles('examples/E2ETestApp/ios/Podfile.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-e2e-pods-
+ - name: Install pods
+ if: steps.app.outputs.cache-hit != 'true'
+ working-directory: examples/SampleApp
+ run: USE_CCACHE=1 bundle exec fastlane e2e_pod_install
+ - name: Build app
+ if: steps.app.outputs.cache-hit != 'true'
+ working-directory: examples/E2ETestApp
+ run: yarn e2e:build -c ios.sim.release
+ - name: Save app
+ if: steps.app.outputs.cache-hit != 'true'
+ uses: actions/cache/save@v5
+ with:
+ path: ${{ env.APP_PATH }}
+ key: ${{ steps.app.outputs.cache-primary-key }}
+
+ # --- Test tooling ---
+ - name: Install applesimutils
+ # Homebrew refuses formulae from non-official taps until they are trusted.
+ run: brew tap wix/brew && brew trust --formula wix/brew/applesimutils && brew install wix/brew/applesimutils
+ - name: Restore Detox framework
+ id: detox-framework
+ uses: actions/cache/restore@v5
+ with:
+ path: ~/Library/Detox
+ key: ${{ runner.os }}-detox-framework-xcode${{ env.XCODE_VERSION }}-${{ hashFiles('yarn.lock') }}
+ # Yarn's `enableScripts: false` skips Detox's postinstall, which would build this.
+ - name: Build Detox framework
+ if: steps.detox-framework.outputs.cache-hit != 'true'
+ working-directory: examples/E2ETestApp
+ run: yarn detox build-framework-cache
+ - name: Save Detox framework
+ if: steps.detox-framework.outputs.cache-hit != 'true'
+ uses: actions/cache/save@v5
+ with:
+ path: ~/Library/Detox
+ key: ${{ steps.detox-framework.outputs.cache-primary-key }}
+ - name: Resolve mock server revision
+ id: mock-server
+ run: echo "sha=$(git ls-remote https://github.com/GetStream/stream-chat-test-mock-server "refs/heads/$MOCK_SERVER_BRANCH" | cut -f1)" >> "$GITHUB_OUTPUT"
+ - name: Cache mock server gems
+ uses: actions/cache@v5
+ with:
+ path: ${{ env.MOCK_SERVER_BUNDLE_PATH }}
+ key: ${{ runner.os }}-mock-server-gems-${{ steps.mock-server.outputs.sha }}
+ restore-keys: |
+ ${{ runner.os }}-mock-server-gems-
+
+ - name: Wait for the simulator
+ if: env.DETOX_IOS_UDID != ''
+ timeout-minutes: 15
+ # `-b` boots it if the background boot never started; it errors (405) when the device is
+ # already booted, and then the plain call returns at once.
+ run: xcrun simctl bootstatus "$DETOX_IOS_UDID" -b || xcrun simctl bootstatus "$DETOX_IOS_UDID"
+ - name: Run e2e tests
+ working-directory: examples/SampleApp
+ run: bundle exec fastlane test_e2e platform:ios skip_build:true mock_server_branch:"$MOCK_SERVER_BRANCH"
+ - uses: actions/upload-artifact@v6
+ if: failure()
+ with:
+ name: e2e-ios-logs
+ path: |
+ examples/E2ETestApp/stream-chat-test-mock-server/logs
+ examples/E2ETestApp/artifacts
+
+ android:
+ needs: check
+ if: needs.check.outputs.required == 'true' && (github.event_name != 'workflow_dispatch' || inputs.android)
+ runs-on: ubuntu-latest
+ timeout-minutes: 60
+ env:
+ # Same as the native Android SDK e2e jobs, which run stably on these runners
+ ANDROID_API_LEVEL: "36"
+ ANDROID_EMULATOR_OPTIONS: -no-snapshot-save -no-window -no-audio -no-boot-anim -gpu swiftshader_indirect -camera-back none -camera-front none
+ DETOX_ADB_NAME: "emulator-5554"
+ APK_PATHS: |
+ examples/E2ETestApp/android/app/build/outputs/apk/release/app-release.apk
+ examples/E2ETestApp/android/app/build/outputs/apk/androidTest/release/app-release-androidTest.apk
+ MOCK_SERVER_BUNDLE_PATH: ${{ github.workspace }}/../mock-server-gems
+ # The emulator is x86_64: skip compiling native code for the other ABIs.
+ ORG_GRADLE_PROJECT_reactNativeArchitectures: x86_64
+ steps:
+ - uses: actions/checkout@v6
+ - uses: actions/setup-node@v6
+ with:
+ node-version: 24.x
+ cache: "yarn"
+ cache-dependency-path: "yarn.lock"
+ - uses: actions/setup-java@v5
+ with:
+ distribution: "zulu"
+ java-version: "21"
+ # Caches Gradle's dependencies, wrapper and build cache. It only writes on the default branch by
+ # default, and this workflow doesn't run there, so let PR runs write: their reruns reuse it.
+ - uses: gradle/actions/setup-gradle@v4
+ with:
+ cache-read-only: false
+ - uses: ./.github/actions/ruby-cache
+
+ # --- JS dependencies ---
+ - name: Restore node_modules
+ id: node-modules
+ uses: actions/cache/restore@v5
+ with:
+ path: ${{ env.NODE_MODULES_PATHS }}
+ key: ${{ runner.os }}-e2e-node-modules-${{ hashFiles('yarn.lock') }}
+ # Only the e2e app's dependency tree, not every example app.
+ - name: Install dependencies
+ run: yarn workspaces focus e2etestapp
+ - name: Save node_modules
+ if: steps.node-modules.outputs.cache-hit != 'true'
+ uses: actions/cache/save@v5
+ with:
+ path: ${{ env.NODE_MODULES_PATHS }}
+ key: ${{ steps.node-modules.outputs.cache-primary-key }}
+
+ # --- App binaries: rebuilt only when the app or SDK sources change, not for test-only changes ---
+ - name: Restore APKs
+ id: apk
+ uses: actions/cache/restore@v5
+ with:
+ path: ${{ env.APK_PATHS }}
+ key: e2e-android-apk-${{ hashFiles('yarn.lock', 'package/package.json', 'package/src/**', 'package/shared-native/**', 'package/native-package/package.json', 'package/native-package/src/**', 'package/native-package/android/**', '!package/native-package/android/build/**', 'examples/E2ETestApp/*.js', '!examples/E2ETestApp/.detoxrc.js', 'examples/E2ETestApp/*.json', 'examples/E2ETestApp/*.tsx', 'examples/E2ETestApp/src/**', 'examples/E2ETestApp/android/**', '!examples/E2ETestApp/android/**/build/**', '!examples/E2ETestApp/android/.gradle/**') }}
+ # Built before the emulator boots so the emulator doesn't idle through the Gradle build.
+ - name: Build app
+ if: steps.apk.outputs.cache-hit != 'true'
+ working-directory: examples/E2ETestApp
+ run: yarn e2e:build -c android.att.release
+ - name: Save APKs
+ if: steps.apk.outputs.cache-hit != 'true'
+ uses: actions/cache/save@v5
+ with:
+ path: ${{ env.APK_PATHS }}
+ key: ${{ steps.apk.outputs.cache-primary-key }}
+ # Frees the daemons' memory for the emulator, which otherwise can get killed mid-run.
+ - name: Stop Gradle daemons
+ if: steps.apk.outputs.cache-hit != 'true'
+ working-directory: examples/E2ETestApp/android
+ run: ./gradlew --stop
+
+ # --- Emulator: same setup as the native Android SDK's e2e jobs (AOSP image, no Play services) ---
+ - name: Enable KVM
+ run: |
+ echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
+ sudo udevadm control --reload-rules
+ sudo udevadm trigger --name-match=kvm
+
+ # --- Test tooling ---
+ - name: Resolve mock server revision
+ id: mock-server
+ run: echo "sha=$(git ls-remote https://github.com/GetStream/stream-chat-test-mock-server "refs/heads/$MOCK_SERVER_BRANCH" | cut -f1)" >> "$GITHUB_OUTPUT"
+ - name: Cache mock server gems
+ uses: actions/cache@v5
+ with:
+ path: ${{ env.MOCK_SERVER_BUNDLE_PATH }}
+ key: ${{ runner.os }}-mock-server-gems-${{ steps.mock-server.outputs.sha }}
+ restore-keys: |
+ ${{ runner.os }}-mock-server-gems-
+
+ - name: Run e2e tests (Android emulator)
+ uses: reactivecircus/android-emulator-runner@v2
+ with:
+ api-level: ${{ env.ANDROID_API_LEVEL }}
+ arch: x86_64
+ profile: pixel
+ emulator-options: ${{ env.ANDROID_EMULATOR_OPTIONS }}
+ disable-animations: true
+ working-directory: examples/SampleApp
+ script: bundle exec fastlane test_e2e platform:android device:att skip_build:true mock_server_branch:"$MOCK_SERVER_BRANCH"
+ # The emulator has vanished mid-run without any output; this shows whether the kernel killed it.
+ - name: Diagnose emulator
+ if: failure()
+ run: |
+ sudo dmesg -T | grep -i -E 'out of memory|oom-kill|killed process' || echo "No OOM kills in dmesg"
+ free -m
+ df -h
+ ls -la /tmp/android-runner 2>/dev/null || true
+ - uses: actions/upload-artifact@v6
+ if: failure()
+ with:
+ name: e2e-android-logs
+ path: |
+ examples/E2ETestApp/stream-chat-test-mock-server/logs
+ examples/E2ETestApp/artifacts
+ /tmp/android-runner
+
+ result:
+ name: Test E2E Result
+ runs-on: ubuntu-latest
+ if: always()
+ needs:
+ - check
+ - android
+ steps:
+ - name: Check E2E results
+ if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
+ run: |
+ echo "$NEEDS"
+ exit 1
+ env:
+ NEEDS: ${{ toJson(needs) }}
diff --git a/.prettierignore b/.prettierignore
index c4f36f8ee4..55d7ebb190 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -24,6 +24,10 @@ examples/SampleApp/patches/
.yarn/
yarn.lock
+# Detox e2e: mock server checkout cloned by `fastlane start_mock_server`, test artifacts
+examples/E2ETestApp/stream-chat-test-mock-server/
+examples/E2ETestApp/artifacts/
+
# Generated SDK assets
package/src/components/docs/
package/src/theme/generated/
diff --git a/AGENTS.md b/AGENTS.md
index be4dd9dce5..fa8cbbd6b9 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -20,7 +20,7 @@ Targets iOS and Android.
- **Languages:** TypeScript + React Native
- **Runtime:** Node 24 (`.nvmrc` is `v24`; root `engines.node` is `>=20.19.4`; CI runs `24.x`)
- **Package manager:** Yarn 4.15.0 (Berry). The binary lives at `.yarn/releases/yarn-4.15.0.cjs` and is activated via `yarnPath` in `.yarnrc.yml`. Any globally installed `yarn` (even the Homebrew classic 1.x) acts only as a launcher — no Corepack required.
-- **Workspaces:** single root `yarn.lock`; workspaces are `configs/typescript-config`, `package`, `package/native-package`, `package/expo-package`, `examples/SampleApp`, `examples/ExpoMessaging`. **No Lerna.**
+- **Workspaces:** single root `yarn.lock`; workspaces are `configs/typescript-config`, `package`, `package/native-package`, `package/expo-package`, `examples/SampleApp`, `examples/E2ETestApp`, `examples/ExpoMessaging`. **No Lerna.**
- **Testing:** Jest with the `@react-native/jest-preset` + `@testing-library/react-native`.
- **Build:** `react-native-builder-bob` → CommonJS (`lib/commonjs`), ESM (`lib/module`), types (`lib/typescript`)
- **Lint/format:** ESLint 9 flat config + Prettier, strict (`--max-warnings 0`)
@@ -41,7 +41,7 @@ Respect repo-specific rules. Do not suppress lint rules broadly; justify and sco
- `native-package/` — bare RN wrapper (`stream-chat-react-native`)
- `expo-package/` — Expo wrapper (`stream-chat-expo`)
- `shared-native/{ios,android}` — native source shared by both wrappers; synced into them, never edited in place
-- `examples/` — `SampleApp` (full-featured), `ExpoMessaging`
+- `examples/` — `SampleApp` (full-featured), `E2ETestApp` (minimal app for the Detox e2e suite), `ExpoMessaging`
- `configs/typescript-config/` — shared `tsconfig` presets
- `ai-docs/` — agent-facing deep dives (see [References](#references))
- `perf/` — on-device performance toolkit (see [Accessibility, RTL & performance](#accessibility-rtl--performance))
@@ -244,6 +244,8 @@ Native pieces live in `package/shared-native/`: the Android-only `PerfText` Fabr
To run one test file, prefer `cd package && TZ=UTC npx jest path/to/file.test.tsx`. The `testRegex` array in `jest.config.js` also accepts a temporary path — revert it before committing.
+**E2E:** Detox suite in `examples/E2ETestApp/e2e/` against the shared `stream-chat-test-mock-server`, with robots and page objects mirroring the native iOS/Android suites. Run it with `bundle exec fastlane test_e2e platform:ios|android` from `examples/SampleApp`; see `examples/E2ETestApp/e2e/README.md`. Elements it needs get a `testID` in the SDK (kebab-case, additive).
+
**Mock builders** (`package/src/mock-builders/`):
- `api/initiateClientWithChannels` — creates a test client + channels in one call (fastest path)
@@ -369,7 +371,7 @@ Follow `PULL_REQUEST_TEMPLATE.md`. Keep PRs small and focused.
### CI expectations
-`.github/workflows/check-pr.yml` (Node 24): `yarn install --immutable` → `yarn build` → `yarn lint` → `yarn typecheck` → `yarn test:coverage`. Other workflows: `changelog-preview`, `lint-pr-title`, `release`, `sample-distribution`, `sdk-size-metrics`.
+`.github/workflows/check-pr.yml` (Node 24): `yarn install --immutable` → `yarn build` → `yarn lint` → `yarn typecheck` → `yarn test:coverage`. Other workflows: `changelog-preview`, `e2e-test` (Detox on `examples/E2ETestApp`, gated by `is_check_required`; require its `Test E2E Result` check), `lint-pr-title`, `release`, `sample-distribution`, `sdk-size-metrics`.
Failing or flaky tests: fix them, or quarantine with a justification comment and a follow-up.
diff --git a/eslint.config.mjs b/eslint.config.mjs
index 97425a89b6..468d782eab 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -44,6 +44,10 @@ export default tsEslint.config(
'**/android/',
'**/fastlane/',
+ // Detox e2e: mock server checkout cloned by `fastlane start_mock_server`, test artifacts
+ 'examples/E2ETestApp/stream-chat-test-mock-server/',
+ 'examples/E2ETestApp/artifacts/',
+
// Generated SDK assets
'package/src/components/docs/',
'package/src/theme/generated/',
diff --git a/examples/E2ETestApp/.detoxrc.js b/examples/E2ETestApp/.detoxrc.js
new file mode 100644
index 0000000000..2e090e80c7
--- /dev/null
+++ b/examples/E2ETestApp/.detoxrc.js
@@ -0,0 +1,67 @@
+/** @type {Detox.DetoxConfig} */
+module.exports = {
+ testRunner: {
+ args: {
+ $0: 'jest',
+ config: 'e2e/jest.config.js',
+ },
+ jest: {
+ setupTimeout: 300000,
+ },
+ },
+ apps: {
+ 'ios.debug': {
+ type: 'ios.app',
+ binaryPath: 'ios/build/detox/Build/Products/Debug-iphonesimulator/E2ETestApp.app',
+ build:
+ 'xcodebuild -workspace ios/E2ETestApp.xcworkspace -scheme E2ETestApp -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build/detox',
+ },
+ 'ios.release': {
+ type: 'ios.app',
+ binaryPath: 'ios/build/detox/Build/Products/Release-iphonesimulator/E2ETestApp.app',
+ build:
+ 'xcodebuild -workspace ios/E2ETestApp.xcworkspace -scheme E2ETestApp -configuration Release -sdk iphonesimulator -derivedDataPath ios/build/detox',
+ },
+ 'android.debug': {
+ type: 'android.apk',
+ binaryPath: 'android/app/build/outputs/apk/debug/app-debug.apk',
+ testBinaryPath: 'android/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk',
+ build:
+ 'cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug && cd ..',
+ reversePorts: [8081],
+ },
+ 'android.release': {
+ type: 'android.apk',
+ binaryPath: 'android/app/build/outputs/apk/release/app-release.apk',
+ testBinaryPath:
+ 'android/app/build/outputs/apk/androidTest/release/app-release-androidTest.apk',
+ build:
+ 'cd android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release && cd ..',
+ },
+ },
+ devices: {
+ simulator: {
+ type: 'ios.simulator',
+ // CI pins the simulator it boots early (DETOX_IOS_UDID), so Detox reuses it.
+ device: process.env.DETOX_IOS_UDID
+ ? { id: process.env.DETOX_IOS_UDID }
+ : { type: process.env.DETOX_IOS_DEVICE || 'iPhone 16 Pro' },
+ },
+ emulator: {
+ type: 'android.emulator',
+ device: { avdName: process.env.DETOX_AVD_NAME || 'Pixel_API_37' },
+ },
+ attached: {
+ type: 'android.attached',
+ device: { adbName: process.env.DETOX_ADB_NAME || '.*' },
+ },
+ },
+ configurations: {
+ 'ios.sim.debug': { app: 'ios.debug', device: 'simulator' },
+ 'ios.sim.release': { app: 'ios.release', device: 'simulator' },
+ 'android.emu.debug': { app: 'android.debug', device: 'emulator' },
+ 'android.emu.release': { app: 'android.release', device: 'emulator' },
+ 'android.att.debug': { app: 'android.debug', device: 'attached' },
+ 'android.att.release': { app: 'android.release', device: 'attached' },
+ },
+};
diff --git a/examples/E2ETestApp/.gitignore b/examples/E2ETestApp/.gitignore
new file mode 100644
index 0000000000..9be6361de6
--- /dev/null
+++ b/examples/E2ETestApp/.gitignore
@@ -0,0 +1,79 @@
+# OSX
+#
+.DS_Store
+
+# Xcode
+#
+build/
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+xcuserdata
+*.xccheckout
+*.moved-aside
+DerivedData
+*.hmap
+*.ipa
+*.xcuserstate
+**/.xcode.env.local
+
+# Android/IntelliJ
+#
+build/
+.idea
+.gradle
+local.properties
+*.iml
+*.hprof
+.cxx/
+*.keystore
+!debug.keystore
+.kotlin/
+
+# node.js
+#
+node_modules/
+npm-debug.log
+yarn-error.log
+
+# fastlane
+#
+# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
+# screenshots whenever they are needed.
+# For more information about the recommended setup visit:
+# https://docs.fastlane.tools/best-practices/source-control/
+
+**/fastlane/report.xml
+**/fastlane/Preview.html
+**/fastlane/screenshots
+**/fastlane/test_output
+
+# Bundle artifact
+*.jsbundle
+
+# Ruby / CocoaPods
+**/Pods/
+/vendor/bundle/
+
+# Temporary files created by Metro to check the health of the file watcher
+.metro-health-check*
+
+# testing
+/coverage
+
+# Yarn
+.yarn/*
+!.yarn/patches
+!.yarn/plugins
+!.yarn/releases
+!.yarn/sdks
+!.yarn/versions
+
+# Detox e2e: mock server checkout cloned by `fastlane start_mock_server`, test artifacts
+/stream-chat-test-mock-server/
+/artifacts/
diff --git a/examples/E2ETestApp/.watchmanconfig b/examples/E2ETestApp/.watchmanconfig
new file mode 100644
index 0000000000..0967ef424b
--- /dev/null
+++ b/examples/E2ETestApp/.watchmanconfig
@@ -0,0 +1 @@
+{}
diff --git a/examples/E2ETestApp/App.tsx b/examples/E2ETestApp/App.tsx
new file mode 100644
index 0000000000..653961dc5f
--- /dev/null
+++ b/examples/E2ETestApp/App.tsx
@@ -0,0 +1,133 @@
+import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import { BackHandler, Pressable, StyleSheet, Text, View } from 'react-native';
+import { GestureHandlerRootView } from 'react-native-gesture-handler';
+import { SafeAreaProvider, SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
+
+import { Channel as ChannelType, ChannelFilters, ChannelSort, StreamChat } from 'stream-chat';
+import {
+ Channel,
+ ChannelList,
+ Chat,
+ MessageComposer,
+ MessageList,
+ OverlayProvider,
+} from 'stream-chat-react-native';
+
+import { apiKey, appUser, appUserToken, mockServerUrl } from './src/config';
+
+// Same opt-in as the SampleApp, so the e2e suite sees the same accessibility tree.
+const accessibility = { enabled: true };
+const sort: ChannelSort = { last_message_at: -1 };
+
+/** Lists the mock server's app user, like the SampleApp's user selector. */
+const LoginScreen = ({ onLogin }: { onLogin: () => void }) => (
+
+ E2E Test App
+ {mockServerUrl ? (
+
+ {appUser.name}
+
+ ) : (
+ Launch with the MOCK_SERVER_URL argument (see e2e/README.md).
+ )}
+
+);
+
+const ChannelScreen = ({ channel, onBack }: { channel: ChannelType; onBack: () => void }) => {
+ const { top } = useSafeAreaInsets();
+
+ useEffect(() => {
+ const subscription = BackHandler.addEventListener('hardwareBackPress', () => {
+ onBack();
+ return true;
+ });
+ return () => subscription.remove();
+ }, [onBack]);
+
+ // Laid out like the SampleApp's channel screen: the header lives inside , which sizes
+ // itself to the screen and handles the bottom inset and keyboard for the composer.
+ return (
+
+
+
+
+ ‹ Back
+
+
+ {channel.id}
+
+
+
+
+
+
+ );
+};
+
+const ChatScreens = ({ client }: { client: StreamChat }) => {
+ const [channel, setChannel] = useState();
+ const filters = useMemo(
+ () => ({ members: { $in: [client.userID ?? appUser.id] } }),
+ [client.userID],
+ );
+ const closeChannel = useCallback(() => setChannel(undefined), []);
+
+ return (
+
+ {/* The list stays mounted under the channel, as in a navigation stack. */}
+
+
+
+ {channel ? : null}
+
+ );
+};
+
+const App = () => {
+ const [client, setClient] = useState();
+
+ const login = useCallback(async () => {
+ const chatClient = StreamChat.getInstance(apiKey, { baseURL: mockServerUrl, timeout: 6000 });
+ await chatClient.connectUser(appUser, appUserToken);
+ setClient(chatClient);
+ }, []);
+
+ return (
+
+
+
+ {client ? : }
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ back: { fontSize: 17, paddingRight: 12 },
+ container: { backgroundColor: '#FFFFFF', flex: 1 },
+ flex: { flex: 1 },
+ header: {
+ alignItems: 'center',
+ flexDirection: 'row',
+ paddingHorizontal: 16,
+ paddingVertical: 12,
+ },
+ headerTitle: { flex: 1, fontSize: 17, fontWeight: '600' },
+ hint: { padding: 16 },
+ title: { fontSize: 22, fontWeight: '700', padding: 16 },
+ userName: { fontSize: 17 },
+ userRow: { borderBottomColor: '#E5E5E5', borderBottomWidth: 1, padding: 16 },
+});
+
+export default App;
diff --git a/examples/E2ETestApp/android/app/build.gradle b/examples/E2ETestApp/android/app/build.gradle
new file mode 100644
index 0000000000..879f64489c
--- /dev/null
+++ b/examples/E2ETestApp/android/app/build.gradle
@@ -0,0 +1,124 @@
+apply plugin: "com.android.application"
+apply plugin: "org.jetbrains.kotlin.android"
+apply plugin: "com.facebook.react"
+
+/**
+ * This is the configuration block to customize your React Native Android app.
+ * By default you don't need to apply any configuration, just uncomment the lines you need.
+ */
+react {
+ /* Folders */
+ // The root of your project, i.e. where "package.json" lives. Default is '../..'
+ // root = file("../../")
+ // The folder where the react-native NPM package is. Default is ../../node_modules/react-native
+ // reactNativeDir = file("../../node_modules/react-native")
+ // The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
+ // codegenDir = file("../../node_modules/@react-native/codegen")
+ // The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js
+ // cliFile = file("../../node_modules/react-native/cli.js")
+
+ /* Variants */
+ // The list of variants to that are debuggable. For those we're going to
+ // skip the bundling of the JS bundle and the assets. Default is "debug", "debugOptimized".
+ // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
+ // debuggableVariants = ["liteDebug", "liteDebugOptimized", "prodDebug", "prodDebugOptimized"]
+
+ /* Bundling */
+ // A list containing the node command and its flags. Default is just 'node'.
+ // nodeExecutableAndArgs = ["node"]
+ //
+ // The command to run when bundling. By default is 'bundle'
+ // bundleCommand = "ram-bundle"
+ //
+ // The path to the CLI configuration file. Default is empty.
+ // bundleConfig = file(../rn-cli.config.js)
+ //
+ // The name of the generated asset file containing your JS bundle
+ // bundleAssetName = "MyApplication.android.bundle"
+ //
+ // The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
+ // entryFile = file("../js/MyApplication.android.js")
+ //
+ // A list of extra flags to pass to the 'bundle' commands.
+ // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
+ // extraPackagerArgs = []
+
+ /* Hermes Commands */
+ // The hermes compiler command to run. By default it is 'hermesc'
+ // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
+ //
+ // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
+ // hermesFlags = ["-O", "-output-source-map"]
+
+ /* Autolinking */
+ autolinkLibrariesWithApp()
+}
+
+/**
+ * Set this to true to Run Proguard on Release builds to minify the Java bytecode.
+ */
+def enableProguardInReleaseBuilds = false
+
+/**
+ * The preferred build flavor of JavaScriptCore (JSC)
+ *
+ * For example, to use the international variant, you can use:
+ * `def jscFlavor = io.github.react-native-community:jsc-android-intl:2026004.+`
+ *
+ * The international variant includes ICU i18n library and necessary data
+ * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
+ * give correct results when using with locales other than en-US. Note that
+ * this variant is about 6MiB larger per architecture than default.
+ */
+def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+'
+
+android {
+ ndkVersion rootProject.ext.ndkVersion
+ buildToolsVersion rootProject.ext.buildToolsVersion
+ compileSdk rootProject.ext.compileSdkVersion
+
+ namespace "io.getstream.reactnative.e2etestapp"
+ defaultConfig {
+ applicationId "io.getstream.reactnative.e2etestapp"
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
+ versionCode 1
+ versionName "1.0"
+ // Detox: builds the instrumentation APK against the variant under test
+ testBuildType System.getProperty('testBuildType', 'debug')
+ testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
+ }
+ signingConfigs {
+ debug {
+ storeFile file('debug.keystore')
+ storePassword 'android'
+ keyAlias 'androiddebugkey'
+ keyPassword 'android'
+ }
+ }
+ buildTypes {
+ debug {
+ signingConfig signingConfigs.debug
+ }
+ release {
+ // Caution! In production, you need to generate your own keystore file.
+ // see https://reactnative.dev/docs/signed-apk-android.
+ signingConfig signingConfigs.debug
+ minifyEnabled enableProguardInReleaseBuilds
+ proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
+ }
+ }
+}
+
+dependencies {
+ // The version of react-native is set by the React Native Gradle Plugin
+ implementation("com.facebook.react:react-android")
+
+ if (hermesEnabled.toBoolean()) {
+ implementation("com.facebook.react:hermes-android")
+ } else {
+ implementation jscFlavor
+ }
+
+ androidTestImplementation('com.wix:detox:+')
+}
diff --git a/examples/E2ETestApp/android/app/debug.keystore b/examples/E2ETestApp/android/app/debug.keystore
new file mode 100644
index 0000000000..364e105ed3
Binary files /dev/null and b/examples/E2ETestApp/android/app/debug.keystore differ
diff --git a/examples/E2ETestApp/android/app/proguard-rules.pro b/examples/E2ETestApp/android/app/proguard-rules.pro
new file mode 100644
index 0000000000..11b025724a
--- /dev/null
+++ b/examples/E2ETestApp/android/app/proguard-rules.pro
@@ -0,0 +1,10 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
diff --git a/examples/E2ETestApp/android/app/src/androidTest/java/io/getstream/reactnative/e2etestapp/DetoxTest.kt b/examples/E2ETestApp/android/app/src/androidTest/java/io/getstream/reactnative/e2etestapp/DetoxTest.kt
new file mode 100644
index 0000000000..18e8533735
--- /dev/null
+++ b/examples/E2ETestApp/android/app/src/androidTest/java/io/getstream/reactnative/e2etestapp/DetoxTest.kt
@@ -0,0 +1,27 @@
+package io.getstream.reactnative.e2etestapp
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.rule.ActivityTestRule
+import com.wix.detox.Detox
+import com.wix.detox.config.DetoxConfig
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@LargeTest
+class DetoxTest {
+ @get:Rule
+ val activityRule = ActivityTestRule(MainActivity::class.java, false, false)
+
+ @Test
+ fun runDetoxTests() {
+ val detoxConfig = DetoxConfig().apply {
+ idlePolicyConfig.masterTimeoutSec = 90
+ idlePolicyConfig.idleResourceTimeoutSec = 60
+ rnContextLoadTimeoutSec = if (BuildConfig.DEBUG) 180 else 60
+ }
+ Detox.runTests(activityRule, detoxConfig)
+ }
+}
diff --git a/examples/E2ETestApp/android/app/src/main/AndroidManifest.xml b/examples/E2ETestApp/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..d5ac9c6e7c
--- /dev/null
+++ b/examples/E2ETestApp/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/E2ETestApp/android/app/src/main/java/io/getstream/reactnative/e2etestapp/MainActivity.kt b/examples/E2ETestApp/android/app/src/main/java/io/getstream/reactnative/e2etestapp/MainActivity.kt
new file mode 100644
index 0000000000..b59b475ece
--- /dev/null
+++ b/examples/E2ETestApp/android/app/src/main/java/io/getstream/reactnative/e2etestapp/MainActivity.kt
@@ -0,0 +1,22 @@
+package io.getstream.reactnative.e2etestapp
+
+import com.facebook.react.ReactActivity
+import com.facebook.react.ReactActivityDelegate
+import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
+import com.facebook.react.defaults.DefaultReactActivityDelegate
+
+class MainActivity : ReactActivity() {
+
+ /**
+ * Returns the name of the main component registered from JavaScript. This is used to schedule
+ * rendering of the component.
+ */
+ override fun getMainComponentName(): String = "E2ETestApp"
+
+ /**
+ * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
+ * which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
+ */
+ override fun createReactActivityDelegate(): ReactActivityDelegate =
+ DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
+}
diff --git a/examples/E2ETestApp/android/app/src/main/java/io/getstream/reactnative/e2etestapp/MainApplication.kt b/examples/E2ETestApp/android/app/src/main/java/io/getstream/reactnative/e2etestapp/MainApplication.kt
new file mode 100644
index 0000000000..dd573a42aa
--- /dev/null
+++ b/examples/E2ETestApp/android/app/src/main/java/io/getstream/reactnative/e2etestapp/MainApplication.kt
@@ -0,0 +1,27 @@
+package io.getstream.reactnative.e2etestapp
+
+import android.app.Application
+import com.facebook.react.PackageList
+import com.facebook.react.ReactApplication
+import com.facebook.react.ReactHost
+import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
+import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
+
+class MainApplication : Application(), ReactApplication {
+
+ override val reactHost: ReactHost by lazy {
+ getDefaultReactHost(
+ context = applicationContext,
+ packageList =
+ PackageList(this).packages.apply {
+ // Packages that cannot be autolinked yet can be added manually here, for example:
+ // add(MyReactNativePackage())
+ },
+ )
+ }
+
+ override fun onCreate() {
+ super.onCreate()
+ loadReactNative(this)
+ }
+}
diff --git a/examples/E2ETestApp/android/app/src/main/res/drawable/rn_edit_text_material.xml b/examples/E2ETestApp/android/app/src/main/res/drawable/rn_edit_text_material.xml
new file mode 100644
index 0000000000..5c25e728ea
--- /dev/null
+++ b/examples/E2ETestApp/android/app/src/main/res/drawable/rn_edit_text_material.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/E2ETestApp/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/examples/E2ETestApp/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000000..a2f5908281
Binary files /dev/null and b/examples/E2ETestApp/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/examples/E2ETestApp/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/examples/E2ETestApp/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..1b52399808
Binary files /dev/null and b/examples/E2ETestApp/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/examples/E2ETestApp/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/examples/E2ETestApp/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000000..ff10afd6e1
Binary files /dev/null and b/examples/E2ETestApp/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/examples/E2ETestApp/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/examples/E2ETestApp/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..115a4c768a
Binary files /dev/null and b/examples/E2ETestApp/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/examples/E2ETestApp/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/examples/E2ETestApp/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000000..dcd3cd8083
Binary files /dev/null and b/examples/E2ETestApp/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/examples/E2ETestApp/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/examples/E2ETestApp/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..459ca609d3
Binary files /dev/null and b/examples/E2ETestApp/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/examples/E2ETestApp/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/examples/E2ETestApp/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000000..8ca12fe024
Binary files /dev/null and b/examples/E2ETestApp/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/examples/E2ETestApp/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/examples/E2ETestApp/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..8e19b410a1
Binary files /dev/null and b/examples/E2ETestApp/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/examples/E2ETestApp/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/examples/E2ETestApp/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000000..b824ebdd48
Binary files /dev/null and b/examples/E2ETestApp/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/examples/E2ETestApp/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/examples/E2ETestApp/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..4c19a13c23
Binary files /dev/null and b/examples/E2ETestApp/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/examples/E2ETestApp/android/app/src/main/res/values/strings.xml b/examples/E2ETestApp/android/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..a0ea08d876
--- /dev/null
+++ b/examples/E2ETestApp/android/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ E2ETestApp
+
diff --git a/examples/E2ETestApp/android/app/src/main/res/values/styles.xml b/examples/E2ETestApp/android/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000000..7ba83a2ad5
--- /dev/null
+++ b/examples/E2ETestApp/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/examples/E2ETestApp/android/app/src/main/res/xml/network_security_config.xml b/examples/E2ETestApp/android/app/src/main/res/xml/network_security_config.xml
new file mode 100644
index 0000000000..a667072fee
--- /dev/null
+++ b/examples/E2ETestApp/android/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,8 @@
+
+
+
+
+ 10.0.2.2
+ localhost
+
+
diff --git a/examples/E2ETestApp/android/build.gradle b/examples/E2ETestApp/android/build.gradle
new file mode 100644
index 0000000000..49baeef939
--- /dev/null
+++ b/examples/E2ETestApp/android/build.gradle
@@ -0,0 +1,34 @@
+buildscript {
+ ext {
+ buildToolsVersion = "37.0.0"
+ minSdkVersion = 24
+ compileSdkVersion = 37
+ targetSdkVersion = 36
+ ndkVersion = "27.1.12297006"
+ kotlinVersion = "2.2.0"
+ }
+ repositories {
+ google()
+ mavenCentral()
+ }
+ dependencies {
+ classpath("com.android.tools.build:gradle")
+ classpath("com.facebook.react:react-native-gradle-plugin")
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")
+ }
+}
+
+ext.REACT_NATIVE_NODE_MODULES_DIR = file("$rootDir/../node_modules/react-native").absolutePath
+ext.REACT_NATIVE_WORKLETS_NODE_MODULES_DIR =
+ file("$rootDir/../node_modules/react-native-worklets").absolutePath
+
+allprojects {
+ repositories {
+ // Detox's Android library ships inside its npm package
+ maven {
+ url "$rootDir/../node_modules/detox/Detox-android"
+ }
+ }
+}
+
+apply plugin: "com.facebook.react.rootproject"
diff --git a/examples/E2ETestApp/android/gradle.properties b/examples/E2ETestApp/android/gradle.properties
new file mode 100644
index 0000000000..ab47cc1f7b
--- /dev/null
+++ b/examples/E2ETestApp/android/gradle.properties
@@ -0,0 +1,54 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
+org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+
+# Use this property to specify which architecture you want to build.
+# You can also override it from the CLI using
+# ./gradlew -PreactNativeArchitectures=x86_64
+# Emulator ABIs only (arm64 for Apple Silicon, x86_64 for CI); CI narrows it to x86_64 with
+# ORG_GRADLE_PROJECT_reactNativeArchitectures.
+reactNativeArchitectures=arm64-v8a,x86_64
+
+# Use this property to enable support to the new architecture.
+# This will allow you to use TurboModules and the Fabric render in
+# your application. You should enable this flag either if you want
+# to write custom TurboModules/Fabric components OR use libraries that
+# are providing them.
+newArchEnabled=true
+
+# Use this property to enable or disable the Hermes JS engine.
+# If set to false, you will be using JSC instead.
+hermesEnabled=true
+
+# Use this property to enable edge-to-edge display support.
+# This allows your app to draw behind system bars for an immersive UI.
+# Note: Only works with ReactActivity and should not be used with custom Activity.
+edgeToEdgeEnabled=true
+
+# Opt out of built-in kotlin and new DSL behavior that ships with AGP 9.
+# Starting from AGP 10.x these opt outs will be removed.
+android.builtInKotlin=false
+android.newDsl=false
+# Reuse task outputs across builds (and CI runs, via the Gradle cache)
+org.gradle.caching=true
+org.gradle.parallel=true
diff --git a/examples/E2ETestApp/android/gradle/wrapper/gradle-wrapper.jar b/examples/E2ETestApp/android/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000..d997cfc60f
Binary files /dev/null and b/examples/E2ETestApp/android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/examples/E2ETestApp/android/gradle/wrapper/gradle-wrapper.properties b/examples/E2ETestApp/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000..c61a118f7d
--- /dev/null
+++ b/examples/E2ETestApp/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/examples/E2ETestApp/android/gradlew b/examples/E2ETestApp/android/gradlew
new file mode 100755
index 0000000000..739907dfd1
--- /dev/null
+++ b/examples/E2ETestApp/android/gradlew
@@ -0,0 +1,248 @@
+#!/bin/sh
+
+#
+# Copyright © 2015 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/examples/E2ETestApp/android/gradlew.bat b/examples/E2ETestApp/android/gradlew.bat
new file mode 100644
index 0000000000..39baf4d684
--- /dev/null
+++ b/examples/E2ETestApp/android/gradlew.bat
@@ -0,0 +1,98 @@
+@REM Copyright (c) Meta Platforms, Inc. and affiliates.
+@REM
+@REM This source code is licensed under the MIT license found in the
+@REM LICENSE file in the root directory of this source tree.
+
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/examples/E2ETestApp/android/settings.gradle b/examples/E2ETestApp/android/settings.gradle
new file mode 100644
index 0000000000..96b171f560
--- /dev/null
+++ b/examples/E2ETestApp/android/settings.gradle
@@ -0,0 +1,6 @@
+pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") }
+plugins { id("com.facebook.react.settings") }
+extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() }
+rootProject.name = 'io.getstream.reactnative.e2etestapp'
+include ':app'
+includeBuild('../node_modules/@react-native/gradle-plugin')
diff --git a/examples/E2ETestApp/app.json b/examples/E2ETestApp/app.json
new file mode 100644
index 0000000000..73849fcf35
--- /dev/null
+++ b/examples/E2ETestApp/app.json
@@ -0,0 +1,4 @@
+{
+ "name": "E2ETestApp",
+ "displayName": "E2ETestApp"
+}
diff --git a/examples/E2ETestApp/babel.config.js b/examples/E2ETestApp/babel.config.js
new file mode 100644
index 0000000000..8ba8eb658c
--- /dev/null
+++ b/examples/E2ETestApp/babel.config.js
@@ -0,0 +1,4 @@
+module.exports = {
+ presets: ['module:@react-native/babel-preset'],
+ plugins: ['react-native-worklets/plugin'],
+};
diff --git a/examples/E2ETestApp/e2e/README.md b/examples/E2ETestApp/e2e/README.md
new file mode 100644
index 0000000000..7088447cf3
--- /dev/null
+++ b/examples/E2ETestApp/e2e/README.md
@@ -0,0 +1,119 @@
+# E2E tests (Detox)
+
+End-to-end tests for the SDK, driving `examples/E2ETestApp` with [Detox](https://wix.github.io/Detox/) against the shared
+[`stream-chat-test-mock-server`](https://github.com/GetStream/stream-chat-test-mock-server). The layout mirrors the
+native iOS/Android (and Flutter) suites, so tests can be ported almost line by line:
+
+| Path | What | Native counterpart |
+| ------------------------------------------- | ---------------------------------------------------------------------------------- | -------------------------------------------- |
+| `mock-server/` | `MockServer` (driver `/start/:test` → per-test server), `DataTypes` | `MockServer.kt`, `StreamMockServer.swift` |
+| `robots/BackendRobot.ts` | server-side state via test-control endpoints (`/mock`, `/add_member`, `/jwt/*`, …) | `BackendRobot` |
+| `robots/ParticipantRobot.ts` | the other user, `count_dooku` (`/participant/*`) | `ParticipantRobot` |
+| `robots/UserRobot.ts` + `UserRobot*Asserts` | UI actions as the app user + assert extensions | `UserRobot` + `UserRobot*Asserts.kt` |
+| `pages/` | page objects: `LoginPage`, `ChannelListPage`, `MessageListPage` | `pages/*Page.kt`, `Pages/*Page.swift` |
+| `support/` | `setUpStreamTestCase()`, `step()`, uiautomator-like `Element` helpers | `StreamTestCase`, `step {}`, `uiautomator/*` |
+| `tests/*.e2e.ts` | the tests | `*Tests.kt`, `*_Tests.swift` |
+
+Robots are fluent like the native ones; every call is queued and the chain runs when awaited:
+
+```ts
+await step('GIVEN user opens a channel', () => userRobot.login().openChannel());
+await step('WHEN participant sends a message', () => participantRobot.sendMessage('Hi'));
+await step('THEN user receives it', () => userRobot.assertMessage('Hi').assertMessageAuthor(false));
+```
+
+## The app
+
+`examples/E2ETestApp` exists only for this suite, like the native SDKs' `StreamChatUITestsApp`. It has the SDK and its
+required peer dependencies, and nothing else: no Firebase, maps, video or navigation library. That keeps native builds
+short (a clean Release build is ~2 min on an M-series Mac, versus ~15 min for the SampleApp on Android). It has three
+screens: a user selector, the channel list, and a channel stacked on top of the list (`App.tsx`), laid out like the
+SampleApp's, so the same SDK paths run.
+
+`setUpStreamTestCase()` starts a mock server per test and relaunches the app with the launch argument
+`MOCK_SERVER_URL` (`localhost` on iOS, `10.0.2.2` on the Android emulator), read in `src/config.ts` via
+`react-native-launch-arguments`. The app only lists the mock user (`luke_skywalker`), never persists a login and runs
+without offline storage, so every test starts clean.
+
+## Running
+
+The fastlane lanes live with the repo's other lanes in `examples/SampleApp/fastlane` (run them from
+`examples/SampleApp`). The e2e app has no Gemfile of its own; `e2e_pod_install` installs its pods with that bundle.
+
+```bash
+bundle exec fastlane e2e_pod_install # once, and after native dependency changes
+# Everything: clones + starts the mock server, builds, tests, stops the mock server
+bundle exec fastlane test_e2e platform:ios
+bundle exec fastlane test_e2e platform:android # AVD from DETOX_AVD_NAME (default Pixel_API_37)
+# Options: configuration:debug, skip_build:true, local_server:,
+# mock_server_branch:, test:e2e/tests/MessageListTests.e2e.ts
+
+# Or by hand (yarn commands in examples/E2ETestApp)
+bundle exec fastlane start_mock_server # driver on MOCK_DRIVER_PORT (default 4569)
+yarn e2e:build -c ios.sim.release # or android.emu.release
+MOCK_DRIVER_PORT=4569 yarn e2e:test -c ios.sim.release
+bundle exec fastlane stop_mock_server
+```
+
+Android builds only the `arm64-v8a` and `x86_64` ABIs (emulators); set `ORG_GRADLE_PROJECT_reactNativeArchitectures` to
+narrow it further.
+
+Release configurations bundle the JS, so no Metro is needed. Debug configurations need `yarn start`. Android builds need
+JDK 17 or 21 (`JAVA_HOME`).
+
+## CI
+
+`.github/workflows/e2e-test.yml` runs on pull requests and on demand (`workflow_dispatch`, with iOS/Android toggles and
+a mock server branch). Like the iOS SDK, a cheap `Check E2E Required` job first runs `fastlane e2e_check_required`
+(`is_check_required` over the `e2e` sources in the Fastfile's `impact_analysis`). The simulator/emulator jobs run
+only when the PR touches those sources, or when the last change to them hasn't passed yet. `Test E2E Result` is the
+job to require in branch protection: it passes when the e2e jobs pass or are skipped as not required.
+
+iOS runs on `macos-15` (Xcode 26.2, iPhone 17 Pro, `ios.sim.release`). Android runs on `ubuntu-latest` with KVM and an
+API 36 x86_64 emulator (`android.att.release`). Both call `fastlane test_e2e skip_build:true`, which on CI adds
+`--retries 2 --headless` and keeps failure logs and screenshots in `artifacts/`. Those and the mock server logs are
+uploaded when a job fails.
+
+What CI caches. The workflow doesn't run on `develop`, and GitHub only lets a PR restore caches from its own branch or
+the base branch, so each PR fills its own: its first run builds cold, and later pushes to it reuse the caches.
+
+- **The built app** (`.app`; release + test `.apk`), keyed on the app and SDK sources. A change that only touches
+ `e2e/` reuses the binary and skips pods, Gradle and Xcode entirely.
+- `node_modules` of `yarn workspaces focus e2etestapp`, so only the e2e app's dependency tree is installed.
+- iOS: CocoaPods, ccache (the RN ccache wrappers need `CCACHE_BINARY` in the environment, which the workflow sets), the
+ Detox framework.
+- Android: Gradle (`gradle/actions/setup-gradle` with `cache-read-only: false`, `org.gradle.caching`), a single ABI
+ (`x86_64`). The emulator matches the native Android SDK's e2e jobs (API 36 AOSP image, `pixel` profile, no snapshot);
+ on API 34 (Google APIs image, then AOSP) it died mid-run with no crash output.
+- The mock server's gems, keyed on the mock server revision.
+
+## Gotchas
+
+- iOS runs with Detox's idle synchronization off (`detoxEnableSynchronization: 0` in `StreamTestCase.ts`): it can wedge
+ on RN's UIManager shadow queue, whose pending-work counter underflows to 2^64-1, so the app looks busy until the test
+ times out. Robots wait explicitly instead, and taps retry while the target is not hittable yet (e.g. under the
+ keyboard as it animates in). Android keeps Espresso's synchronization.
+- Don't pass `permissions` to `device.launchApp` unless a test needs one: on iOS Detox applies each with
+ `applesimutils --restartSB`, which restarts SpringBoard on every launch. That cost 1.5–3 min per test on CI (hitting the
+ hook timeout) and ~15s locally.
+- CI boots the simulator at the start of the job and pins it with `DETOX_IOS_UDID` (`.detoxrc.js`), so the boot
+ overlaps with setup instead of delaying the first test by ~7 min.
+- A freshly booted CI emulator can show "Quickstep isn't responding" (a launcher ANR). The dialog takes window focus, and
+ every Espresso action then fails with "Waited for the root of the view hierarchy to have window focus". The
+ `test_e2e` lane hides error dialogs and waits up to 60s for the emulator to settle, and `StreamTestCase` dismisses
+ any ANR dialog before each Android launch (`support/AndroidSystemDialogs.ts`). Read the focus from
+ `dumpsys window`: `dumpsys window windows` no longer prints `mCurrentFocus`.
+- `detox test --reuse` does not reinstall the app. After rebuilding, run without it, or you test the old binary.
+- Yarn's `enableScripts: false` skips Detox's postinstall; run `yarn detox build-framework-cache` once on a new machine.
+- The SDK's shared native sources are synced into `stream-chat-react-native` and gitignored; `yarn e2e:build` and
+ `e2e_pod_install` run `yarn sync-native` first.
+- Don't commit `ios/E2ETestApp.xcodeproj` after `USE_CCACHE=1 pod install`: it writes machine-specific ccache paths into
+ it.
+- Detox replaces Jest's global `expect`. Use it for element expectations and `expect as jestExpect` from
+ `@jest/globals` for values.
+- Fabric mounts some views that carry a `testID` (`message-list-item-*`, `message-text-container`) empty, with their
+ content as siblings. They are not usable as `withAncestor` scopes or visibility targets; the page objects scope message
+ elements to `message-content-wrapper` or the message list instead.
+- Detox iOS never reports avatars as visible (their remote image renders transparent until loaded), so avatar asserts
+ check existence.
+- A ported test keeps the native expectation. If the SDK disagrees, fix the SDK or skip the test against a ticket.
diff --git a/examples/E2ETestApp/e2e/jest.config.js b/examples/E2ETestApp/e2e/jest.config.js
new file mode 100644
index 0000000000..5456675188
--- /dev/null
+++ b/examples/E2ETestApp/e2e/jest.config.js
@@ -0,0 +1,18 @@
+/** @type {import('jest').Config} */
+module.exports = {
+ rootDir: '..',
+ testMatch: ['/e2e/tests/**/*.e2e.ts'],
+ testTimeout: 180000,
+ maxWorkers: 1,
+ globalSetup: 'detox/runners/jest/globalSetup',
+ globalTeardown: 'detox/runners/jest/globalTeardown',
+ reporters: ['detox/runners/jest/reporter'],
+ testEnvironment: 'detox/runners/jest/testEnvironment',
+ verbose: true,
+ transform: {
+ '\\.ts$': [
+ 'babel-jest',
+ { babelrc: false, configFile: false, presets: ['module:@react-native/babel-preset'] },
+ ],
+ },
+};
diff --git a/examples/E2ETestApp/e2e/mock-server/DataTypes.ts b/examples/E2ETestApp/e2e/mock-server/DataTypes.ts
new file mode 100644
index 0000000000..a13549c994
--- /dev/null
+++ b/examples/E2ETestApp/e2e/mock-server/DataTypes.ts
@@ -0,0 +1,25 @@
+export const forbiddenWord = 'wth';
+
+export enum AttachmentType {
+ IMAGE = 'image',
+ VIDEO = 'video',
+ FILE = 'file',
+}
+
+export enum ReactionType {
+ LOVE = 'love',
+ LOL = 'haha',
+ WOW = 'wow',
+ SAD = 'sad',
+ LIKE = 'like',
+}
+
+export enum MessageDeliveryStatus {
+ READ = 'read',
+ DELIVERED = 'delivered',
+ PENDING = 'pending',
+ SENT = 'sent',
+ FAILED = 'failed',
+ /** No delivery status icon is expected. */
+ NIL = 'nil',
+}
diff --git a/examples/E2ETestApp/e2e/mock-server/MockServer.ts b/examples/E2ETestApp/e2e/mock-server/MockServer.ts
new file mode 100644
index 0000000000..1d273d12cf
--- /dev/null
+++ b/examples/E2ETestApp/e2e/mock-server/MockServer.ts
@@ -0,0 +1,84 @@
+declare const process: { env: Record };
+
+/**
+ * Client for `stream-chat-test-mock-server`. The driver (`driver.rb`) spawns one mock server per
+ * test on its own port; `start` asks it for one and `stop` shuts it down.
+ *
+ * Unlike the native suites, the test code runs on the host, so robots always talk to `localhost`
+ * while the app gets `appUrl`, which is the host as the device sees it.
+ */
+export class MockServer {
+ static readonly driverPort = process.env.MOCK_DRIVER_PORT ?? '4569';
+ private static readonly driverUrl = `http://localhost:${MockServer.driverPort}`;
+
+ private port?: string;
+
+ /** The mock server as the test runner (host) sees it. */
+ get url(): string {
+ if (!this.port) {
+ throw new Error('MockServer is not started');
+ }
+ return `http://localhost:${this.port}`;
+ }
+
+ /** The mock server as the app under test sees it: the Android emulator reaches the host via 10.0.2.2. */
+ get appUrl(): string {
+ const host = device.getPlatform() === 'android' ? '10.0.2.2' : 'localhost';
+ return this.url.replace('localhost', host);
+ }
+
+ /** Never retried: every call to the driver's `/start` spawns a new server on a new port. */
+ async start(testName: string): Promise {
+ const response = await this.execute(
+ `${MockServer.driverUrl}/start/${encodeURIComponent(testName)}`,
+ );
+ this.port = (await response.text()).trim();
+ await this.waitUntilReady();
+ }
+
+ async stop(): Promise {
+ if (!this.port) {
+ return;
+ }
+ await this.getRequest('stop').catch(() => undefined);
+ this.port = undefined;
+ }
+
+ async postRequest(endpoint: string, body = ''): Promise {
+ const response = await this.execute(`${this.url}/${endpoint}`, {
+ body,
+ headers: { 'Content-Type': 'text/plain' },
+ method: 'POST',
+ });
+ return response.text();
+ }
+
+ async getRequest(endpoint: string): Promise {
+ const response = await this.execute(`${this.url}/${endpoint}`);
+ return response.text();
+ }
+
+ private async waitUntilReady(timeoutMs = 5000): Promise {
+ const deadline = Date.now() + timeoutMs;
+ while (Date.now() < deadline) {
+ try {
+ const response = await fetch(`${this.url}/ping`);
+ if (response.ok) {
+ return;
+ }
+ } catch {
+ // The server process is still booting.
+ }
+ await new Promise((resolve) => setTimeout(resolve, 250));
+ }
+ throw new Error(`MockServer did not start within ${timeoutMs}ms on ${this.url}`);
+ }
+
+ private async execute(url: string, init?: RequestInit): Promise {
+ const response = await fetch(url, init);
+ if (!response.ok) {
+ throw new Error(`${init?.method ?? 'GET'} ${url} failed: ${response.status}`);
+ }
+ return response;
+ }
+}
diff --git a/examples/E2ETestApp/e2e/pages/ChannelListPage.ts b/examples/E2ETestApp/e2e/pages/ChannelListPage.ts
new file mode 100644
index 0000000000..4cc136b9b0
--- /dev/null
+++ b/examples/E2ETestApp/e2e/pages/ChannelListPage.ts
@@ -0,0 +1,32 @@
+export const ChannelListPage = {
+ ChannelList: {
+ get channelList() {
+ return by.id('channel-list-view');
+ },
+ get channels() {
+ return by.id('channel-preview-button');
+ },
+
+ Channel: {
+ get avatar() {
+ return by.id('avatar-image').withAncestor(by.id('channel-preview-button'));
+ },
+ get name() {
+ return by.id('channel-preview-title');
+ },
+ nameWithText(text: string) {
+ return by.id('channel-preview-title').and(by.text(text));
+ },
+ get messagePreview() {
+ return by.id('channel-preview-message');
+ },
+ /** "You:" or ":" in front of the preview text, rendered as its own text. */
+ get messageSender() {
+ return by.id('channel-preview-sender');
+ },
+ get unreadCount() {
+ return by.id('unread-count').withAncestor(by.id('channel-preview-button'));
+ },
+ },
+ },
+};
diff --git a/examples/E2ETestApp/e2e/pages/LoginPage.ts b/examples/E2ETestApp/e2e/pages/LoginPage.ts
new file mode 100644
index 0000000000..069eab4a75
--- /dev/null
+++ b/examples/E2ETestApp/e2e/pages/LoginPage.ts
@@ -0,0 +1,11 @@
+/** The mock server's app user (`appUser` in `src/config.ts`), the only one listed in e2e mode. */
+export const appUserId = 'luke_skywalker';
+
+export const LoginPage = {
+ get userSelector() {
+ return by.id('user-selector-screen');
+ },
+ get loginButton() {
+ return by.id(`user-selector-button-${appUserId}`);
+ },
+};
diff --git a/examples/E2ETestApp/e2e/pages/MessageListPage.ts b/examples/E2ETestApp/e2e/pages/MessageListPage.ts
new file mode 100644
index 0000000000..4559f48590
--- /dev/null
+++ b/examples/E2ETestApp/e2e/pages/MessageListPage.ts
@@ -0,0 +1,87 @@
+const messageCell = () => by.id(/^message-list-item-/);
+// Fabric mounts `message-list-item-*` empty with its content beside it, so the list, not the cell,
+// is the ancestor that scopes message elements (the channel list stays mounted underneath).
+const inMessageList = (matcher: Detox.NativeMatcher) =>
+ matcher.withAncestor(by.id(/^message-(flat|flash)-list$/));
+
+export const MessageListPage = {
+ Header: {
+ get backButton() {
+ return by.id('back-button');
+ },
+ },
+
+ Composer: {
+ get inputField() {
+ return by.id('auto-complete-text-input');
+ },
+ get sendButton() {
+ return by.id('send-button');
+ },
+ get attachmentsButton() {
+ return by.id('attach-button');
+ },
+ get cooldownIndicator() {
+ return by.id('cooldown-timer');
+ },
+ },
+
+ MessageList: {
+ get messageList() {
+ return by.id(/^message-(flat|flash)-list$/);
+ },
+ get messages() {
+ return messageCell();
+ },
+ get dateSeparator() {
+ return by.id('date-separator');
+ },
+ get typingIndicator() {
+ return by.id('typing-indicator');
+ },
+ get scrollToBottomButton() {
+ return by.id('scroll-to-bottom-button');
+ },
+
+ Message: {
+ /** Wraps the author's avatar; only rendered for other users' messages. */
+ get avatar() {
+ return by.id('message-author');
+ },
+ text(text: string) {
+ // Not under `message-text-container`: Fabric mounts that view empty, with the text beside it.
+ return by.text(text).withAncestor(by.id('message-content-wrapper'));
+ },
+ get timestamp() {
+ return by.id('message-status-time');
+ },
+ get deliveryStatusIsRead() {
+ return inMessageList(by.id('message-status-read'));
+ },
+ get deliveryStatusIsDelivered() {
+ return inMessageList(by.id('message-status-delivered'));
+ },
+ get deliveryStatusIsPending() {
+ return inMessageList(by.id('message-status-sending'));
+ },
+ get deliveryStatusIsSent() {
+ return inMessageList(by.id('message-status-sent'));
+ },
+ get deliveryStatusIsFailed() {
+ return inMessageList(by.id('message-error'));
+ },
+ get deletedMessage() {
+ return by.id('message-deleted');
+ },
+ get threadRepliesLabel() {
+ return by.id('message-replies');
+ },
+
+ Reactions: {
+ get reactions() {
+ return by.id('reaction-list-item');
+ },
+ },
+ },
+ },
+};
diff --git a/examples/E2ETestApp/e2e/robots/BackendRobot.ts b/examples/E2ETestApp/e2e/robots/BackendRobot.ts
new file mode 100644
index 0000000000..c62e3eea5c
--- /dev/null
+++ b/examples/E2ETestApp/e2e/robots/BackendRobot.ts
@@ -0,0 +1,129 @@
+import { Robot } from './Robot';
+
+import type { MockServer } from '../mock-server/MockServer';
+
+/** Drives server-side state through the mock server's test-control endpoints. */
+export class BackendRobot extends Robot {
+ constructor(private readonly mockServer: MockServer) {
+ super();
+ }
+
+ generateChannels({
+ channelsCount,
+ messagesCount = 0,
+ repliesCount = 0,
+ messagesText,
+ repliesText,
+ channelNames = [],
+ withDirectMessageChannel = false,
+ }: {
+ channelsCount: number;
+ messagesCount?: number;
+ repliesCount?: number;
+ messagesText?: string;
+ repliesText?: string;
+ channelNames?: string[];
+ withDirectMessageChannel?: boolean;
+ }): this {
+ const params = new URLSearchParams();
+ if (messagesText !== undefined) params.set('messages_text', messagesText);
+ if (repliesText !== undefined) params.set('replies_text', repliesText);
+ if (channelNames.length > 0) params.set('channel_names', channelNames.join(','));
+ if (withDirectMessageChannel) params.set('dm', 'true');
+ params.set('channels', `${channelsCount}`);
+ params.set('messages', `${messagesCount}`);
+ params.set('replies', `${repliesCount}`);
+ return this.post(`mock?${params}`);
+ }
+
+ failNewMessages(): this {
+ return this.post('fail_messages');
+ }
+
+ freezeNewMessages(): this {
+ return this.post('freeze_messages');
+ }
+
+ setCooldown(enabled: boolean, duration: number): this {
+ return this.post(`config/cooldown?enabled=${enabled}&duration=${duration}`);
+ }
+
+ /**
+ * Truncates the currently open channel on the server side. The app receives `channel.truncated`.
+ *
+ * @param withMessage also delivers a "Channel truncated" system message.
+ */
+ truncateChannel(withMessage: boolean): this {
+ return this.post(`truncate_channel?with_message=${withMessage}`);
+ }
+
+ /** Enables or disables read events on every channel. Call before the channel is opened. */
+ setReadEvents(enabled: boolean): this {
+ return this.post(`config/read_events?value=${enabled}`);
+ }
+
+ /** Adds a member to the currently open channel. The app receives `member.added` + `channel.updated`. */
+ addMember(userId: string): this {
+ return this.post(`add_member?user_id=${encodeURIComponent(userId)}`);
+ }
+
+ /** Removes a member from the currently open channel. The app receives `member.removed` + `channel.updated`. */
+ removeMember(userId: string): this {
+ return this.post(`remove_member?user_id=${encodeURIComponent(userId)}`);
+ }
+
+ /**
+ * Creates a reminder for the last message of the currently open channel.
+ *
+ * @param remindAtSeconds how far in the future it is due; omit for a "saved for later" reminder.
+ */
+ createReminder(remindAtSeconds?: number): this {
+ return this.post(
+ remindAtSeconds === undefined
+ ? 'create_reminder'
+ : `create_reminder?remind_at=${remindAtSeconds}`,
+ );
+ }
+
+ revokeToken(duration = 5): this {
+ return this.post(`jwt/revoke_token?duration=${duration}`);
+ }
+
+ invalidateToken(duration = 5): this {
+ return this.post(`jwt/invalidate_token?duration=${duration}`);
+ }
+
+ invalidateTokenDate(duration = 5): this {
+ return this.post(`jwt/invalidate_token_date?duration=${duration}`);
+ }
+
+ invalidateTokenSignature(duration = 5): this {
+ return this.post(`jwt/invalidate_token_signature?duration=${duration}`);
+ }
+
+ breakTokenGeneration(duration = 5): this {
+ return this.post(`jwt/break_token_generation?duration=${duration}`);
+ }
+
+ /**
+ * Waits until the app closes its WebSocket. The SDK keeps the socket open for a while after the
+ * app goes to background, so call this before server-side events that must not arrive live.
+ */
+ waitForWebSocketDisconnection(timeoutMs = 10000): this {
+ return this.perform(async () => {
+ const deadline = Date.now() + timeoutMs;
+ while (Date.now() < deadline) {
+ const status = JSON.parse(await this.mockServer.getRequest('ws/status'));
+ if (!status.connected) {
+ return;
+ }
+ await new Promise((resolve) => setTimeout(resolve, 500));
+ }
+ throw new Error(`WebSocket was not disconnected within ${timeoutMs}ms`);
+ });
+ }
+
+ private post(endpoint: string): this {
+ return this.perform(() => this.mockServer.postRequest(endpoint));
+ }
+}
diff --git a/examples/E2ETestApp/e2e/robots/ParticipantRobot.ts b/examples/E2ETestApp/e2e/robots/ParticipantRobot.ts
new file mode 100644
index 0000000000..0615c8a469
--- /dev/null
+++ b/examples/E2ETestApp/e2e/robots/ParticipantRobot.ts
@@ -0,0 +1,161 @@
+import { Robot } from './Robot';
+
+import type { AttachmentType, ReactionType } from '../mock-server/DataTypes';
+import type { MockServer } from '../mock-server/MockServer';
+
+const MULTIPLE_MESSAGES_INTERVAL_MS = 300;
+
+const quoteParam = (last: boolean) => (last ? 'quote_last=true' : 'quote_first=true');
+
+/** Acts as the other channel member (`count_dooku`) through the mock server's participant endpoints. */
+export class ParticipantRobot extends Robot {
+ static readonly userName = 'Count Dooku';
+ static readonly userId = 'count_dooku';
+
+ constructor(private readonly mockServer: MockServer) {
+ super();
+ }
+
+ startTyping(): this {
+ return this.post('participant/typing/start');
+ }
+
+ startTypingInThread(): this {
+ return this.post('participant/typing/start?thread=true');
+ }
+
+ stopTyping(): this {
+ return this.post('participant/typing/stop');
+ }
+
+ stopTypingInThread(): this {
+ return this.post('participant/typing/stop?thread=true');
+ }
+
+ readMessage(): this {
+ return this.post('participant/read');
+ }
+
+ /** Marks the newest message as delivered to the participant (`message.delivered`). */
+ markMessagesDelivered(): this {
+ return this.post('participant/delivered');
+ }
+
+ sendMessage(text: string, delay = 0): this {
+ return this.post(
+ delay > 0 ? `participant/message?delay=${delay}` : 'participant/message',
+ text,
+ );
+ }
+
+ /** Sends `count` messages named `${text}-1` through `${text}-${count}`, 300ms apart. */
+ sendMultipleMessages(text: string, count: number): this {
+ for (let index = 1; index <= count; index++) {
+ this.sendMessage(`${text}-${index}`).sleep(MULTIPLE_MESSAGES_INTERVAL_MS);
+ }
+ return this;
+ }
+
+ sendMessageInThread(text: string, alsoSendInChannel = false): this {
+ return this.post(
+ `participant/message?thread=true&thread_and_channel=${alsoSendInChannel}`,
+ text,
+ );
+ }
+
+ editMessage(text: string): this {
+ return this.post('participant/message?action=edit', text);
+ }
+
+ deleteMessage(hard = false): this {
+ return this.post(`participant/message?action=delete&hard_delete=${hard}`);
+ }
+
+ quoteMessage(text: string, last = true): this {
+ return this.post(`participant/message?${quoteParam(last)}`, text);
+ }
+
+ quoteMessageInThread(text: string, alsoSendInChannel = false, last = true): this {
+ return this.post(
+ `participant/message?${quoteParam(last)}&thread=true&thread_and_channel=${alsoSendInChannel}`,
+ text,
+ );
+ }
+
+ uploadGiphy(): this {
+ return this.post('participant/message?giphy=true');
+ }
+
+ uploadGiphyInThread(): this {
+ return this.post('participant/message?giphy=true&thread=true');
+ }
+
+ quoteMessageWithGiphy(last = true): this {
+ return this.post(`participant/message?giphy=true&${quoteParam(last)}`);
+ }
+
+ quoteMessageWithGiphyInThread(alsoSendInChannel = false, last = true): this {
+ return this.post(
+ `participant/message?giphy=true&${quoteParam(last)}&thread=true&thread_and_channel=${alsoSendInChannel}`,
+ );
+ }
+
+ pinMessage(): this {
+ return this.post('participant/message?action=pin');
+ }
+
+ unpinMessage(): this {
+ return this.post('participant/message?action=unpin');
+ }
+
+ uploadAttachment(type: AttachmentType, count = 1): this {
+ return this.post(`participant/message?${type}=${count}`);
+ }
+
+ quoteMessageWithAttachment(type: AttachmentType, count = 1, last = true): this {
+ return this.post(`participant/message?${quoteParam(last)}&${type}=${count}`);
+ }
+
+ uploadAttachmentInThread(type: AttachmentType, count = 1, alsoSendInChannel = false): this {
+ return this.post(
+ `participant/message?${type}=${count}&thread=true&thread_and_channel=${alsoSendInChannel}`,
+ );
+ }
+
+ quoteMessageWithAttachmentInThread(
+ type: AttachmentType,
+ count = 1,
+ alsoSendInChannel = false,
+ last = true,
+ ): this {
+ return this.post(
+ `participant/message?${quoteParam(last)}&${type}=${count}&thread=true&thread_and_channel=${alsoSendInChannel}`,
+ );
+ }
+
+ /** Votes for `option` in the poll of the newest poll message. */
+ castPollVote(option: string): this {
+ return this.post(`participant/poll_vote?option=${encodeURIComponent(option)}`);
+ }
+
+ /** Adds an answer (comment) to the poll of the newest poll message. */
+ addPollAnswer(answer: string): this {
+ return this.post(`participant/poll_vote?answer=${encodeURIComponent(answer)}`);
+ }
+
+ addReaction(type: ReactionType, delay = 0): this {
+ return this.post(
+ delay > 0
+ ? `participant/reaction?type=${type}&delay=${delay}`
+ : `participant/reaction?type=${type}`,
+ );
+ }
+
+ deleteReaction(type: ReactionType): this {
+ return this.post(`participant/reaction?type=${type}&delete=true`);
+ }
+
+ private post(endpoint: string, body?: string): this {
+ return this.perform(() => this.mockServer.postRequest(endpoint, body));
+ }
+}
diff --git a/examples/E2ETestApp/e2e/robots/Robot.ts b/examples/E2ETestApp/e2e/robots/Robot.ts
new file mode 100644
index 0000000000..44dbaaecb7
--- /dev/null
+++ b/examples/E2ETestApp/e2e/robots/Robot.ts
@@ -0,0 +1,33 @@
+/**
+ * Base for the fluent robots. Native robots chain synchronous calls
+ * (`userRobot.login().openChannel()`); Detox is async, so each call queues its action and
+ * returns `this`, and awaiting the robot runs the queue:
+ *
+ * await userRobot.login().openChannel().assertMessage('Hi');
+ *
+ * A failed action rejects the awaited chain and skips the rest of it.
+ */
+export abstract class Robot implements PromiseLike {
+ private queue: Promise = Promise.resolve();
+
+ /** Queues `action` after the previous ones. Used by the robots and their assert extensions. */
+ perform(action: () => Promise): this {
+ this.queue = this.queue.then(async () => {
+ await action();
+ });
+ return this;
+ }
+
+ sleep(ms: number): this {
+ return this.perform(() => new Promise((resolve) => setTimeout(resolve, ms)));
+ }
+
+ then(
+ onfulfilled?: ((value: void) => TResult1 | PromiseLike) | null,
+ onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null,
+ ): PromiseLike {
+ const queue = this.queue;
+ this.queue = Promise.resolve();
+ return queue.then(onfulfilled, onrejected);
+ }
+}
diff --git a/examples/E2ETestApp/e2e/robots/UserRobot.ts b/examples/E2ETestApp/e2e/robots/UserRobot.ts
new file mode 100644
index 0000000000..f8e99e6bee
--- /dev/null
+++ b/examples/E2ETestApp/e2e/robots/UserRobot.ts
@@ -0,0 +1,135 @@
+import { Robot } from './Robot';
+
+import { ChannelListPage } from '../pages/ChannelListPage';
+import { LoginPage } from '../pages/LoginPage';
+import { MessageListPage } from '../pages/MessageListPage';
+import {
+ waitToAppear,
+ waitToAppearAndClick,
+ waitToAppearAndLongPress,
+ waitToDisappear,
+} from '../support/Element';
+
+const { ChannelList } = ChannelListPage;
+const { Composer, Header, MessageList } = MessageListPage;
+
+/** Drives the app as the logged-in user. Asserts live in the `UserRobot*Asserts` extensions. */
+export class UserRobot extends Robot {
+ login(): this {
+ return this.perform(() => waitToAppearAndClick(LoginPage.loginButton));
+ }
+
+ waitForChannelListToLoad(): this {
+ return this.perform(() => waitToAppear(ChannelList.channels, { index: 0 }));
+ }
+
+ waitForMessageListToLoad(): this {
+ return this.perform(() => waitToAppear(Composer.inputField));
+ }
+
+ openChannel(channelCellIndex = 0): this {
+ return this.perform(() =>
+ waitToAppearAndClick(ChannelList.channels, { index: channelCellIndex }),
+ ).waitForMessageListToLoad();
+ }
+
+ openChannelWithName(channelName: string): this {
+ return this.perform(() =>
+ waitToAppearAndClick(ChannelList.Channel.nameWithText(channelName)),
+ ).waitForMessageListToLoad();
+ }
+
+ openContextMenu(messageText: string): this {
+ return this.perform(() => waitToAppearAndLongPress(MessageList.Message.text(messageText)));
+ }
+
+ /**
+ * iOS types key by key, like XCUITest. Android sets the text, like the native suite's
+ * `typeText` (UiAutomator `setText`): typing through the soft keyboard leaves the text in the
+ * IME's composing state, which the composer doesn't pick up, so the send button never shows.
+ */
+ typeText(text: string): this {
+ return this.perform(async () => {
+ const inputField = await waitToAppear(Composer.inputField);
+ if (device.getPlatform() === 'android') {
+ await inputField.replaceText(text);
+ } else {
+ await inputField.typeText(text);
+ }
+ });
+ }
+
+ clearComposer(): this {
+ return this.perform(async () => {
+ const inputField = await waitToAppear(Composer.inputField);
+ await inputField.clearText();
+ });
+ }
+
+ tapOnSendButton(): this {
+ return this.perform(() => waitToAppearAndClick(Composer.sendButton));
+ }
+
+ sendMessage(text: string): this {
+ return this.typeText(text).tapOnSendButton();
+ }
+
+ tapOnBackButton(): this {
+ return this.perform(() => waitToAppearAndClick(Header.backButton));
+ }
+
+ /** Android hardware back; iOS has none, so it taps the header's back button there. */
+ pressBack(): this {
+ return this.perform(async () => {
+ if (device.getPlatform() === 'android') {
+ await device.pressBack();
+ } else {
+ await waitToAppearAndClick(Header.backButton);
+ }
+ });
+ }
+
+ tapOnScrollToBottomButton(): this {
+ return this.perform(() => waitToAppearAndClick(MessageList.scrollToBottomButton));
+ }
+
+ moveToChannelListFromMessageList(): this {
+ return this.tapOnBackButton()
+ .perform(() => waitToDisappear(Composer.inputField))
+ .waitForChannelListToLoad();
+ }
+
+ scrollChannelListDown(times = 3): this {
+ return this.swipe(ChannelList.channelList, 'up', times);
+ }
+
+ scrollChannelListUp(times = 3): this {
+ return this.swipe(ChannelList.channelList, 'down', times);
+ }
+
+ scrollMessageListDown(times = 3): this {
+ // The message list is inverted: newer messages are at the bottom, reached by swiping down.
+ return this.swipe(MessageList.messageList, 'down', times);
+ }
+
+ scrollMessageListUp(times = 3): this {
+ return this.swipe(MessageList.messageList, 'up', times);
+ }
+
+ backgroundApp(): this {
+ return this.perform(() => device.sendToHome());
+ }
+
+ foregroundApp(): this {
+ return this.perform(() => device.launchApp({ newInstance: false }));
+ }
+
+ private swipe(list: Detox.NativeMatcher, direction: Detox.Direction, times: number): this {
+ return this.perform(async () => {
+ const target = await waitToAppear(list);
+ for (let i = 0; i < times; i++) {
+ await target.swipe(direction, 'fast', 0.6);
+ }
+ });
+ }
+}
diff --git a/examples/E2ETestApp/e2e/robots/UserRobotChannelListAsserts.ts b/examples/E2ETestApp/e2e/robots/UserRobotChannelListAsserts.ts
new file mode 100644
index 0000000000..068ed8c6e6
--- /dev/null
+++ b/examples/E2ETestApp/e2e/robots/UserRobotChannelListAsserts.ts
@@ -0,0 +1,72 @@
+import { expect as jestExpect } from '@jest/globals';
+
+import { ParticipantRobot } from './ParticipantRobot';
+import { UserRobot } from './UserRobot';
+
+import { ChannelListPage } from '../pages/ChannelListPage';
+import { waitForCount, waitForExistence, waitForText, waitToDisappear } from '../support/Element';
+
+const { ChannelList } = ChannelListPage;
+const { Channel } = ChannelList;
+
+declare module './UserRobot' {
+ interface UserRobot {
+ assertChannelAvatar(): this;
+ assertChannelCount(count: number): this;
+ assertChannelListIsEmpty(): this;
+ assertChannelName(name: string, channelCellIndex?: number): this;
+ assertChannelUnreadCount(count: number): this;
+ /**
+ * @param fromCurrentUser `true` expects a "You: " prefix, `false` the participant's name,
+ * `undefined` only the text.
+ */
+ assertMessageInChannelPreview(text: string, fromCurrentUser?: boolean): this;
+ }
+}
+
+UserRobot.prototype.assertChannelAvatar = function () {
+ return this.perform(async () => {
+ jestExpect(await waitForExistence(Channel.avatar, { index: 0 })).toBe(true);
+ });
+};
+
+UserRobot.prototype.assertChannelCount = function (count) {
+ return this.perform(async () => {
+ jestExpect(await waitForCount(ChannelList.channels, count)).toBe(count);
+ });
+};
+
+UserRobot.prototype.assertChannelListIsEmpty = function () {
+ return this.perform(async () => {
+ await waitToDisappear(ChannelList.channels);
+ jestExpect(await waitForCount(ChannelList.channels, 0)).toBe(0);
+ });
+};
+
+UserRobot.prototype.assertChannelName = function (name, channelCellIndex = 0) {
+ return this.perform(async () => {
+ jestExpect(await waitForText(Channel.name, name, { index: channelCellIndex })).toBe(name);
+ });
+};
+
+UserRobot.prototype.assertChannelUnreadCount = function (count) {
+ return this.perform(async () => {
+ jestExpect(await waitForText(Channel.unreadCount, `${count}`)).toBe(`${count}`);
+ });
+};
+
+UserRobot.prototype.assertMessageInChannelPreview = function (text, fromCurrentUser) {
+ const expectedSender =
+ fromCurrentUser === true
+ ? 'You:'
+ : fromCurrentUser === false
+ ? `${ParticipantRobot.userName}:`
+ : undefined;
+ return this.perform(async () => {
+ const preview = await waitForText(Channel.messagePreview, text, { mustBeEqual: false });
+ jestExpect(preview.trimEnd()).toContain(text);
+ if (expectedSender !== undefined) {
+ jestExpect(await waitForText(Channel.messageSender, expectedSender)).toBe(expectedSender);
+ }
+ });
+};
diff --git a/examples/E2ETestApp/e2e/robots/UserRobotMessageListAsserts.ts b/examples/E2ETestApp/e2e/robots/UserRobotMessageListAsserts.ts
new file mode 100644
index 0000000000..7596ce79c8
--- /dev/null
+++ b/examples/E2ETestApp/e2e/robots/UserRobotMessageListAsserts.ts
@@ -0,0 +1,105 @@
+import { expect as jestExpect } from '@jest/globals';
+
+import { UserRobot } from './UserRobot';
+
+import { MessageDeliveryStatus } from '../mock-server/DataTypes';
+import { MessageListPage } from '../pages/MessageListPage';
+import {
+ defaultTimeout,
+ isDisplayed,
+ waitForCount,
+ waitForExistence,
+ waitToAppear,
+ waitToDisappear,
+} from '../support/Element';
+
+const { MessageList } = MessageListPage;
+const { Message } = MessageList;
+
+declare module './UserRobot' {
+ interface UserRobot {
+ assertMessage(text: string, isDisplayed?: boolean): this;
+ assertMessageAuthor(isCurrentUser: boolean): this;
+ assertMessageDeliveryStatus(status: MessageDeliveryStatus, count?: number): this;
+ assertMessageFailedIcon(isDisplayed: boolean): this;
+ assertTypingIndicator(isDisplayed: boolean): this;
+ assertScrollToBottomButton(isDisplayed: boolean): this;
+ }
+}
+
+export const assertVisibility = async (
+ selector: Detox.NativeMatcher,
+ shouldBeDisplayed: boolean,
+ timeout = defaultTimeout,
+) => {
+ if (shouldBeDisplayed) {
+ await waitToAppear(selector, { index: 0, timeout });
+ } else {
+ await waitToDisappear(selector, { index: 0, timeout });
+ jestExpect(await isDisplayed(selector, 0)).toBe(false);
+ }
+};
+
+const assertDeliveryStatusCount = async (selector: Detox.NativeMatcher, count?: number) => {
+ await assertVisibility(selector, true, 30000);
+ if (count !== undefined) {
+ jestExpect(await waitForCount(selector, count)).toBe(count);
+ }
+};
+
+UserRobot.prototype.assertMessage = function (text, shouldBeDisplayed = true) {
+ return this.perform(async () => {
+ await assertVisibility(Message.text(text), shouldBeDisplayed);
+ if (shouldBeDisplayed) {
+ jestExpect(await isDisplayed(Message.timestamp, 0)).toBe(true);
+ }
+ });
+};
+
+/** The current user's messages carry no avatar; other users' do. */
+UserRobot.prototype.assertMessageAuthor = function (isCurrentUser) {
+ return this.perform(async () => {
+ const exists = await waitForExistence(Message.avatar, {
+ index: 0,
+ shouldExist: !isCurrentUser,
+ });
+ jestExpect(exists).toBe(!isCurrentUser);
+ });
+};
+
+UserRobot.prototype.assertMessageDeliveryStatus = function (status, count) {
+ return this.perform(async () => {
+ switch (status) {
+ case MessageDeliveryStatus.READ:
+ return assertDeliveryStatusCount(Message.deliveryStatusIsRead, count);
+ case MessageDeliveryStatus.DELIVERED:
+ return assertDeliveryStatusCount(Message.deliveryStatusIsDelivered, count);
+ case MessageDeliveryStatus.PENDING:
+ return assertDeliveryStatusCount(Message.deliveryStatusIsPending, count);
+ case MessageDeliveryStatus.SENT:
+ return assertDeliveryStatusCount(Message.deliveryStatusIsSent, count);
+ case MessageDeliveryStatus.FAILED:
+ return assertDeliveryStatusCount(Message.deliveryStatusIsFailed, count);
+ case MessageDeliveryStatus.NIL:
+ await assertVisibility(Message.deliveryStatusIsRead, false);
+ await assertVisibility(Message.deliveryStatusIsDelivered, false);
+ await assertVisibility(Message.deliveryStatusIsPending, false);
+ await assertVisibility(Message.deliveryStatusIsSent, false);
+ return;
+ default:
+ throw new Error(`Unsupported delivery status: ${status}`);
+ }
+ });
+};
+
+UserRobot.prototype.assertMessageFailedIcon = function (shouldBeDisplayed) {
+ return this.perform(() => assertVisibility(Message.deliveryStatusIsFailed, shouldBeDisplayed));
+};
+
+UserRobot.prototype.assertTypingIndicator = function (shouldBeDisplayed) {
+ return this.perform(() => assertVisibility(MessageList.typingIndicator, shouldBeDisplayed));
+};
+
+UserRobot.prototype.assertScrollToBottomButton = function (shouldBeDisplayed) {
+ return this.perform(() => assertVisibility(MessageList.scrollToBottomButton, shouldBeDisplayed));
+};
diff --git a/examples/E2ETestApp/e2e/robots/index.ts b/examples/E2ETestApp/e2e/robots/index.ts
new file mode 100644
index 0000000000..bc92c7f124
--- /dev/null
+++ b/examples/E2ETestApp/e2e/robots/index.ts
@@ -0,0 +1,7 @@
+// The assert files extend UserRobot's prototype, so they must be loaded with it.
+import './UserRobotMessageListAsserts';
+import './UserRobotChannelListAsserts';
+
+export { BackendRobot } from './BackendRobot';
+export { ParticipantRobot } from './ParticipantRobot';
+export { UserRobot } from './UserRobot';
diff --git a/examples/E2ETestApp/e2e/support/AndroidSystemDialogs.ts b/examples/E2ETestApp/e2e/support/AndroidSystemDialogs.ts
new file mode 100644
index 0000000000..a7d2c61dcd
--- /dev/null
+++ b/examples/E2ETestApp/e2e/support/AndroidSystemDialogs.ts
@@ -0,0 +1,43 @@
+// Node built-ins, typed locally: the e2e project's types are limited to `detox/globals`.
+declare const process: { env: Record };
+declare const require: (module: 'child_process') => {
+ execFileSync: (file: string, args: string[], options: { encoding: 'utf8' }) => string;
+};
+
+const { execFileSync } = require('child_process');
+
+const sdkRoot = process.env.ANDROID_HOME ?? process.env.ANDROID_SDK_ROOT;
+const adbPath = sdkRoot ? `${sdkRoot}/platform-tools/adb` : 'adb';
+
+const adb = (...args: string[]) => {
+ const serial = process.env.DETOX_ADB_NAME;
+ const deviceArgs = serial && !serial.includes('*') ? ['-s', serial] : [];
+ return execFileSync(adbPath, [...deviceArgs, ...args], { encoding: 'utf8' });
+};
+
+/**
+ * Dismisses an " isn't responding" dialog, if one is showing. On a slow CI emulator the
+ * launcher (Quickstep) can hit an ANR; its dialog takes window focus, and Espresso then fails every
+ * test waiting for the app's window to get it. Same handling as the `wait_android_emu_idle` fastlane
+ * action: Enter picks "Close app", except for System UI, where it picks "Wait".
+ */
+export const dismissAnrDialog = () => {
+ try {
+ const focus = adb('shell', 'dumpsys', 'window')
+ .split('\n')
+ .find(
+ (line) => line.includes('mCurrentFocus') && line.includes('Application Not Responding'),
+ );
+ if (!focus) {
+ return;
+ }
+ console.warn(`Dismissing an ANR dialog: ${focus.trim()}`);
+ if (focus.includes('com.android.systemui')) {
+ adb('shell', 'input', 'keyevent', 'KEYCODE_DPAD_DOWN');
+ }
+ adb('shell', 'input', 'keyevent', 'KEYCODE_ENTER');
+ } catch (error) {
+ // Best effort: a failed check must not fail the test on its own.
+ console.warn(`Could not check for ANR dialogs: ${String(error)}`);
+ }
+};
diff --git a/examples/E2ETestApp/e2e/support/Element.ts b/examples/E2ETestApp/e2e/support/Element.ts
new file mode 100644
index 0000000000..edefaf1414
--- /dev/null
+++ b/examples/E2ETestApp/e2e/support/Element.ts
@@ -0,0 +1,164 @@
+/**
+ * Element helpers mirroring the Android suite's `uiautomator` extensions (`Element.kt`, `Wait.kt`),
+ * so robot code reads the same: `selector.waitToAppearAndClick()` becomes
+ * `await waitToAppearAndClick(selector)`.
+ */
+
+export const defaultTimeout = 15000;
+
+type Selector = Detox.NativeMatcher;
+
+type WaitOptions = {
+ /** Picks one match when the selector matches several elements. */
+ index?: number;
+ timeout?: number;
+};
+
+const findElement = (selector: Selector, index?: number) =>
+ index === undefined ? element(selector) : element(selector).atIndex(index);
+
+export const waitToAppear = async (
+ selector: Selector,
+ { index, timeout = defaultTimeout }: WaitOptions = {},
+) => {
+ const target = findElement(selector, index);
+ await waitFor(target).toBeVisible().withTimeout(timeout);
+ return target;
+};
+
+/**
+ * Retries `action` while Detox reports the element as not hittable (e.g. covered by the keyboard
+ * while it animates in). iOS runs without Detox's idle synchronization, which used to absorb that.
+ */
+const retryWhileNotHittable = async (action: () => Promise, timeout = defaultTimeout) => {
+ const deadline = Date.now() + timeout;
+ for (;;) {
+ try {
+ return await action();
+ } catch (error) {
+ if (Date.now() > deadline || !/not hittable/i.test(String(error))) {
+ throw error;
+ }
+ await new Promise((resolve) => setTimeout(resolve, 300));
+ }
+ }
+};
+
+export const waitToAppearAndClick = async (selector: Selector, options?: WaitOptions) => {
+ const target = await waitToAppear(selector, options);
+ await retryWhileNotHittable(() => target.tap(), options?.timeout);
+ return target;
+};
+
+export const waitToAppearAndLongPress = async (selector: Selector, options?: WaitOptions) => {
+ const target = await waitToAppear(selector, options);
+ await retryWhileNotHittable(() => target.longPress(), options?.timeout);
+ return target;
+};
+
+/** Waits until nothing matching `selector` is visible. Resolves (does not throw) on timeout. */
+export const waitToDisappear = async (
+ selector: Selector,
+ { index, timeout = defaultTimeout }: WaitOptions = {},
+) => {
+ try {
+ await waitFor(findElement(selector, index)).not.toBeVisible().withTimeout(timeout);
+ } catch {
+ // The caller asserts on `isDisplayed` afterwards, like `waitToDisappear().isDisplayed()` on Android.
+ }
+};
+
+/**
+ * Waits until `selector` exists (or, with `shouldExist: false`, until it no longer does), and
+ * returns whether it exists then. For elements Detox iOS never reports as visible, such as avatars
+ * whose remote image has not loaded: its visibility check needs rendered pixels.
+ */
+export const waitForExistence = async (
+ selector: Selector,
+ {
+ index,
+ shouldExist = true,
+ timeout = defaultTimeout,
+ }: WaitOptions & { shouldExist?: boolean } = {},
+) => {
+ const target = findElement(selector, index);
+ try {
+ if (shouldExist) {
+ await waitFor(target).toExist().withTimeout(timeout);
+ } else {
+ await waitFor(target).not.toExist().withTimeout(timeout);
+ }
+ return shouldExist;
+ } catch {
+ return !shouldExist;
+ }
+};
+
+export const isDisplayed = async (selector: Selector, index?: number) => {
+ try {
+ await expect(findElement(selector, index)).toBeVisible();
+ return true;
+ } catch {
+ return false;
+ }
+};
+
+/** Polls until `predicate` holds, then returns `true`; returns `false` once `timeout` elapses. */
+export const waitUntil = async (
+ predicate: () => Promise,
+ timeout = defaultTimeout,
+ interval = 500,
+) => {
+ const deadline = Date.now() + timeout;
+ while (Date.now() < deadline) {
+ if (await predicate()) {
+ return true;
+ }
+ await new Promise((resolve) => setTimeout(resolve, interval));
+ }
+ return predicate();
+};
+
+/** Number of elements currently matching `selector` (Detox has no count query of its own). */
+export const count = async (selector: Selector) => {
+ try {
+ const attributes = await element(selector).getAttributes();
+ return 'elements' in attributes ? attributes.elements.length : 1;
+ } catch {
+ return 0;
+ }
+};
+
+/** Waits until `selector` matches exactly `expected` elements and returns the last count seen. */
+export const waitForCount = async (selector: Selector, expected: number, timeout?: number) => {
+ let actual = 0;
+ await waitUntil(async () => {
+ actual = await count(selector);
+ return actual === expected;
+ }, timeout);
+ return actual;
+};
+
+/** Waits until `selector` (or its `index`-th match) shows `text` and returns the text it shows. */
+export const waitForText = async (
+ selector: Selector,
+ text: string,
+ { index = 0, mustBeEqual = true, timeout }: WaitOptions & { mustBeEqual?: boolean } = {},
+) => {
+ let actual = '';
+ await waitUntil(async () => {
+ actual = await textOf(selector, index);
+ return mustBeEqual ? actual === text : actual.includes(text);
+ }, timeout);
+ return actual;
+};
+
+export const textOf = async (selector: Selector, index = 0) => {
+ try {
+ const attributes = await element(selector).getAttributes();
+ const match = 'elements' in attributes ? attributes.elements[index] : attributes;
+ return match?.text ?? match?.label ?? '';
+ } catch {
+ return '';
+ }
+};
diff --git a/examples/E2ETestApp/e2e/support/StreamTestCase.ts b/examples/E2ETestApp/e2e/support/StreamTestCase.ts
new file mode 100644
index 0000000000..4a4ddb1b9a
--- /dev/null
+++ b/examples/E2ETestApp/e2e/support/StreamTestCase.ts
@@ -0,0 +1,61 @@
+import { afterEach, beforeEach, expect as jestExpect } from '@jest/globals';
+
+import { dismissAnrDialog } from './AndroidSystemDialogs';
+
+import { MockServer } from '../mock-server/MockServer';
+import { BackendRobot, ParticipantRobot, UserRobot } from '../robots';
+
+/**
+ * Per-test fixture, the counterpart of `StreamTestCase` on iOS and Android: before each test it
+ * starts a fresh mock server and relaunches the app pointed at it; after each test it stops the
+ * server.
+ *
+ * describe('MessageListTests', () => {
+ * const { userRobot, participantRobot, backendRobot } = setUpStreamTestCase();
+ * it('test_...', async () => { ... });
+ * });
+ */
+export class StreamTestCase {
+ readonly mockServer = new MockServer();
+ readonly userRobot = new UserRobot();
+ readonly backendRobot = new BackendRobot(this.mockServer);
+ readonly participantRobot = new ParticipantRobot(this.mockServer);
+}
+
+/** `describe` + `it` names `MessageListTests test_x` → `test_x`, which names the mock server log. */
+const currentTestName = () =>
+ (jestExpect.getState().currentTestName ?? 'unknown')
+ .split(' ')
+ .pop()!
+ .replace(/[^\w-]/g, '_');
+
+export const setUpStreamTestCase = (): StreamTestCase => {
+ const testCase = new StreamTestCase();
+
+ beforeEach(async () => {
+ await testCase.mockServer.start(currentTestName());
+ if (device.getPlatform() === 'android') {
+ dismissAnrDialog();
+ }
+ await device.launchApp({
+ launchArgs: {
+ MOCK_SERVER_URL: testCase.mockServer.appUrl,
+ // iOS: Detox's idle tracking can wedge on RN's UIManager shadow queue (its pending-work
+ // counter underflows to 2^64-1), leaving the app "busy" until the test times out. Every
+ // robot action and assert waits explicitly, like the native XCUITest suites, so it runs
+ // without that synchronization. Android's Espresso synchronization stays on.
+ detoxEnableSynchronization: device.getPlatform() === 'ios' ? 0 : 1,
+ },
+ newInstance: true,
+ // No `permissions`: the app asks for none, and on iOS Detox applies each one with
+ // `applesimutils --restartSB`, restarting SpringBoard per permission on every launch
+ // (minutes per test on CI).
+ });
+ });
+
+ afterEach(async () => {
+ await testCase.mockServer.stop();
+ });
+
+ return testCase;
+};
diff --git a/examples/E2ETestApp/e2e/support/step.ts b/examples/E2ETestApp/e2e/support/step.ts
new file mode 100644
index 0000000000..6ff6d18688
--- /dev/null
+++ b/examples/E2ETestApp/e2e/support/step.ts
@@ -0,0 +1,14 @@
+/**
+ * A GIVEN / WHEN / THEN step, like `step("...") { }` on Android and `GIVEN("...") { }` on iOS.
+ * A failure is reported with the step it happened in.
+ */
+export const step = async (name: string, body: () => PromiseLike) => {
+ try {
+ await body();
+ } catch (error) {
+ if (error instanceof Error) {
+ error.message = `[${name}] ${error.message}`;
+ }
+ throw error;
+ }
+};
diff --git a/examples/E2ETestApp/e2e/tests/ChannelListTests.e2e.ts b/examples/E2ETestApp/e2e/tests/ChannelListTests.e2e.ts
new file mode 100644
index 0000000000..9a742a8e80
--- /dev/null
+++ b/examples/E2ETestApp/e2e/tests/ChannelListTests.e2e.ts
@@ -0,0 +1,43 @@
+import { describe, it } from '@jest/globals';
+
+import { step } from '../support/step';
+import { setUpStreamTestCase } from '../support/StreamTestCase';
+
+describe('ChannelListTests', () => {
+ const { backendRobot, participantRobot, userRobot } = setUpStreamTestCase();
+ const sampleText = 'Test';
+
+ it('test_channelListShowsGeneratedChannels', async () => {
+ await step('GIVEN backend has 3 channels', () =>
+ backendRobot.generateChannels({ channelsCount: 3, channelNames: ['Alpha', 'Beta', 'Gamma'] }),
+ );
+ await step('WHEN user logs in', () => userRobot.login().waitForChannelListToLoad());
+ await step('THEN user observes all channels in the list', () =>
+ userRobot.assertChannelCount(3).assertChannelAvatar(),
+ );
+ });
+
+ it('test_channelPreviewUpdates_whenParticipantSendsMessage', async () => {
+ await step('GIVEN user opens a channel', () => userRobot.login().openChannel());
+ await step('WHEN participant sends a message', () => participantRobot.sendMessage(sampleText));
+ await step('AND user goes back to the channel list', () =>
+ userRobot.assertMessage(sampleText).moveToChannelListFromMessageList(),
+ );
+ await step('THEN user observes the new message in preview', () =>
+ userRobot.assertMessageInChannelPreview(sampleText, false).assertChannelAvatar(),
+ );
+ });
+
+ it('test_channelPreviewUpdates_whenUserSendsMessage', async () => {
+ await step('GIVEN user opens a channel', () => userRobot.login().openChannel());
+ await step('WHEN user sends a message', () =>
+ userRobot.sendMessage(sampleText).assertMessage(sampleText),
+ );
+ await step('AND user goes back to the channel list', () =>
+ userRobot.moveToChannelListFromMessageList(),
+ );
+ await step('THEN user observes the new message in preview', () =>
+ userRobot.assertMessageInChannelPreview(sampleText, true),
+ );
+ });
+});
diff --git a/examples/E2ETestApp/e2e/tests/MessageListTests.e2e.ts b/examples/E2ETestApp/e2e/tests/MessageListTests.e2e.ts
new file mode 100644
index 0000000000..265ed0d70d
--- /dev/null
+++ b/examples/E2ETestApp/e2e/tests/MessageListTests.e2e.ts
@@ -0,0 +1,44 @@
+import { describe, it } from '@jest/globals';
+
+import { MessageDeliveryStatus } from '../mock-server/DataTypes';
+import { step } from '../support/step';
+import { setUpStreamTestCase } from '../support/StreamTestCase';
+
+describe('MessageListTests', () => {
+ const { backendRobot, participantRobot, userRobot } = setUpStreamTestCase();
+ const sampleText = 'Test';
+
+ it('test_messageListUpdates_whenUserSendsMessage', async () => {
+ await step('GIVEN user opens a channel', () => userRobot.login().openChannel());
+ await step('WHEN user sends a message', () => userRobot.sendMessage(sampleText));
+ await step('THEN message list updates', () =>
+ userRobot
+ .assertMessage(sampleText)
+ .assertMessageAuthor(true)
+ .assertMessageDeliveryStatus(MessageDeliveryStatus.SENT),
+ );
+ });
+
+ it('test_messageListUpdates_whenParticipantSendsMessage', async () => {
+ await step('GIVEN user opens a channel', () => userRobot.login().openChannel());
+ await step('WHEN participant sends a message', () => participantRobot.sendMessage(sampleText));
+ await step('THEN user receives a message', () =>
+ userRobot.assertMessage(sampleText).assertMessageAuthor(false),
+ );
+ });
+
+ it('test_typingIndicator', async () => {
+ await step('GIVEN user opens the channel', async () => {
+ await backendRobot.generateChannels({ channelsCount: 1, messagesCount: 1 });
+ await userRobot.login().openChannel();
+ });
+ await step('WHEN participant starts typing', () => participantRobot.startTyping());
+ await step('THEN user observes typing indicator is shown', () =>
+ userRobot.assertTypingIndicator(true),
+ );
+ await step('WHEN participant stops typing', () => participantRobot.stopTyping());
+ await step('THEN user observes typing indicator has disappeared', () =>
+ userRobot.assertTypingIndicator(false),
+ );
+ });
+});
diff --git a/examples/E2ETestApp/e2e/tsconfig.json b/examples/E2ETestApp/e2e/tsconfig.json
new file mode 100644
index 0000000000..2f08e6cc4d
--- /dev/null
+++ b/examples/E2ETestApp/e2e/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../tsconfig.json",
+ "compilerOptions": {
+ "lib": ["es2022", "dom"],
+ "types": ["detox/globals"]
+ },
+ "include": ["./**/*.ts"],
+ "exclude": []
+}
diff --git a/examples/E2ETestApp/index.js b/examples/E2ETestApp/index.js
new file mode 100644
index 0000000000..d2660dcb40
--- /dev/null
+++ b/examples/E2ETestApp/index.js
@@ -0,0 +1,7 @@
+import 'react-native-gesture-handler';
+import { AppRegistry } from 'react-native';
+
+import App from './App';
+import { name as appName } from './app.json';
+
+AppRegistry.registerComponent(appName, () => App);
diff --git a/examples/E2ETestApp/ios/.xcode.env b/examples/E2ETestApp/ios/.xcode.env
new file mode 100644
index 0000000000..3d5782c715
--- /dev/null
+++ b/examples/E2ETestApp/ios/.xcode.env
@@ -0,0 +1,11 @@
+# This `.xcode.env` file is versioned and is used to source the environment
+# used when running script phases inside Xcode.
+# To customize your local environment, you can create an `.xcode.env.local`
+# file that is not versioned.
+
+# NODE_BINARY variable contains the PATH to the node executable.
+#
+# Customize the NODE_BINARY variable here.
+# For example, to use nvm with brew, add the following line
+# . "$(brew --prefix nvm)/nvm.sh" --no-use
+export NODE_BINARY=$(command -v node)
diff --git a/examples/E2ETestApp/ios/E2ETestApp.xcodeproj/project.pbxproj b/examples/E2ETestApp/ios/E2ETestApp.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000..756385091b
--- /dev/null
+++ b/examples/E2ETestApp/ios/E2ETestApp.xcodeproj/project.pbxproj
@@ -0,0 +1,498 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 54;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 0C80B921A6F3F58F76C31292 /* libPods-E2ETestApp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-E2ETestApp.a */; };
+ 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
+ 761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; };
+ 761780EF2CA45674006654EF /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EE2CA45674006654EF /* SceneDelegate.swift */; };
+ 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
+ AE4AFD92A8A3756E73E2B1AB /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 13B07F961A680F5B00A75B9A /* E2ETestApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = E2ETestApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = E2ETestApp/Images.xcassets; sourceTree = ""; };
+ 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = E2ETestApp/Info.plist; sourceTree = ""; };
+ 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = E2ETestApp/PrivacyInfo.xcprivacy; sourceTree = ""; };
+ 3B4392A12AC88292D35C810B /* Pods-E2ETestApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-E2ETestApp.debug.xcconfig"; path = "Target Support Files/Pods-E2ETestApp/Pods-E2ETestApp.debug.xcconfig"; sourceTree = ""; };
+ 5709B34CF0A7D63546082F79 /* Pods-E2ETestApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-E2ETestApp.release.xcconfig"; path = "Target Support Files/Pods-E2ETestApp/Pods-E2ETestApp.release.xcconfig"; sourceTree = ""; };
+ 5DCACB8F33CDC322A6C60F78 /* libPods-E2ETestApp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-E2ETestApp.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 761780EC2CA45674006654EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = E2ETestApp/AppDelegate.swift; sourceTree = ""; };
+ 761780EE2CA45674006654EF /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SceneDelegate.swift; path = E2ETestApp/SceneDelegate.swift; sourceTree = ""; };
+ 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = E2ETestApp/LaunchScreen.storyboard; sourceTree = ""; };
+ ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 0C80B921A6F3F58F76C31292 /* libPods-E2ETestApp.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 13B07FAE1A68108700A75B9A /* E2ETestApp */ = {
+ isa = PBXGroup;
+ children = (
+ 13B07FB51A68108700A75B9A /* Images.xcassets */,
+ 761780EC2CA45674006654EE /* AppDelegate.swift */,
+ 761780EE2CA45674006654EF /* SceneDelegate.swift */,
+ 13B07FB61A68108700A75B9A /* Info.plist */,
+ 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */,
+ 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */,
+ );
+ name = E2ETestApp;
+ sourceTree = "";
+ };
+ 2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
+ 5DCACB8F33CDC322A6C60F78 /* libPods-E2ETestApp.a */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ 832341AE1AAA6A7D00B99B32 /* Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ );
+ name = Libraries;
+ sourceTree = "";
+ };
+ 83CBB9F61A601CBA00E9B192 = {
+ isa = PBXGroup;
+ children = (
+ 13B07FAE1A68108700A75B9A /* E2ETestApp */,
+ 832341AE1AAA6A7D00B99B32 /* Libraries */,
+ 83CBBA001A601CBA00E9B192 /* Products */,
+ 2D16E6871FA4F8E400B85C8A /* Frameworks */,
+ BBD78D7AC51CEA395F1C20DB /* Pods */,
+ );
+ indentWidth = 2;
+ sourceTree = "";
+ tabWidth = 2;
+ usesTabs = 0;
+ };
+ 83CBBA001A601CBA00E9B192 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 13B07F961A680F5B00A75B9A /* E2ETestApp.app */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ BBD78D7AC51CEA395F1C20DB /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ 3B4392A12AC88292D35C810B /* Pods-E2ETestApp.debug.xcconfig */,
+ 5709B34CF0A7D63546082F79 /* Pods-E2ETestApp.release.xcconfig */,
+ );
+ path = Pods;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 13B07F861A680F5B00A75B9A /* E2ETestApp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "E2ETestApp" */;
+ buildPhases = (
+ C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */,
+ 13B07F871A680F5B00A75B9A /* Sources */,
+ 13B07F8C1A680F5B00A75B9A /* Frameworks */,
+ 13B07F8E1A680F5B00A75B9A /* Resources */,
+ 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
+ 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */,
+ E235C05ADACE081382539298 /* [CP] Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = E2ETestApp;
+ productName = E2ETestApp;
+ productReference = 13B07F961A680F5B00A75B9A /* E2ETestApp.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 83CBB9F71A601CBA00E9B192 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 1210;
+ TargetAttributes = {
+ 13B07F861A680F5B00A75B9A = {
+ LastSwiftMigration = 1120;
+ };
+ };
+ };
+ buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "E2ETestApp" */;
+ compatibilityVersion = "Xcode 12.0";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 83CBB9F61A601CBA00E9B192;
+ productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 13B07F861A680F5B00A75B9A /* E2ETestApp */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 13B07F8E1A680F5B00A75B9A /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
+ 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
+ AE4AFD92A8A3756E73E2B1AB /* PrivacyInfo.xcprivacy in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/.xcode.env.local",
+ "$(SRCROOT)/.xcode.env",
+ );
+ name = "Bundle React Native code and images";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "set -e\n\nWITH_ENVIRONMENT=\"$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"$REACT_NATIVE_PATH/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"\\\"$WITH_ENVIRONMENT\\\" \\\"$REACT_NATIVE_XCODE\\\"\"\n";
+ };
+ 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-E2ETestApp/Pods-E2ETestApp-frameworks-${CONFIGURATION}-input-files.xcfilelist",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-E2ETestApp/Pods-E2ETestApp-frameworks-${CONFIGURATION}-output-files.xcfilelist",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-E2ETestApp/Pods-E2ETestApp-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-E2ETestApp-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ E235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-E2ETestApp/Pods-E2ETestApp-resources-${CONFIGURATION}-input-files.xcfilelist",
+ );
+ name = "[CP] Copy Pods Resources";
+ outputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-E2ETestApp/Pods-E2ETestApp-resources-${CONFIGURATION}-output-files.xcfilelist",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-E2ETestApp/Pods-E2ETestApp-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 13B07F871A680F5B00A75B9A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 761780ED2CA45674006654EE /* AppDelegate.swift in Sources */,
+ 761780EF2CA45674006654EF /* SceneDelegate.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 13B07F941A680F5B00A75B9A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 3B4392A12AC88292D35C810B /* Pods-E2ETestApp.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = 1;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = E2ETestApp/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.1;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0;
+ OTHER_LDFLAGS = (
+ "$(inherited)",
+ "-ObjC",
+ "-lc++",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = io.getstream.reactnative.e2etestapp;
+ PRODUCT_NAME = E2ETestApp;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Debug;
+ };
+ 13B07F951A680F5B00A75B9A /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 5709B34CF0A7D63546082F79 /* Pods-E2ETestApp.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = 1;
+ INFOPLIST_FILE = E2ETestApp/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.1;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0;
+ OTHER_LDFLAGS = (
+ "$(inherited)",
+ "-ObjC",
+ "-lc++",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = io.getstream.reactnative.e2etestapp;
+ PRODUCT_NAME = E2ETestApp;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Release;
+ };
+ 83CBBA201A601CBA00E9B192 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "c++20";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.1;
+ LD_RUNPATH_SEARCH_PATHS = (
+ /usr/lib/swift,
+ "$(inherited)",
+ );
+ LIBRARY_SEARCH_PATHS = (
+ "\"$(SDKROOT)/usr/lib/swift\"",
+ "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
+ "\"$(inherited)\"",
+ );
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ OTHER_CFLAGS = (
+ "$(inherited)",
+ "-DRCT_REMOVE_LEGACY_ARCH=1",
+ );
+ OTHER_CPLUSPLUSFLAGS = (
+ "$(OTHER_CFLAGS)",
+ "-DFOLLY_NO_CONFIG",
+ "-DFOLLY_MOBILE=1",
+ "-DFOLLY_USE_LIBCPP=1",
+ "-DFOLLY_CFG_NO_COROUTINES=1",
+ "-DFOLLY_HAVE_CLOCK_GETTIME=1",
+ "-DRCT_REMOVE_LEGACY_ARCH=1",
+ );
+ PODFILE_DIR = "$(SRCROOT)";
+ REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
+ SDKROOT = iphoneos;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
+ USE_HERMES = true;
+ };
+ name = Debug;
+ };
+ 83CBBA211A601CBA00E9B192 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "c++20";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = YES;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.1;
+ LD_RUNPATH_SEARCH_PATHS = (
+ /usr/lib/swift,
+ "$(inherited)",
+ );
+ LIBRARY_SEARCH_PATHS = (
+ "\"$(SDKROOT)/usr/lib/swift\"",
+ "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
+ "\"$(inherited)\"",
+ );
+ MTL_ENABLE_DEBUG_INFO = NO;
+ OTHER_CFLAGS = (
+ "$(inherited)",
+ "-DRCT_REMOVE_LEGACY_ARCH=1",
+ );
+ OTHER_CPLUSPLUSFLAGS = (
+ "$(OTHER_CFLAGS)",
+ "-DFOLLY_NO_CONFIG",
+ "-DFOLLY_MOBILE=1",
+ "-DFOLLY_USE_LIBCPP=1",
+ "-DFOLLY_CFG_NO_COROUTINES=1",
+ "-DFOLLY_HAVE_CLOCK_GETTIME=1",
+ "-DRCT_REMOVE_LEGACY_ARCH=1",
+ );
+ PODFILE_DIR = "$(SRCROOT)";
+ REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
+ SDKROOT = iphoneos;
+ USE_HERMES = true;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "E2ETestApp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 13B07F941A680F5B00A75B9A /* Debug */,
+ 13B07F951A680F5B00A75B9A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "E2ETestApp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 83CBBA201A601CBA00E9B192 /* Debug */,
+ 83CBBA211A601CBA00E9B192 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
+}
diff --git a/examples/E2ETestApp/ios/E2ETestApp.xcodeproj/xcshareddata/xcschemes/E2ETestApp.xcscheme b/examples/E2ETestApp/ios/E2ETestApp.xcodeproj/xcshareddata/xcschemes/E2ETestApp.xcscheme
new file mode 100644
index 0000000000..cd9bdbadeb
--- /dev/null
+++ b/examples/E2ETestApp/ios/E2ETestApp.xcodeproj/xcshareddata/xcschemes/E2ETestApp.xcscheme
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/E2ETestApp/ios/E2ETestApp.xcworkspace/contents.xcworkspacedata b/examples/E2ETestApp/ios/E2ETestApp.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000000..bd672bb7e5
--- /dev/null
+++ b/examples/E2ETestApp/ios/E2ETestApp.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/examples/E2ETestApp/ios/E2ETestApp/AppDelegate.swift b/examples/E2ETestApp/ios/E2ETestApp/AppDelegate.swift
new file mode 100644
index 0000000000..0d14d1b0ac
--- /dev/null
+++ b/examples/E2ETestApp/ios/E2ETestApp/AppDelegate.swift
@@ -0,0 +1,11 @@
+import UIKit
+
+@main
+class AppDelegate: UIResponder, UIApplicationDelegate {
+ func application(
+ _ application: UIApplication,
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
+ ) -> Bool {
+ true
+ }
+}
diff --git a/examples/E2ETestApp/ios/E2ETestApp/Images.xcassets/AppIcon.appiconset/Contents.json b/examples/E2ETestApp/ios/E2ETestApp/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000000..81213230de
--- /dev/null
+++ b/examples/E2ETestApp/ios/E2ETestApp/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,53 @@
+{
+ "images" : [
+ {
+ "idiom" : "iphone",
+ "scale" : "2x",
+ "size" : "20x20"
+ },
+ {
+ "idiom" : "iphone",
+ "scale" : "3x",
+ "size" : "20x20"
+ },
+ {
+ "idiom" : "iphone",
+ "scale" : "2x",
+ "size" : "29x29"
+ },
+ {
+ "idiom" : "iphone",
+ "scale" : "3x",
+ "size" : "29x29"
+ },
+ {
+ "idiom" : "iphone",
+ "scale" : "2x",
+ "size" : "40x40"
+ },
+ {
+ "idiom" : "iphone",
+ "scale" : "3x",
+ "size" : "40x40"
+ },
+ {
+ "idiom" : "iphone",
+ "scale" : "2x",
+ "size" : "60x60"
+ },
+ {
+ "idiom" : "iphone",
+ "scale" : "3x",
+ "size" : "60x60"
+ },
+ {
+ "idiom" : "ios-marketing",
+ "scale" : "1x",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/examples/E2ETestApp/ios/E2ETestApp/Images.xcassets/Contents.json b/examples/E2ETestApp/ios/E2ETestApp/Images.xcassets/Contents.json
new file mode 100644
index 0000000000..2d92bd53fd
--- /dev/null
+++ b/examples/E2ETestApp/ios/E2ETestApp/Images.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/examples/E2ETestApp/ios/E2ETestApp/Info.plist b/examples/E2ETestApp/ios/E2ETestApp/Info.plist
new file mode 100644
index 0000000000..cf6c5bcfd6
--- /dev/null
+++ b/examples/E2ETestApp/ios/E2ETestApp/Info.plist
@@ -0,0 +1,78 @@
+
+
+
+
+ CADisableMinimumFrameDurationOnPhone
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleDisplayName
+ E2ETestApp
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ $(MARKETING_VERSION)
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ $(CURRENT_PROJECT_VERSION)
+ LSRequiresIPhoneOS
+
+ NSAppTransportSecurity
+
+
+ NSAllowsArbitraryLoads
+
+ NSAllowsLocalNetworking
+
+
+ NSLocationWhenInUseUsageDescription
+
+ RCTNewArchEnabled
+
+ UIApplicationSceneManifest
+
+ UIApplicationSupportsMultipleScenes
+
+ UISceneConfigurations
+
+ UIWindowSceneSessionRoleApplication
+
+
+ UISceneConfigurationName
+ Default Configuration
+ UISceneDelegateClassName
+ $(PRODUCT_MODULE_NAME).SceneDelegate
+
+
+
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIRequiredDeviceCapabilities
+
+ arm64
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+
+ UIViewControllerBasedStatusBarAppearance
+
+
+
diff --git a/examples/E2ETestApp/ios/E2ETestApp/LaunchScreen.storyboard b/examples/E2ETestApp/ios/E2ETestApp/LaunchScreen.storyboard
new file mode 100644
index 0000000000..600e8dc84b
--- /dev/null
+++ b/examples/E2ETestApp/ios/E2ETestApp/LaunchScreen.storyboard
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/E2ETestApp/ios/E2ETestApp/PrivacyInfo.xcprivacy b/examples/E2ETestApp/ios/E2ETestApp/PrivacyInfo.xcprivacy
new file mode 100644
index 0000000000..fc90547a7a
--- /dev/null
+++ b/examples/E2ETestApp/ios/E2ETestApp/PrivacyInfo.xcprivacy
@@ -0,0 +1,37 @@
+
+
+
+
+ NSPrivacyAccessedAPITypes
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryFileTimestamp
+ NSPrivacyAccessedAPITypeReasons
+
+ C617.1
+
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategorySystemBootTime
+ NSPrivacyAccessedAPITypeReasons
+
+ 35F9.1
+
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryUserDefaults
+ NSPrivacyAccessedAPITypeReasons
+
+ CA92.1
+
+
+
+ NSPrivacyCollectedDataTypes
+
+ NSPrivacyTracking
+
+
+
diff --git a/examples/E2ETestApp/ios/E2ETestApp/SceneDelegate.swift b/examples/E2ETestApp/ios/E2ETestApp/SceneDelegate.swift
new file mode 100644
index 0000000000..b5c4d45824
--- /dev/null
+++ b/examples/E2ETestApp/ios/E2ETestApp/SceneDelegate.swift
@@ -0,0 +1,56 @@
+import React
+import React_RCTAppDelegate
+import ReactAppDependencyProvider
+import UIKit
+
+class SceneDelegate: RCTDefaultReactNativeFactoryDelegate, UIWindowSceneDelegate {
+ var window: UIWindow?
+ var reactNativeFactory: RCTReactNativeFactory?
+
+ func scene(
+ _ scene: UIScene,
+ willConnectTo session: UISceneSession,
+ options connectionOptions: UIScene.ConnectionOptions
+ ) {
+ guard let windowScene = scene as? UIWindowScene else {
+ return
+ }
+
+ dependencyProvider = RCTAppDependencyProvider()
+ reactNativeFactory = RCTReactNativeFactory(delegate: self)
+ window = UIWindow(windowScene: windowScene)
+
+ #if DEBUG
+ let devMenuConfiguration = RCTDevMenuConfiguration(
+ devMenuEnabled: true,
+ shakeGestureEnabled: true,
+ keyboardShortcutsEnabled: true
+ )
+ reactNativeFactory?.devMenuConfiguration = devMenuConfiguration
+ #endif
+
+ reactNativeFactory?.startReactNative(
+ withModuleName: "E2ETestApp",
+ in: window,
+ connectionOptions: connectionOptions
+ )
+
+
+ }
+
+ func scene(_ scene: UIScene, openURLContexts URLContexts: Set) {
+ RCTLinkingManager.scene(scene, openURLContexts: URLContexts)
+ }
+
+ func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
+ RCTLinkingManager.scene(scene, continue: userActivity)
+ }
+
+ override func bundleURL() -> URL? {
+ #if DEBUG
+ RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
+ #else
+ Bundle.main.url(forResource: "main", withExtension: "jsbundle")
+ #endif
+ }
+}
diff --git a/examples/E2ETestApp/ios/Podfile b/examples/E2ETestApp/ios/Podfile
new file mode 100644
index 0000000000..10e8a8c808
--- /dev/null
+++ b/examples/E2ETestApp/ios/Podfile
@@ -0,0 +1,45 @@
+# Resolve react_native_pods.rb with node to allow for hoisting
+require Pod::Executable.execute_command('node', ['-p',
+ 'require.resolve(
+ "react-native/scripts/react_native_pods.rb",
+ {paths: [process.argv[1]]},
+ )', __dir__]).strip
+
+platform :ios, min_ios_version_supported
+prepare_react_native_project!
+
+linkage = ENV['USE_FRAMEWORKS']
+if linkage != nil
+ Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
+ use_frameworks! :linkage => linkage.to_sym
+end
+
+target 'E2ETestApp' do
+ config = use_native_modules!
+
+ use_react_native!(
+ :path => config[:reactNativePath],
+ # An absolute path to your application root.
+ :app_path => "#{Pod::Config.instance.installation_root}/.."
+ )
+
+ post_install do |installer|
+ react_native_post_install(
+ installer,
+ config[:reactNativePath],
+ :mac_catalyst_enabled => false,
+ # CI sets USE_CCACHE=1 so compiled objects are reused across runs.
+ :ccache_enabled => ENV['USE_CCACHE'] == '1',
+ )
+
+ # Some pods pin an iOS deployment target (e.g. RNSVG at 12.4) below the range supported by
+ # current Xcode. Clamp them up to the app's minimum, as the SampleApp does.
+ installer.pods_project.targets.each do |target|
+ target.build_configurations.each do |config|
+ if config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'].to_f < min_ios_version_supported.to_f
+ config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = min_ios_version_supported
+ end
+ end
+ end
+ end
+end
diff --git a/examples/E2ETestApp/ios/Podfile.lock b/examples/E2ETestApp/ios/Podfile.lock
new file mode 100644
index 0000000000..cb27ec2bdd
--- /dev/null
+++ b/examples/E2ETestApp/ios/Podfile.lock
@@ -0,0 +1,2554 @@
+PODS:
+ - boost (1.84.0):
+ - ReactNativeDependencies
+ - DoubleConversion (1.1.6):
+ - ReactNativeDependencies
+ - fast_float (8.0.0):
+ - ReactNativeDependencies
+ - FBLazyVector (0.88.0):
+ - React-Core-prebuilt
+ - fmt (12.1.0):
+ - ReactNativeDependencies
+ - glog (0.3.5):
+ - ReactNativeDependencies
+ - hermes-engine (260318099.0.4):
+ - hermes-engine/Pre-built (= 260318099.0.4)
+ - hermes-engine/Pre-built (260318099.0.4)
+ - RCT-Folly (2024.11.18.00):
+ - RCT-Folly/Default (= 2024.11.18.00)
+ - ReactNativeDependencies
+ - RCT-Folly/Default (2024.11.18.00):
+ - ReactNativeDependencies
+ - RCTDeprecation (0.88.0):
+ - React-Core-prebuilt
+ - RCTRequired (0.88.0):
+ - React-Core-prebuilt
+ - RCTSwiftUI (0.88.0)
+ - RCTSwiftUIWrapper (0.88.0):
+ - RCTSwiftUI
+ - RCTTypeSafety (0.88.0):
+ - FBLazyVector (= 0.88.0)
+ - RCTRequired (= 0.88.0)
+ - React-Core (= 0.88.0)
+ - React (0.88.0):
+ - React-Core (= 0.88.0)
+ - React-Core/DevSupport (= 0.88.0)
+ - React-Core/RCTWebSocket (= 0.88.0)
+ - React-RCTActionSheet (= 0.88.0)
+ - React-RCTAnimation (= 0.88.0)
+ - React-RCTBlob (= 0.88.0)
+ - React-RCTImage (= 0.88.0)
+ - React-RCTLinking (= 0.88.0)
+ - React-RCTNetwork (= 0.88.0)
+ - React-RCTSettings (= 0.88.0)
+ - React-RCTText (= 0.88.0)
+ - React-RCTVibration (= 0.88.0)
+ - React-bridging (0.88.0):
+ - React-callinvoker
+ - React-Core-prebuilt
+ - React-jsi
+ - React-timing
+ - ReactNativeDependencies
+ - React-callinvoker (0.88.0):
+ - React-callinvoker/callinvokerUmbrella (= 0.88.0)
+ - React-cxxstableapi
+ - React-callinvoker/callinvokerUmbrella (0.88.0):
+ - React-cxxstableapi
+ - React-Core (0.88.0):
+ - React-Core-prebuilt
+ - React-Core/Default (= 0.88.0)
+ - React-Core-prebuilt (0.88.0):
+ - ReactNativeDependencies
+ - React-Core/CoreModulesHeaders (0.88.0):
+ - React-Core-prebuilt
+ - React-Core/Default (0.88.0):
+ - React-Core-prebuilt
+ - React-Core/DevSupport (0.88.0):
+ - React-Core-prebuilt
+ - React-Core/RCTActionSheetHeaders (0.88.0):
+ - React-Core-prebuilt
+ - React-Core/RCTAnimationHeaders (0.88.0):
+ - React-Core-prebuilt
+ - React-Core/RCTBlobHeaders (0.88.0):
+ - React-Core-prebuilt
+ - React-Core/RCTImageHeaders (0.88.0):
+ - React-Core-prebuilt
+ - React-Core/RCTLinkingHeaders (0.88.0):
+ - React-Core-prebuilt
+ - React-Core/RCTNetworkHeaders (0.88.0):
+ - React-Core-prebuilt
+ - React-Core/RCTSettingsHeaders (0.88.0):
+ - React-Core-prebuilt
+ - React-Core/RCTTextHeaders (0.88.0):
+ - React-Core-prebuilt
+ - React-Core/RCTVibrationHeaders (0.88.0):
+ - React-Core-prebuilt
+ - React-Core/RCTWebSocket (0.88.0):
+ - React-Core-prebuilt
+ - React-CoreModules (0.88.0):
+ - RCTTypeSafety (= 0.88.0)
+ - React-Core-prebuilt
+ - React-Core/CoreModulesHeaders (= 0.88.0)
+ - React-debug
+ - React-featureflags
+ - React-jsi (= 0.88.0)
+ - React-jsinspector
+ - React-jsinspectorcdp
+ - React-jsinspectortracing
+ - React-NativeModulesApple
+ - React-networking
+ - React-RCTBlob
+ - React-RCTFBReactNativeSpec
+ - React-RCTImage (= 0.88.0)
+ - React-runtimeexecutor
+ - React-utils
+ - ReactCommon
+ - ReactNativeDependencies
+ - React-cxxreact (0.88.0):
+ - hermes-engine
+ - React-callinvoker (= 0.88.0)
+ - React-Core-prebuilt
+ - React-debug (= 0.88.0)
+ - React-jserrorhandler (= 0.88.0)
+ - React-jsi (= 0.88.0)
+ - React-jsinspector
+ - React-jsinspectorcdp
+ - React-jsinspectortracing
+ - React-logger (= 0.88.0)
+ - React-perflogger (= 0.88.0)
+ - React-runtimeexecutor
+ - React-timing (= 0.88.0)
+ - React-utils
+ - ReactNativeDependencies
+ - React-cxxstableapi (0.88.0)
+ - React-debug (0.88.0):
+ - React-cxxstableapi
+ - React-debug/debugUmbrella (= 0.88.0)
+ - React-debug/redbox (= 0.88.0)
+ - React-debug/debugUmbrella (0.88.0):
+ - React-cxxstableapi
+ - React-debug/redbox (0.88.0):
+ - React-cxxstableapi
+ - React-defaultsnativemodule (0.88.0):
+ - hermes-engine
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-domnativemodule
+ - React-Fabric/animated
+ - React-featureflags
+ - React-featureflagsnativemodule
+ - React-idlecallbacksnativemodule
+ - React-intersectionobservernativemodule
+ - React-jsi
+ - React-jsiexecutor
+ - React-microtasksnativemodule
+ - React-mutationobservernativemodule
+ - React-RCTFBReactNativeSpec
+ - React-resizeobservernativemodule
+ - React-viewtransitionnativemodule
+ - React-webperformancenativemodule
+ - ReactNativeDependencies
+ - Yoga
+ - React-domnativemodule (0.88.0):
+ - hermes-engine
+ - React-bridging
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-Fabric
+ - React-Fabric/bridging
+ - React-FabricComponents
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-RCTFBReactNativeSpec
+ - React-runtimeexecutor
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - React-Fabric (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric/animated (= 0.88.0)
+ - React-Fabric/animationbackend (= 0.88.0)
+ - React-Fabric/animations (= 0.88.0)
+ - React-Fabric/attributedstring (= 0.88.0)
+ - React-Fabric/bridging (= 0.88.0)
+ - React-Fabric/componentregistry (= 0.88.0)
+ - React-Fabric/componentregistrynative (= 0.88.0)
+ - React-Fabric/components (= 0.88.0)
+ - React-Fabric/consistency (= 0.88.0)
+ - React-Fabric/core (= 0.88.0)
+ - React-Fabric/dom (= 0.88.0)
+ - React-Fabric/imagemanager (= 0.88.0)
+ - React-Fabric/leakchecker (= 0.88.0)
+ - React-Fabric/mounting (= 0.88.0)
+ - React-Fabric/observers (= 0.88.0)
+ - React-Fabric/scheduler (= 0.88.0)
+ - React-Fabric/telemetry (= 0.88.0)
+ - React-Fabric/uimanager (= 0.88.0)
+ - React-Fabric/viewtransition (= 0.88.0)
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/animated (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric/animationbackend
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/animationbackend (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/animations (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/attributedstring (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/bridging (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/componentregistry (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/componentregistrynative (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/components (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric/components/legacyviewmanagerinterop (= 0.88.0)
+ - React-Fabric/components/root (= 0.88.0)
+ - React-Fabric/components/scrollview (= 0.88.0)
+ - React-Fabric/components/view (= 0.88.0)
+ - React-Fabric/components/viewUmbrella (= 0.88.0)
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/components/legacyviewmanagerinterop (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/components/root (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/components/scrollview (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/components/view (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-renderercss
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - React-Fabric/components/viewUmbrella (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/consistency (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/core (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/dom (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/imagemanager (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/leakchecker (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/mounting (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-jsinspectortracing
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/observers (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric/observers/events (= 0.88.0)
+ - React-Fabric/observers/intersection (= 0.88.0)
+ - React-Fabric/observers/mutation (= 0.88.0)
+ - React-Fabric/observers/resize (= 0.88.0)
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/observers/events (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/observers/intersection (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/observers/mutation (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/observers/resize (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/scheduler (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric/animationbackend
+ - React-Fabric/observers/events
+ - React-Fabric/viewtransition
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-performancecdpmetrics
+ - React-performancetimeline
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/telemetry (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/uimanager (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric/uimanager/consistency (= 0.88.0)
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererconsistency
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/uimanager/consistency (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererconsistency
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-Fabric/viewtransition (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-FabricComponents (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-FabricComponents/components (= 0.88.0)
+ - React-FabricComponents/textlayoutmanager (= 0.88.0)
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-RCTFBReactNativeSpec
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - React-FabricComponents/components (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-FabricComponents/components/inputaccessory (= 0.88.0)
+ - React-FabricComponents/components/iostextinput (= 0.88.0)
+ - React-FabricComponents/components/modal (= 0.88.0)
+ - React-FabricComponents/components/rncore (= 0.88.0)
+ - React-FabricComponents/components/safeareaview (= 0.88.0)
+ - React-FabricComponents/components/switch (= 0.88.0)
+ - React-FabricComponents/components/text (= 0.88.0)
+ - React-FabricComponents/components/textinput (= 0.88.0)
+ - React-FabricComponents/components/unimplementedview (= 0.88.0)
+ - React-FabricComponents/components/virtualview (= 0.88.0)
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-RCTFBReactNativeSpec
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - React-FabricComponents/components/inputaccessory (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-RCTFBReactNativeSpec
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - React-FabricComponents/components/iostextinput (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-RCTFBReactNativeSpec
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - React-FabricComponents/components/modal (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-RCTFBReactNativeSpec
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - React-FabricComponents/components/rncore (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-RCTFBReactNativeSpec
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - React-FabricComponents/components/safeareaview (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-RCTFBReactNativeSpec
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - React-FabricComponents/components/switch (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-RCTFBReactNativeSpec
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - React-FabricComponents/components/text (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-RCTFBReactNativeSpec
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - React-FabricComponents/components/textinput (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-RCTFBReactNativeSpec
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - React-FabricComponents/components/unimplementedview (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-RCTFBReactNativeSpec
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - React-FabricComponents/components/virtualview (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-RCTFBReactNativeSpec
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - React-FabricComponents/textlayoutmanager (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-RCTFBReactNativeSpec
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - React-FabricImage (0.88.0):
+ - hermes-engine
+ - RCTRequired (= 0.88.0)
+ - RCTTypeSafety (= 0.88.0)
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-ImageManager
+ - React-jsi
+ - React-jsiexecutor (= 0.88.0)
+ - React-logger
+ - React-rendererdebug
+ - React-utils
+ - ReactCommon
+ - ReactNativeDependencies
+ - Yoga
+ - React-featureflags (0.88.0):
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-featureflags/featureflagsUmbrella (= 0.88.0)
+ - ReactNativeDependencies
+ - React-featureflags/featureflagsUmbrella (0.88.0):
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - ReactNativeDependencies
+ - React-featureflagsnativemodule (0.88.0):
+ - hermes-engine
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-featureflags
+ - React-jsi
+ - React-jsiexecutor
+ - React-RCTFBReactNativeSpec
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-graphics (0.88.0):
+ - hermes-engine
+ - React-Core-prebuilt
+ - React-featureflags
+ - React-jsi
+ - React-jsiexecutor
+ - React-rendererdebug
+ - React-utils
+ - ReactNativeDependencies
+ - React-hermes (0.88.0):
+ - hermes-engine
+ - React-Core-prebuilt
+ - React-cxxreact (= 0.88.0)
+ - React-cxxstableapi
+ - React-jsi
+ - React-jsiexecutor (= 0.88.0)
+ - React-jsinspector
+ - React-jsinspectorcdp
+ - React-jsinspectortracing
+ - React-jsitooling
+ - React-oscompat
+ - React-perflogger (= 0.88.0)
+ - React-runtimeexecutor
+ - ReactNativeDependencies
+ - React-idlecallbacksnativemodule (0.88.0):
+ - hermes-engine
+ - React-bridging
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-jsi
+ - React-jsiexecutor
+ - React-RCTFBReactNativeSpec
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-ImageManager (0.88.0):
+ - React-Core-prebuilt
+ - React-Core/Default
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-graphics
+ - React-rendererdebug
+ - React-utils
+ - ReactNativeDependencies
+ - React-intersectionobservernativemodule (0.88.0):
+ - hermes-engine
+ - React-bridging
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-Fabric
+ - React-Fabric/bridging
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-RCTFBReactNativeSpec
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - React-jserrorhandler (0.88.0):
+ - hermes-engine
+ - React-bridging
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-jsi
+ - ReactNativeDependencies
+ - React-jsi (0.88.0):
+ - hermes-engine
+ - React-Core-prebuilt
+ - ReactNativeDependencies
+ - React-jsiexecutor (0.88.0):
+ - hermes-engine
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-jserrorhandler
+ - React-jsi
+ - React-jsinspector
+ - React-jsinspectorcdp
+ - React-jsinspectortracing
+ - React-jsitooling
+ - React-perflogger
+ - React-runtimeexecutor
+ - React-utils
+ - ReactNativeDependencies
+ - React-jsinspector (0.88.0):
+ - hermes-engine
+ - React-Core-prebuilt
+ - React-featureflags
+ - React-jsi
+ - React-jsinspectorcdp
+ - React-jsinspectornetwork
+ - React-jsinspectortracing
+ - React-oscompat
+ - React-perflogger (= 0.88.0)
+ - React-runtimeexecutor
+ - React-utils
+ - ReactNativeDependencies
+ - React-jsinspectorcdp (0.88.0):
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - ReactNativeDependencies
+ - React-jsinspectornetwork (0.88.0):
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-jsinspectorcdp
+ - ReactNativeDependencies
+ - React-jsinspectortracing (0.88.0):
+ - hermes-engine
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-jsi
+ - React-jsinspectornetwork
+ - React-oscompat
+ - React-timing
+ - React-utils
+ - ReactNativeDependencies
+ - React-jsitooling (0.88.0):
+ - hermes-engine
+ - React-Core-prebuilt
+ - React-cxxreact (= 0.88.0)
+ - React-cxxstableapi
+ - React-debug
+ - React-jsi (= 0.88.0)
+ - React-jsinspector
+ - React-jsinspectorcdp
+ - React-jsinspectortracing
+ - React-runtimeexecutor
+ - React-utils
+ - ReactNativeDependencies
+ - React-jsitracing (0.88.0):
+ - React-jsi
+ - React-logger (0.88.0):
+ - React-Core-prebuilt
+ - ReactNativeDependencies
+ - React-Mapbuffer (0.88.0):
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - React-Mapbuffer/mapbufferUmbrella (= 0.88.0)
+ - ReactNativeDependencies
+ - React-Mapbuffer/mapbufferUmbrella (0.88.0):
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - ReactNativeDependencies
+ - React-microtasksnativemodule (0.88.0):
+ - hermes-engine
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-jsi
+ - React-jsiexecutor
+ - React-RCTFBReactNativeSpec
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-mutationobservernativemodule (0.88.0):
+ - hermes-engine
+ - React-bridging
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-Fabric
+ - React-Fabric/bridging
+ - React-Fabric/observers/mutation
+ - React-featureflags
+ - React-jsi
+ - React-jsiexecutor
+ - React-RCTFBReactNativeSpec
+ - React-runtimeexecutor
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - react-native-launch-arguments (4.1.1):
+ - React
+ - react-native-netinfo (12.0.1):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-ImageManager
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-renderercss
+ - React-rendererdebug
+ - React-utils
+ - ReactCodegen
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - react-native-safe-area-context (5.10.1):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-ImageManager
+ - React-jsi
+ - react-native-safe-area-context/common (= 5.10.1)
+ - react-native-safe-area-context/fabric (= 5.10.1)
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-renderercss
+ - React-rendererdebug
+ - React-utils
+ - ReactCodegen
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - react-native-safe-area-context/common (5.10.1):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-ImageManager
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-renderercss
+ - React-rendererdebug
+ - React-utils
+ - ReactCodegen
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - react-native-safe-area-context/fabric (5.10.1):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-ImageManager
+ - React-jsi
+ - react-native-safe-area-context/common
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-renderercss
+ - React-rendererdebug
+ - React-utils
+ - ReactCodegen
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - React-NativeModulesApple (0.88.0):
+ - hermes-engine
+ - React-bridging
+ - React-callinvoker
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-debug
+ - React-featureflags
+ - React-jsi
+ - React-jsinspector
+ - React-jsinspectorcdp
+ - React-runtimeexecutor
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - React-networking (0.88.0):
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-jsinspectornetwork
+ - React-jsinspectortracing
+ - React-performancetimeline
+ - React-timing
+ - ReactNativeDependencies
+ - React-oscompat (0.88.0):
+ - React-cxxstableapi
+ - React-perflogger (0.88.0):
+ - React-Core-prebuilt
+ - ReactNativeDependencies
+ - React-performancecdpmetrics (0.88.0):
+ - hermes-engine
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-jsi
+ - React-performancetimeline
+ - React-runtimeexecutor
+ - React-timing
+ - ReactNativeDependencies
+ - React-performancetimeline (0.88.0):
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-featureflags
+ - React-jsinspector
+ - React-jsinspectortracing
+ - React-perflogger
+ - React-timing
+ - ReactNativeDependencies
+ - React-RCTActionSheet (0.88.0):
+ - React-Core/RCTActionSheetHeaders (= 0.88.0)
+ - React-RCTAnimatedModuleProvider (0.88.0):
+ - hermes-engine
+ - React-Core
+ - React-Core-prebuilt
+ - React-Fabric/animated
+ - React-featureflags
+ - ReactCommon
+ - ReactNativeDependencies
+ - Yoga
+ - React-RCTAnimation (0.88.0):
+ - RCTTypeSafety
+ - React-Core-prebuilt
+ - React-Core/RCTAnimationHeaders
+ - React-debug
+ - React-featureflags
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFBReactNativeSpec
+ - ReactCommon
+ - ReactNativeDependencies
+ - React-RCTAppDelegate (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-Core-prebuilt
+ - React-CoreModules
+ - React-debug
+ - React-defaultsnativemodule
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-hermes
+ - React-jsitooling
+ - React-NativeModulesApple
+ - React-RCTAnimatedModuleProvider
+ - React-RCTFabric
+ - React-RCTFBReactNativeSpec
+ - React-RCTImage
+ - React-RCTLinking
+ - React-RCTNetwork
+ - React-RCTRuntime
+ - React-rendererdebug
+ - React-RuntimeApple
+ - React-RuntimeCore
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon
+ - ReactNativeDependencies
+ - React-RCTBlob (0.88.0):
+ - hermes-engine
+ - React-Core-prebuilt
+ - React-Core/RCTBlobHeaders
+ - React-Core/RCTWebSocket
+ - React-jsi
+ - React-jsinspector
+ - React-jsinspectorcdp
+ - React-NativeModulesApple
+ - React-RCTFBReactNativeSpec
+ - React-RCTNetwork
+ - ReactCommon
+ - ReactNativeDependencies
+ - React-RCTFabric (0.88.0):
+ - React-Core-prebuilt
+ - React-RCTFBReactNativeSpec (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFBReactNativeSpec/components (= 0.88.0)
+ - ReactCommon
+ - ReactNativeDependencies
+ - React-RCTFBReactNativeSpec/components (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-NativeModulesApple
+ - React-rendererdebug
+ - React-utils
+ - ReactCommon
+ - ReactNativeDependencies
+ - Yoga
+ - React-RCTImage (0.88.0):
+ - RCTTypeSafety
+ - React-Core-prebuilt
+ - React-Core/RCTImageHeaders
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFBReactNativeSpec
+ - React-RCTNetwork
+ - ReactCommon
+ - ReactNativeDependencies
+ - React-RCTLinking (0.88.0):
+ - React-Core/RCTLinkingHeaders (= 0.88.0)
+ - React-jsi (= 0.88.0)
+ - React-NativeModulesApple
+ - React-RCTFBReactNativeSpec
+ - ReactCommon
+ - ReactCommon/turbomodule/core (= 0.88.0)
+ - React-RCTNetwork (0.88.0):
+ - RCTTypeSafety
+ - React-Core-prebuilt
+ - React-Core/RCTNetworkHeaders
+ - React-debug
+ - React-featureflags
+ - React-jsi
+ - React-jsinspectorcdp
+ - React-jsinspectornetwork
+ - React-NativeModulesApple
+ - React-networking
+ - React-RCTFBReactNativeSpec
+ - ReactCommon
+ - ReactNativeDependencies
+ - React-RCTRuntime (0.88.0):
+ - React-Core-prebuilt
+ - React-RCTSettings (0.88.0):
+ - RCTTypeSafety
+ - React-Core-prebuilt
+ - React-Core/RCTSettingsHeaders
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFBReactNativeSpec
+ - ReactCommon
+ - ReactNativeDependencies
+ - React-RCTText (0.88.0):
+ - React-Core/RCTTextHeaders (= 0.88.0)
+ - Yoga
+ - React-RCTVibration (0.88.0):
+ - React-Core-prebuilt
+ - React-Core/RCTVibrationHeaders
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFBReactNativeSpec
+ - ReactCommon
+ - ReactNativeDependencies
+ - React-rendererconsistency (0.88.0)
+ - React-renderercss (0.88.0):
+ - React-debug
+ - React-utils
+ - React-rendererdebug (0.88.0):
+ - React-Core-prebuilt
+ - React-debug
+ - ReactNativeDependencies
+ - React-resizeobservernativemodule (0.88.0):
+ - hermes-engine
+ - React-bridging
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-Fabric
+ - React-Fabric/bridging
+ - React-Fabric/observers/resize
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-RCTFBReactNativeSpec
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - React-RuntimeApple (0.88.0):
+ - hermes-engine
+ - React-callinvoker
+ - React-Core-prebuilt
+ - React-Core/Default
+ - React-CoreModules
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-featureflags
+ - React-jserrorhandler
+ - React-jsi
+ - React-jsiexecutor
+ - React-jsinspector
+ - React-jsitooling
+ - React-Mapbuffer
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-RCTFBReactNativeSpec
+ - React-RuntimeCore
+ - React-runtimeexecutor
+ - React-RuntimeHermes
+ - React-runtimescheduler
+ - React-utils
+ - ReactNativeDependencies
+ - React-RuntimeCore (0.88.0):
+ - hermes-engine
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-Fabric
+ - React-featureflags
+ - React-jserrorhandler
+ - React-jsi
+ - React-jsiexecutor
+ - React-jsinspector
+ - React-jsitooling
+ - React-performancetimeline
+ - React-runtimeexecutor
+ - React-runtimescheduler
+ - React-utils
+ - ReactNativeDependencies
+ - React-runtimeexecutor (0.88.0):
+ - React-Core-prebuilt
+ - React-debug
+ - React-featureflags
+ - React-jsi (= 0.88.0)
+ - React-utils
+ - ReactNativeDependencies
+ - React-RuntimeHermes (0.88.0):
+ - hermes-engine
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-featureflags
+ - React-hermes
+ - React-jsi
+ - React-jsinspector
+ - React-jsinspectorcdp
+ - React-jsinspectortracing
+ - React-jsitooling
+ - React-jsitracing
+ - React-RuntimeCore
+ - React-runtimeexecutor
+ - React-utils
+ - ReactNativeDependencies
+ - React-runtimescheduler (0.88.0):
+ - hermes-engine
+ - React-callinvoker
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-debug
+ - React-featureflags
+ - React-jserrorhandler
+ - React-jsi
+ - React-jsinspectortracing
+ - React-performancetimeline
+ - React-rendererconsistency
+ - React-rendererdebug
+ - React-runtimeexecutor
+ - React-timing
+ - React-utils
+ - ReactNativeDependencies
+ - React-timing (0.88.0):
+ - React-cxxstableapi
+ - React-debug
+ - React-timing/timingUmbrella (= 0.88.0)
+ - React-timing/timingUmbrella (0.88.0):
+ - React-cxxstableapi
+ - React-debug
+ - React-utils (0.88.0):
+ - hermes-engine
+ - React-Core-prebuilt
+ - React-debug
+ - React-jsi (= 0.88.0)
+ - ReactNativeDependencies
+ - React-viewtransitionnativemodule (0.88.0):
+ - hermes-engine
+ - React-Core-prebuilt
+ - React-Fabric
+ - React-Fabric/bridging
+ - React-jsi
+ - React-jsiexecutor
+ - React-RCTFBReactNativeSpec
+ - React-runtimeexecutor
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - React-webperformancenativemodule (0.88.0):
+ - hermes-engine
+ - React-bridging
+ - React-Core-prebuilt
+ - React-cxxreact
+ - React-cxxstableapi
+ - React-jsi
+ - React-jsiexecutor
+ - React-performancetimeline
+ - React-RCTFBReactNativeSpec
+ - React-runtimeexecutor
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - ReactAppDependencyProvider (0.88.0):
+ - ReactCodegen
+ - ReactCodegen (0.88.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-debug
+ - React-Fabric
+ - React-FabricImage
+ - React-featureflags
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-NativeModulesApple
+ - React-RCTAppDelegate
+ - React-rendererdebug
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - ReactCommon (0.88.0):
+ - React-Core-prebuilt
+ - ReactCommon/turbomodule (= 0.88.0)
+ - ReactNativeDependencies
+ - ReactCommon/turbomodule (0.88.0):
+ - hermes-engine
+ - React-callinvoker (= 0.88.0)
+ - React-Core-prebuilt
+ - React-jsi (= 0.88.0)
+ - React-logger (= 0.88.0)
+ - React-perflogger (= 0.88.0)
+ - ReactCommon/turbomodule/core (= 0.88.0)
+ - ReactNativeDependencies
+ - ReactCommon/turbomodule/core (0.88.0):
+ - hermes-engine
+ - React-bridging
+ - React-callinvoker (= 0.88.0)
+ - React-Core-prebuilt
+ - React-cxxreact (= 0.88.0)
+ - React-debug (= 0.88.0)
+ - React-featureflags (= 0.88.0)
+ - React-jsi (= 0.88.0)
+ - React-logger (= 0.88.0)
+ - React-perflogger (= 0.88.0)
+ - React-utils (= 0.88.0)
+ - ReactNativeDependencies
+ - ReactNativeDependencies (0.88.0)
+ - RNGestureHandler (3.4.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-ImageManager
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-renderercss
+ - React-rendererdebug
+ - React-utils
+ - ReactCodegen
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - RNWorklets (>= 0.8.0)
+ - Yoga
+ - RNReanimated (4.7.1):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-hermes
+ - React-ImageManager
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-renderercss
+ - React-rendererdebug
+ - React-utils
+ - ReactCodegen
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - RNReanimated/apple (= 4.7.1)
+ - RNReanimated/common (= 4.7.1)
+ - RNReanimated/view (= 4.7.1)
+ - RNWorklets
+ - Yoga
+ - RNReanimated/apple (4.7.1):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-hermes
+ - React-ImageManager
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-renderercss
+ - React-rendererdebug
+ - React-utils
+ - ReactCodegen
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - RNWorklets
+ - Yoga
+ - RNReanimated/common (4.7.1):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-hermes
+ - React-ImageManager
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-renderercss
+ - React-rendererdebug
+ - React-utils
+ - ReactCodegen
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - RNWorklets
+ - Yoga
+ - RNReanimated/view (4.7.1):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-hermes
+ - React-ImageManager
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-renderercss
+ - React-rendererdebug
+ - React-utils
+ - ReactCodegen
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - RNWorklets
+ - Yoga
+ - RNSVG (15.15.5):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-ImageManager
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-renderercss
+ - React-rendererdebug
+ - React-utils
+ - ReactCodegen
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - RNSVG/common (= 15.15.5)
+ - Yoga
+ - RNSVG/common (15.15.5):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-ImageManager
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-renderercss
+ - React-rendererdebug
+ - React-utils
+ - ReactCodegen
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - RNWorklets (0.13.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-hermes
+ - React-ImageManager
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-renderercss
+ - React-rendererdebug
+ - React-utils
+ - ReactCodegen
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - RNWorklets/apple (= 0.13.0)
+ - RNWorklets/common (= 0.13.0)
+ - Yoga
+ - RNWorklets/apple (0.13.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-hermes
+ - React-ImageManager
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-renderercss
+ - React-rendererdebug
+ - React-utils
+ - ReactCodegen
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - RNWorklets/common (0.13.0):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-hermes
+ - React-ImageManager
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-renderercss
+ - React-rendererdebug
+ - React-utils
+ - ReactCodegen
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - SocketRocket (0.7.1):
+ - ReactNativeDependencies
+ - stream-chat-react-native (9.10.1):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-ImageManager
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-renderercss
+ - React-rendererdebug
+ - React-utils
+ - ReactCodegen
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - Teleport (1.2.2):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-ImageManager
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-renderercss
+ - React-rendererdebug
+ - React-utils
+ - ReactCodegen
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Teleport/common (= 1.2.2)
+ - Yoga
+ - Teleport/common (1.2.2):
+ - hermes-engine
+ - RCTRequired
+ - RCTTypeSafety
+ - React-bridging
+ - React-Core
+ - React-Core-prebuilt
+ - React-cxxstableapi
+ - React-debug
+ - React-Fabric
+ - React-featureflags
+ - React-graphics
+ - React-ImageManager
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-renderercss
+ - React-rendererdebug
+ - React-utils
+ - ReactCodegen
+ - ReactCommon/turbomodule/core
+ - ReactNativeDependencies
+ - Yoga
+ - Yoga (0.0.0):
+ - React-Core-prebuilt
+
+DEPENDENCIES:
+ - boost (from `build/rndeps-facades/boost`)
+ - DoubleConversion (from `build/rndeps-facades/DoubleConversion`)
+ - fast_float (from `build/rndeps-facades/fast_float`)
+ - FBLazyVector (from `build/rncore-facades/FBLazyVector`)
+ - fmt (from `build/rndeps-facades/fmt`)
+ - glog (from `build/rndeps-facades/glog`)
+ - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`)
+ - RCT-Folly (from `build/rndeps-facades/RCT-Folly`)
+ - RCTDeprecation (from `build/rncore-facades/RCTDeprecation`)
+ - RCTRequired (from `build/rncore-facades/RCTRequired`)
+ - RCTSwiftUI (from `../node_modules/react-native/ReactApple/RCTSwiftUI`)
+ - RCTSwiftUIWrapper (from `../node_modules/react-native/ReactApple/RCTSwiftUIWrapper`)
+ - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
+ - React (from `../node_modules/react-native/`)
+ - React-bridging (from `../node_modules/react-native/ReactCommon/react/bridging`)
+ - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`)
+ - React-Core (from `build/rncore-facades/React-Core`)
+ - React-Core-prebuilt (from `../node_modules/react-native/React-Core-prebuilt.podspec`)
+ - React-Core/RCTWebSocket (from `build/rncore-facades/React-Core`)
+ - React-CoreModules (from `../node_modules/react-native/React/CoreModules`)
+ - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`)
+ - React-cxxstableapi (from `../node_modules/react-native/ReactCommon/react/cxxstableapi`)
+ - React-debug (from `../node_modules/react-native/ReactCommon/react/debug`)
+ - React-defaultsnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/defaults`)
+ - React-domnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/dom`)
+ - React-Fabric (from `../node_modules/react-native/ReactCommon`)
+ - React-FabricComponents (from `../node_modules/react-native/ReactCommon`)
+ - React-FabricImage (from `../node_modules/react-native/ReactCommon`)
+ - React-featureflags (from `../node_modules/react-native/ReactCommon/react/featureflags`)
+ - React-featureflagsnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/featureflags`)
+ - React-graphics (from `../node_modules/react-native/ReactCommon/react/renderer/graphics`)
+ - React-hermes (from `../node_modules/react-native/ReactCommon/hermes`)
+ - React-idlecallbacksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/idlecallbacks`)
+ - React-ImageManager (from `../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios`)
+ - React-intersectionobservernativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/intersectionobserver`)
+ - React-jserrorhandler (from `../node_modules/react-native/ReactCommon/jserrorhandler`)
+ - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
+ - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
+ - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector-modern`)
+ - React-jsinspectorcdp (from `../node_modules/react-native/ReactCommon/jsinspector-modern/cdp`)
+ - React-jsinspectornetwork (from `../node_modules/react-native/ReactCommon/jsinspector-modern/network`)
+ - React-jsinspectortracing (from `../node_modules/react-native/ReactCommon/jsinspector-modern/tracing`)
+ - React-jsitooling (from `../node_modules/react-native/ReactCommon/jsitooling`)
+ - React-jsitracing (from `../node_modules/react-native/ReactCommon/hermes/executor/`)
+ - React-logger (from `../node_modules/react-native/ReactCommon/logger`)
+ - React-Mapbuffer (from `../node_modules/react-native/ReactCommon`)
+ - React-microtasksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`)
+ - React-mutationobservernativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/mutationobserver`)
+ - react-native-launch-arguments (from `../node_modules/react-native-launch-arguments`)
+ - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
+ - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
+ - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
+ - React-networking (from `../node_modules/react-native/ReactCommon/react/networking`)
+ - React-oscompat (from `../node_modules/react-native/ReactCommon/oscompat`)
+ - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`)
+ - React-performancecdpmetrics (from `../node_modules/react-native/ReactCommon/react/performance/cdpmetrics`)
+ - React-performancetimeline (from `../node_modules/react-native/ReactCommon/react/performance/timeline`)
+ - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
+ - React-RCTAnimatedModuleProvider (from `../node_modules/react-native/ReactApple/RCTAnimatedModuleProvider`)
+ - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`)
+ - React-RCTAppDelegate (from `../node_modules/react-native/Libraries/AppDelegate`)
+ - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`)
+ - React-RCTFabric (from `build/rncore-facades/React-RCTFabric`)
+ - React-RCTFBReactNativeSpec (from `../node_modules/react-native/React`)
+ - React-RCTImage (from `../node_modules/react-native/Libraries/Image`)
+ - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`)
+ - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`)
+ - React-RCTRuntime (from `build/rncore-facades/React-RCTRuntime`)
+ - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`)
+ - React-RCTText (from `../node_modules/react-native/Libraries/Text`)
+ - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
+ - React-rendererconsistency (from `../node_modules/react-native/ReactCommon/react/renderer/consistency`)
+ - React-renderercss (from `../node_modules/react-native/ReactCommon/react/renderer/css`)
+ - React-rendererdebug (from `../node_modules/react-native/ReactCommon/react/renderer/debug`)
+ - React-resizeobservernativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/resizeobserver`)
+ - React-RuntimeApple (from `../node_modules/react-native/ReactCommon/react/runtime/platform/ios`)
+ - React-RuntimeCore (from `../node_modules/react-native/ReactCommon/react/runtime`)
+ - React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`)
+ - React-RuntimeHermes (from `../node_modules/react-native/ReactCommon/react/runtime`)
+ - React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`)
+ - React-timing (from `../node_modules/react-native/ReactCommon/react/timing`)
+ - React-utils (from `../node_modules/react-native/ReactCommon/react/utils`)
+ - React-viewtransitionnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/viewtransition`)
+ - React-webperformancenativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/webperformance`)
+ - ReactAppDependencyProvider (from `build/generated/ios/ReactAppDependencyProvider`)
+ - ReactCodegen (from `build/generated/ios/ReactCodegen`)
+ - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
+ - ReactNativeDependencies (from `../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec`)
+ - RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
+ - RNReanimated (from `../node_modules/react-native-reanimated`)
+ - RNSVG (from `../node_modules/react-native-svg`)
+ - RNWorklets (from `../node_modules/react-native-worklets`)
+ - SocketRocket (from `build/rndeps-facades/SocketRocket`)
+ - stream-chat-react-native (from `../node_modules/stream-chat-react-native`)
+ - Teleport (from `../node_modules/react-native-teleport`)
+ - Yoga (from `build/rncore-facades/Yoga`)
+
+EXTERNAL SOURCES:
+ boost:
+ :path: build/rndeps-facades/boost
+ DoubleConversion:
+ :path: build/rndeps-facades/DoubleConversion
+ fast_float:
+ :path: build/rndeps-facades/fast_float
+ FBLazyVector:
+ :path: build/rncore-facades/FBLazyVector
+ fmt:
+ :path: build/rndeps-facades/fmt
+ glog:
+ :path: build/rndeps-facades/glog
+ hermes-engine:
+ :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec"
+ :tag: hermes-v260318099.0.2
+ RCT-Folly:
+ :path: build/rndeps-facades/RCT-Folly
+ RCTDeprecation:
+ :path: build/rncore-facades/RCTDeprecation
+ RCTRequired:
+ :path: build/rncore-facades/RCTRequired
+ RCTSwiftUI:
+ :path: "../node_modules/react-native/ReactApple/RCTSwiftUI"
+ RCTSwiftUIWrapper:
+ :path: "../node_modules/react-native/ReactApple/RCTSwiftUIWrapper"
+ RCTTypeSafety:
+ :path: "../node_modules/react-native/Libraries/TypeSafety"
+ React:
+ :path: "../node_modules/react-native/"
+ React-bridging:
+ :path: "../node_modules/react-native/ReactCommon/react/bridging"
+ React-callinvoker:
+ :path: "../node_modules/react-native/ReactCommon/callinvoker"
+ React-Core:
+ :path: build/rncore-facades/React-Core
+ React-Core-prebuilt:
+ :podspec: "../node_modules/react-native/React-Core-prebuilt.podspec"
+ React-CoreModules:
+ :path: "../node_modules/react-native/React/CoreModules"
+ React-cxxreact:
+ :path: "../node_modules/react-native/ReactCommon/cxxreact"
+ React-cxxstableapi:
+ :path: "../node_modules/react-native/ReactCommon/react/cxxstableapi"
+ React-debug:
+ :path: "../node_modules/react-native/ReactCommon/react/debug"
+ React-defaultsnativemodule:
+ :path: "../node_modules/react-native/ReactCommon/react/nativemodule/defaults"
+ React-domnativemodule:
+ :path: "../node_modules/react-native/ReactCommon/react/nativemodule/dom"
+ React-Fabric:
+ :path: "../node_modules/react-native/ReactCommon"
+ React-FabricComponents:
+ :path: "../node_modules/react-native/ReactCommon"
+ React-FabricImage:
+ :path: "../node_modules/react-native/ReactCommon"
+ React-featureflags:
+ :path: "../node_modules/react-native/ReactCommon/react/featureflags"
+ React-featureflagsnativemodule:
+ :path: "../node_modules/react-native/ReactCommon/react/nativemodule/featureflags"
+ React-graphics:
+ :path: "../node_modules/react-native/ReactCommon/react/renderer/graphics"
+ React-hermes:
+ :path: "../node_modules/react-native/ReactCommon/hermes"
+ React-idlecallbacksnativemodule:
+ :path: "../node_modules/react-native/ReactCommon/react/nativemodule/idlecallbacks"
+ React-ImageManager:
+ :path: "../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios"
+ React-intersectionobservernativemodule:
+ :path: "../node_modules/react-native/ReactCommon/react/nativemodule/intersectionobserver"
+ React-jserrorhandler:
+ :path: "../node_modules/react-native/ReactCommon/jserrorhandler"
+ React-jsi:
+ :path: "../node_modules/react-native/ReactCommon/jsi"
+ React-jsiexecutor:
+ :path: "../node_modules/react-native/ReactCommon/jsiexecutor"
+ React-jsinspector:
+ :path: "../node_modules/react-native/ReactCommon/jsinspector-modern"
+ React-jsinspectorcdp:
+ :path: "../node_modules/react-native/ReactCommon/jsinspector-modern/cdp"
+ React-jsinspectornetwork:
+ :path: "../node_modules/react-native/ReactCommon/jsinspector-modern/network"
+ React-jsinspectortracing:
+ :path: "../node_modules/react-native/ReactCommon/jsinspector-modern/tracing"
+ React-jsitooling:
+ :path: "../node_modules/react-native/ReactCommon/jsitooling"
+ React-jsitracing:
+ :path: "../node_modules/react-native/ReactCommon/hermes/executor/"
+ React-logger:
+ :path: "../node_modules/react-native/ReactCommon/logger"
+ React-Mapbuffer:
+ :path: "../node_modules/react-native/ReactCommon"
+ React-microtasksnativemodule:
+ :path: "../node_modules/react-native/ReactCommon/react/nativemodule/microtasks"
+ React-mutationobservernativemodule:
+ :path: "../node_modules/react-native/ReactCommon/react/nativemodule/mutationobserver"
+ react-native-launch-arguments:
+ :path: "../node_modules/react-native-launch-arguments"
+ react-native-netinfo:
+ :path: "../node_modules/@react-native-community/netinfo"
+ react-native-safe-area-context:
+ :path: "../node_modules/react-native-safe-area-context"
+ React-NativeModulesApple:
+ :path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios"
+ React-networking:
+ :path: "../node_modules/react-native/ReactCommon/react/networking"
+ React-oscompat:
+ :path: "../node_modules/react-native/ReactCommon/oscompat"
+ React-perflogger:
+ :path: "../node_modules/react-native/ReactCommon/reactperflogger"
+ React-performancecdpmetrics:
+ :path: "../node_modules/react-native/ReactCommon/react/performance/cdpmetrics"
+ React-performancetimeline:
+ :path: "../node_modules/react-native/ReactCommon/react/performance/timeline"
+ React-RCTActionSheet:
+ :path: "../node_modules/react-native/Libraries/ActionSheetIOS"
+ React-RCTAnimatedModuleProvider:
+ :path: "../node_modules/react-native/ReactApple/RCTAnimatedModuleProvider"
+ React-RCTAnimation:
+ :path: "../node_modules/react-native/Libraries/NativeAnimation"
+ React-RCTAppDelegate:
+ :path: "../node_modules/react-native/Libraries/AppDelegate"
+ React-RCTBlob:
+ :path: "../node_modules/react-native/Libraries/Blob"
+ React-RCTFabric:
+ :path: build/rncore-facades/React-RCTFabric
+ React-RCTFBReactNativeSpec:
+ :path: "../node_modules/react-native/React"
+ React-RCTImage:
+ :path: "../node_modules/react-native/Libraries/Image"
+ React-RCTLinking:
+ :path: "../node_modules/react-native/Libraries/LinkingIOS"
+ React-RCTNetwork:
+ :path: "../node_modules/react-native/Libraries/Network"
+ React-RCTRuntime:
+ :path: build/rncore-facades/React-RCTRuntime
+ React-RCTSettings:
+ :path: "../node_modules/react-native/Libraries/Settings"
+ React-RCTText:
+ :path: "../node_modules/react-native/Libraries/Text"
+ React-RCTVibration:
+ :path: "../node_modules/react-native/Libraries/Vibration"
+ React-rendererconsistency:
+ :path: "../node_modules/react-native/ReactCommon/react/renderer/consistency"
+ React-renderercss:
+ :path: "../node_modules/react-native/ReactCommon/react/renderer/css"
+ React-rendererdebug:
+ :path: "../node_modules/react-native/ReactCommon/react/renderer/debug"
+ React-resizeobservernativemodule:
+ :path: "../node_modules/react-native/ReactCommon/react/nativemodule/resizeobserver"
+ React-RuntimeApple:
+ :path: "../node_modules/react-native/ReactCommon/react/runtime/platform/ios"
+ React-RuntimeCore:
+ :path: "../node_modules/react-native/ReactCommon/react/runtime"
+ React-runtimeexecutor:
+ :path: "../node_modules/react-native/ReactCommon/runtimeexecutor"
+ React-RuntimeHermes:
+ :path: "../node_modules/react-native/ReactCommon/react/runtime"
+ React-runtimescheduler:
+ :path: "../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler"
+ React-timing:
+ :path: "../node_modules/react-native/ReactCommon/react/timing"
+ React-utils:
+ :path: "../node_modules/react-native/ReactCommon/react/utils"
+ React-viewtransitionnativemodule:
+ :path: "../node_modules/react-native/ReactCommon/react/nativemodule/viewtransition"
+ React-webperformancenativemodule:
+ :path: "../node_modules/react-native/ReactCommon/react/nativemodule/webperformance"
+ ReactAppDependencyProvider:
+ :path: build/generated/ios/ReactAppDependencyProvider
+ ReactCodegen:
+ :path: build/generated/ios/ReactCodegen
+ ReactCommon:
+ :path: "../node_modules/react-native/ReactCommon"
+ ReactNativeDependencies:
+ :podspec: "../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec"
+ RNGestureHandler:
+ :path: "../node_modules/react-native-gesture-handler"
+ RNReanimated:
+ :path: "../node_modules/react-native-reanimated"
+ RNSVG:
+ :path: "../node_modules/react-native-svg"
+ RNWorklets:
+ :path: "../node_modules/react-native-worklets"
+ SocketRocket:
+ :path: build/rndeps-facades/SocketRocket
+ stream-chat-react-native:
+ :path: "../node_modules/stream-chat-react-native"
+ Teleport:
+ :path: "../node_modules/react-native-teleport"
+ Yoga:
+ :path: build/rncore-facades/Yoga
+
+SPEC CHECKSUMS:
+ boost: 8502bfdc46e2804408af2e163049ece181009af4
+ DoubleConversion: 501a575c40c0b50c89685762dd3e415e6bb26fb0
+ fast_float: 7c925d1cebf8328d4018d061f49377e9f887e3b4
+ FBLazyVector: fdebac2dfe9c53bca49f8218fbdf1e24e36c8be0
+ fmt: ba0886e864ebb21d14c98b2e12e164b8002f5b93
+ glog: 3cf7cb46f743c4bc758ae3e6d9c15bd1b4cfd6d4
+ hermes-engine: a1158910bb7e300b9e3d2f1e2d433f817ec1a4b5
+ RCT-Folly: 82921e585c0400eda46fac1068297aa9dfb035e4
+ RCTDeprecation: e134f2a2c096a6450f5fcbbe949531f913a2ff04
+ RCTRequired: f1a68295837ee8f91e112ed1b5694d12e7ff1784
+ RCTSwiftUI: 4b21ec5b1f86acb9c96bb429100ad88d4023ed76
+ RCTSwiftUIWrapper: 68bd9fac4e710259cb2b202472adc5f4d113e872
+ RCTTypeSafety: 77078a9c26030dd84a6bdae74ed900159f89a098
+ React: 8dafd0ef058191e9e7238cfa6b3deaa24398e5dd
+ React-bridging: 658efeb1b4704d5f60ea2fb6e8ca826ab0ae3234
+ React-callinvoker: 4e40c208c1ea46686c084a7c23da6a65cbb99482
+ React-Core: a831be15fcea0e345a24cb10d6cc0b87e9913d03
+ React-Core-prebuilt: 0fd2555a42f40e7770ced1c7dfc5ee1dbfe041cd
+ React-CoreModules: a86fbe698fd817c17b3936832dc1106a130c4694
+ React-cxxreact: 48ca56bd4f26de869478a803a5544b101a57cde6
+ React-cxxstableapi: f35502b4c542a0d44031b42f91c4ca813d267e16
+ React-debug: 238e15d17dfded9419a6d739d4c8b60968bad02e
+ React-defaultsnativemodule: c028edc7e48914344b823931aec1cc4ffabe631e
+ React-domnativemodule: b09770fc69f5ce5759de98f8065cab900b6d87d6
+ React-Fabric: a157c978603fa2796f349f3a27d17861e55804c5
+ React-FabricComponents: c7c58a1deea5db215e9d5a2aec890e208d5d5075
+ React-FabricImage: 234346bf5a3ef918f3873e845b57b93b2b1f31c0
+ React-featureflags: a00ac5c38e63d5f86de895ca923f07f5ff76de66
+ React-featureflagsnativemodule: 6b93ba0aef46757b9d54166475abc5e4fa80e70d
+ React-graphics: 634bc2e5884b4a29f56aa8aef719e03171a23f6b
+ React-hermes: 9ce7aaf6784709e196ac51bfd89dd6c551e3fb4c
+ React-idlecallbacksnativemodule: e02e194086278377ced48b7fd7816b6c925b9e7e
+ React-ImageManager: 452d4b3587f21d3384868e2abaab7c0a952b1d1c
+ React-intersectionobservernativemodule: 3ddbc206bc95c086f1df6eea04aa617ae02627d2
+ React-jserrorhandler: a0d842e1f74cc10e597fde2a6447860483df2b13
+ React-jsi: 489de0620905b88a17ccb0ac2328046af43e7ebd
+ React-jsiexecutor: f0e2ae6d98b587d3505ebde246599ee3ad97cee1
+ React-jsinspector: 515bf11caeda5df444f39aec63e377ef77ad7696
+ React-jsinspectorcdp: be9ac71a77880a6fcc95375e7e61a79e152a3203
+ React-jsinspectornetwork: a4bc1475897a2301d114d7a8605af3e8760f9e52
+ React-jsinspectortracing: 7d35952c944dc337d1a4167605c1338108880219
+ React-jsitooling: 1886dc5058e9feded2136b0d9ba5c189c6af5faa
+ React-jsitracing: 76b58feee3fb0539c8967e5b9de1a40ad8014f09
+ React-logger: 3d2b406a780fed50ad0bbd07452b373c2a515308
+ React-Mapbuffer: a2dae4f2cb335ebb97f2240494d0c2bab84cd339
+ React-microtasksnativemodule: 8b3aaa5f3b907ecf071b105589868d9f027a448d
+ React-mutationobservernativemodule: 11d77d3f7360578f07847843544ada23cc473049
+ react-native-launch-arguments: eab68037b01ea7c78a0b3b55da3a5e967e9aaf92
+ react-native-netinfo: 687391ecedb199c6d67fbc46c87cbae3277de967
+ react-native-safe-area-context: b1c9f15a36e597e9cef4c5526e209ef2645bc2e0
+ React-NativeModulesApple: 52f3def085f129de1307e3eb78e26729ff70f421
+ React-networking: 1e6441349ac72bfd4f7a79c300c3dd76993a7058
+ React-oscompat: e64123dd8199f9e99cede19fa542c3da3445481e
+ React-perflogger: f1466e0f46ce706aef73a559337eca85f51a40b7
+ React-performancecdpmetrics: f238752e99eb7c69c782020827bff38a4b1b2ef2
+ React-performancetimeline: f1b216fa02200c859cd18ef345d4230cd712137a
+ React-RCTActionSheet: 81662769b1f576e9c2e074deb41d6b83d1c7e29f
+ React-RCTAnimatedModuleProvider: a9829773197f782c19ad86c5438a2cc199203774
+ React-RCTAnimation: ad9dd2c6c3b4d07e583c2b79354858c4f34481a0
+ React-RCTAppDelegate: 70398a06e10ada27cdf77dc2b43f883126a91ac0
+ React-RCTBlob: f3d86b491b8f28c36ced0cb750878b62f72e1380
+ React-RCTFabric: 3767f97183c40ba3dadf007b17a01be2cd4e632a
+ React-RCTFBReactNativeSpec: d7ad5d9edc1865f38b9aac5b7091c3abb6978eed
+ React-RCTImage: 46ad408f777dce991d4095d7e73a568212be6baa
+ React-RCTLinking: 547427cc885bfa74b3cbba405971c5270defde7a
+ React-RCTNetwork: 52c00c0fe07327df9b9fe9881b4f5550dc5ced37
+ React-RCTRuntime: 081fd457d305c3aee76c335c568e693ed107f48e
+ React-RCTSettings: 9cd0b2be41404574ec280b6b8e73c2208c842050
+ React-RCTText: 5a6d38456eabc0a1a7c0d47d592390d35c6de57c
+ React-RCTVibration: c1815b4f471462954a4b7d8835155e053cec5412
+ React-rendererconsistency: b7996da82c8d3f4a7928b39be3e437b72ad92012
+ React-renderercss: 4c256900eba87661178771766da0171493f88848
+ React-rendererdebug: 4d9df8cf2cac6eee7002a4d14358c79fdf6ad8c5
+ React-resizeobservernativemodule: 750d334554e7c44bacf14568a8a0d0048cc4c278
+ React-RuntimeApple: 2045a6206895ad5ce90d141d1bd384888fd06c42
+ React-RuntimeCore: b051facffbc7ca038097278cabf810d6d86dd328
+ React-runtimeexecutor: b06ec9bb745a97cbd3ce25e3e02be7b8058fb374
+ React-RuntimeHermes: fcfa8baca49a6d37d331147568d51d5b8b0a175d
+ React-runtimescheduler: c2afe74d1db006bafd9270186101f5378b1bef81
+ React-timing: 6a1a8cfb0caae8de243aba16fa92fa81de23efaf
+ React-utils: 2384e5db98378df8c0bf2c0d5489ec1b8e80b398
+ React-viewtransitionnativemodule: 8505b253586f792c6c722869a664889797ecae3e
+ React-webperformancenativemodule: 67f32fde92ed7e8470ee1c669bdb7c2fcb760141
+ ReactAppDependencyProvider: 782ee9546c9cd3b53b73f1e9e3dd728540085fc7
+ ReactCodegen: 7b71f4464442e9b6eae41094d11076d56c51c0e3
+ ReactCommon: 145a14b942b19fc2fe38927f261955ada56978aa
+ ReactNativeDependencies: d3b7423ba1e52525e42085c8470109abde583d2e
+ RNGestureHandler: b5512a093e6923dd1c31fbdd8e6186cd0ebb3541
+ RNReanimated: 3018727dbf272754d0f31ef73f619e49ade7baf0
+ RNSVG: 8b5f2fdb9f0245a863cdd6e9c48a7689821a08b0
+ RNWorklets: 488806637a21eb17812a48dadca7cb8c698c8cfd
+ SocketRocket: 37aec555668fb852ec12e3c0de59a86ca58f0871
+ stream-chat-react-native: 7f1fdf2d1ce87c0b8a6c1d581308dff0c84e8e21
+ Teleport: 90f0d7e81c6b40db9b253e1ef73b2f4f4f3f6b53
+ Yoga: d1c536142c5ff8ec8cd856ab2a7c227a1d875c8e
+
+PODFILE CHECKSUM: 84fecefd0a807b1cfa8b4184065b9bbd44fa58d1
+
+COCOAPODS: 1.15.2
diff --git a/examples/E2ETestApp/metro.config.js b/examples/E2ETestApp/metro.config.js
new file mode 100644
index 0000000000..c96816d4be
--- /dev/null
+++ b/examples/E2ETestApp/metro.config.js
@@ -0,0 +1,81 @@
+const { getDefaultConfig } = require('@react-native/metro-config');
+const { resolveUniqueModule } = require('@rnx-kit/metro-config');
+
+/**
+ * Metro configuration
+ * https://reactnative.dev/docs/metro
+ *
+ * @type {import('@react-native/metro-config').MetroConfig}
+ */
+const config = getDefaultConfig(__dirname);
+
+const PATH = require('path');
+const metroConfigPackageJsonPath = require.resolve('metro-config/package.json', {
+ paths: [__dirname],
+});
+const metroExclusionList = require(
+ PATH.join(PATH.dirname(metroConfigPackageJsonPath), 'src/defaults/exclusionList.js'),
+);
+const exclusionList = metroExclusionList.default || metroExclusionList;
+const packageDirPath = PATH.resolve(__dirname, '../../package');
+const nativePackageDirPath = PATH.resolve(__dirname, '../../package/native-package');
+
+const symlinked = {
+ 'stream-chat-react-native': nativePackageDirPath,
+ 'stream-chat-react-native-core': packageDirPath,
+};
+
+// find what all modules need to be unique for the app (mainly react and react-native)
+// note: we filter the symlinked modules as they are already unique
+// and as they dont follow the workspace pattern the auto-generated path to the module is incorrect
+const dependencyPackageNames = Object.keys(require('./package.json').dependencies);
+
+const uniqueModules = dependencyPackageNames.map((packageName) => {
+ if (symlinked[packageName]) {
+ const modulePath = symlinked[packageName];
+ const escapedPackageName = PATH.normalize(packageName).replace(/\\/g, '\\\\');
+
+ // exclude the symlinked package from being resolved from node_modules
+ // example: .*\/node_modules\/stream-chat-react-native-core\/.*
+ // the above would avoid native-package to resolve core from its own node_modules
+ const exclusionRE = new RegExp(
+ `.*${PATH.sep}node_modules\\${PATH.sep}${escapedPackageName}\\${PATH.sep}.*`,
+ );
+
+ return {
+ packageName, // name of the package
+ modulePath,
+ blockPattern: exclusionRE, // paths that match this pattern will be blocked from being resolved
+ };
+ }
+ const [modulePath, blockPattern] = resolveUniqueModule(packageName, __dirname);
+ // resolveUniqueModule emits a regex ending in `/` (package-dir boundary). metro-config's
+ // exclusionList anchors every alternation branch with `$`, which would require file paths to
+ // literally end with `/node_modules//`. Append `.*` so the anchor lands at end-of-file
+ // instead of end-of-directory, otherwise the blocklist silently matches nothing.
+ const fixedBlockPattern = new RegExp(blockPattern.source + '.*');
+ return {
+ packageName, // name of the package
+ modulePath, // actual path to the module in the project's node modules
+ blockPattern: fixedBlockPattern, // paths that match this pattern will be blocked from being resolved
+ };
+});
+
+// block the other paths for unique modules from being resolved
+const blockList = uniqueModules.map(({ blockPattern }) => blockPattern);
+
+// provide the path for the unique modules
+const extraNodeModules = uniqueModules.reduce((acc, item) => {
+ acc[item.packageName] = item.modulePath;
+ return acc;
+}, {});
+
+config.resolver.blockList = exclusionList(blockList);
+config.resolver.extraNodeModules = extraNodeModules;
+
+config.resolver.nodeModulesPaths = [PATH.resolve(__dirname, 'node_modules')];
+
+// add the package dir for metro to access the package folder
+config.watchFolders = [packageDirPath];
+
+module.exports = config;
diff --git a/examples/E2ETestApp/package.json b/examples/E2ETestApp/package.json
new file mode 100644
index 0000000000..3329927fda
--- /dev/null
+++ b/examples/E2ETestApp/package.json
@@ -0,0 +1,50 @@
+{
+ "name": "e2etestapp",
+ "version": "0.0.1",
+ "private": true,
+ "description": "Minimal app driven by the Detox e2e suite (e2e/). Only the SDK and its required peer dependencies.",
+ "scripts": {
+ "sync-native": "bash ../../package/scripts/reconcile-shared-native.sh native-package && bash ../../package/scripts/sync-shared-native.sh native-package",
+ "android": "yarn sync-native && react-native run-android",
+ "ios": "yarn sync-native && react-native run-ios",
+ "start": "yarn sync-native && react-native start",
+ "typecheck": "tsc --noEmit && tsc --noEmit -p e2e",
+ "e2e:build": "yarn sync-native && detox build",
+ "e2e:test": "detox test"
+ },
+ "dependencies": {
+ "@react-native-community/netinfo": "^12.0.1",
+ "react": "19.3.0",
+ "react-native": "0.88.0",
+ "react-native-gesture-handler": "^3.4.0",
+ "react-native-launch-arguments": "^4.1.1",
+ "react-native-reanimated": "4.7.1",
+ "react-native-safe-area-context": "^5.10.1",
+ "react-native-svg": "^15.15.5",
+ "react-native-teleport": "^1.2.2",
+ "react-native-worklets": "^0.13.0",
+ "stream-chat": "^9.54.0",
+ "stream-chat-react-native": "workspace:^"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.29.0",
+ "@babel/runtime": "^7.29.2",
+ "@jest/globals": "^30.4.1",
+ "@react-native-community/cli": "20.2.0",
+ "@react-native-community/cli-platform-android": "20.2.0",
+ "@react-native-community/cli-platform-ios": "20.2.0",
+ "@react-native/babel-preset": "0.88.0",
+ "@react-native/metro-config": "0.88.0",
+ "@react-native/typescript-config": "0.88.0",
+ "@rnx-kit/metro-config": "^2.2.6",
+ "@stream-io/typescript-config": "workspace:^",
+ "@types/react": "^19.3.0",
+ "babel-jest": "30.0.0",
+ "detox": "^20.51.4",
+ "jest": "^30.4.2",
+ "typescript": "6.0.3"
+ },
+ "engines": {
+ "node": ">= 22.11.0"
+ }
+}
diff --git a/examples/E2ETestApp/src/config.ts b/examples/E2ETestApp/src/config.ts
new file mode 100644
index 0000000000..8d10c2d95b
--- /dev/null
+++ b/examples/E2ETestApp/src/config.ts
@@ -0,0 +1,26 @@
+import { LaunchArguments } from 'react-native-launch-arguments';
+
+import type { UserResponse } from 'stream-chat';
+
+/**
+ * Launch arguments passed by the Detox suite (`e2e/support/StreamTestCase.ts`). The counterpart of
+ * `USE_MOCK_SERVER` + `MOCK_SERVER_*` on iOS and the `BASE_URL` intent extra on Android.
+ */
+type E2ELaunchArguments = {
+ /** Base URL of the per-test `stream-chat-test-mock-server` instance, e.g. `http://localhost:54321`. */
+ MOCK_SERVER_URL?: string;
+};
+
+export const mockServerUrl = LaunchArguments.value().MOCK_SERVER_URL;
+
+/** The app user every mock server fixture is recorded for. */
+export const appUser: UserResponse = {
+ id: 'luke_skywalker',
+ image: 'https://vignette.wikia.nocookie.net/starwars/images/2/20/LukeTLJ.jpg',
+ name: 'Luke Skywalker',
+};
+
+// The mock server accepts any key and token; these match the native SDKs' e2e apps.
+export const apiKey = '8br4watad788';
+export const appUserToken =
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoibHVrZV9za3l3YWxrZXIifQ.kFSLHRB5X62t0Zlc7nwczWUfsQMwfkpylC6jCUZ6Mc0';
diff --git a/examples/E2ETestApp/tsconfig.json b/examples/E2ETestApp/tsconfig.json
new file mode 100644
index 0000000000..d1be171213
--- /dev/null
+++ b/examples/E2ETestApp/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "extends": ["@react-native/typescript-config", "@stream-io/typescript-config/base.json"],
+ "compilerOptions": {
+ "types": []
+ },
+ "exclude": ["node_modules", "e2e"]
+}
diff --git a/examples/SampleApp/fastlane/Fastfile b/examples/SampleApp/fastlane/Fastfile
index f2680950ee..c491a81025 100644
--- a/examples/SampleApp/fastlane/Fastfile
+++ b/examples/SampleApp/fastlane/Fastfile
@@ -5,6 +5,7 @@ github_repo = ENV['GITHUB_REPOSITORY'] || 'GetStream/stream-chat-react-native'
root_path = File.absolute_path('../../../')
sdk_size_ext = 'KB'
@force_check = false
+@impact = nil
build_output_directory = "./app-build"
# iOS Platform Configuration
@@ -20,6 +21,7 @@ apk_path = "#{build_output_directory}/#{output_apk_name}"
before_all do
+ @impact = impact_analysis
if is_ci
setup_ci
setup_git_config
@@ -183,9 +185,109 @@ platform :android do
end
end
-##########################
-###### Common lanes ######
-##########################
+#######################
+###### E2E lanes ######
+#######################
+
+# The e2e suite drives the dedicated examples/E2ETestApp; its lanes live here with the repo's other lanes.
+e2e_app_path = File.absolute_path('../../E2ETestApp')
+mock_server_repo_name = 'stream-chat-test-mock-server'
+mock_server_driver_port = ENV['MOCK_DRIVER_PORT'] || '4569'
+
+desc 'Starts the stream-chat-test-mock-server driver. Options: local_server (path to a checkout), branch'
+lane :start_mock_server do |options|
+ Dir.chdir(e2e_app_path) do
+ mock_server_repo = options[:local_server] || mock_server_repo_name
+ stop_mock_server unless is_ci
+
+ unless options[:local_server]
+ branch = options[:branch].to_s.empty? ? 'main' : options[:branch]
+ sh("rm -rf #{mock_server_repo}") if File.directory?(mock_server_repo)
+ sh("git clone --depth 1 -b #{branch} https://github.com/#{github_repo.split('/').first}/#{mock_server_repo}.git")
+ end
+
+ Dir.chdir(mock_server_repo) do
+ FileUtils.mkdir_p('logs')
+ # The mock server has its own Gemfile; don't let the SampleApp bundle leak into it.
+ Bundler.with_unbundled_env do
+ # CI caches the mock server's gems in MOCK_SERVER_BUNDLE_PATH.
+ sh("bundle config set --local path '#{ENV['MOCK_SERVER_BUNDLE_PATH']}'") if ENV['MOCK_SERVER_BUNDLE_PATH']
+ sh('bundle install')
+ sh("bundle exec ruby driver.rb #{mock_server_driver_port} > logs/driver.log 2>&1 &")
+ end
+ end
+
+ wait_for_mock_server_driver(port: mock_server_driver_port)
+ end
+end
+
+lane :stop_mock_server do
+ Net::HTTP.get_response(URI("http://localhost:#{mock_server_driver_port}/stop")) rescue nil
+end
+
+private_lane :wait_for_mock_server_driver do |options|
+ require 'socket'
+ ready = false
+ 60.times do
+ begin
+ TCPSocket.new('localhost', options[:port].to_i).close
+ ready = true
+ break
+ rescue Errno::ECONNREFUSED
+ sleep(1)
+ end
+ end
+ UI.user_error!("Mock server driver did not start on port #{options[:port]}") unless ready
+end
+
+desc 'Writes `required=true|false` to $GITHUB_OUTPUT, so CI can skip the e2e jobs before building anything'
+lane :e2e_check_required do
+ required = is_check_required(sources: @impact[:e2e][:sources], force_check: @force_check, required_checks: @impact[:e2e][:checks])
+ File.write(ENV['GITHUB_OUTPUT'], "required=#{required}\n", mode: 'a') if ENV['GITHUB_OUTPUT']
+ required
+end
+
+desc 'Installs the E2ETestApp pods with this bundle (the e2e app has no Gemfile of its own)'
+lane :e2e_pod_install do
+ Dir.chdir(e2e_app_path) do
+ sh('yarn sync-native')
+ sh('bundle exec pod install --project-directory=ios')
+ end
+end
+
+# A freshly booted CI emulator is slow enough for the launcher to hit an ANR ("Quickstep isn't
+# responding"). The dialog takes window focus, and Espresso then fails every test waiting for it.
+private_lane :prepare_android_emulator do
+ sh('adb shell settings put global hide_error_dialogs 1')
+ # Gives the post-boot CPU load a minute to settle, dismissing ANR dialogs meanwhile. Capped: the
+ # load can stay above the threshold for minutes, and each test dismisses ANR dialogs too.
+ wait_android_emu_idle(timeout: 60)
+end
+
+desc 'Runs the Detox e2e tests. Options: platform (ios|android), configuration (release|debug), ' \
+ 'device (android: emu|att), skip_build, test (a test file or -t filter), local_server, mock_server_branch'
+lane :test_e2e do |options|
+ next unless is_check_required(sources: @impact[:e2e][:sources], force_check: @force_check, required_checks: @impact[:e2e][:checks])
+
+ platform = options[:platform] || 'ios'
+ device = platform == 'ios' ? 'sim' : (options[:device] || 'emu')
+ detox_config = "#{platform}.#{device}.#{options[:configuration] || 'release'}"
+
+ start_mock_server(local_server: options[:local_server], branch: options[:mock_server_branch])
+ # An attached emulator is already booted; Detox boots `emu` devices itself.
+ prepare_android_emulator if platform == 'android' && device == 'att'
+
+ begin
+ Dir.chdir(e2e_app_path) do
+ sh("yarn e2e:build -c #{detox_config}") unless options[:skip_build]
+ # On CI: retry flaky tests, run the simulator headless, and keep logs + screenshots of failures in ./artifacts.
+ ci_flags = is_ci ? '--retries 2 --headless --record-logs failing --take-screenshots failing' : ''
+ sh("MOCK_DRIVER_PORT=#{mock_server_driver_port} yarn detox test -c #{detox_config} --cleanup #{ci_flags} #{options[:test]}")
+ end
+ ensure
+ stop_mock_server
+ end
+end
lane :file_size do |options|
File.size(options[:path]) / 1024.0
@@ -213,10 +315,7 @@ lane :frameworks_sizes do
end
lane :show_frameworks_sizes do |options|
- # Besides the SDK itself, changes to how the size is measured (this lane, its plugin, the root
- # `minify-*` scripts) re-run the check too.
- sources = ['package/', 'package.json', 'examples/SampleApp/fastlane/', 'examples/SampleApp/Gemfile.lock']
- next unless is_check_required(sources: sources, force_check: @force_check)
+ next unless is_check_required(sources: @impact[:size][:sources], force_check: @force_check)
sizes = options[:sizes] || frameworks_sizes
show_sdk_size(branch_sizes: sizes, github_repo: github_repo, size_ext: sdk_size_ext)
@@ -232,3 +331,15 @@ lane :update_img_shields_sdk_sizes do |options|
size_ext: sdk_size_ext
)
end
+
+lane :impact_analysis do
+ {
+ e2e: {
+ sources: ['package/', 'examples/E2ETestApp/', 'examples/SampleApp/fastlane/', 'package.json'],
+ checks: ['Test E2E Result']
+ },
+ size: {
+ sources: ['package/', 'package.json']
+ }
+ }
+end
diff --git a/package.json b/package.json
index 73df92c8a5..ee702cd07b 100644
--- a/package.json
+++ b/package.json
@@ -7,6 +7,7 @@
"package/native-package",
"package/expo-package",
"examples/SampleApp",
+ "examples/E2ETestApp",
"examples/ExpoMessaging",
"examples/ExpoChatGPTSample"
],
@@ -71,7 +72,7 @@
"lint-fix": "prettier --write . && eslint . --fix --max-warnings 0",
"prettier": "prettier --list-different .",
"prettier-fix": "prettier --write .",
- "typecheck": "yarn workspaces foreach -A --parallel --include 'stream-chat-react-native-core' --include 'stream-chat-react-native' --include 'stream-chat-expo' --include 'sampleapp' --include 'ExpoMessaging' --include 'expochatgptsample' run typecheck",
+ "typecheck": "yarn workspaces foreach -A --parallel --include 'stream-chat-react-native-core' --include 'stream-chat-react-native' --include 'stream-chat-expo' --include 'sampleapp' --include 'e2etestapp' --include 'ExpoMessaging' --include 'expochatgptsample' run typecheck",
"build": "yarn workspace stream-chat-react-native-core build",
"test:coverage": "yarn workspace stream-chat-react-native-core test:coverage",
"test:unit": "yarn workspace stream-chat-react-native-core test:unit",
diff --git a/package/src/components/ChannelPreview/ChannelLastMessagePreview.tsx b/package/src/components/ChannelPreview/ChannelLastMessagePreview.tsx
index 30d323c839..e005c42649 100644
--- a/package/src/components/ChannelPreview/ChannelLastMessagePreview.tsx
+++ b/package/src/components/ChannelPreview/ChannelLastMessagePreview.tsx
@@ -29,7 +29,7 @@ export const ChannelLastMessagePreview = ({ message }: ChannelLastMessagePreview
width={16}
/>
) : null}
-
+
{messagePreviewTitle}
diff --git a/package/src/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.tsx b/package/src/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.tsx
index 96ea6dc072..0a08077eda 100644
--- a/package/src/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.tsx
+++ b/package/src/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.tsx
@@ -81,7 +81,11 @@ export const ChannelMessagePreviewDeliveryStatus = ({
}
if (!isLastMessageByCurrentUser) {
- return {message?.user?.name || message?.user?.id}:;
+ return (
+
+ {message?.user?.name || message?.user?.id}:
+
+ );
}
return (
@@ -107,7 +111,9 @@ export const ChannelMessagePreviewDeliveryStatus = ({
) : status === MessageDeliveryStatus.SENT ? (
) : null}
- {t('You')}:
+
+ {t('You')}:
+
);
diff --git a/package/src/components/ChannelPreview/ChannelPreviewTitle.tsx b/package/src/components/ChannelPreview/ChannelPreviewTitle.tsx
index e91d33b41f..28e1b7982c 100644
--- a/package/src/components/ChannelPreview/ChannelPreviewTitle.tsx
+++ b/package/src/components/ChannelPreview/ChannelPreviewTitle.tsx
@@ -21,7 +21,7 @@ export const ChannelPreviewTitle = ({ channel, title }: ChannelPreviewTitleProps
const displayName = useChannelPreviewDisplayName(channel);
return (
-
+
{title ?? displayName}
);
diff --git a/package/src/components/Message/MessageItemView/MessageStatus.tsx b/package/src/components/Message/MessageItemView/MessageStatus.tsx
index db86a63105..4095fd1deb 100644
--- a/package/src/components/Message/MessageItemView/MessageStatus.tsx
+++ b/package/src/components/Message/MessageItemView/MessageStatus.tsx
@@ -61,6 +61,16 @@ const MessageStatusWithContext = (props: MessageStatusPropsWithContext) => {
return null;
}
+ const testID = read
+ ? 'message-status-read'
+ : delivered
+ ? 'message-status-delivered'
+ : sending
+ ? 'message-status-sending'
+ : sent
+ ? 'message-status-sent'
+ : undefined;
+
return (
<>
@@ -68,6 +78,7 @@ const MessageStatusWithContext = (props: MessageStatusPropsWithContext) => {
accessibilityElementsHidden={!!accessibilityLabel}
importantForAccessibility={accessibilityLabel ? 'no-hide-descendants' : undefined}
style={[styles.container, container]}
+ testID={testID}
>
{read ? (
{
});
},
);
+
+ it.each([
+ [1, 1, 'sending', 'message-status-sending'],
+ [2, 2, 'received', 'message-status-read'],
+ [1, 1, 'received', 'message-status-sent'],
+ [2, 1, 'received', 'message-status-delivered'],
+ ] as [number, number, string, string][])(
+ 'should expose a status testID when deliveredToCount is %s, readBy is %s and status is %s',
+ async (deliveredToCount, readBy, status, testID) => {
+ const message = generateMessage({ user: generateUser() });
+ const { getByTestId } = renderMessageStatus({
+ deliveredToCount,
+ message: { ...message, status },
+ readBy,
+ });
+ // The icon row is hidden from screen readers in favour of the hidden text label.
+ await waitFor(() => {
+ expect(getByTestId(testID, { includeHiddenElements: true })).toBeTruthy();
+ });
+ },
+ );
});
diff --git a/yarn.lock b/yarn.lock
index 6d8e94f376..95ca73ae46 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1610,6 +1610,20 @@ __metadata:
languageName: node
linkType: hard
+"@colors/colors@npm:1.6.0":
+ version: 1.6.0
+ resolution: "@colors/colors@npm:1.6.0"
+ checksum: 10c0/9328a0778a5b0db243af54455b79a69e3fb21122d6c15ef9e9fcc94881d8d17352d8b2b2590f9bdd46fac5c2d6c1636dcfc14358a20c70e22daf89e1a759b629
+ languageName: node
+ linkType: hard
+
+"@colors/colors@npm:^1.6.0":
+ version: 1.6.1
+ resolution: "@colors/colors@npm:1.6.1"
+ checksum: 10c0/8fb995f2421210284305fd07b4b70e9873a417cda8b0d66ba3f7beccd2e0f4ebbe0b2ba3afbef8f07740ad707c379d94e836cffd6a8df394387e210b4338b4c9
+ languageName: node
+ linkType: hard
+
"@commitlint/cli@npm:^21.0.0":
version: 21.0.0
resolution: "@commitlint/cli@npm:21.0.0"
@@ -1839,6 +1853,17 @@ __metadata:
languageName: node
linkType: hard
+"@dabh/diagnostics@npm:^2.0.8":
+ version: 2.0.9
+ resolution: "@dabh/diagnostics@npm:2.0.9"
+ dependencies:
+ "@so-ric/colorspace": "npm:^1.1.6"
+ enabled: "npm:2.0.x"
+ kuler: "npm:^2.0.0"
+ checksum: 10c0/3d341a52fbf2277883c4aa1153ce092932d9ecad79a54749553206b83e568cd563f66c6e1cc1416a403bd5662335193a19e8bcc1082f047f28b6402eeb16c01d
+ languageName: node
+ linkType: hard
+
"@emnapi/core@npm:^1.4.3":
version: 1.10.0
resolution: "@emnapi/core@npm:1.10.0"
@@ -3060,6 +3085,13 @@ __metadata:
languageName: node
linkType: hard
+"@flatten-js/interval-tree@npm:^1.1.2":
+ version: 1.1.4
+ resolution: "@flatten-js/interval-tree@npm:1.1.4"
+ checksum: 10c0/e4055e99b1b5958e0a1adea7413d9602f3d7ebed0dd47fcac1ad995a97151e02187fe1aa778c14be56c7faa3a29b2a71ece84be43312eff6850ebf316b3490b3
+ languageName: node
+ linkType: hard
+
"@gorhom/bottom-sheet@npm:^5.2.14":
version: 5.2.14
resolution: "@gorhom/bottom-sheet@npm:5.2.14"
@@ -3544,6 +3576,13 @@ __metadata:
languageName: node
linkType: hard
+"@jest/diff-sequences@npm:30.5.0":
+ version: 30.5.0
+ resolution: "@jest/diff-sequences@npm:30.5.0"
+ checksum: 10c0/a8d4fef9b266cb025b2f1c1be9ae2e807077def93f36e34a628aff383910fa7a26ba0921a43744841231ead54ea87469fb2acf89de47c12ad4fead802e0ccfc3
+ languageName: node
+ linkType: hard
+
"@jest/environment@npm:30.4.1":
version: 30.4.1
resolution: "@jest/environment@npm:30.4.1"
@@ -3556,6 +3595,18 @@ __metadata:
languageName: node
linkType: hard
+"@jest/environment@npm:30.5.2":
+ version: 30.5.2
+ resolution: "@jest/environment@npm:30.5.2"
+ dependencies:
+ "@jest/fake-timers": "npm:30.5.2"
+ "@jest/types": "npm:30.5.1"
+ "@types/node": "npm:*"
+ jest-mock: "npm:30.5.2"
+ checksum: 10c0/f060f2d94dfccd7de4890a419e803735921d8358a3ecc8e424e5f6a632da80fc37372f6e54f1397876b721cec5bae2da515e6dce2ac6558bd90f0c1cbeb5c105
+ languageName: node
+ linkType: hard
+
"@jest/environment@npm:^29.7.0":
version: 29.7.0
resolution: "@jest/environment@npm:29.7.0"
@@ -3577,6 +3628,15 @@ __metadata:
languageName: node
linkType: hard
+"@jest/expect-utils@npm:30.5.2":
+ version: 30.5.2
+ resolution: "@jest/expect-utils@npm:30.5.2"
+ dependencies:
+ "@jest/get-type": "npm:30.5.0"
+ checksum: 10c0/0db00595907f6705c5acc8d10ee9d11d74960cd459beaae66bd7a1d6845c7df1d123295e957bb56b6882b380f2e7d55d277ced7646e0229fc4a67abeb713c048
+ languageName: node
+ linkType: hard
+
"@jest/expect@npm:30.4.1":
version: 30.4.1
resolution: "@jest/expect@npm:30.4.1"
@@ -3587,6 +3647,16 @@ __metadata:
languageName: node
linkType: hard
+"@jest/expect@npm:30.5.2":
+ version: 30.5.2
+ resolution: "@jest/expect@npm:30.5.2"
+ dependencies:
+ expect: "npm:30.5.2"
+ jest-snapshot: "npm:30.5.2"
+ checksum: 10c0/ceebb291be34707e3d2ac99bc5e4a5039927e01d28650b1dc51888dfa3963a3a75a3c72f0abe4df9aa243dc3b31af72e467072d75b52bd11b80a84ebe765d8f9
+ languageName: node
+ linkType: hard
+
"@jest/fake-timers@npm:30.4.1":
version: 30.4.1
resolution: "@jest/fake-timers@npm:30.4.1"
@@ -3601,6 +3671,20 @@ __metadata:
languageName: node
linkType: hard
+"@jest/fake-timers@npm:30.5.2":
+ version: 30.5.2
+ resolution: "@jest/fake-timers@npm:30.5.2"
+ dependencies:
+ "@jest/types": "npm:30.5.1"
+ "@sinonjs/fake-timers": "npm:^15.4.0"
+ "@types/node": "npm:*"
+ jest-message-util: "npm:30.5.1"
+ jest-mock: "npm:30.5.2"
+ jest-util: "npm:30.5.1"
+ checksum: 10c0/c8ff08f541743210abaf07b75bfe6224458c816a500d5be954690fd1661cd14b054201dfe2a6ebdc0083290d4c03d73bbac4f3c1fbef5c3b16d1981642dfff57
+ languageName: node
+ linkType: hard
+
"@jest/fake-timers@npm:^29.7.0":
version: 29.7.0
resolution: "@jest/fake-timers@npm:29.7.0"
@@ -3622,6 +3706,13 @@ __metadata:
languageName: node
linkType: hard
+"@jest/get-type@npm:30.5.0":
+ version: 30.5.0
+ resolution: "@jest/get-type@npm:30.5.0"
+ checksum: 10c0/820a2af9902522d169ae4ede17a99249baad59ff6aead02f8100acbc937b082090b04d5f32ec0d9938491cf89c9fc99930ed469202700c110c0239c7f7ac67a2
+ languageName: node
+ linkType: hard
+
"@jest/globals@npm:30.4.1":
version: 30.4.1
resolution: "@jest/globals@npm:30.4.1"
@@ -3634,6 +3725,18 @@ __metadata:
languageName: node
linkType: hard
+"@jest/globals@npm:^30.4.1":
+ version: 30.5.2
+ resolution: "@jest/globals@npm:30.5.2"
+ dependencies:
+ "@jest/environment": "npm:30.5.2"
+ "@jest/expect": "npm:30.5.2"
+ "@jest/types": "npm:30.5.1"
+ jest-mock: "npm:30.5.2"
+ checksum: 10c0/e60738080d4866350b2152d98ddf99728cc1ac19983b80bea5d5ab219f82ef271fadd102b0cee2c01808367d6e054bea1c4ec4aa7c69e45b4e14b79a30f76538
+ languageName: node
+ linkType: hard
+
"@jest/pattern@npm:30.0.0":
version: 30.0.0
resolution: "@jest/pattern@npm:30.0.0"
@@ -3654,6 +3757,30 @@ __metadata:
languageName: node
linkType: hard
+"@jest/pattern@npm:30.5.0":
+ version: 30.5.0
+ resolution: "@jest/pattern@npm:30.5.0"
+ dependencies:
+ "@types/node": "npm:*"
+ jest-regex-util: "npm:30.5.0"
+ checksum: 10c0/3e960b25c7a32fee97a2cdf9ea810ada41f676c84db3c1afab138ee089e0e1cf4849372dd576acb18ac5219309695991c38e23ddacd9b95802ee3f76b4caaea4
+ languageName: node
+ linkType: hard
+
+"@jest/react-is-18@npm:react-is@^18.3.1, react-is-18@npm:react-is@^18.3.1, react-is@npm:^18.0.0":
+ version: 18.3.1
+ resolution: "react-is@npm:18.3.1"
+ checksum: 10c0/f2f1e60010c683479e74c63f96b09fb41603527cd131a9959e2aee1e5a8b0caf270b365e5ca77d4a6b18aae659b60a86150bb3979073528877029b35aecd2072
+ languageName: node
+ linkType: hard
+
+"@jest/react-is-19@npm:react-is@^19.2.5":
+ version: 19.3.1
+ resolution: "react-is@npm:19.3.1"
+ checksum: 10c0/428e02d986d56f1859c57756084489f6d2900fd686905003c405b32f1168738b78772bfa4bb6c706f5ac821199171522c28bf6434281f524f901459390a19606
+ languageName: node
+ linkType: hard
+
"@jest/reporters@npm:30.4.1":
version: 30.4.1
resolution: "@jest/reporters@npm:30.4.1"
@@ -3708,6 +3835,15 @@ __metadata:
languageName: node
linkType: hard
+"@jest/schemas@npm:30.5.0":
+ version: 30.5.0
+ resolution: "@jest/schemas@npm:30.5.0"
+ dependencies:
+ "@sinclair/typebox": "npm:^0.34.0"
+ checksum: 10c0/632c45a06a0984051c908fa9b3c9445bac7be8b7a6d1cc7ce2ecae7d4e44c612509ad41fca16449607c4ea49a333e0d3f10bb1510bafb4b6d9051ca15d9b4b14
+ languageName: node
+ linkType: hard
+
"@jest/schemas@npm:^29.6.3":
version: 29.6.3
resolution: "@jest/schemas@npm:29.6.3"
@@ -3729,6 +3865,18 @@ __metadata:
languageName: node
linkType: hard
+"@jest/snapshot-utils@npm:30.5.1":
+ version: 30.5.1
+ resolution: "@jest/snapshot-utils@npm:30.5.1"
+ dependencies:
+ "@jest/types": "npm:30.5.1"
+ chalk: "npm:^4.1.2"
+ graceful-fs: "npm:^4.2.11"
+ natural-compare: "npm:^1.4.0"
+ checksum: 10c0/0e31aa45c4be7b6e7dabcccc7316458f53bda262ab42f23b749430110d0ac908d4905db993708723a4f6457bc9208c636fd7b886e3ffc26974d55126cf597d6e
+ languageName: node
+ linkType: hard
+
"@jest/source-map@npm:30.0.1":
version: 30.0.1
resolution: "@jest/source-map@npm:30.0.1"
@@ -3809,6 +3957,28 @@ __metadata:
languageName: node
linkType: hard
+"@jest/transform@npm:30.5.2":
+ version: 30.5.2
+ resolution: "@jest/transform@npm:30.5.2"
+ dependencies:
+ "@babel/core": "npm:^7.27.4"
+ "@jest/types": "npm:30.5.1"
+ "@jridgewell/trace-mapping": "npm:^0.3.31"
+ babel-plugin-istanbul: "npm:^8.0.0"
+ chalk: "npm:^4.1.2"
+ convert-source-map: "npm:^2.0.0"
+ fast-json-stable-stringify: "npm:^2.1.0"
+ graceful-fs: "npm:^4.2.11"
+ jest-haste-map: "npm:30.5.1"
+ jest-regex-util: "npm:30.5.0"
+ jest-util: "npm:30.5.1"
+ pirates: "npm:^4.0.7"
+ slash: "npm:^3.0.0"
+ write-file-atomic: "npm:^5.0.1"
+ checksum: 10c0/be3f9aa812a442402ed41a37d0f11d174a0a9037038dc1326c32d1d55e22fc7bc5f5146284c5a18db3da572afb81739f0a93d3f1d519e811d25dacaeb380c647
+ languageName: node
+ linkType: hard
+
"@jest/transform@npm:^29.7.0":
version: 29.7.0
resolution: "@jest/transform@npm:29.7.0"
@@ -3862,6 +4032,21 @@ __metadata:
languageName: node
linkType: hard
+"@jest/types@npm:30.5.1":
+ version: 30.5.1
+ resolution: "@jest/types@npm:30.5.1"
+ dependencies:
+ "@jest/pattern": "npm:30.5.0"
+ "@jest/schemas": "npm:30.5.0"
+ "@types/istanbul-lib-coverage": "npm:^2.0.6"
+ "@types/istanbul-reports": "npm:^3.0.4"
+ "@types/node": "npm:*"
+ "@types/yargs": "npm:^17.0.33"
+ chalk: "npm:^4.1.2"
+ checksum: 10c0/da9e46449371ddd43b89627c93fb7088fdad01e9f57dce376c65914a6f4617a558f54ec51a917ca10c9b9794a1e76c3cb450308eca303f830bb21e9529b1719a
+ languageName: node
+ linkType: hard
+
"@jest/types@npm:^29.6.3":
version: 29.6.3
resolution: "@jest/types@npm:29.6.3"
@@ -4399,6 +4584,140 @@ __metadata:
languageName: node
linkType: hard
+"@parcel/watcher-android-arm64@npm:2.6.0":
+ version: 2.6.0
+ resolution: "@parcel/watcher-android-arm64@npm:2.6.0"
+ conditions: os=android & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@parcel/watcher-darwin-arm64@npm:2.6.0":
+ version: 2.6.0
+ resolution: "@parcel/watcher-darwin-arm64@npm:2.6.0"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@parcel/watcher-darwin-x64@npm:2.6.0":
+ version: 2.6.0
+ resolution: "@parcel/watcher-darwin-x64@npm:2.6.0"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@parcel/watcher-freebsd-x64@npm:2.6.0":
+ version: 2.6.0
+ resolution: "@parcel/watcher-freebsd-x64@npm:2.6.0"
+ conditions: os=freebsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@parcel/watcher-linux-arm-glibc@npm:2.6.0":
+ version: 2.6.0
+ resolution: "@parcel/watcher-linux-arm-glibc@npm:2.6.0"
+ conditions: os=linux & cpu=arm & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@parcel/watcher-linux-arm-musl@npm:2.6.0":
+ version: 2.6.0
+ resolution: "@parcel/watcher-linux-arm-musl@npm:2.6.0"
+ conditions: os=linux & cpu=arm & libc=musl
+ languageName: node
+ linkType: hard
+
+"@parcel/watcher-linux-arm64-glibc@npm:2.6.0":
+ version: 2.6.0
+ resolution: "@parcel/watcher-linux-arm64-glibc@npm:2.6.0"
+ conditions: os=linux & cpu=arm64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@parcel/watcher-linux-arm64-musl@npm:2.6.0":
+ version: 2.6.0
+ resolution: "@parcel/watcher-linux-arm64-musl@npm:2.6.0"
+ conditions: os=linux & cpu=arm64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@parcel/watcher-linux-x64-glibc@npm:2.6.0":
+ version: 2.6.0
+ resolution: "@parcel/watcher-linux-x64-glibc@npm:2.6.0"
+ conditions: os=linux & cpu=x64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@parcel/watcher-linux-x64-musl@npm:2.6.0":
+ version: 2.6.0
+ resolution: "@parcel/watcher-linux-x64-musl@npm:2.6.0"
+ conditions: os=linux & cpu=x64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@parcel/watcher-win32-arm64@npm:2.6.0":
+ version: 2.6.0
+ resolution: "@parcel/watcher-win32-arm64@npm:2.6.0"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@parcel/watcher-win32-x64@npm:2.6.0":
+ version: 2.6.0
+ resolution: "@parcel/watcher-win32-x64@npm:2.6.0"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@parcel/watcher@npm:^2.6.0":
+ version: 2.6.0
+ resolution: "@parcel/watcher@npm:2.6.0"
+ dependencies:
+ "@parcel/watcher-android-arm64": "npm:2.6.0"
+ "@parcel/watcher-darwin-arm64": "npm:2.6.0"
+ "@parcel/watcher-darwin-x64": "npm:2.6.0"
+ "@parcel/watcher-freebsd-x64": "npm:2.6.0"
+ "@parcel/watcher-linux-arm-glibc": "npm:2.6.0"
+ "@parcel/watcher-linux-arm-musl": "npm:2.6.0"
+ "@parcel/watcher-linux-arm64-glibc": "npm:2.6.0"
+ "@parcel/watcher-linux-arm64-musl": "npm:2.6.0"
+ "@parcel/watcher-linux-x64-glibc": "npm:2.6.0"
+ "@parcel/watcher-linux-x64-musl": "npm:2.6.0"
+ "@parcel/watcher-win32-arm64": "npm:2.6.0"
+ "@parcel/watcher-win32-x64": "npm:2.6.0"
+ detect-libc: "npm:^2.0.3"
+ is-glob: "npm:^4.0.3"
+ node-addon-api: "npm:^7.0.0"
+ node-gyp: "npm:latest"
+ picomatch: "npm:^4.0.4"
+ dependenciesMeta:
+ "@parcel/watcher-android-arm64":
+ optional: true
+ "@parcel/watcher-darwin-arm64":
+ optional: true
+ "@parcel/watcher-darwin-x64":
+ optional: true
+ "@parcel/watcher-freebsd-x64":
+ optional: true
+ "@parcel/watcher-linux-arm-glibc":
+ optional: true
+ "@parcel/watcher-linux-arm-musl":
+ optional: true
+ "@parcel/watcher-linux-arm64-glibc":
+ optional: true
+ "@parcel/watcher-linux-arm64-musl":
+ optional: true
+ "@parcel/watcher-linux-x64-glibc":
+ optional: true
+ "@parcel/watcher-linux-x64-musl":
+ optional: true
+ "@parcel/watcher-win32-arm64":
+ optional: true
+ "@parcel/watcher-win32-x64":
+ optional: true
+ checksum: 10c0/0d6799bdf7d59a1ab5e4a79859035f387a66078586d9543eef0b9bd01c9d61cebe3b64eb96f0bd1f8bf50f07ed7266a1628604b66dc63025a3cee19be2e60d65
+ languageName: node
+ linkType: hard
+
"@pkgjs/parseargs@npm:^0.11.0":
version: 0.11.0
resolution: "@pkgjs/parseargs@npm:0.11.0"
@@ -6056,6 +6375,16 @@ __metadata:
languageName: node
linkType: hard
+"@so-ric/colorspace@npm:^1.1.6":
+ version: 1.1.6
+ resolution: "@so-ric/colorspace@npm:1.1.6"
+ dependencies:
+ color: "npm:^5.0.2"
+ text-hex: "npm:1.0.x"
+ checksum: 10c0/f3ad26afefbb8d6101ea7c385cd5f402d4291c2ffc9cabe37030d5fdb8bda980ee534a0d7c250f8233fc3a59b99272410177cd98b219f6b3770f91a0fdb6eb3e
+ languageName: node
+ linkType: hard
+
"@stream-io/state-store@npm:^1.1.6":
version: 1.1.6
resolution: "@stream-io/state-store@npm:1.1.6"
@@ -6569,6 +6898,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/triple-beam@npm:^1.3.2":
+ version: 1.3.5
+ resolution: "@types/triple-beam@npm:1.3.5"
+ checksum: 10c0/d5d7f25da612f6d79266f4f1bb9c1ef8f1684e9f60abab251e1261170631062b656ba26ff22631f2760caeafd372abc41e64867cde27fba54fafb73a35b9056a
+ languageName: node
+ linkType: hard
+
"@types/ungap__structured-clone@npm:^1.2.0":
version: 1.2.0
resolution: "@types/ungap__structured-clone@npm:1.2.0"
@@ -6920,6 +7256,33 @@ __metadata:
languageName: node
linkType: hard
+"@wix-pilot/core@npm:^3.4.2":
+ version: 3.4.2
+ resolution: "@wix-pilot/core@npm:3.4.2"
+ dependencies:
+ chalk: "npm:^4.1.0"
+ pngjs: "npm:^7.0.0"
+ winston: "npm:^3.17.0"
+ peerDependencies:
+ expect: "*"
+ peerDependenciesMeta:
+ expect:
+ optional: true
+ checksum: 10c0/606dcd0951cfdfb6bda69718512e6daedda22b15dcc4b2029739e3d02b2d676b30d5d97a6d6558d12a8cfae332b6beb48e32ac620eae4ca5eefa43543dd9e14a
+ languageName: node
+ linkType: hard
+
+"@wix-pilot/detox@npm:^1.0.13":
+ version: 1.0.13
+ resolution: "@wix-pilot/detox@npm:1.0.13"
+ peerDependencies:
+ "@wix-pilot/core": ^3.4.1
+ detox: ">=20.33.0"
+ expect: 29.x.x || 28.x.x || ^27.2.5
+ checksum: 10c0/210b1834ce628cfacdc7417ed8596455045bd6c87bc4ef01b99558ddeeab00648d8ed73abdd212f7cb3d96110b0d36bf8812fd31e1d61a4d3b8f7cad41ab69bf
+ languageName: node
+ linkType: hard
+
"@xmldom/xmldom@npm:^0.8.8":
version: 0.8.13
resolution: "@xmldom/xmldom@npm:0.8.13"
@@ -7090,7 +7453,7 @@ __metadata:
languageName: node
linkType: hard
-"ajv@npm:^8.11.0":
+"ajv@npm:^8.11.0, ajv@npm:^8.6.3":
version: 8.20.0
resolution: "ajv@npm:8.20.0"
dependencies:
@@ -7442,6 +7805,13 @@ __metadata:
languageName: node
linkType: hard
+"async@npm:^3.2.3":
+ version: 3.2.6
+ resolution: "async@npm:3.2.6"
+ checksum: 10c0/36484bb15ceddf07078688d95e27076379cc2f87b10c03b6dd8a83e89475a3c8df5848859dd06a4c95af1e4c16fc973de0171a77f18ea00be899aca2a4f85e70
+ languageName: node
+ linkType: hard
+
"asynckit@npm:^0.4.0":
version: 0.4.0
resolution: "asynckit@npm:0.4.0"
@@ -7565,6 +7935,19 @@ __metadata:
languageName: node
linkType: hard
+"babel-plugin-istanbul@npm:^8.0.0":
+ version: 8.0.2
+ resolution: "babel-plugin-istanbul@npm:8.0.2"
+ dependencies:
+ "@babel/helper-plugin-utils": "npm:^7.0.0"
+ "@istanbuljs/load-nyc-config": "npm:^1.0.0"
+ "@istanbuljs/schema": "npm:^0.1.3"
+ istanbul-lib-instrument: "npm:^6.0.2"
+ test-exclude: "npm:^7.0.1"
+ checksum: 10c0/795577336196114ea19d2cd9efae41cde66b08bc8b7a326ed35bfe7da85b5756ebe19d9fcf3c98d3bd0e194d1258229178414a79fe3a623a66a449e468cf7af5
+ languageName: node
+ linkType: hard
+
"babel-plugin-jest-hoist@npm:30.0.0":
version: 30.0.0
resolution: "babel-plugin-jest-hoist@npm:30.0.0"
@@ -7926,6 +8309,13 @@ __metadata:
languageName: node
linkType: hard
+"bluebird@npm:^3.5.4":
+ version: 3.7.2
+ resolution: "bluebird@npm:3.7.2"
+ checksum: 10c0/680de03adc54ff925eaa6c7bb9a47a0690e8b5de60f4792604aae8ed618c65e6b63a7893b57ca924beaf53eee69c5af4f8314148c08124c550fe1df1add897d2
+ languageName: node
+ linkType: hard
+
"body-parser@npm:^2.2.2":
version: 2.3.0
resolution: "body-parser@npm:2.3.0"
@@ -8021,6 +8411,13 @@ __metadata:
languageName: node
linkType: hard
+"browser-process-hrtime@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "browser-process-hrtime@npm:1.0.0"
+ checksum: 10c0/65da78e51e9d7fa5909147f269c54c65ae2e03d1cf797cc3cfbbe49f475578b8160ce4a76c36c1a2ffbff26c74f937d73096c508057491ddf1a6dfd11143f72d
+ languageName: node
+ linkType: hard
+
"browserslist@npm:^4.20.4, browserslist@npm:^4.24.0, browserslist@npm:^4.25.0, browserslist@npm:^4.28.1":
version: 4.28.2
resolution: "browserslist@npm:4.28.2"
@@ -8069,6 +8466,87 @@ __metadata:
languageName: node
linkType: hard
+"bunyamin@npm:^1.5.2":
+ version: 1.6.3
+ resolution: "bunyamin@npm:1.6.3"
+ dependencies:
+ "@flatten-js/interval-tree": "npm:^1.1.2"
+ multi-sort-stream: "npm:^1.0.4"
+ stream-json: "npm:^1.7.5"
+ trace-event-lib: "npm:^1.3.1"
+ peerDependencies:
+ "@types/bunyan": ^1.8.8
+ bunyan: ^1.8.15 || ^2.0.0
+ peerDependenciesMeta:
+ "@types/bunyan":
+ optional: true
+ bunyan:
+ optional: true
+ checksum: 10c0/150a93cbf0ea83ff38f73de42742fc162e24d87551d9b5454769a4c2966b900a4e2a63dbd3d1f616a1178e65f0966cd76b2a48981764de7ae93b55de79410c83
+ languageName: node
+ linkType: hard
+
+"bunyan-debug-stream@npm:^3.1.0":
+ version: 3.1.1
+ resolution: "bunyan-debug-stream@npm:3.1.1"
+ dependencies:
+ chalk: "npm:^4.1.2"
+ peerDependencies:
+ bunyan: "*"
+ peerDependenciesMeta:
+ bunyan:
+ optional: true
+ checksum: 10c0/3682454c08910ffbe4b9d9c3e4ba97d36ca5d78e9bac5d71f639c12e35cfa921df76dd736d08c061c673c5cb232fcc3ecb05cbcc4868cd60c816edc4e6f06028
+ languageName: node
+ linkType: hard
+
+"bunyan@npm:^1.8.12":
+ version: 1.8.15
+ resolution: "bunyan@npm:1.8.15"
+ dependencies:
+ dtrace-provider: "npm:~0.8"
+ moment: "npm:^2.19.3"
+ mv: "npm:~2"
+ safe-json-stringify: "npm:~1"
+ dependenciesMeta:
+ dtrace-provider:
+ optional: true
+ moment:
+ optional: true
+ mv:
+ optional: true
+ safe-json-stringify:
+ optional: true
+ bin:
+ bunyan: bin/bunyan
+ checksum: 10c0/c7b3adc07a4db3256f857dcba42b97dd6c35ab054cb26766643aae2b90e1b614795cdf231774ddaf374572d952f52ef4f4205047e15414e155e478aa0672e041
+ languageName: node
+ linkType: hard
+
+"bunyan@npm:^2.0.5":
+ version: 2.0.5
+ resolution: "bunyan@npm:2.0.5"
+ dependencies:
+ dtrace-provider: "npm:~0.8"
+ exeunt: "npm:1.1.0"
+ moment: "npm:^2.19.3"
+ mv: "npm:~2"
+ safe-json-stringify: "npm:~1"
+ dependenciesMeta:
+ dtrace-provider:
+ optional: true
+ moment:
+ optional: true
+ mv:
+ optional: true
+ safe-json-stringify:
+ optional: true
+ bin:
+ bunyan: bin/bunyan
+ checksum: 10c0/b3a2f0ccc4473c7a83d94f64805dd4ae70e4f7afff8658262a782a8a41ad71e062749e67ec7be57ab3ae724d3d199247ef4b6976ac6c0c67a114f442224977aa
+ languageName: node
+ linkType: hard
+
"bytes@npm:3.1.2, bytes@npm:^3.1.2, bytes@npm:~3.1.2":
version: 3.1.2
resolution: "bytes@npm:3.1.2"
@@ -8095,6 +8573,13 @@ __metadata:
languageName: node
linkType: hard
+"caf@npm:^15.0.1":
+ version: 15.0.1
+ resolution: "caf@npm:15.0.1"
+ checksum: 10c0/9a852c3c93c44499ab1e2cc58c264dd99bb2eaeb17b46df84e6fa5302d6829f776e84a1c13da5bbc2830ba274087eddbde9fe23334f7eb00ce89da9333d1a5cc
+ languageName: node
+ linkType: hard
+
"call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2":
version: 1.0.2
resolution: "call-bind-apply-helpers@npm:1.0.2"
@@ -8166,7 +8651,7 @@ __metadata:
languageName: node
linkType: hard
-"camelcase@npm:^6.2.0, camelcase@npm:^6.3.0":
+"camelcase@npm:^6.0.0, camelcase@npm:^6.2.0, camelcase@npm:^6.3.0":
version: 6.3.0
resolution: "camelcase@npm:6.3.0"
checksum: 10c0/0d701658219bd3116d12da3eab31acddb3f9440790c0792e0d398f0a520a6a4058018e546862b6fba89d7ae990efaeb97da71e1913e9ebf5a8b5621a3d55c710
@@ -8533,6 +9018,15 @@ __metadata:
languageName: node
linkType: hard
+"color-convert@npm:^3.1.3":
+ version: 3.1.3
+ resolution: "color-convert@npm:3.1.3"
+ dependencies:
+ color-name: "npm:^2.0.0"
+ checksum: 10c0/427648b442c6ea6dab5ba03f4962201ee59f128c80b25d5a0f7d9aab0ef52519a9db8a9bb3cf40b73f86eb19b5ca6aeb0ab930665f3d14973ce776d7d0448a15
+ languageName: node
+ linkType: hard
+
"color-name@npm:1.1.3":
version: 1.1.3
resolution: "color-name@npm:1.1.3"
@@ -8547,6 +9041,13 @@ __metadata:
languageName: node
linkType: hard
+"color-name@npm:^2.0.0":
+ version: 2.1.1
+ resolution: "color-name@npm:2.1.1"
+ checksum: 10c0/6a1096d761b84ad18bdf1464d449800dbb1e613c914aafd9551514884f5e0cc47b5478fea32048188ec7a28424c6ded55fd4a81f39ca351e2ca4dd7729e05128
+ languageName: node
+ linkType: hard
+
"color-string@npm:^1.9.0":
version: 1.9.1
resolution: "color-string@npm:1.9.1"
@@ -8557,6 +9058,15 @@ __metadata:
languageName: node
linkType: hard
+"color-string@npm:^2.1.3":
+ version: 2.1.4
+ resolution: "color-string@npm:2.1.4"
+ dependencies:
+ color-name: "npm:^2.0.0"
+ checksum: 10c0/18a9fefec153d885e0dbfb076f3a65cdcd19f52d96c719f2f261e90e5b7dafd13c51baac399d7099eac290f004d340045ab9467312dcc8afefe6f877ec5c4428
+ languageName: node
+ linkType: hard
+
"color@npm:^4.2.3":
version: 4.2.3
resolution: "color@npm:4.2.3"
@@ -8567,6 +9077,16 @@ __metadata:
languageName: node
linkType: hard
+"color@npm:^5.0.2":
+ version: 5.0.3
+ resolution: "color@npm:5.0.3"
+ dependencies:
+ color-convert: "npm:^3.1.3"
+ color-string: "npm:^2.1.3"
+ checksum: 10c0/f08a03c5113ae4aa36dba9d2438596b194b897e18b961310643cb63872add1da507cd238df264eb434bbdbe3a377ec41f90d877531acca611523cfcd365db1b6
+ languageName: node
+ linkType: hard
+
"colorette@npm:^1.0.7":
version: 1.4.0
resolution: "colorette@npm:1.4.0"
@@ -9155,6 +9675,13 @@ __metadata:
languageName: node
linkType: hard
+"decamelize@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "decamelize@npm:4.0.0"
+ checksum: 10c0/e06da03fc05333e8cd2778c1487da67ffbea5b84e03ca80449519b8fa61f888714bbc6f459ea963d5641b4aa98832130eb5cd193d90ae9f0a27eee14be8e278d
+ languageName: node
+ linkType: hard
+
"decode-named-character-reference@npm:^1.0.0":
version: 1.3.0
resolution: "decode-named-character-reference@npm:1.3.0"
@@ -9309,6 +9836,58 @@ __metadata:
languageName: node
linkType: hard
+"detox@npm:^20.51.4":
+ version: 20.51.4
+ resolution: "detox@npm:20.51.4"
+ dependencies:
+ "@wix-pilot/core": "npm:^3.4.2"
+ "@wix-pilot/detox": "npm:^1.0.13"
+ ajv: "npm:^8.6.3"
+ bunyan: "npm:^1.8.12"
+ bunyan-debug-stream: "npm:^3.1.0"
+ caf: "npm:^15.0.1"
+ chalk: "npm:^4.0.0"
+ execa: "npm:^5.1.1"
+ find-up: "npm:^5.0.0"
+ fs-extra: "npm:^11.0.0"
+ funpermaproxy: "npm:^1.1.0"
+ glob: "npm:^8.0.3"
+ ini: "npm:^1.3.4"
+ jest-environment-emit: "npm:^1.2.0"
+ json-cycle: "npm:^1.3.0"
+ lodash: "npm:^4.17.11"
+ multi-sort-stream: "npm:^1.0.3"
+ multipipe: "npm:^4.0.0"
+ node-ipc: "npm:9.2.1"
+ promisify-child-process: "npm:^4.1.2"
+ proper-lockfile: "npm:^3.0.2"
+ resolve-from: "npm:^5.0.0"
+ sanitize-filename: "npm:^1.6.1"
+ semver: "npm:^7.0.0"
+ serialize-error: "npm:^8.0.1"
+ shell-quote: "npm:^1.7.2"
+ signal-exit: "npm:^3.0.3"
+ stream-json: "npm:^1.7.4"
+ strip-ansi: "npm:^6.0.1"
+ telnet-client: "npm:1.2.8"
+ tmp: "npm:^0.2.1"
+ trace-event-lib: "npm:^1.3.1"
+ which: "npm:^1.3.1"
+ ws: "npm:^7.0.0"
+ yargs: "npm:^17.0.0"
+ yargs-parser: "npm:^21.0.0"
+ yargs-unparser: "npm:^2.0.0"
+ peerDependencies:
+ jest: 30.x.x || 29.x.x || 28.x.x || ^27.2.5
+ peerDependenciesMeta:
+ jest:
+ optional: true
+ bin:
+ detox: local-cli/cli.js
+ checksum: 10c0/4be674954c6ca60d8efb5d396848eefd5241018c78f64b503a462b0a66b9e7805d0af984318546ee8810063a95f9d92892d3e1e3d9b589ce703d2210da80fb16
+ languageName: node
+ linkType: hard
+
"diff-sequences@npm:^29.6.3":
version: 29.6.3
resolution: "diff-sequences@npm:29.6.3"
@@ -9402,6 +9981,16 @@ __metadata:
languageName: node
linkType: hard
+"dtrace-provider@npm:~0.8":
+ version: 0.8.8
+ resolution: "dtrace-provider@npm:0.8.8"
+ dependencies:
+ nan: "npm:^2.14.0"
+ node-gyp: "npm:latest"
+ checksum: 10c0/33bfc18462dd59ae1de094c64b7b093d2f7f67dec48f138df3a7507c09aaed2a964a245e7bdf2bde7d1a6cc467b11d7396e0fb13a6b882642d42a44cc08c61da
+ languageName: node
+ linkType: hard
+
"dunder-proto@npm:^1.0.0, dunder-proto@npm:^1.0.1":
version: 1.0.1
resolution: "dunder-proto@npm:1.0.1"
@@ -9413,7 +10002,7 @@ __metadata:
languageName: node
linkType: hard
-"duplexer2@npm:~0.1.0":
+"duplexer2@npm:^0.1.2, duplexer2@npm:~0.1.0":
version: 0.1.4
resolution: "duplexer2@npm:0.1.4"
dependencies:
@@ -9422,6 +10011,41 @@ __metadata:
languageName: node
linkType: hard
+"e2etestapp@workspace:examples/E2ETestApp":
+ version: 0.0.0-use.local
+ resolution: "e2etestapp@workspace:examples/E2ETestApp"
+ dependencies:
+ "@babel/core": "npm:^7.29.0"
+ "@babel/runtime": "npm:^7.29.2"
+ "@jest/globals": "npm:^30.4.1"
+ "@react-native-community/cli": "npm:20.2.0"
+ "@react-native-community/cli-platform-android": "npm:20.2.0"
+ "@react-native-community/cli-platform-ios": "npm:20.2.0"
+ "@react-native-community/netinfo": "npm:^12.0.1"
+ "@react-native/babel-preset": "npm:0.88.0"
+ "@react-native/metro-config": "npm:0.88.0"
+ "@react-native/typescript-config": "npm:0.88.0"
+ "@rnx-kit/metro-config": "npm:^2.2.6"
+ "@stream-io/typescript-config": "workspace:^"
+ "@types/react": "npm:^19.3.0"
+ babel-jest: "npm:30.0.0"
+ detox: "npm:^20.51.4"
+ jest: "npm:^30.4.2"
+ react: "npm:19.3.0"
+ react-native: "npm:0.88.0"
+ react-native-gesture-handler: "npm:^3.4.0"
+ react-native-launch-arguments: "npm:^4.1.1"
+ react-native-reanimated: "npm:4.7.1"
+ react-native-safe-area-context: "npm:^5.10.1"
+ react-native-svg: "npm:^15.15.5"
+ react-native-teleport: "npm:^1.2.2"
+ react-native-worklets: "npm:^0.13.0"
+ stream-chat: "npm:^9.54.0"
+ stream-chat-react-native: "workspace:^"
+ typescript: "npm:6.0.3"
+ languageName: unknown
+ linkType: soft
+
"eastasianwidth@npm:^0.2.0":
version: 0.2.0
resolution: "eastasianwidth@npm:0.2.0"
@@ -9429,6 +10053,13 @@ __metadata:
languageName: node
linkType: hard
+"easy-stack@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "easy-stack@npm:1.0.1"
+ checksum: 10c0/1eaf066169a20f6cc3cafd2bb36b00baacd60b6414c8d8bf51bfd50bc6f1c487140c8af86bbb8e1ff9ded2faea5e138c55a37867fc79cbbc985bf5a5ebe4b109
+ languageName: node
+ linkType: hard
+
"ecdsa-sig-formatter@npm:1.0.11":
version: 1.0.11
resolution: "ecdsa-sig-formatter@npm:1.0.11"
@@ -9494,6 +10125,13 @@ __metadata:
languageName: node
linkType: hard
+"enabled@npm:2.0.x":
+ version: 2.0.0
+ resolution: "enabled@npm:2.0.0"
+ checksum: 10c0/3b2c2af9bc7f8b9e291610f2dde4a75cf6ee52a68f4dd585482fbdf9a55d65388940e024e56d40bb03e05ef6671f5f53021fa8b72a20e954d7066ec28166713f
+ languageName: node
+ linkType: hard
+
"encodeurl@npm:~1.0.2":
version: 1.0.2
resolution: "encodeurl@npm:1.0.2"
@@ -10189,6 +10827,13 @@ __metadata:
languageName: node
linkType: hard
+"event-pubsub@npm:4.3.0":
+ version: 4.3.0
+ resolution: "event-pubsub@npm:4.3.0"
+ checksum: 10c0/47fa4fb5b55b3ed08b912862cc913e03603fa063cd3ec5cf3dfeb39a19314d3ca327e938a2cf70685254ab3a71af8178969963c705a030c6081d625bec835114
+ languageName: node
+ linkType: hard
+
"execa@npm:^4.0.3":
version: 4.1.0
resolution: "execa@npm:4.1.0"
@@ -10260,6 +10905,13 @@ __metadata:
languageName: node
linkType: hard
+"exeunt@npm:1.1.0":
+ version: 1.1.0
+ resolution: "exeunt@npm:1.1.0"
+ checksum: 10c0/dc2012d9016c01ec321e4d642d2f165ce7dc4a4d141c523a818416035bcfe11bd1d9abc142f6f608d6a7719824295131a1b8c89006eb308aafd3aba385bf40d2
+ languageName: node
+ linkType: hard
+
"exit-x@npm:^0.2.2":
version: 0.2.2
resolution: "exit-x@npm:0.2.2"
@@ -10288,6 +10940,20 @@ __metadata:
languageName: node
linkType: hard
+"expect@npm:30.5.2":
+ version: 30.5.2
+ resolution: "expect@npm:30.5.2"
+ dependencies:
+ "@jest/expect-utils": "npm:30.5.2"
+ "@jest/get-type": "npm:30.5.0"
+ jest-matcher-utils: "npm:30.5.2"
+ jest-message-util: "npm:30.5.1"
+ jest-mock: "npm:30.5.2"
+ jest-util: "npm:30.5.1"
+ checksum: 10c0/31bf2307499008f267c84992a8ea27f76e97f207f685075439aa12f60b93dd81d024e5fcb0142755ed499233056f27fa51d01843d04cba437dfe7588387c352f
+ languageName: node
+ linkType: hard
+
"expo-asset@npm:~58.0.14":
version: 58.0.14
resolution: "expo-asset@npm:58.0.14"
@@ -10972,6 +11638,13 @@ __metadata:
languageName: node
linkType: hard
+"fecha@npm:^4.2.0":
+ version: 4.2.3
+ resolution: "fecha@npm:4.2.3"
+ checksum: 10c0/0e895965959cf6a22bb7b00f0bf546f2783836310f510ddf63f463e1518d4c96dec61ab33fdfd8e79a71b4856a7c865478ce2ee8498d560fe125947703c9b1cf
+ languageName: node
+ linkType: hard
+
"fetch-nodeshim@npm:^0.4.10":
version: 0.4.10
resolution: "fetch-nodeshim@npm:0.4.10"
@@ -11147,6 +11820,15 @@ __metadata:
languageName: node
linkType: hard
+"flat@npm:^5.0.2":
+ version: 5.0.2
+ resolution: "flat@npm:5.0.2"
+ bin:
+ flat: cli.js
+ checksum: 10c0/f178b13482f0cd80c7fede05f4d10585b1f2fdebf26e12edc138e32d3150c6ea6482b7f12813a1091143bad52bb6d3596bca51a162257a21163c0ff438baa5fe
+ languageName: node
+ linkType: hard
+
"flatted@npm:^3.2.9":
version: 3.4.2
resolution: "flatted@npm:3.4.2"
@@ -11193,6 +11875,13 @@ __metadata:
languageName: node
linkType: hard
+"fn.name@npm:1.x.x":
+ version: 1.1.0
+ resolution: "fn.name@npm:1.1.0"
+ checksum: 10c0/8ad62aa2d4f0b2a76d09dba36cfec61c540c13a0fd72e5d94164e430f987a7ce6a743112bbeb14877c810ef500d1f73d7f56e76d029d2e3413f20d79e3460a9a
+ languageName: node
+ linkType: hard
+
"follow-redirects@npm:^1.16.0":
version: 1.16.0
resolution: "follow-redirects@npm:1.16.0"
@@ -11369,6 +12058,13 @@ __metadata:
languageName: node
linkType: hard
+"funpermaproxy@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "funpermaproxy@npm:1.1.0"
+ checksum: 10c0/058d5f56499dac0a275d7115c74230e339f7481618b96c21e8cafa8260a6db7c16f1e4127f5be2aeb167876ff5f33846503a07148279b2f68ca45d04771d666e
+ languageName: node
+ linkType: hard
+
"generator-function@npm:^2.0.0":
version: 2.0.1
resolution: "generator-function@npm:2.0.1"
@@ -11544,7 +12240,7 @@ __metadata:
languageName: node
linkType: hard
-"glob@npm:^10.5.0":
+"glob@npm:^10.4.1, glob@npm:^10.5.0":
version: 10.5.0
resolution: "glob@npm:10.5.0"
dependencies:
@@ -11571,6 +12267,19 @@ __metadata:
languageName: node
linkType: hard
+"glob@npm:^6.0.1":
+ version: 6.0.4
+ resolution: "glob@npm:6.0.4"
+ dependencies:
+ inflight: "npm:^1.0.4"
+ inherits: "npm:2"
+ minimatch: "npm:2 || 3"
+ once: "npm:^1.3.0"
+ path-is-absolute: "npm:^1.0.0"
+ checksum: 10c0/520146ebce0f4594b8357338f86281b38ee14214debce398a2902176a28f18e0f98911ea48516d85022de64fbbaa57f074aa13715d1daa5d70e21b82cea22183
+ languageName: node
+ linkType: hard
+
"glob@npm:^7.1.3, glob@npm:^7.1.4":
version: 7.2.3
resolution: "glob@npm:7.2.3"
@@ -11671,7 +12380,7 @@ __metadata:
languageName: node
linkType: hard
-"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.3, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9":
+"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.3, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9":
version: 4.2.11
resolution: "graceful-fs@npm:4.2.11"
checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2
@@ -13166,6 +13875,18 @@ __metadata:
languageName: node
linkType: hard
+"jest-diff@npm:30.5.2":
+ version: 30.5.2
+ resolution: "jest-diff@npm:30.5.2"
+ dependencies:
+ "@jest/diff-sequences": "npm:30.5.0"
+ "@jest/get-type": "npm:30.5.0"
+ chalk: "npm:^4.1.2"
+ pretty-format: "npm:30.5.1"
+ checksum: 10c0/b11524e4b7a0c7b83c5b6a3775f705b1002bf086c211e9bd2e481686e3fa0ee1a87e61fa7453232aef2808f085f254f4f8fcbb41b69681d1b9384ec321cf6002
+ languageName: node
+ linkType: hard
+
"jest-diff@npm:^29.0.1, jest-diff@npm:^29.7.0":
version: 29.7.0
resolution: "jest-diff@npm:29.7.0"
@@ -13200,6 +13921,39 @@ __metadata:
languageName: node
linkType: hard
+"jest-environment-emit@npm:^1.2.0":
+ version: 1.2.0
+ resolution: "jest-environment-emit@npm:1.2.0"
+ dependencies:
+ bunyamin: "npm:^1.5.2"
+ bunyan: "npm:^2.0.5"
+ bunyan-debug-stream: "npm:^3.1.0"
+ funpermaproxy: "npm:^1.1.0"
+ lodash.merge: "npm:^4.6.2"
+ node-ipc: "npm:9.2.1"
+ strip-ansi: "npm:^6.0.0"
+ tslib: "npm:^2.5.3"
+ peerDependencies:
+ "@jest/environment": ">=27.2.5"
+ "@jest/types": ">=27.2.5"
+ jest: ">=27.2.5"
+ jest-environment-jsdom: ">=27.2.5"
+ jest-environment-node: ">=27.2.5"
+ peerDependenciesMeta:
+ "@jest/environment":
+ optional: true
+ "@jest/types":
+ optional: true
+ jest:
+ optional: true
+ jest-environment-jsdom:
+ optional: true
+ jest-environment-node:
+ optional: true
+ checksum: 10c0/4e1230b447b54c54eecbc6e52782e2133a07b0556a43d34b9f7733b4be8d3a390be7a444863abed31cef638a259815f65b41b588dabc9f9ee478af9ea0ab419b
+ languageName: node
+ linkType: hard
+
"jest-environment-node@npm:30.4.1":
version: 30.4.1
resolution: "jest-environment-node@npm:30.4.1"
@@ -13280,6 +14034,25 @@ __metadata:
languageName: node
linkType: hard
+"jest-haste-map@npm:30.5.1":
+ version: 30.5.1
+ resolution: "jest-haste-map@npm:30.5.1"
+ dependencies:
+ "@jest/types": "npm:30.5.1"
+ "@parcel/watcher": "npm:^2.6.0"
+ "@types/node": "npm:*"
+ anymatch: "npm:^3.1.3"
+ fb-watchman: "npm:^2.0.2"
+ fdir: "npm:^6.5.0"
+ graceful-fs: "npm:^4.2.11"
+ jest-regex-util: "npm:30.5.0"
+ jest-util: "npm:30.5.1"
+ jest-worker: "npm:30.5.1"
+ picomatch: "npm:^4.0.3"
+ checksum: 10c0/a9838762f84c54b1d551650e3c956f8d72370a15b2e9291d4b0c9aab0b4d4f3d1758bbc619ffb028af567d5dc53a73c5e72af078c56c5fa47cd73a2a309ca89a
+ languageName: node
+ linkType: hard
+
"jest-haste-map@npm:^29.7.0":
version: 29.7.0
resolution: "jest-haste-map@npm:29.7.0"
@@ -13325,6 +14098,18 @@ __metadata:
languageName: node
linkType: hard
+"jest-matcher-utils@npm:30.5.2":
+ version: 30.5.2
+ resolution: "jest-matcher-utils@npm:30.5.2"
+ dependencies:
+ "@jest/get-type": "npm:30.5.0"
+ chalk: "npm:^4.1.2"
+ jest-diff: "npm:30.5.2"
+ pretty-format: "npm:30.5.1"
+ checksum: 10c0/30f075c6f897335415817ad25e6caae8994de87c31ad59ae8f501e2c8bf6c925635abb481c562436b6add42a784902f105ee2fa0eca3357bd26e038f7e004cb8
+ languageName: node
+ linkType: hard
+
"jest-matcher-utils@npm:^29.0.1, jest-matcher-utils@npm:^29.7.0":
version: 29.7.0
resolution: "jest-matcher-utils@npm:29.7.0"
@@ -13355,6 +14140,24 @@ __metadata:
languageName: node
linkType: hard
+"jest-message-util@npm:30.5.1":
+ version: 30.5.1
+ resolution: "jest-message-util@npm:30.5.1"
+ dependencies:
+ "@babel/code-frame": "npm:^7.27.1"
+ "@jest/types": "npm:30.5.1"
+ "@types/stack-utils": "npm:^2.0.3"
+ chalk: "npm:^4.1.2"
+ graceful-fs: "npm:^4.2.11"
+ jest-util: "npm:30.5.1"
+ picomatch: "npm:^4.0.3"
+ pretty-format: "npm:30.5.1"
+ slash: "npm:^3.0.0"
+ stack-utils: "npm:^2.0.6"
+ checksum: 10c0/f542d07f8ceba19da26c547aa86abc51e6fad518999a18853e7c2acc2a55845ad759aa94cbe650d0453b036b81fcafee710d467b55e1e509f9939db033e76919
+ languageName: node
+ linkType: hard
+
"jest-message-util@npm:^29.7.0":
version: 29.7.0
resolution: "jest-message-util@npm:29.7.0"
@@ -13383,6 +14186,18 @@ __metadata:
languageName: node
linkType: hard
+"jest-mock@npm:30.5.2":
+ version: 30.5.2
+ resolution: "jest-mock@npm:30.5.2"
+ dependencies:
+ "@jest/expect-utils": "npm:30.5.2"
+ "@jest/types": "npm:30.5.1"
+ "@types/node": "npm:*"
+ jest-util: "npm:30.5.1"
+ checksum: 10c0/24cc9ac6449c536ef5009c531e14ee6b145f5d68db6e4c5616a8f775c5c81173e83e2c6c47922d413da4dbf804eab555b91ab424b0bf918495ee1b29d8a8ebaa
+ languageName: node
+ linkType: hard
+
"jest-mock@npm:^29.7.0":
version: 29.7.0
resolution: "jest-mock@npm:29.7.0"
@@ -13420,6 +14235,13 @@ __metadata:
languageName: node
linkType: hard
+"jest-regex-util@npm:30.5.0":
+ version: 30.5.0
+ resolution: "jest-regex-util@npm:30.5.0"
+ checksum: 10c0/f0e5ef257b906862821e1fb58c1d3d7bb3c4fc1fb11915673f04d3693673e0656b8f502c9871900e13e58329039c73e5b5c59a2622cbd6ba5c7fc7463b60ce48
+ languageName: node
+ linkType: hard
+
"jest-regex-util@npm:^29.6.3":
version: 29.6.3
resolution: "jest-regex-util@npm:29.6.3"
@@ -13542,6 +14364,35 @@ __metadata:
languageName: node
linkType: hard
+"jest-snapshot@npm:30.5.2":
+ version: 30.5.2
+ resolution: "jest-snapshot@npm:30.5.2"
+ dependencies:
+ "@babel/core": "npm:^7.27.4"
+ "@babel/generator": "npm:^7.27.5"
+ "@babel/plugin-syntax-jsx": "npm:^7.27.1"
+ "@babel/plugin-syntax-typescript": "npm:^7.27.1"
+ "@babel/types": "npm:^7.27.3"
+ "@jest/expect-utils": "npm:30.5.2"
+ "@jest/get-type": "npm:30.5.0"
+ "@jest/snapshot-utils": "npm:30.5.1"
+ "@jest/transform": "npm:30.5.2"
+ "@jest/types": "npm:30.5.1"
+ babel-preset-current-node-syntax: "npm:^1.2.0"
+ chalk: "npm:^4.1.2"
+ expect: "npm:30.5.2"
+ graceful-fs: "npm:^4.2.11"
+ jest-diff: "npm:30.5.2"
+ jest-matcher-utils: "npm:30.5.2"
+ jest-message-util: "npm:30.5.1"
+ jest-util: "npm:30.5.1"
+ pretty-format: "npm:30.5.1"
+ semver: "npm:^7.7.2"
+ synckit: "npm:^0.11.8"
+ checksum: 10c0/cef6b102f743cbefd5d8ad0cf15b5694c09522904c43ace56537990475805b7c6eaebf82e6c5564e225e8db7617ebdda77340acc9a47d9909f338fbb84fca345
+ languageName: node
+ linkType: hard
+
"jest-util@npm:30.0.0":
version: 30.0.0
resolution: "jest-util@npm:30.0.0"
@@ -13560,13 +14411,27 @@ __metadata:
version: 30.4.1
resolution: "jest-util@npm:30.4.1"
dependencies:
- "@jest/types": "npm:30.4.1"
+ "@jest/types": "npm:30.4.1"
+ "@types/node": "npm:*"
+ chalk: "npm:^4.1.2"
+ ci-info: "npm:^4.2.0"
+ graceful-fs: "npm:^4.2.11"
+ picomatch: "npm:^4.0.3"
+ checksum: 10c0/3efe1f25e5a172d04c6af8612d82867ab603b7c1bd8cb89073ff834679b44eba178793cf3af162cf5e25be13aa736ebd23a7826683acc85bddc5873f305b1f6e
+ languageName: node
+ linkType: hard
+
+"jest-util@npm:30.5.1":
+ version: 30.5.1
+ resolution: "jest-util@npm:30.5.1"
+ dependencies:
+ "@jest/types": "npm:30.5.1"
"@types/node": "npm:*"
chalk: "npm:^4.1.2"
ci-info: "npm:^4.2.0"
graceful-fs: "npm:^4.2.11"
picomatch: "npm:^4.0.3"
- checksum: 10c0/3efe1f25e5a172d04c6af8612d82867ab603b7c1bd8cb89073ff834679b44eba178793cf3af162cf5e25be13aa736ebd23a7826683acc85bddc5873f305b1f6e
+ checksum: 10c0/5f3b250f1ada29b877cab75db5808f1318af99ba7f68032e0966ddb6d853186ad2dbaeac679842684c4676dfd35083470f2d26eee65a28161fcd9e43c7146fab
languageName: node
linkType: hard
@@ -13654,6 +14519,19 @@ __metadata:
languageName: node
linkType: hard
+"jest-worker@npm:30.5.1":
+ version: 30.5.1
+ resolution: "jest-worker@npm:30.5.1"
+ dependencies:
+ "@types/node": "npm:*"
+ "@ungap/structured-clone": "npm:^1.3.0"
+ jest-util: "npm:30.5.1"
+ merge-stream: "npm:^2.0.0"
+ supports-color: "npm:^8.1.1"
+ checksum: 10c0/fe3806769014920c5256ef01e2e9a5aba91a7ded90d7c86a82196f3da03070087c8c6b591f8bbb0b500c184c7cc8c5f22191e51cce504163b24a8b42c4cadd8b
+ languageName: node
+ linkType: hard
+
"jest-worker@npm:^29.6.3, jest-worker@npm:^29.7.0":
version: 29.7.0
resolution: "jest-worker@npm:29.7.0"
@@ -13723,6 +14601,22 @@ __metadata:
languageName: node
linkType: hard
+"js-message@npm:1.0.7":
+ version: 1.0.7
+ resolution: "js-message@npm:1.0.7"
+ checksum: 10c0/2dc2ff5a594613a9690c157a921999237164a3c213523f406dee23985ed81c92be9afdc7b34e67a2838d447d7d79cbf1662048effe8367bedcd71a950e4e292e
+ languageName: node
+ linkType: hard
+
+"js-queue@npm:2.0.2":
+ version: 2.0.2
+ resolution: "js-queue@npm:2.0.2"
+ dependencies:
+ easy-stack: "npm:^1.0.1"
+ checksum: 10c0/cdadc65576c6d46817f47c27d7a57a1f3acbe3a4da2a4bc7303218f06d6ee7971358db28ec0d6b6835b4cd93332c52792b535064fee706453ef9d2bfe03b4a1a
+ languageName: node
+ linkType: hard
+
"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0":
version: 4.0.0
resolution: "js-tokens@npm:4.0.0"
@@ -13787,6 +14681,13 @@ __metadata:
languageName: node
linkType: hard
+"json-cycle@npm:^1.3.0":
+ version: 1.5.0
+ resolution: "json-cycle@npm:1.5.0"
+ checksum: 10c0/43ba321cf186b22573826ee76d64601bdfe57fe787d74162626c453bd860595c4c62ebfc338b5a64994fb4e4d7a947e6c2ef5f202e3a2ee4b01ca23ebc0cd710
+ languageName: node
+ linkType: hard
+
"json-parse-better-errors@npm:^1.0.1":
version: 1.0.2
resolution: "json-parse-better-errors@npm:1.0.2"
@@ -13983,6 +14884,13 @@ __metadata:
languageName: node
linkType: hard
+"kuler@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "kuler@npm:2.0.0"
+ checksum: 10c0/0a4e99d92ca373f8f74d1dc37931909c4d0d82aebc94cf2ba265771160fc12c8df34eaaac80805efbda367e2795cb1f1dd4c3d404b6b1cf38aec94035b503d2d
+ languageName: node
+ linkType: hard
+
"lan-network@npm:^0.2.1":
version: 0.2.1
resolution: "lan-network@npm:0.2.1"
@@ -14440,7 +15348,7 @@ __metadata:
languageName: node
linkType: hard
-"lodash@npm:4.18.1, lodash@npm:^4.17.15, lodash@npm:^4.17.4":
+"lodash@npm:4.18.1, lodash@npm:^4.17.11, lodash@npm:^4.17.15, lodash@npm:^4.17.4":
version: 4.18.1
resolution: "lodash@npm:4.18.1"
checksum: 10c0/757228fc68805c59789e82185135cf85f05d0b2d3d54631d680ca79ec21944ec8314d4533639a14b8bcfbd97a517e78960933041a5af17ecb693ec6eecb99a27
@@ -14476,6 +15384,20 @@ __metadata:
languageName: node
linkType: hard
+"logform@npm:^2.7.0":
+ version: 2.7.0
+ resolution: "logform@npm:2.7.0"
+ dependencies:
+ "@colors/colors": "npm:1.6.0"
+ "@types/triple-beam": "npm:^1.3.2"
+ fecha: "npm:^4.2.0"
+ ms: "npm:^2.1.1"
+ safe-stable-stringify: "npm:^2.3.1"
+ triple-beam: "npm:^1.3.0"
+ checksum: 10c0/4789b4b37413c731d1835734cb799240d31b865afde6b7b3e06051d6a4127bfda9e88c99cfbf296d084a315ccbed2647796e6a56b66e725bcb268c586f57558f
+ languageName: node
+ linkType: hard
+
"logkitty@npm:^0.7.1":
version: 0.7.1
resolution: "logkitty@npm:0.7.1"
@@ -15281,6 +16203,15 @@ __metadata:
languageName: node
linkType: hard
+"minimatch@npm:2 || 3, minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2, minimatch@npm:^3.1.5":
+ version: 3.1.5
+ resolution: "minimatch@npm:3.1.5"
+ dependencies:
+ brace-expansion: "npm:^1.1.7"
+ checksum: 10c0/2ecbdc0d33f07bddb0315a8b5afbcb761307a8778b48f0b312418ccbced99f104a2d17d8aca7573433c70e8ccd1c56823a441897a45e384ea76ef401a26ace70
+ languageName: node
+ linkType: hard
+
"minimatch@npm:^10.0.3, minimatch@npm:^10.1.1, minimatch@npm:^10.2.2, minimatch@npm:^10.2.5":
version: 10.2.5
resolution: "minimatch@npm:10.2.5"
@@ -15290,15 +16221,6 @@ __metadata:
languageName: node
linkType: hard
-"minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2, minimatch@npm:^3.1.5":
- version: 3.1.5
- resolution: "minimatch@npm:3.1.5"
- dependencies:
- brace-expansion: "npm:^1.1.7"
- checksum: 10c0/2ecbdc0d33f07bddb0315a8b5afbcb761307a8778b48f0b312418ccbced99f104a2d17d8aca7573433c70e8ccd1c56823a441897a45e384ea76ef401a26ace70
- languageName: node
- linkType: hard
-
"minimatch@npm:^5.0.1":
version: 5.1.9
resolution: "minimatch@npm:5.1.9"
@@ -15423,6 +16345,17 @@ __metadata:
languageName: node
linkType: hard
+"mkdirp@npm:~0.5.1":
+ version: 0.5.6
+ resolution: "mkdirp@npm:0.5.6"
+ dependencies:
+ minimist: "npm:^1.2.6"
+ bin:
+ mkdirp: bin/cmd.js
+ checksum: 10c0/e2e2be789218807b58abced04e7b49851d9e46e88a2f9539242cc8a92c9b5c3a0b9bab360bd3014e02a140fc4fbc58e31176c408b493f8a2a6f4986bd7527b01
+ languageName: node
+ linkType: hard
+
"moment-timezone@npm:^0.6.0":
version: 0.6.2
resolution: "moment-timezone@npm:0.6.2"
@@ -15432,6 +16365,13 @@ __metadata:
languageName: node
linkType: hard
+"moment@npm:^2.19.3":
+ version: 2.31.0
+ resolution: "moment@npm:2.31.0"
+ checksum: 10c0/3755b186b8ff62c565685ce69dde55bf46003c0329139be5c8dd7845cd567bfd7d02be3a13e379a25acb9e98f6b87136c4776745e440615a4f5ca8dd9a8815b9
+ languageName: node
+ linkType: hard
+
"moment@npm:^2.29.4":
version: 2.30.1
resolution: "moment@npm:2.30.1"
@@ -15453,6 +16393,23 @@ __metadata:
languageName: node
linkType: hard
+"multi-sort-stream@npm:^1.0.3, multi-sort-stream@npm:^1.0.4":
+ version: 1.0.4
+ resolution: "multi-sort-stream@npm:1.0.4"
+ checksum: 10c0/74820fd8f4287798f56f5c0b390d52d0fa0efd46b22a880390c6182c4b2ff6bd608dc90974fe7b0981c9243ae4f857d3389e74ebf6d071d7465056c29772196d
+ languageName: node
+ linkType: hard
+
+"multipipe@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "multipipe@npm:4.0.0"
+ dependencies:
+ duplexer2: "npm:^0.1.2"
+ object-assign: "npm:^4.1.0"
+ checksum: 10c0/60b547f85a3c692fe24c4e15988bdbb6c7985665fd7c4f6228bbf2630f699badeefd8d492bff5b295ea02a284e12917ff21e324a2f660e3d5667bb656a01792d
+ languageName: node
+ linkType: hard
+
"multitars@npm:^1.0.2":
version: 1.0.2
resolution: "multitars@npm:1.0.2"
@@ -15467,6 +16424,17 @@ __metadata:
languageName: node
linkType: hard
+"mv@npm:~2":
+ version: 2.1.1
+ resolution: "mv@npm:2.1.1"
+ dependencies:
+ mkdirp: "npm:~0.5.1"
+ ncp: "npm:~2.0.0"
+ rimraf: "npm:~2.4.0"
+ checksum: 10c0/5da59a9f4ec16da0867289b5018c81c25c59b06bb9da717bc7bd0b40363d6653dc88d6da32a9434fd7416bfc3f67184c306ea44d3856ff97f3214cc96960efcd
+ languageName: node
+ linkType: hard
+
"mz@npm:^2.4.0":
version: 2.7.0
resolution: "mz@npm:2.7.0"
@@ -15478,6 +16446,15 @@ __metadata:
languageName: node
linkType: hard
+"nan@npm:^2.14.0":
+ version: 2.29.0
+ resolution: "nan@npm:2.29.0"
+ dependencies:
+ node-gyp: "npm:latest"
+ checksum: 10c0/c90586afb3f101f64c2997e7481f7c2c5528e196399a1c2653e4fff7354a01f35009e10fd43aa567a4b68be0ac8ed45a60794f5ca0a863120b74aecf4a45ad2c
+ languageName: node
+ linkType: hard
+
"nanoid@npm:^3.3.1, nanoid@npm:^3.3.11":
version: 3.3.12
resolution: "nanoid@npm:3.3.12"
@@ -15519,6 +16496,15 @@ __metadata:
languageName: node
linkType: hard
+"ncp@npm:~2.0.0":
+ version: 2.0.0
+ resolution: "ncp@npm:2.0.0"
+ bin:
+ ncp: ./bin/ncp
+ checksum: 10c0/d515babf9d3205ab9252e7d640af7c3e1a880317016d41f2fce2e6b9c8f60eb8bb6afde30e8c4f8e1e3fa551465f094433c3f364b25a85d6a28ec52c1ad6e067
+ languageName: node
+ linkType: hard
+
"negotiator@npm:0.6.3":
version: 0.6.3
resolution: "negotiator@npm:0.6.3"
@@ -15584,6 +16570,15 @@ __metadata:
languageName: node
linkType: hard
+"node-addon-api@npm:^7.0.0":
+ version: 7.1.1
+ resolution: "node-addon-api@npm:7.1.1"
+ dependencies:
+ node-gyp: "npm:latest"
+ checksum: 10c0/fb32a206276d608037fa1bcd7e9921e177fe992fc610d098aa3128baca3c0050fc1e014fa007e9b3874cf865ddb4f5bd9f43ccb7cbbbe4efaff6a83e920b17e9
+ languageName: node
+ linkType: hard
+
"node-emoji@npm:^2.2.0":
version: 2.2.0
resolution: "node-emoji@npm:2.2.0"
@@ -15656,6 +16651,17 @@ __metadata:
languageName: node
linkType: hard
+"node-ipc@npm:9.2.1":
+ version: 9.2.1
+ resolution: "node-ipc@npm:9.2.1"
+ dependencies:
+ event-pubsub: "npm:4.3.0"
+ js-message: "npm:1.0.7"
+ js-queue: "npm:2.0.2"
+ checksum: 10c0/ed6448e2c643a831b9795a52de727658417a2cbedd3a59988b9be7654383982577dc507e0ec13211d10ed90377124366e3869a137b05093a424caf647eba0523
+ languageName: node
+ linkType: hard
+
"node-releases@npm:^2.0.36":
version: 2.0.44
resolution: "node-releases@npm:2.0.44"
@@ -16118,6 +17124,15 @@ __metadata:
languageName: node
linkType: hard
+"one-time@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "one-time@npm:1.0.0"
+ dependencies:
+ fn.name: "npm:1.x.x"
+ checksum: 10c0/6e4887b331edbb954f4e915831cbec0a7b9956c36f4feb5f6de98c448ac02ff881fd8d9b55a6b1b55030af184c6b648f340a76eb211812f4ad8c9b4b8692fdaa
+ languageName: node
+ linkType: hard
+
"onetime@npm:^2.0.0":
version: 2.0.1
resolution: "onetime@npm:2.0.1"
@@ -16721,6 +17736,13 @@ __metadata:
languageName: node
linkType: hard
+"pngjs@npm:^7.0.0":
+ version: 7.0.0
+ resolution: "pngjs@npm:7.0.0"
+ checksum: 10c0/0d4c7a0fd476a9c33df7d0a2a73e1d56537628a668841f6995c2bca070cf30819f9254a64363266bc14ef2fee47659dd3b4f2b18eec7ab65143015139f497b38
+ languageName: node
+ linkType: hard
+
"possible-typed-array-names@npm:^1.0.0":
version: 1.0.0
resolution: "possible-typed-array-names@npm:1.0.0"
@@ -16815,6 +17837,18 @@ __metadata:
languageName: node
linkType: hard
+"pretty-format@npm:30.5.1":
+ version: 30.5.1
+ resolution: "pretty-format@npm:30.5.1"
+ dependencies:
+ "@jest/react-is-18": "npm:react-is@^18.3.1"
+ "@jest/react-is-19": "npm:react-is@^19.2.5"
+ "@jest/schemas": "npm:30.5.0"
+ ansi-styles: "npm:^5.2.0"
+ checksum: 10c0/bdef1790b9c93d1aa329c93885b0d1b8b6a3273bb680377531c70151b2e1b0a465210cae100661fc19b0bf35f507587f78b1a2f1afcf08791b9fe5630c23c076
+ languageName: node
+ linkType: hard
+
"pretty-format@npm:^29.0.3, pretty-format@npm:^29.7.0":
version: 29.7.0
resolution: "pretty-format@npm:29.7.0"
@@ -16933,6 +17967,13 @@ __metadata:
languageName: node
linkType: hard
+"promisify-child-process@npm:^4.1.2":
+ version: 4.1.2
+ resolution: "promisify-child-process@npm:4.1.2"
+ checksum: 10c0/e5347137f1c333af4b7b4d2272a091d31007b30320af4b852f30f41776db378e22b3db1e67e40026a18301c243d9c9780e41c211cfce76ba26aedba17e3a385c
+ languageName: node
+ linkType: hard
+
"prompts@npm:^2.3.2, prompts@npm:^2.4.2":
version: 2.4.2
resolution: "prompts@npm:2.4.2"
@@ -16963,6 +18004,17 @@ __metadata:
languageName: node
linkType: hard
+"proper-lockfile@npm:^3.0.2":
+ version: 3.2.0
+ resolution: "proper-lockfile@npm:3.2.0"
+ dependencies:
+ graceful-fs: "npm:^4.1.11"
+ retry: "npm:^0.12.0"
+ signal-exit: "npm:^3.0.2"
+ checksum: 10c0/b3a0bbf87f1b842ab57d91bee2e8c73d6cb2e90558aad259e83561cf5467f20885a1eb127343ecd9db214c78aaa196867ef8edb76e3681dc07ee43a489fd53bd
+ languageName: node
+ linkType: hard
+
"property-information@npm:^7.0.0":
version: 7.2.0
resolution: "property-information@npm:7.2.0"
@@ -17155,13 +18207,6 @@ __metadata:
languageName: node
linkType: hard
-"react-is-18@npm:react-is@^18.3.1, react-is@npm:^18.0.0":
- version: 18.3.1
- resolution: "react-is@npm:18.3.1"
- checksum: 10c0/f2f1e60010c683479e74c63f96b09fb41603527cd131a9959e2aee1e5a8b0caf270b365e5ca77d4a6b18aae659b60a86150bb3979073528877029b35aecd2072
- languageName: node
- linkType: hard
-
"react-is-19@npm:react-is@^19.2.5, react-is@npm:^19.1.0":
version: 19.2.6
resolution: "react-is@npm:19.2.6"
@@ -17317,6 +18362,16 @@ __metadata:
languageName: node
linkType: hard
+"react-native-launch-arguments@npm:^4.1.1":
+ version: 4.1.1
+ resolution: "react-native-launch-arguments@npm:4.1.1"
+ peerDependencies:
+ react: ">=16.8.1"
+ react-native: ">=0.60.0-rc.0 <1.0.x"
+ checksum: 10c0/94a88b3c6ba583b20108200c794f2c132a5b94383f0eb22797ff21194d140904bd62510ee9a01ea464ba831ddd69b3c49fb9b2799728d1d7fbaebf0ed683edd2
+ languageName: node
+ linkType: hard
+
"react-native-lightbox@npm:^0.7.0":
version: 0.7.0
resolution: "react-native-lightbox@npm:0.7.0"
@@ -17758,7 +18813,7 @@ __metadata:
languageName: node
linkType: hard
-"readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0":
+"readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.6.2":
version: 3.6.2
resolution: "readable-stream@npm:3.6.2"
dependencies:
@@ -18084,6 +19139,17 @@ __metadata:
languageName: node
linkType: hard
+"rimraf@npm:~2.4.0":
+ version: 2.4.5
+ resolution: "rimraf@npm:2.4.5"
+ dependencies:
+ glob: "npm:^6.0.1"
+ bin:
+ rimraf: ./bin.js
+ checksum: 10c0/5251a36053165d23248efec5077f9addc13ad7f742a02dcd9ac7adda9e208cbf7523901e96a9ca6c33059bd0b573b97eab3334cf1d9976cc5ddc8b3c24d9ddd7
+ languageName: node
+ linkType: hard
+
"root@workspace:.":
version: 0.0.0-use.local
resolution: "root@workspace:."
@@ -18177,6 +19243,13 @@ __metadata:
languageName: node
linkType: hard
+"safe-json-stringify@npm:~1":
+ version: 1.2.0
+ resolution: "safe-json-stringify@npm:1.2.0"
+ checksum: 10c0/9c21c7b63a35a9e52d248eea2ad7bc9e790dde5aa418f0d4eed3c0b4c866e15337425b0d973173d30dd70a9e422271619f17e13574e0c8371d0c240cf72b871f
+ languageName: node
+ linkType: hard
+
"safe-push-apply@npm:^1.0.0":
version: 1.0.0
resolution: "safe-push-apply@npm:1.0.0"
@@ -18198,6 +19271,13 @@ __metadata:
languageName: node
linkType: hard
+"safe-stable-stringify@npm:^2.3.1":
+ version: 2.5.0
+ resolution: "safe-stable-stringify@npm:2.5.0"
+ checksum: 10c0/baea14971858cadd65df23894a40588ed791769db21bafb7fd7608397dbdce9c5aac60748abae9995e0fc37e15f2061980501e012cd48859740796bea2987f49
+ languageName: node
+ linkType: hard
+
"safer-buffer@npm:>= 2.1.2 < 3.0.0":
version: 2.1.2
resolution: "safer-buffer@npm:2.1.2"
@@ -18278,6 +19358,15 @@ __metadata:
languageName: node
linkType: hard
+"sanitize-filename@npm:^1.6.1":
+ version: 1.6.4
+ resolution: "sanitize-filename@npm:1.6.4"
+ dependencies:
+ truncate-utf8-bytes: "npm:^1.0.0"
+ checksum: 10c0/b56415a95e4f90dc992cd126b5f45c7b39d178662fbd0dc48f03203e35c58ab8e9eb3f5cebfaabc46f1438093d65a3a3cc96875e2b036a1474e19593bee9a540
+ languageName: node
+ linkType: hard
+
"sax@npm:>=0.6.0":
version: 1.6.0
resolution: "sax@npm:1.6.0"
@@ -18353,6 +19442,15 @@ __metadata:
languageName: node
linkType: hard
+"semver@npm:^7.0.0":
+ version: 7.8.5
+ resolution: "semver@npm:7.8.5"
+ bin:
+ semver: bin/semver.js
+ checksum: 10c0/b1f3127a5be8125a94f37188b361c212466c292c6910adce3ec106cff5dc211ccaedc4739c11bb70fda59d6fc1f040a9bca289f4e093451521a2372e5231fe0c
+ languageName: node
+ linkType: hard
+
"semver@npm:^7.1.1, semver@npm:^7.1.2, semver@npm:^7.1.3, semver@npm:^7.3.2, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.7.2, semver@npm:^7.7.3, semver@npm:^7.7.4":
version: 7.8.1
resolution: "semver@npm:7.8.1"
@@ -18390,6 +19488,15 @@ __metadata:
languageName: node
linkType: hard
+"serialize-error@npm:^8.0.1":
+ version: 8.1.0
+ resolution: "serialize-error@npm:8.1.0"
+ dependencies:
+ type-fest: "npm:^0.20.2"
+ checksum: 10c0/8cfd89f43ca93e283c5f1d16178a536bdfac9bc6029f4a9df988610cc399bc4f2478d1f10ce40b9dff66b863a5158a19b438fbec929045c96d92174f6bca1e88
+ languageName: node
+ linkType: hard
+
"serve-static@npm:^1.13.1, serve-static@npm:^1.16.2":
version: 1.16.3
resolution: "serve-static@npm:1.16.3"
@@ -18497,6 +19604,13 @@ __metadata:
languageName: node
linkType: hard
+"shell-quote@npm:^1.7.2":
+ version: 1.12.0
+ resolution: "shell-quote@npm:1.12.0"
+ checksum: 10c0/1605a4ed6a758bf13de7cb8197a4184d8015f7a4dbdcd6cd4a717d5b30b3ae7666300cc4ae7f3155cf80ace9739e9e82061ee5aa1a648f53f5fab31a220816d0
+ languageName: node
+ linkType: hard
+
"side-channel-list@npm:^1.0.0, side-channel-list@npm:^1.0.1":
version: 1.0.1
resolution: "side-channel-list@npm:1.0.1"
@@ -18837,6 +19951,13 @@ __metadata:
languageName: node
linkType: hard
+"stack-trace@npm:0.0.x":
+ version: 0.0.10
+ resolution: "stack-trace@npm:0.0.10"
+ checksum: 10c0/9ff3dabfad4049b635a85456f927a075c9d0c210e3ea336412d18220b2a86cbb9b13ec46d6c37b70a302a4ea4d49e30e5d4944dd60ae784073f1cde778ac8f4b
+ languageName: node
+ linkType: hard
+
"stack-utils@npm:^2.0.3, stack-utils@npm:^2.0.6":
version: 2.0.6
resolution: "stack-utils@npm:2.0.6"
@@ -18916,6 +20037,13 @@ __metadata:
languageName: node
linkType: hard
+"stream-chain@npm:^2.2.5":
+ version: 2.2.5
+ resolution: "stream-chain@npm:2.2.5"
+ checksum: 10c0/c512f50190d7c92d688fa64e7af540c51b661f9c2b775fc72bca38ea9bca515c64c22c2197b1be463741daacbaaa2dde8a8ea24ebda46f08391224f15249121a
+ languageName: node
+ linkType: hard
+
"stream-chat-expo@workspace:^, stream-chat-expo@workspace:package/expo-package":
version: 0.0.0-use.local
resolution: "stream-chat-expo@workspace:package/expo-package"
@@ -19155,6 +20283,15 @@ __metadata:
languageName: node
linkType: hard
+"stream-json@npm:^1.7.4, stream-json@npm:^1.7.5":
+ version: 1.9.1
+ resolution: "stream-json@npm:1.9.1"
+ dependencies:
+ stream-chain: "npm:^2.2.5"
+ checksum: 10c0/0521e5cb3fb6b0e2561d715975e891bd81fa77d0239c8d0b1756846392bc3c7cdd7f1ddb0fe7ed77e6fdef58daab9e665d3b39f7d677bd0859e65a2bff59b92c
+ languageName: node
+ linkType: hard
+
"string-length@npm:^4.0.2":
version: 4.0.2
resolution: "string-length@npm:4.0.2"
@@ -19536,6 +20673,15 @@ __metadata:
languageName: node
linkType: hard
+"telnet-client@npm:1.2.8":
+ version: 1.2.8
+ resolution: "telnet-client@npm:1.2.8"
+ dependencies:
+ bluebird: "npm:^3.5.4"
+ checksum: 10c0/f6700268a9734305655e305540b21e18f0ab05923d4917fcf8c3192ced596ce4675c61e8b8d6ad12c89bf7eb2d38f2792ead5eb721c7055c4e924f9312913a34
+ languageName: node
+ linkType: hard
+
"temp-dir@npm:^3.0.0":
version: 3.0.0
resolution: "temp-dir@npm:3.0.0"
@@ -19590,6 +20736,24 @@ __metadata:
languageName: node
linkType: hard
+"test-exclude@npm:^7.0.1":
+ version: 7.0.2
+ resolution: "test-exclude@npm:7.0.2"
+ dependencies:
+ "@istanbuljs/schema": "npm:^0.1.2"
+ glob: "npm:^10.4.1"
+ minimatch: "npm:^10.2.2"
+ checksum: 10c0/b79b855af9168c6a362146015ccf40f5e3a25e307304ba9bea930818507f6319d230380d5d7b5baa659c981ccc11f1bd21b6f012f85606353dec07e02dee67c9
+ languageName: node
+ linkType: hard
+
+"text-hex@npm:1.0.x":
+ version: 1.0.0
+ resolution: "text-hex@npm:1.0.0"
+ checksum: 10c0/57d8d320d92c79d7c03ffb8339b825bb9637c2cbccf14304309f51d8950015c44464b6fd1b6820a3d4821241c68825634f09f5a2d9d501e84f7c6fd14376860d
+ languageName: node
+ linkType: hard
+
"text-table@npm:~0.2.0":
version: 0.2.0
resolution: "text-table@npm:0.2.0"
@@ -19665,6 +20829,13 @@ __metadata:
languageName: node
linkType: hard
+"tmp@npm:^0.2.1":
+ version: 0.2.7
+ resolution: "tmp@npm:0.2.7"
+ checksum: 10c0/59eb55584f2f07210d3231b6a1f6b5c2b9794d8a7b509c8ee867ed2acad6d2245ee2448b7937b676ffbff3155a70077edde8a69f9d7cf0f90c86a62e8910c357
+ languageName: node
+ linkType: hard
+
"tmpl@npm:1.0.5":
version: 1.0.5
resolution: "tmpl@npm:1.0.5"
@@ -19702,6 +20873,15 @@ __metadata:
languageName: node
linkType: hard
+"trace-event-lib@npm:^1.3.1":
+ version: 1.4.1
+ resolution: "trace-event-lib@npm:1.4.1"
+ dependencies:
+ browser-process-hrtime: "npm:^1.0.0"
+ checksum: 10c0/301faf760c8d956d9879f1eaf8a949d480126a1af0d88d33299f1580401e32358d48726750ac8903a4e9be1d0c5f68bdc13453e067ca2bc93565ea381123c4bd
+ languageName: node
+ linkType: hard
+
"traverse@npm:0.6.8":
version: 0.6.8
resolution: "traverse@npm:0.6.8"
@@ -19716,6 +20896,22 @@ __metadata:
languageName: node
linkType: hard
+"triple-beam@npm:^1.3.0":
+ version: 1.4.1
+ resolution: "triple-beam@npm:1.4.1"
+ checksum: 10c0/4bf1db71e14fe3ff1c3adbe3c302f1fdb553b74d7591a37323a7badb32dc8e9c290738996cbb64f8b10dc5a3833645b5d8c26221aaaaa12e50d1251c9aba2fea
+ languageName: node
+ linkType: hard
+
+"truncate-utf8-bytes@npm:^1.0.0":
+ version: 1.0.2
+ resolution: "truncate-utf8-bytes@npm:1.0.2"
+ dependencies:
+ utf8-byte-length: "npm:^1.0.1"
+ checksum: 10c0/af2b431fc4314f119b551e5fccfad49d4c0ef82e13ba9ca61be6567801195b08e732ce9643542e8ad1b3df44f3df2d7345b3dd34f723954b6bb43a14584d6b3c
+ languageName: node
+ linkType: hard
+
"ts-api-utils@npm:^2.5.0":
version: 2.5.0
resolution: "ts-api-utils@npm:2.5.0"
@@ -19737,7 +20933,7 @@ __metadata:
languageName: node
linkType: hard
-"tslib@npm:^2.1.0, tslib@npm:^2.4.0":
+"tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.5.3":
version: 2.8.1
resolution: "tslib@npm:2.8.1"
checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62
@@ -19787,6 +20983,13 @@ __metadata:
languageName: node
linkType: hard
+"type-fest@npm:^0.20.2":
+ version: 0.20.2
+ resolution: "type-fest@npm:0.20.2"
+ checksum: 10c0/dea9df45ea1f0aaa4e2d3bed3f9a0bfe9e5b2592bddb92eb1bf06e50bcf98dbb78189668cd8bc31a0511d3fc25539b4cd5c704497e53e93e2d40ca764b10bfc3
+ languageName: node
+ linkType: hard
+
"type-fest@npm:^0.21.3":
version: 0.21.3
resolution: "type-fest@npm:0.21.3"
@@ -20235,6 +21438,13 @@ __metadata:
languageName: node
linkType: hard
+"utf8-byte-length@npm:^1.0.1":
+ version: 1.0.5
+ resolution: "utf8-byte-length@npm:1.0.5"
+ checksum: 10c0/e69bda3299608f4cc75976da9fb74ac94801a58b9ca29fdad03a20ec952e7477d7f226c12716b5f36bd4cff8151d1d152d02ee1df3752f017d4b2c725ce3e47a
+ languageName: node
+ linkType: hard
+
"util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2, util-deprecate@npm:~1.0.1":
version: 1.0.2
resolution: "util-deprecate@npm:1.0.2"
@@ -20532,6 +21742,17 @@ __metadata:
languageName: node
linkType: hard
+"which@npm:^1.3.1":
+ version: 1.3.1
+ resolution: "which@npm:1.3.1"
+ dependencies:
+ isexe: "npm:^2.0.0"
+ bin:
+ which: ./bin/which
+ checksum: 10c0/e945a8b6bbf6821aaaef7f6e0c309d4b615ef35699576d5489b4261da9539f70393c6b2ce700ee4321c18f914ebe5644bc4631b15466ffbaad37d83151f6af59
+ languageName: node
+ linkType: hard
+
"which@npm:^2.0.1, which@npm:^2.0.2":
version: 2.0.2
resolution: "which@npm:2.0.2"
@@ -20554,6 +21775,36 @@ __metadata:
languageName: node
linkType: hard
+"winston-transport@npm:^4.9.0":
+ version: 4.9.0
+ resolution: "winston-transport@npm:4.9.0"
+ dependencies:
+ logform: "npm:^2.7.0"
+ readable-stream: "npm:^3.6.2"
+ triple-beam: "npm:^1.3.0"
+ checksum: 10c0/e2990a172e754dbf27e7823772214a22dc8312f7ec9cfba831e5ef30a5d5528792e5ea8f083c7387ccfc5b2af20e3691f64738546c8869086110a26f98671095
+ languageName: node
+ linkType: hard
+
+"winston@npm:^3.17.0":
+ version: 3.19.0
+ resolution: "winston@npm:3.19.0"
+ dependencies:
+ "@colors/colors": "npm:^1.6.0"
+ "@dabh/diagnostics": "npm:^2.0.8"
+ async: "npm:^3.2.3"
+ is-stream: "npm:^2.0.0"
+ logform: "npm:^2.7.0"
+ one-time: "npm:^1.0.0"
+ readable-stream: "npm:^3.4.0"
+ safe-stable-stringify: "npm:^2.3.1"
+ stack-trace: "npm:0.0.x"
+ triple-beam: "npm:^1.3.0"
+ winston-transport: "npm:^4.9.0"
+ checksum: 10c0/341a8ccfb726120209d34e2466040e2ca72cadb1a3402c4fc90425facad002b81275675b4ab9b4432a624311bc47ef7c9fb7652c86fca454d2be2f2ee1882226
+ languageName: node
+ linkType: hard
+
"word-wrap@npm:^1.2.5":
version: 1.2.5
resolution: "word-wrap@npm:1.2.5"
@@ -20673,6 +21924,21 @@ __metadata:
languageName: node
linkType: hard
+"ws@npm:^7.0.0":
+ version: 7.5.13
+ resolution: "ws@npm:7.5.13"
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: ^5.0.2
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+ checksum: 10c0/e223726bbda5768ed58ec9252d04eda7018ef380ea122bb94e595a4d7a02b5baeb423933936576fddb8fa51b642375f7ae814bf0f6f5d9a3ce290566578a8c5a
+ languageName: node
+ linkType: hard
+
"ws@npm:^8.12.1, ws@npm:^8.20.1":
version: 8.21.0
resolution: "ws@npm:8.21.0"
@@ -20797,7 +22063,7 @@ __metadata:
languageName: node
linkType: hard
-"yargs-parser@npm:^21.1.1":
+"yargs-parser@npm:^21.0.0, yargs-parser@npm:^21.1.1":
version: 21.1.1
resolution: "yargs-parser@npm:21.1.1"
checksum: 10c0/f84b5e48169479d2f402239c59f084cfd1c3acc197a05c59b98bab067452e6b3ea46d4dd8ba2985ba7b3d32a343d77df0debd6b343e5dae3da2aab2cdf5886b2
@@ -20811,6 +22077,18 @@ __metadata:
languageName: node
linkType: hard
+"yargs-unparser@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "yargs-unparser@npm:2.0.0"
+ dependencies:
+ camelcase: "npm:^6.0.0"
+ decamelize: "npm:^4.0.0"
+ flat: "npm:^5.0.2"
+ is-plain-obj: "npm:^2.1.0"
+ checksum: 10c0/a5a7d6dc157efa95122e16780c019f40ed91d4af6d2bac066db8194ed0ec5c330abb115daa5a79ff07a9b80b8ea80c925baacf354c4c12edd878c0529927ff03
+ languageName: node
+ linkType: hard
+
"yargs@npm:^15.1.0":
version: 15.4.1
resolution: "yargs@npm:15.4.1"
@@ -20845,6 +22123,21 @@ __metadata:
languageName: node
linkType: hard
+"yargs@npm:^17.0.0":
+ version: 17.7.3
+ resolution: "yargs@npm:17.7.3"
+ dependencies:
+ cliui: "npm:^8.0.1"
+ escalade: "npm:^3.1.1"
+ get-caller-file: "npm:^2.0.5"
+ require-directory: "npm:^2.1.1"
+ string-width: "npm:^4.2.3"
+ y18n: "npm:^5.0.5"
+ yargs-parser: "npm:^21.1.1"
+ checksum: 10c0/7a28572f7e785a57886e34fdbddb9b28756dec552e1453d5f6e7cdd00ad8721a4e8c4321d33683f5e61cacb36ad43258adbb48396b71ec4ed14abee0fc0d0c1f
+ languageName: node
+ linkType: hard
+
"yargs@npm:^17.5.1, yargs@npm:^17.6.2, yargs@npm:^17.7.2":
version: 17.7.2
resolution: "yargs@npm:17.7.2"