feat: add session replay support for react native#357
feat: add session replay support for react native#357mario-launchdarkly wants to merge 60 commits intomainfrom
Conversation
3e1346c to
8b1fb92
Compare
sdk/@launchdarkly/react-native-ld-session-replay/android/src/main/AndroidManifest.xml
Dismissed
Show dismissed
Hide dismissed
...launchdarkly/react-native-ld-session-replay/example/android/app/src/main/AndroidManifest.xml
Dismissed
Show dismissed
Hide dismissed
...native-ld-session-replay/example/android/app/src/main/res/drawable/rn_edit_text_material.xml
Dismissed
Show dismissed
Hide dismissed
...native-ld-session-replay/example/android/app/src/main/res/drawable/rn_edit_text_material.xml
Dismissed
Show dismissed
Hide dismissed
...-replay/android/src/main/java/com/sessionreplayreactnative/SessionReplayReactNativeModule.kt
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayReactNative.mm
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayReactNative.mm
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayReactNative.mm
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/SessionReplayReactNative.podspec
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
73e0355 to
cbb094f
Compare
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayAdapter.swift
Outdated
Show resolved
Hide resolved
- Added @launchdarkly/react-native-client-sdk version 10.12.5 to dependencies. - Updated import statement for session replay plugin to use the scoped package @launchdarkly/session-replay-react-native.
- Updated the session replay plugin import to use the scoped package @launchdarkly/session-replay-react-native for better compatibility. - Ensured that the example project dependencies are aligned with the latest version of the LaunchDarkly SDK.
…= true (line 86) outside the clientQueue
… better readability
…apter - Refactored state handling in start and stop methods to ensure proper synchronization and prevent race conditions. - Enhanced logic to manage ldReplayState transitions more clearly, ensuring that stopping and starting behaviors are correctly handled in a thread-safe manner.
- Updated the state handling to set ldReplayState to .starting before invoking LDClient.start(), ensuring accurate detection of in-flight start and stop processes. - Removed redundant state assignment within the completion handler to streamline the logic and enhance clarity.
…mpletion callback
a54e553 to
c0cf2e0
Compare
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayClientAdapter.swift
Show resolved
Hide resolved
| /// offline is considered a short circuited timed out case | ||
| setLDReplayEnabled(true) { | ||
| completion(true, nil) | ||
| } |
There was a problem hiding this comment.
Reconfigure has no effect after start
Medium Severity
After the first successful start, later configure calls update stored mobileKey and sessionReplayOptions, but start in the .started state only toggles LDReplay.shared.isEnabled and never rebuilds LDClient with new settings. This causes silent stale configuration at runtime.
Additional Locations (1)
...ReactNativeExample.xcodeproj/xcshareddata/xcschemes/SessionReplayReactNativeExample.xcscheme
Show resolved
Hide resolved
...ReactNativeExample.xcodeproj/xcshareddata/xcschemes/SessionReplayReactNativeExample.xcscheme
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayClientAdapter.swift
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayClientAdapter.swift
Show resolved
Hide resolved
| /// offline is considered a short circuited timed out case | ||
| setLDReplayEnabled(true) { | ||
| completion(true, nil) | ||
| } |
There was a problem hiding this comment.
Reconfigure does not update active replay client
Medium Severity
After LDClient reaches .started, start only flips LDReplay.shared.isEnabled and never rebuilds the client with updated mobileKey or sessionReplayOptions. Calls to configure after the first start update stored values but do not affect the running configuration, so replay can continue with stale settings.
Additional Locations (1)
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayClientAdapter.swift
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayClientAdapter.swift
Show resolved
Hide resolved
| "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", | ||
| "prepare": "bob build", | ||
| "typecheck": "tsc", | ||
| "lint": "echo 'Linting temporarily disabled - TODO: fix ESLint config'", |
Check notice
Code scanning / devskim
A "TODO" or similar was left in source code, possibly indicating incomplete functionality Note
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayClientAdapter.swift
Show resolved
Hide resolved
sdk/@launchdarkly/react-native-ld-session-replay/ios/SessionReplayClientAdapter.swift
Show resolved
Hide resolved
| { | ||
| ignores: ['node_modules/', 'lib/'], | ||
| }, | ||
| ]); |
There was a problem hiding this comment.
Backup .bak file accidentally included in commit
Low Severity
The file eslint.config.mjs.bak is a backup file that appears to have been accidentally committed. It's an unused copy of an ESLint flat config that was likely created during migration. The lint script in package.json is also disabled with a placeholder message, suggesting this file is leftover from incomplete ESLint configuration work.
| completion(true, nil) | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Potential deadlock from nested clientQueue.sync calls
High Severity
The public start(completion:) executes inside clientQueue.sync, and the LDClient.start completion handler at line 96 also calls self.clientQueue.sync. Since config.startOnline is false, the LDClient may complete initialization immediately and invoke the completion handler synchronously on the same thread. Calling sync on a serial DispatchQueue from within a block already executing on that queue is a guaranteed deadlock, which would freeze the app permanently.
Additional Locations (1)
| { | ||
| ignores: ['node_modules/', 'lib/'], | ||
| }, | ||
| ]); |
There was a problem hiding this comment.


Summary
Implement support for session replay into react native through swift-observability-sdk
How did you test this change?
e2e testing, example app is provided
Are there any deployment considerations?
it is a front-end package for building mobile apps
Note
Medium Risk
Introduces new native mobile build artifacts and a new iOS session-replay startup path (including offline SDK initialization), which may affect app build/config and runtime behavior; Android support is explicitly non-functional but present.
Overview
Adds a new
@launchdarkly/session-replay-react-nativeworkspace package that exposesconfigureSessionReplay/startSessionReplay/stopSessionReplayand anLDPluginadapter (createSessionReplayPlugin) to initialize session replay from LaunchDarkly React Native client metadata.Implements the native bridge: iOS uses a Swift
SessionReplayClientAdapter+ TurboModule ObjC++ wrapper to start an offline SwiftLDClientwithObservability+SessionReplayplugins and toggleLDReplayenablement; Android is stubbed to reject calls as not supported.Includes a full React Native example app (iOS/Android projects, env setup) and adds repo/tooling tweaks: pin
turboto2.8.7viaresolutions, changeobservability-sharedtests tovitest run, and add Lefthook configuration (root example + package-specific hooks).Written by Cursor Bugbot for commit de1939b. This will update automatically on new commits. Configure here.