# Contributing ## Prerequisites ### Required (all platforms) - **nodenv with Node 22** — Stripe's standard Node version manager. The repo includes a `.node-version` file, so nodenv selects the right version automatically. ```sh nodenv install # installs the pinned version if not already present ``` Not using nodenv? Install Node 22 via [nodejs.org](https://nodejs.org) or your preferred method. - **Yarn 1.x** — install if not already present: ```sh npm install --global yarn@1 ``` - **Watchman** (macOS — required for Metro file watching): ```sh brew install watchman ``` ### iOS - **Xcode** with iOS simulator runtimes installed - **CocoaPods**: ```sh brew install cocoapods ``` - **SwiftLint** (required for pre-commit hooks): ```sh brew install swiftlint ``` ### Android - **Android Studio** with Android SDK installed - Open Android Studio via terminal to pick up your shell environment: `open /Applications/Android\ Studio.app` - **JDK 17+** (Android Gradle Plugin requirement). Homebrew OpenJDK works: ```sh brew install openjdk@17 ``` ## Getting started ### 1. Clone and bootstrap ```sh git clone https://github.com/stripe/stripe-react-native.git cd stripe-react-native yarn bootstrap ``` `yarn bootstrap` runs three steps: 1. `yarn example` — installs JS dependencies for the example app 2. `yarn` — installs JS dependencies for the SDK itself (and runs `prepare`, which builds the TypeScript) 3. `yarn pods` — runs `pod install` for the iOS example app If `pod install` fails with a CDN error, retry — CocoaPods CDN can be flaky: ```sh cd example/ios && pod install --repo-update ``` ### 2. Run the example app The example app uses a remote demo backend at `rigorous-heartbreaking-cephalopod.stripedemos.com`, so **no local server setup is required**. If you need to modify the backend (e.g. add a new endpoint), update the sandbox app at [sandbox-apps/rigorous-heartbreaking-cephalopod](https://codesandbox.io/p/devbox/rigorous-heartbreaking-cephalopod-m358cz) and deploy to stripedemos.com. **iOS:** ```sh # Terminal 1: Start Metro bundler yarn example start # Terminal 2: Build and run on simulator yarn example ios ``` Or open `example/ios/example.xcworkspace` in Xcode and run the `ReactTestApp` scheme. **Android:** ```sh # Terminal 1: Start Metro bundler yarn example start # Terminal 2: Build and run on emulator/device yarn example android ``` Or open `example/android` in Android Studio and run the app from there. ### Editing native code - **iOS**: Open `example/ios/example.xcworkspace` in Xcode. Find SDK source files at `Pods > Development Pods > stripe-react-native`. - **Android**: Open `example/android` in Android Studio. Find SDK source files under `reactnativestripesdk`. - **TypeScript**: Edit files in `src/` and `example/` with your editor of choice. Metro picks up JS/TS changes from `src/` directly, but type definitions are served from `lib/`. If you change the SDK's public API and your editor shows stale types, run `yarn` at the repo root to rebuild `lib/`. ## Tests ### TypeScript unit tests ```sh yarn test ``` ### iOS native unit tests ```sh yarn test:unit:ios ``` ### Android native unit tests ```sh yarn test:unit:android ``` ### E2E tests (Maestro) We use [Maestro](https://maestro.mobile.dev/) for end-to-end testing. Install it first: ```sh brew tap mobile-dev-inc/tap brew install maestro ``` Then build and run the example app, and run the tests: ```sh # Build the example app first yarn run-example-ios # or: yarn run-example-android # Run all e2e tests yarn test:e2e:ios # or: yarn test:e2e:android # Run a single test yarn test-ios ./e2e-tests/ios-only/financial-connections-token.yml ``` If Maestro can't find a device, create one: ```sh maestro start-device --platform=ios --os-version 18 ``` ## Linting and formatting Pre-commit hooks (via [Husky](https://typicode.github.io/husky/)) automatically run lint, typecheck, and formatting on every commit. You can also run them manually: ```sh yarn lint # ESLint yarn typescript # TypeScript type-check yarn format:android:check # Kotlin formatting (spotless) yarn format:android:write # Auto-fix Kotlin formatting yarn format:ios:check # SwiftLint yarn format:ios:write # Auto-fix Swift formatting (changed files only) ``` To fix ESLint issues: ```sh yarn lint --fix ``` ## Commit message convention We follow the [conventional commits specification](https://www.conventionalcommits.org/en): - `fix`: bug fixes, e.g. fix crash due to deprecated method. - `feat`: new features, e.g. add new method to the module. - `refactor`: code refactor, e.g. migrate from class components to hooks. - `docs`: changes to documentation, e.g. add usage example for the module. - `test`: adding or updating tests, e.g. add integration tests using Maestro or native unit tests. - `chore`: tooling changes, e.g. change CI config. ## Updating native SDKs The React Native SDK depends on underlying native [iOS](https://github.com/stripe/stripe-ios) and [Android](https://github.com/stripe/stripe-android) SDKs. To update: **iOS:** Update `stripe_version` in `stripe-react-native.podspec`, then run `yarn pods`. The single `stripe_version` value pins both resolution paths: the Swift Package Manager pin (the default; see the section below) and the CocoaPods fallback dependencies. `yarn update-pods` is only relevant when working in the CocoaPods fallback mode. **Android:** Update `StripeSdk_stripeVersion` in `android/gradle.properties`. ## iOS dependency resolution The Stripe iOS SDK is deprecating CocoaPods support, and accordingly the Stripe React Native SDK is in a transition phase where it resolves the iOS dependency through Swift Package Manager (SPM) by default while still supporting and exposing an opt-out option. For a full explanation of the SPM resolution mechanism, see the documentation in `stripe_spm.rb`. | Toggle | Effect | |--------|--------| | `STRIPE_DISABLE_SPM=1 yarn pods` | Builds the example app using the CocoaPods fallback (static libraries), for verifying the opt-out path. | | `OVERRIDE_STRIPE_IOS_VERSION_GIT_BRANCH=` | Resolves the Swift package from that branch instead of the pinned release. Used by CI and developers to test against unreleased stripe-ios changes. | ## Changing the public APIs The public API is everything exported from `src/index.tsx`. **Important**: After you make changes, run `yarn api-extractor:update`. ### In-development (not yet public) APIs - Don't export from `src/index.tsx`. - Exception - if a public type must reference it, tag it with `@internal`. ### Private Preview / Public Preview APIs - Export from `src/index.tsx`. - Use `@MyFeaturePrivatePreview` / `@MyFeaturePublicPreview`. ## React Native architecture compatibility The SDK requires the new architecture. React Native versions before 0.80 still require the event-emitter compatibility layers in `src/events.ts`, Android's `EventEmitterCompat.kt`, and `ios/StripeSdkEventEmitterCompat.{h,m}`. ## Scripts reference | Script | Description | |--------|-------------| | `yarn bootstrap` | Install all dependencies and pods | | `yarn test` | Run TypeScript unit tests (Jest) | | `yarn test:unit:ios` | Run iOS native unit tests (xcodebuild) | | `yarn test:unit:android` | Run Android native unit tests (Gradle) | | `yarn test:e2e:ios` | Run iOS e2e tests (Maestro) | | `yarn test:e2e:android` | Run Android e2e tests (Maestro) | | `yarn typescript` | Type-check with TypeScript | | `yarn lint` | Lint with ESLint | | `yarn example start` | Start Metro bundler | | `yarn example ios` | Run example app on iOS simulator | | `yarn example android` | Run example app on Android emulator | | `yarn run-example-ios` | Build and run iOS example (iPhone 16 Pro Max) | | `yarn run-example-android` | Build and run Android example | | `yarn format:android:check` | Check Kotlin formatting | | `yarn format:android:write` | Fix Kotlin formatting | | `yarn format:ios:check` | Check Swift formatting (SwiftLint) | | `yarn format:ios:write` | Fix Swift formatting (changed files) |