Skip to content

Comments

feat: add session replay support for react native#357

Open
mario-launchdarkly wants to merge 60 commits intomainfrom
feature/react-native-swift-session-replay
Open

feat: add session replay support for react native#357
mario-launchdarkly wants to merge 60 commits intomainfrom
feature/react-native-swift-session-replay

Conversation

@mario-launchdarkly
Copy link

@mario-launchdarkly mario-launchdarkly commented Jan 27, 2026

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-native workspace package that exposes configureSessionReplay/startSessionReplay/stopSessionReplay and an LDPlugin adapter (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 Swift LDClient with Observability + SessionReplay plugins and toggle LDReplay enablement; 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 turbo to 2.8.7 via resolutions, change observability-shared tests to vitest 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.

@mario-launchdarkly mario-launchdarkly requested a review from a team as a code owner January 27, 2026 20:27
@mario-launchdarkly mario-launchdarkly force-pushed the feature/react-native-swift-session-replay branch from 3e1346c to 8b1fb92 Compare January 27, 2026 20:38
@Vadman97 Vadman97 force-pushed the feature/react-native-swift-session-replay branch from 73e0355 to cbb094f Compare February 9, 2026 18:44
Vadman97 and others added 19 commits February 13, 2026 16:58
- 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.
…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.
@Vadman97 Vadman97 force-pushed the feature/react-native-swift-session-replay branch from a54e553 to c0cf2e0 Compare February 13, 2026 22:59
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

/// offline is considered a short circuited timed out case
setLDReplayEnabled(true) {
completion(true, nil)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Fix in Cursor Fix in Web

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

/// offline is considered a short circuited timed out case
setLDReplayEnabled(true) {
completion(true, nil)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Fix in Cursor Fix in Web

"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

Suspicious comment
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

{
ignores: ['node_modules/', 'lib/'],
},
]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Fix in Cursor Fix in Web

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

completion(true, nil)
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Fix in Cursor Fix in Web

{
ignores: ['node_modules/', 'lib/'],
},
]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backup file accidentally committed to repository

Low Severity

The file eslint.config.mjs.bak is a backup of a previous ESLint config that appears to have been accidentally included in the commit. It serves no purpose alongside the active .eslintrc.js and isn't excluded by .gitignore.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants