@mixpanel/react-native-session-replay 0.1.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MixpanelReactNativeSessionReplay.podspec +1 -1
- package/README.md +60 -18
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/mixpanelreactnativesessionreplay/MixpanelReactNativeSessionReplayModule.kt +16 -1
- package/ios/MixpanelReactNativeSessionReplay.h +8 -0
- package/ios/MixpanelReactNativeSessionReplay.mm +29 -10
- package/ios/MixpanelSwiftSessionReplay.swift +34 -21
- package/lib/module/MixpanelSessionReplayView.js +1 -1
- package/lib/module/MixpanelSessionReplayView.js.map +1 -1
- package/lib/module/NativeMixpanelReactNativeSessionReplay.js +29 -2
- package/lib/module/NativeMixpanelReactNativeSessionReplay.js.map +1 -1
- package/lib/module/index.js +26 -6
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/MixpanelSessionReplayView.d.ts +1 -1
- package/lib/typescript/src/MixpanelSessionReplayView.d.ts.map +1 -1
- package/lib/typescript/src/NativeMixpanelReactNativeSessionReplay.d.ts +4 -0
- package/lib/typescript/src/NativeMixpanelReactNativeSessionReplay.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +23 -6
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/MixpanelSessionReplayView.tsx +1 -1
- package/src/NativeMixpanelReactNativeSessionReplay.ts +47 -4
- package/src/index.tsx +28 -7
|
@@ -15,7 +15,7 @@ Pod::Spec.new do |s|
|
|
|
15
15
|
|
|
16
16
|
s.source_files = "ios/**/*.{h,m,mm,cpp,swift}"
|
|
17
17
|
s.private_header_files = "ios/**/*.h"
|
|
18
|
-
s.dependency 'MixpanelSessionReplay', '1.1.
|
|
18
|
+
s.dependency 'MixpanelSessionReplay', '1.1.6'
|
|
19
19
|
# Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
|
|
20
20
|
# See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
|
|
21
21
|
if respond_to?(:install_modules_dependencies, true)
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Official React Native turbo module for Mixpanel Session Replay. Capture and anal
|
|
|
9
9
|
- ⚡ **High Performance** - Native implementation with minimal JavaScript overhead
|
|
10
10
|
- 🎯 **Selective Recording** - Configurable sampling rates and recording controls
|
|
11
11
|
- 📱 **Cross Platform** - Unified API for both iOS and Android
|
|
12
|
-
-
|
|
12
|
+
- 🏗️ **Dual Architecture Support** - Works with both old (Bridge) and new (Turbo Module) React Native architectures
|
|
13
13
|
|
|
14
14
|
## Installation
|
|
15
15
|
|
|
@@ -41,10 +41,7 @@ Dependencies are automatically added through Gradle. Requirements:
|
|
|
41
41
|
|
|
42
42
|
```typescript
|
|
43
43
|
import {
|
|
44
|
-
|
|
45
|
-
startRecording,
|
|
46
|
-
stopRecording,
|
|
47
|
-
isRecording,
|
|
44
|
+
MPSessionReplay,
|
|
48
45
|
MPSessionReplayConfig,
|
|
49
46
|
MPSessionReplayMask,
|
|
50
47
|
} from '@mixpanel/react-native-session-replay';
|
|
@@ -59,16 +56,16 @@ const config = new MPSessionReplayConfig({
|
|
|
59
56
|
enableLogging: true,
|
|
60
57
|
});
|
|
61
58
|
|
|
62
|
-
await initialize(token, distinctId, config).catch((error) => {
|
|
59
|
+
await MPSessionReplay.initialize(token, distinctId, config).catch((error) => {
|
|
63
60
|
console.error('Initialization error:', error);
|
|
64
61
|
});
|
|
65
62
|
|
|
66
63
|
// Control recording
|
|
67
|
-
await startRecording();
|
|
68
|
-
await stopRecording();
|
|
64
|
+
await MPSessionReplay.startRecording();
|
|
65
|
+
await MPSessionReplay.stopRecording();
|
|
69
66
|
|
|
70
67
|
// Check recording status
|
|
71
|
-
const recording = await isRecording();
|
|
68
|
+
const recording = await MPSessionReplay.isRecording();
|
|
72
69
|
```
|
|
73
70
|
|
|
74
71
|
## Configuration
|
|
@@ -133,39 +130,75 @@ Enables debug logging for development and troubleshooting.
|
|
|
133
130
|
|
|
134
131
|
## API Methods
|
|
135
132
|
|
|
136
|
-
### initialize(token: string, distinctId: string, config: MPSessionReplayConfig): Promise<void>
|
|
133
|
+
### MPSessionReplay.initialize(token: string, distinctId: string, config: MPSessionReplayConfig): Promise<void>
|
|
137
134
|
Initializes the session replay system with your configuration. Checks remote settings to confirm recording is enabled, then creates a new session replay instance. Any existing instance is deinitialized first.
|
|
138
135
|
|
|
139
136
|
**Returns:** Promise that resolves when initialization completes successfully.
|
|
140
137
|
|
|
141
138
|
**Throws:** Error if initialization fails.
|
|
142
139
|
|
|
143
|
-
### startRecording(): Promise<void>
|
|
140
|
+
### MPSessionReplay.startRecording(): Promise<void>
|
|
144
141
|
Manually starts session recording. Has no effect if recording is already active.
|
|
145
142
|
|
|
146
143
|
Recording continues until you stop it manually or the app moves to the background.
|
|
147
144
|
|
|
148
|
-
### stopRecording(): Promise<void>
|
|
145
|
+
### MPSessionReplay.stopRecording(): Promise<void>
|
|
149
146
|
Stops the current recording session and performs cleanup.
|
|
150
147
|
|
|
151
|
-
### isRecording(): Promise<boolean>
|
|
148
|
+
### MPSessionReplay.isRecording(): Promise<boolean>
|
|
152
149
|
Returns whether recording is currently active.
|
|
153
150
|
|
|
154
|
-
### identify(distinctId: string): Promise<void>
|
|
151
|
+
### MPSessionReplay.identify(distinctId: string): Promise<void>
|
|
155
152
|
Updates the distinct ID for session replays after initialization.
|
|
156
153
|
|
|
157
154
|
**Best practice:** Call `identify()` on the main Mixpanel SDK first, then call it on the Session Replay SDK. This ensures users are properly merged.
|
|
158
155
|
|
|
159
|
-
## Privacy &
|
|
160
|
-
|
|
156
|
+
## Privacy & Data Masking
|
|
161
157
|
The SDK automatically masks sensitive information to protect user privacy. Text input fields are always masked and cannot be disabled.
|
|
162
158
|
|
|
163
|
-
|
|
159
|
+
Session Replay provides two approaches to protect sensitive data: automatic masking and manual masking.
|
|
160
|
+
|
|
161
|
+
### Automatic Masking
|
|
162
|
+
Configure which view types are automatically masked during initialization:
|
|
164
163
|
- Images
|
|
165
164
|
- Text elements
|
|
166
165
|
- WebView content
|
|
167
166
|
- Apple Maps (iOS only)
|
|
168
167
|
|
|
168
|
+
```tsx
|
|
169
|
+
import { MPSessionReplayConfig } from '@mixpanel/react-native-session-replay';
|
|
170
|
+
|
|
171
|
+
const config = new MPSessionReplayConfig({
|
|
172
|
+
autoMaskedViews: [
|
|
173
|
+
MPSessionReplayMask.Text, // Masks all text
|
|
174
|
+
MPSessionReplayMask.Image, // Masks all images
|
|
175
|
+
MPSessionReplayMask.Web, // Masks all WebViews
|
|
176
|
+
MPSessionReplayMask.Map, // Masks map views (iOS only)
|
|
177
|
+
],
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Default Behavior:** All view types are masked by default for maximum privacy.
|
|
182
|
+
|
|
183
|
+
### Manual Masking with MPSessionReplayView
|
|
184
|
+
|
|
185
|
+
Use the `MPSessionReplayView` wrapper component for granular control over what gets masked:
|
|
186
|
+
|
|
187
|
+
```tsx
|
|
188
|
+
import { MPSessionReplayView } from '@mixpanel/react-native-session-replay';
|
|
189
|
+
|
|
190
|
+
// Mask sensitive content
|
|
191
|
+
<MPSessionReplayView sensitive={true}>
|
|
192
|
+
<Text>Credit card Number: {ccn}</Text>
|
|
193
|
+
<Text>Social Security Number: {ssn}</Text>
|
|
194
|
+
</MPSessionReplayView>
|
|
195
|
+
|
|
196
|
+
// Explicitly mark content as safe (unmasked)
|
|
197
|
+
<MPSessionReplayView sensitive={false}>
|
|
198
|
+
<Text>Public information that should always be visible</Text>
|
|
199
|
+
</MPSessionReplayView>
|
|
200
|
+
```
|
|
201
|
+
|
|
169
202
|
## Example App
|
|
170
203
|
|
|
171
204
|
Test the integration using the example app:
|
|
@@ -189,7 +222,14 @@ yarn example android
|
|
|
189
222
|
- React Native 0.70 or higher
|
|
190
223
|
- iOS 13.0 or higher
|
|
191
224
|
- Android API Level 21 or higher
|
|
192
|
-
|
|
225
|
+
|
|
226
|
+
## Architecture Support
|
|
227
|
+
|
|
228
|
+
This module supports both the old and new React Native architectures:
|
|
229
|
+
- ✅ **Old Architecture (Bridge)** - Full support for traditional React Native apps
|
|
230
|
+
- ✅ **New Architecture (Turbo Module)** - Optimized for React Native's new architecture
|
|
231
|
+
|
|
232
|
+
The module automatically detects and uses the appropriate architecture at runtime, providing seamless compatibility regardless of your app's configuration.
|
|
193
233
|
|
|
194
234
|
## Contributing
|
|
195
235
|
|
|
@@ -198,3 +238,5 @@ See our [contributing guide](CONTRIBUTING.md) to learn how to contribute and und
|
|
|
198
238
|
## License
|
|
199
239
|
|
|
200
240
|
MIT
|
|
241
|
+
|
|
242
|
+
[](https://deepwiki.com/mixpanel/mixpanel-react-native-session-replay)
|
package/android/build.gradle
CHANGED
|
@@ -79,7 +79,7 @@ dependencies {
|
|
|
79
79
|
implementation "com.mixpanel.android:mixpanel-android:8.0.2"
|
|
80
80
|
|
|
81
81
|
// Mixpanel Android Session Replay SDK dependency
|
|
82
|
-
implementation "com.mixpanel.android:mixpanel-android-session-replay:1.0.
|
|
82
|
+
implementation "com.mixpanel.android:mixpanel-android-session-replay:1.0.4"
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
react {
|
|
@@ -2,6 +2,7 @@ package com.mixpanelreactnativesessionreplay
|
|
|
2
2
|
|
|
3
3
|
import com.facebook.react.bridge.Promise
|
|
4
4
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
|
+
import com.facebook.react.bridge.ReactMethod
|
|
5
6
|
import com.facebook.react.module.annotations.ReactModule
|
|
6
7
|
import com.mixpanel.android.sessionreplay.MPSessionReplay
|
|
7
8
|
import com.mixpanel.android.sessionreplay.MPSessionReplayInstance
|
|
@@ -20,6 +21,7 @@ class MixpanelReactNativeSessionReplayModule(reactContext: ReactApplicationConte
|
|
|
20
21
|
return NAME
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
@ReactMethod
|
|
23
25
|
override fun initialize(token: String, distinctId: String, configJSON: String, promise: Promise) {
|
|
24
26
|
try {
|
|
25
27
|
if (token.isEmpty() || distinctId.isEmpty()) {
|
|
@@ -108,6 +110,7 @@ class MixpanelReactNativeSessionReplayModule(reactContext: ReactApplicationConte
|
|
|
108
110
|
}
|
|
109
111
|
}
|
|
110
112
|
|
|
113
|
+
@ReactMethod
|
|
111
114
|
override fun startRecording(recordingSessionsPercent: Double, promise: Promise) {
|
|
112
115
|
try {
|
|
113
116
|
MPSessionReplay.getInstance()?.startRecording(sessionsPercent = recordingSessionsPercent)
|
|
@@ -117,6 +120,7 @@ class MixpanelReactNativeSessionReplayModule(reactContext: ReactApplicationConte
|
|
|
117
120
|
}
|
|
118
121
|
}
|
|
119
122
|
|
|
123
|
+
@ReactMethod
|
|
120
124
|
override fun stopRecording(promise: Promise) {
|
|
121
125
|
try {
|
|
122
126
|
MPSessionReplay.getInstance()?.stopRecording()
|
|
@@ -126,6 +130,7 @@ class MixpanelReactNativeSessionReplayModule(reactContext: ReactApplicationConte
|
|
|
126
130
|
}
|
|
127
131
|
}
|
|
128
132
|
|
|
133
|
+
@ReactMethod
|
|
129
134
|
override fun isRecording(promise: Promise) {
|
|
130
135
|
try {
|
|
131
136
|
val recording = MPSessionReplay.getInstance()?.isRecording() ?: false
|
|
@@ -135,6 +140,7 @@ class MixpanelReactNativeSessionReplayModule(reactContext: ReactApplicationConte
|
|
|
135
140
|
}
|
|
136
141
|
}
|
|
137
142
|
|
|
143
|
+
@ReactMethod
|
|
138
144
|
override fun identify(distinctId: String, promise: Promise) {
|
|
139
145
|
try {
|
|
140
146
|
if (distinctId.isEmpty()) {
|
|
@@ -149,6 +155,15 @@ class MixpanelReactNativeSessionReplayModule(reactContext: ReactApplicationConte
|
|
|
149
155
|
}
|
|
150
156
|
}
|
|
151
157
|
|
|
158
|
+
@ReactMethod
|
|
159
|
+
override fun getReplayId(promise: Promise) {
|
|
160
|
+
try {
|
|
161
|
+
val replayId = MPSessionReplay.getInstance()?.getReplayId()
|
|
162
|
+
promise.resolve(replayId)
|
|
163
|
+
} catch (e: Exception) {
|
|
164
|
+
promise.reject("GET_REPLAY_ID_ERROR", e.message, e)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
152
167
|
|
|
153
168
|
/**
|
|
154
169
|
* Safely configure sensitive classes for comprehensive React Native view masking
|
|
@@ -281,7 +296,7 @@ class MixpanelReactNativeSessionReplayModule(reactContext: ReactApplicationConte
|
|
|
281
296
|
|
|
282
297
|
companion object {
|
|
283
298
|
const val NAME = "MixpanelReactNativeSessionReplay"
|
|
284
|
-
const val LIB_VERSION = "0.1
|
|
299
|
+
const val LIB_VERSION = "0.2.1"
|
|
285
300
|
const val MP_LIB = "react-native-sr"
|
|
286
301
|
}
|
|
287
302
|
}
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
1
2
|
#import <MixpanelReactNativeSessionReplaySpec/MixpanelReactNativeSessionReplaySpec.h>
|
|
3
|
+
#else
|
|
4
|
+
#import <React/RCTBridgeModule.h>
|
|
5
|
+
#endif
|
|
2
6
|
|
|
7
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
3
8
|
@interface MixpanelReactNativeSessionReplay : NSObject <NativeMixpanelReactNativeSessionReplaySpec>
|
|
9
|
+
#else
|
|
10
|
+
@interface MixpanelReactNativeSessionReplay : NSObject <RCTBridgeModule>
|
|
11
|
+
#endif
|
|
4
12
|
|
|
5
13
|
@end
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
@implementation MixpanelReactNativeSessionReplay
|
|
9
9
|
RCT_EXPORT_MODULE()
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
RCT_EXPORT_METHOD(initialize:(nonnull NSString *)token distinctId:(nonnull NSString *)distinctId configJSON:(nonnull NSString *)configJSON resolve:(nonnull RCTPromiseResolveBlock)resolve reject:(nonnull RCTPromiseRejectBlock)reject)
|
|
12
|
+
{
|
|
12
13
|
@try {
|
|
13
14
|
if (!token || !distinctId) {
|
|
14
15
|
reject(@"INVALID_CONFIG", @"Token and distinctId are required", nil);
|
|
@@ -27,9 +28,10 @@ RCT_EXPORT_MODULE()
|
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
RCT_EXPORT_METHOD(startRecording:(double)recordingSessionsPercent
|
|
31
32
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
32
|
-
reject:(RCTPromiseRejectBlock)reject
|
|
33
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
34
|
+
{
|
|
33
35
|
@try {
|
|
34
36
|
[MixpanelSwiftSessionReplay startRecordingWithRecordingSessionsPercent:recordingSessionsPercent];
|
|
35
37
|
resolve(nil);
|
|
@@ -39,8 +41,9 @@ RCT_EXPORT_MODULE()
|
|
|
39
41
|
}
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
reject:(RCTPromiseRejectBlock)reject
|
|
44
|
+
RCT_EXPORT_METHOD(stopRecording:(RCTPromiseResolveBlock)resolve
|
|
45
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
46
|
+
{
|
|
44
47
|
@try {
|
|
45
48
|
[MixpanelSwiftSessionReplay stopRecording];
|
|
46
49
|
resolve(nil);
|
|
@@ -50,8 +53,9 @@ RCT_EXPORT_MODULE()
|
|
|
50
53
|
}
|
|
51
54
|
}
|
|
52
55
|
|
|
53
|
-
|
|
54
|
-
reject:(RCTPromiseRejectBlock)reject
|
|
56
|
+
RCT_EXPORT_METHOD(isRecording:(RCTPromiseResolveBlock)resolve
|
|
57
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
58
|
+
{
|
|
55
59
|
@try {
|
|
56
60
|
BOOL recording = [MixpanelSwiftSessionReplay isRecording];
|
|
57
61
|
resolve(@(recording));
|
|
@@ -61,15 +65,16 @@ RCT_EXPORT_MODULE()
|
|
|
61
65
|
}
|
|
62
66
|
}
|
|
63
67
|
|
|
64
|
-
|
|
68
|
+
RCT_EXPORT_METHOD(identify:(NSString *)distinctId
|
|
65
69
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
66
|
-
reject:(RCTPromiseRejectBlock)reject
|
|
70
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
71
|
+
{
|
|
67
72
|
@try {
|
|
68
73
|
if (!distinctId || [distinctId isEqualToString: @""]) {
|
|
69
74
|
reject(@"INVALID_DISTINCT_ID", @"distinctId is required", nil);
|
|
70
75
|
return;
|
|
71
76
|
}
|
|
72
|
-
|
|
77
|
+
|
|
73
78
|
[MixpanelSwiftSessionReplay identify:distinctId];
|
|
74
79
|
resolve(nil);
|
|
75
80
|
}
|
|
@@ -78,10 +83,24 @@ RCT_EXPORT_MODULE()
|
|
|
78
83
|
}
|
|
79
84
|
}
|
|
80
85
|
|
|
86
|
+
RCT_EXPORT_METHOD(getReplayId:(RCTPromiseResolveBlock)resolve
|
|
87
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
88
|
+
{
|
|
89
|
+
@try {
|
|
90
|
+
NSString *replayId = [MixpanelSwiftSessionReplay getReplayId];
|
|
91
|
+
resolve(replayId);
|
|
92
|
+
}
|
|
93
|
+
@catch (NSException *exception) {
|
|
94
|
+
reject(@"GET_REPLAY_ID_ERROR", exception.reason, nil);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
81
99
|
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
82
100
|
(const facebook::react::ObjCTurboModule::InitParams &)params
|
|
83
101
|
{
|
|
84
102
|
return std::make_shared<facebook::react::NativeMixpanelReactNativeSessionReplaySpecJSI>(params);
|
|
85
103
|
}
|
|
104
|
+
#endif
|
|
86
105
|
|
|
87
106
|
@end
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import Foundation
|
|
2
|
-
import UIKit
|
|
3
2
|
import MixpanelSessionReplay
|
|
3
|
+
import UIKit
|
|
4
4
|
|
|
5
5
|
@objc public class MixpanelSwiftSessionReplay: NSObject {
|
|
6
|
-
static let libVersion = "0.1
|
|
6
|
+
static let libVersion = "0.2.1"
|
|
7
7
|
static let mpLib = "react-native-sr"
|
|
8
8
|
|
|
9
9
|
@objc public static func startRecording(recordingSessionsPercent: Double = 100.0) {
|
|
@@ -18,13 +18,16 @@ import MixpanelSessionReplay
|
|
|
18
18
|
MPSessionReplay.getInstance()?.captureScreenshot()
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
@objc public static func initialize(
|
|
21
|
+
@objc public static func initialize(
|
|
22
|
+
_ token: String, distinctId: String, configJSON: String,
|
|
23
|
+
completion: @escaping (Bool, NSError?) -> Void
|
|
24
|
+
) {
|
|
22
25
|
guard let data = configJSON.data(using: .utf8) else {
|
|
23
|
-
let error =
|
|
26
|
+
let error = createError("Invalid config JSON string", code: 3840)
|
|
24
27
|
completion(false, error)
|
|
25
28
|
return
|
|
26
29
|
}
|
|
27
|
-
|
|
30
|
+
|
|
28
31
|
do {
|
|
29
32
|
APIConstants.setLibVersion(libVersion)
|
|
30
33
|
APIConstants.setMpLib(mpLib)
|
|
@@ -34,17 +37,22 @@ import MixpanelSessionReplay
|
|
|
34
37
|
case .success(_?):
|
|
35
38
|
setSensitiveClasses(config: config)
|
|
36
39
|
completion(true, nil)
|
|
37
|
-
|
|
40
|
+
|
|
38
41
|
case .success(nil):
|
|
39
42
|
completion(false, createError("Instance found nil after successful initialisation."))
|
|
40
|
-
|
|
43
|
+
|
|
41
44
|
case .failure(let error as MPSessionReplayError):
|
|
42
|
-
let message
|
|
43
|
-
|
|
44
|
-
case .
|
|
45
|
+
let message: String
|
|
46
|
+
switch error {
|
|
47
|
+
case .disabledByRemoteSetting(let msg):
|
|
48
|
+
message = msg
|
|
49
|
+
case .failedToInitialize:
|
|
50
|
+
message = "Failed to initialize the SDK: \(error)"
|
|
51
|
+
default:
|
|
52
|
+
message = "Session replay initialization failed: \(error)"
|
|
45
53
|
}
|
|
46
54
|
completion(false, createError(message))
|
|
47
|
-
|
|
55
|
+
|
|
48
56
|
case .failure(let error):
|
|
49
57
|
completion(false, createError("Session replay initialization failed: \(error)"))
|
|
50
58
|
}
|
|
@@ -53,25 +61,30 @@ import MixpanelSessionReplay
|
|
|
53
61
|
completion(false, error as NSError)
|
|
54
62
|
}
|
|
55
63
|
}
|
|
56
|
-
|
|
64
|
+
|
|
57
65
|
@objc public static func isRecording() -> Bool {
|
|
58
66
|
return MPSessionReplay.getInstance()?.isRecording ?? false
|
|
59
67
|
}
|
|
60
|
-
|
|
68
|
+
|
|
61
69
|
@objc public static func identify(_ distinctId: String) {
|
|
62
70
|
MPSessionReplay.getInstance()?.identify(distinctId: distinctId)
|
|
63
71
|
}
|
|
64
|
-
|
|
72
|
+
|
|
73
|
+
@objc public static func getReplayId() -> String? {
|
|
74
|
+
return MPSessionReplay.getReplayId()
|
|
75
|
+
}
|
|
76
|
+
|
|
65
77
|
@objc public static func setMPReplaySensitive(value: Bool, view: UIView) {
|
|
66
78
|
view.mpReplaySensitive = value
|
|
67
79
|
}
|
|
68
|
-
|
|
80
|
+
|
|
69
81
|
private static func createError(_ message: String, code: Int = -1) -> NSError {
|
|
70
|
-
return NSError(
|
|
71
|
-
|
|
72
|
-
|
|
82
|
+
return NSError(
|
|
83
|
+
domain: "MixpanelSessionReplay",
|
|
84
|
+
code: code,
|
|
85
|
+
userInfo: [NSLocalizedDescriptionKey: message])
|
|
73
86
|
}
|
|
74
|
-
|
|
87
|
+
|
|
75
88
|
private static func setSensitiveClasses(config: MPSessionReplayConfig) {
|
|
76
89
|
let legacyTextViewClass: AnyClass? = NSClassFromString("RCTTextView")
|
|
77
90
|
let fabricTextViewClass: AnyClass? = NSClassFromString("RCTParagraphTextView")
|
|
@@ -81,11 +94,11 @@ import MixpanelSessionReplay
|
|
|
81
94
|
if let imageViewClass, config.autoMaskedViews.contains(.image) {
|
|
82
95
|
sessionReplay?.addSensitiveClass(imageViewClass)
|
|
83
96
|
}
|
|
84
|
-
|
|
97
|
+
|
|
85
98
|
if let fabricTextViewClass, config.autoMaskedViews.contains(.text) {
|
|
86
99
|
sessionReplay?.addSensitiveClass(fabricTextViewClass)
|
|
87
100
|
}
|
|
88
|
-
|
|
101
|
+
|
|
89
102
|
if let legacyTextViewClass, config.autoMaskedViews.contains(.text) {
|
|
90
103
|
sessionReplay?.addSensitiveClass(legacyTextViewClass)
|
|
91
104
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { requireNativeComponent } from 'react-native';
|
|
4
|
-
export const
|
|
4
|
+
export const MPSessionReplayView = requireNativeComponent('MixpanelSessionReplayView');
|
|
5
5
|
//# sourceMappingURL=MixpanelSessionReplayView.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["requireNativeComponent","
|
|
1
|
+
{"version":3,"names":["requireNativeComponent","MPSessionReplayView"],"sourceRoot":"../../src","sources":["MixpanelSessionReplayView.tsx"],"mappings":";;AAAA,SAASA,sBAAsB,QAAwB,cAAc;AAMrE,OAAO,MAAMC,mBAAmB,GAC9BD,sBAAsB,CACpB,2BACF,CAAC","ignoreList":[]}
|
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import { TurboModuleRegistry } from 'react-native';
|
|
4
|
-
|
|
3
|
+
import { NativeModules, TurboModuleRegistry } from 'react-native';
|
|
4
|
+
|
|
5
|
+
// Type declaration for global to include __turboModuleProxy
|
|
6
|
+
|
|
7
|
+
// Support both old and new architectures
|
|
8
|
+
// Try to use TurboModule (new architecture) first, fallback to NativeModules (old architecture)
|
|
9
|
+
const isTurboModuleEnabled = global.__turboModuleProxy != null;
|
|
10
|
+
let MixpanelReactNativeSessionReplay = null;
|
|
11
|
+
if (isTurboModuleEnabled) {
|
|
12
|
+
// New architecture with TurboModule
|
|
13
|
+
try {
|
|
14
|
+
MixpanelReactNativeSessionReplay = TurboModuleRegistry.get('MixpanelReactNativeSessionReplay');
|
|
15
|
+
} catch (e) {
|
|
16
|
+
// TurboModule not available, will fall back to NativeModules
|
|
17
|
+
console.warn('MixpanelReactNativeSessionReplay: TurboModule not available, falling back to NativeModules');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Fallback to NativeModules for old architecture or if TurboModule fails
|
|
22
|
+
if (!MixpanelReactNativeSessionReplay) {
|
|
23
|
+
MixpanelReactNativeSessionReplay = NativeModules.MixpanelReactNativeSessionReplay;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// If still not available, provide helpful error message
|
|
27
|
+
if (!MixpanelReactNativeSessionReplay) {
|
|
28
|
+
const errorMessage = `The package '@mixpanel/react-native-session-replay' doesn't seem to be linked. Make sure:\n\n` + "- You have installed the package using 'yarn add @mixpanel/react-native-session-replay' or 'npm install @mixpanel/react-native-session-replay'.\n" + '- You have rebuilt the app after installing the package.\n' + "- For iOS: You have run 'pod install' in the 'ios' directory and opened the .xcworkspace file in Xcode.\n" + '- For Android: You have synced your project with Gradle files and rebuilt the app.\n' + '- If you are using Expo, this package is not compatible with Expo Go.\n';
|
|
29
|
+
throw new Error(errorMessage);
|
|
30
|
+
}
|
|
31
|
+
export default MixpanelReactNativeSessionReplay;
|
|
5
32
|
//# sourceMappingURL=NativeMixpanelReactNativeSessionReplay.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["TurboModuleRegistry","
|
|
1
|
+
{"version":3,"names":["NativeModules","TurboModuleRegistry","isTurboModuleEnabled","global","__turboModuleProxy","MixpanelReactNativeSessionReplay","get","e","console","warn","errorMessage","Error"],"sourceRoot":"../../src","sources":["NativeMixpanelReactNativeSessionReplay.ts"],"mappings":";;AACA,SAASA,aAAa,EAAEC,mBAAmB,QAAQ,cAAc;;AAgBjE;;AAKA;AACA;AACA,MAAMC,oBAAoB,GAAGC,MAAM,CAACC,kBAAkB,IAAI,IAAI;AAE9D,IAAIC,gCAA6C,GAAG,IAAI;AAExD,IAAIH,oBAAoB,EAAE;EACxB;EACA,IAAI;IACFG,gCAAgC,GAAGJ,mBAAmB,CAACK,GAAG,CACxD,kCACF,CAAC;EACH,CAAC,CAAC,OAAOC,CAAC,EAAE;IACV;IACAC,OAAO,CAACC,IAAI,CACV,4FACF,CAAC;EACH;AACF;;AAEA;AACA,IAAI,CAACJ,gCAAgC,EAAE;EACrCA,gCAAgC,GAC9BL,aAAa,CAACK,gCAAgC;AAClD;;AAEA;AACA,IAAI,CAACA,gCAAgC,EAAE;EACrC,MAAMK,YAAY,GAChB,+FAA+F,GAC/F,mJAAmJ,GACnJ,4DAA4D,GAC5D,2GAA2G,GAC3G,sFAAsF,GACtF,yEAAyE;EAE3E,MAAM,IAAIC,KAAK,CAACD,YAAY,CAAC;AAC/B;AAEA,eAAeL,gCAAgC","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -109,7 +109,6 @@ export class MPSessionReplayConfig {
|
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
|
-
export { MixpanelSessionReplayView } from "./MixpanelSessionReplayView.js";
|
|
113
112
|
|
|
114
113
|
/**
|
|
115
114
|
* Initializes the Mixpanel Session Replay system with the provided configuration.
|
|
@@ -123,7 +122,7 @@ export { MixpanelSessionReplayView } from "./MixpanelSessionReplayView.js";
|
|
|
123
122
|
* @throws An error if the token or distinctId is missing or invalid, or if the configuration is invalid,
|
|
124
123
|
* or if the initialization fails.
|
|
125
124
|
*/
|
|
126
|
-
|
|
125
|
+
async function initialize(token, distinctId, config) {
|
|
127
126
|
if (!token || typeof token !== 'string') {
|
|
128
127
|
throw new Error('Mixpanel token is required and must be a string');
|
|
129
128
|
}
|
|
@@ -147,7 +146,7 @@ export async function initialize(token, distinctId, config) {
|
|
|
147
146
|
* This controls sampling of sessions. The `recordingSessionsPercent` value from the config is ignored when calling this method.
|
|
148
147
|
* @default 100 (record all sessions)
|
|
149
148
|
*/
|
|
150
|
-
|
|
149
|
+
async function startRecording(recordingSessionsPercent = 100) {
|
|
151
150
|
return MixpanelReactNativeSessionReplay.startRecording(recordingSessionsPercent);
|
|
152
151
|
}
|
|
153
152
|
|
|
@@ -156,7 +155,7 @@ export async function startRecording(recordingSessionsPercent = 100) {
|
|
|
156
155
|
*
|
|
157
156
|
* This method stops recording, clears relevant session state, and uploads pending events.
|
|
158
157
|
*/
|
|
159
|
-
|
|
158
|
+
async function stopRecording() {
|
|
160
159
|
return MixpanelReactNativeSessionReplay.stopRecording();
|
|
161
160
|
}
|
|
162
161
|
|
|
@@ -165,7 +164,7 @@ export async function stopRecording() {
|
|
|
165
164
|
*
|
|
166
165
|
* @returns A promise that resolves to `true` if recording is active, `false` otherwise.
|
|
167
166
|
*/
|
|
168
|
-
|
|
167
|
+
async function isRecording() {
|
|
169
168
|
return MixpanelReactNativeSessionReplay.isRecording();
|
|
170
169
|
}
|
|
171
170
|
|
|
@@ -179,10 +178,31 @@ export async function isRecording() {
|
|
|
179
178
|
* @param distinctId - The distinct ID of the user.
|
|
180
179
|
* @throws An error if the distinctId is missing or invalid.
|
|
181
180
|
*/
|
|
182
|
-
|
|
181
|
+
async function identify(distinctId) {
|
|
183
182
|
if (!distinctId || typeof distinctId !== 'string') {
|
|
184
183
|
throw new Error('distinctId is required and must be a string');
|
|
185
184
|
}
|
|
186
185
|
return MixpanelReactNativeSessionReplay.identify(distinctId);
|
|
187
186
|
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Gets the current replay ID.
|
|
190
|
+
*
|
|
191
|
+
* Returns the unique identifier for the current replay session, or null if no replay is active.
|
|
192
|
+
* This ID can be used to correlate session replays with other analytics data.
|
|
193
|
+
*
|
|
194
|
+
* @returns A promise that resolves to the replay ID string or null if no replay is active.
|
|
195
|
+
*/
|
|
196
|
+
async function getReplayId() {
|
|
197
|
+
return MixpanelReactNativeSessionReplay.getReplayId();
|
|
198
|
+
}
|
|
199
|
+
export { MPSessionReplayView } from "./MixpanelSessionReplayView.js";
|
|
200
|
+
export const MPSessionReplay = {
|
|
201
|
+
initialize,
|
|
202
|
+
startRecording,
|
|
203
|
+
stopRecording,
|
|
204
|
+
isRecording,
|
|
205
|
+
identify,
|
|
206
|
+
getReplayId
|
|
207
|
+
};
|
|
188
208
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["Platform","MixpanelReactNativeSessionReplay","MPSessionReplayMask","MPSessionReplayConfig","constructor","wifiOnly","autoStartRecording","recordingSessionsPercent","autoMaskedViews","Image","Text","Web","Map","flushInterval","enableLogging","transformMaskValueForPlatform","value","OS","charAt","toUpperCase","slice","toJSON","transformedAutoMaskedViews","filter","mask","map","config","JSON","stringify","
|
|
1
|
+
{"version":3,"names":["Platform","MixpanelReactNativeSessionReplay","MPSessionReplayMask","MPSessionReplayConfig","constructor","wifiOnly","autoStartRecording","recordingSessionsPercent","autoMaskedViews","Image","Text","Web","Map","flushInterval","enableLogging","transformMaskValueForPlatform","value","OS","charAt","toUpperCase","slice","toJSON","transformedAutoMaskedViews","filter","mask","map","config","JSON","stringify","initialize","token","distinctId","Error","undefined","json","startRecording","stopRecording","isRecording","identify","getReplayId","MPSessionReplayView","MPSessionReplay"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -2,6 +2,6 @@ import { type ViewProps } from 'react-native';
|
|
|
2
2
|
interface MixpanelSessionReplayViewProps extends ViewProps {
|
|
3
3
|
sensitive?: boolean;
|
|
4
4
|
}
|
|
5
|
-
export declare const
|
|
5
|
+
export declare const MPSessionReplayView: import("react-native").HostComponent<MixpanelSessionReplayViewProps>;
|
|
6
6
|
export {};
|
|
7
7
|
//# sourceMappingURL=MixpanelSessionReplayView.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MixpanelSessionReplayView.d.ts","sourceRoot":"","sources":["../../../src/MixpanelSessionReplayView.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAEtE,UAAU,8BAA+B,SAAQ,SAAS;IACxD,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,eAAO,MAAM,
|
|
1
|
+
{"version":3,"file":"MixpanelSessionReplayView.d.ts","sourceRoot":"","sources":["../../../src/MixpanelSessionReplayView.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAEtE,UAAU,8BAA+B,SAAQ,SAAS;IACxD,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,eAAO,MAAM,mBAAmB,sEAG7B,CAAC"}
|
|
@@ -5,6 +5,10 @@ export interface Spec extends TurboModule {
|
|
|
5
5
|
stopRecording(): Promise<void>;
|
|
6
6
|
isRecording(): Promise<boolean>;
|
|
7
7
|
identify(distinctId: string): Promise<void>;
|
|
8
|
+
getReplayId(): Promise<string | null>;
|
|
9
|
+
}
|
|
10
|
+
declare global {
|
|
11
|
+
var __turboModuleProxy: unknown | undefined;
|
|
8
12
|
}
|
|
9
13
|
declare const _default: Spec;
|
|
10
14
|
export default _default;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeMixpanelReactNativeSessionReplay.d.ts","sourceRoot":"","sources":["../../../src/NativeMixpanelReactNativeSessionReplay.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,UAAU,CACR,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,cAAc,CAAC,wBAAwB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/B,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C
|
|
1
|
+
{"version":3,"file":"NativeMixpanelReactNativeSessionReplay.d.ts","sourceRoot":"","sources":["../../../src/NativeMixpanelReactNativeSessionReplay.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,UAAU,CACR,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,cAAc,CAAC,wBAAwB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/B,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,WAAW,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACvC;AAGD,OAAO,CAAC,MAAM,CAAC;IACb,IAAI,kBAAkB,EAAE,OAAO,GAAG,SAAS,CAAC;CAC7C;wBAyCkD,IAAI;AAAvD,wBAAwD"}
|
|
@@ -66,7 +66,6 @@ export declare class MPSessionReplayConfig {
|
|
|
66
66
|
private transformMaskValueForPlatform;
|
|
67
67
|
toJSON(): string;
|
|
68
68
|
}
|
|
69
|
-
export { MixpanelSessionReplayView } from './MixpanelSessionReplayView';
|
|
70
69
|
/**
|
|
71
70
|
* Initializes the Mixpanel Session Replay system with the provided configuration.
|
|
72
71
|
*
|
|
@@ -79,7 +78,7 @@ export { MixpanelSessionReplayView } from './MixpanelSessionReplayView';
|
|
|
79
78
|
* @throws An error if the token or distinctId is missing or invalid, or if the configuration is invalid,
|
|
80
79
|
* or if the initialization fails.
|
|
81
80
|
*/
|
|
82
|
-
|
|
81
|
+
declare function initialize(token: string, distinctId: string, config: MPSessionReplayConfig): Promise<void>;
|
|
83
82
|
/**
|
|
84
83
|
* Manually starts session replay recording.
|
|
85
84
|
*
|
|
@@ -90,19 +89,19 @@ export declare function initialize(token: string, distinctId: string, config: MP
|
|
|
90
89
|
* This controls sampling of sessions. The `recordingSessionsPercent` value from the config is ignored when calling this method.
|
|
91
90
|
* @default 100 (record all sessions)
|
|
92
91
|
*/
|
|
93
|
-
|
|
92
|
+
declare function startRecording(recordingSessionsPercent?: number): Promise<void>;
|
|
94
93
|
/**
|
|
95
94
|
* Stops the session recording and performs cleanup tasks.
|
|
96
95
|
*
|
|
97
96
|
* This method stops recording, clears relevant session state, and uploads pending events.
|
|
98
97
|
*/
|
|
99
|
-
|
|
98
|
+
declare function stopRecording(): Promise<void>;
|
|
100
99
|
/**
|
|
101
100
|
* Tells you if the recording is in-progress.
|
|
102
101
|
*
|
|
103
102
|
* @returns A promise that resolves to `true` if recording is active, `false` otherwise.
|
|
104
103
|
*/
|
|
105
|
-
|
|
104
|
+
declare function isRecording(): Promise<boolean>;
|
|
106
105
|
/**
|
|
107
106
|
* Sets the distinct ID for session replays.
|
|
108
107
|
*
|
|
@@ -113,5 +112,23 @@ export declare function isRecording(): Promise<boolean>;
|
|
|
113
112
|
* @param distinctId - The distinct ID of the user.
|
|
114
113
|
* @throws An error if the distinctId is missing or invalid.
|
|
115
114
|
*/
|
|
116
|
-
|
|
115
|
+
declare function identify(distinctId: string): Promise<void>;
|
|
116
|
+
/**
|
|
117
|
+
* Gets the current replay ID.
|
|
118
|
+
*
|
|
119
|
+
* Returns the unique identifier for the current replay session, or null if no replay is active.
|
|
120
|
+
* This ID can be used to correlate session replays with other analytics data.
|
|
121
|
+
*
|
|
122
|
+
* @returns A promise that resolves to the replay ID string or null if no replay is active.
|
|
123
|
+
*/
|
|
124
|
+
declare function getReplayId(): Promise<string | null>;
|
|
125
|
+
export { MPSessionReplayView } from './MixpanelSessionReplayView';
|
|
126
|
+
export declare const MPSessionReplay: {
|
|
127
|
+
initialize: typeof initialize;
|
|
128
|
+
startRecording: typeof startRecording;
|
|
129
|
+
stopRecording: typeof stopRecording;
|
|
130
|
+
isRecording: typeof isRecording;
|
|
131
|
+
identify: typeof identify;
|
|
132
|
+
getReplayId: typeof getReplayId;
|
|
133
|
+
};
|
|
117
134
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAGA,oBAAY,mBAAmB;IAC7B,IAAI,SAAS;IACb,GAAG,QAAQ;IACX,GAAG,QAAQ;IACX,KAAK,UAAU;CAChB;AAED,qBAAa,qBAAqB;IAChC;;;;;;;OAOG;IACH,QAAQ,EAAE,OAAO,CAAC;IAElB;;;;;;;;;;OAUG;IACH,wBAAwB,EAAE,MAAM,CAAC;IAEjC;;;;;OAKG;IACH,eAAe,EAAE,mBAAmB,EAAE,CAAC;IAEvC;;;;;;;;OAQG;IACH,kBAAkB,EAAE,OAAO,CAAC;IAE5B;;;;;;;;OAQG;IACH,aAAa,EAAE,MAAM,CAAC;IAEtB;;;;;;;OAOG;IACH,aAAa,EAAE,OAAO,CAAC;gBAEX,EACV,QAAe,EACf,kBAAyB,EACzB,wBAA8B,EAC9B,eAKC,EACD,aAAkB,EAClB,aAAqB,GACtB,GAAE,OAAO,CAAC,qBAAqB,CAAM;IAStC,OAAO,CAAC,6BAA6B;IASrC,MAAM,IAAI,MAAM;CAyBjB;AAED
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAGA,oBAAY,mBAAmB;IAC7B,IAAI,SAAS;IACb,GAAG,QAAQ;IACX,GAAG,QAAQ;IACX,KAAK,UAAU;CAChB;AAED,qBAAa,qBAAqB;IAChC;;;;;;;OAOG;IACH,QAAQ,EAAE,OAAO,CAAC;IAElB;;;;;;;;;;OAUG;IACH,wBAAwB,EAAE,MAAM,CAAC;IAEjC;;;;;OAKG;IACH,eAAe,EAAE,mBAAmB,EAAE,CAAC;IAEvC;;;;;;;;OAQG;IACH,kBAAkB,EAAE,OAAO,CAAC;IAE5B;;;;;;;;OAQG;IACH,aAAa,EAAE,MAAM,CAAC;IAEtB;;;;;;;OAOG;IACH,aAAa,EAAE,OAAO,CAAC;gBAEX,EACV,QAAe,EACf,kBAAyB,EACzB,wBAA8B,EAC9B,eAKC,EACD,aAAkB,EAClB,aAAqB,GACtB,GAAE,OAAO,CAAC,qBAAqB,CAAM;IAStC,OAAO,CAAC,6BAA6B;IASrC,MAAM,IAAI,MAAM;CAyBjB;AAED;;;;;;;;;;;GAWG;AACH,iBAAe,UAAU,CACvB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED;;;;;;;;;GASG;AACH,iBAAe,cAAc,CAC3B,wBAAwB,GAAE,MAAY,GACrC,OAAO,CAAC,IAAI,CAAC,CAIf;AAED;;;;GAIG;AACH,iBAAe,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAE5C;AAED;;;;GAIG;AACH,iBAAe,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAE7C;AAED;;;;;;;;;GASG;AACH,iBAAe,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMzD;AAED;;;;;;;GAOG;AACH,iBAAe,WAAW,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAEnD;AAED,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAElE,eAAO,MAAM,eAAe;;;;;;;CAO3B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TurboModule } from 'react-native';
|
|
2
|
-
import { TurboModuleRegistry } from 'react-native';
|
|
2
|
+
import { NativeModules, TurboModuleRegistry } from 'react-native';
|
|
3
3
|
|
|
4
4
|
export interface Spec extends TurboModule {
|
|
5
5
|
initialize(
|
|
@@ -12,8 +12,51 @@ export interface Spec extends TurboModule {
|
|
|
12
12
|
// Functionality not available in Android SDK ATM. It returns true always.
|
|
13
13
|
isRecording(): Promise<boolean>;
|
|
14
14
|
identify(distinctId: string): Promise<void>;
|
|
15
|
+
getReplayId(): Promise<string | null>;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
// Type declaration for global to include __turboModuleProxy
|
|
19
|
+
declare global {
|
|
20
|
+
var __turboModuleProxy: unknown | undefined;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Support both old and new architectures
|
|
24
|
+
// Try to use TurboModule (new architecture) first, fallback to NativeModules (old architecture)
|
|
25
|
+
const isTurboModuleEnabled = global.__turboModuleProxy != null;
|
|
26
|
+
|
|
27
|
+
let MixpanelReactNativeSessionReplay: Spec | null = null;
|
|
28
|
+
|
|
29
|
+
if (isTurboModuleEnabled) {
|
|
30
|
+
// New architecture with TurboModule
|
|
31
|
+
try {
|
|
32
|
+
MixpanelReactNativeSessionReplay = TurboModuleRegistry.get<Spec>(
|
|
33
|
+
'MixpanelReactNativeSessionReplay'
|
|
34
|
+
);
|
|
35
|
+
} catch (e) {
|
|
36
|
+
// TurboModule not available, will fall back to NativeModules
|
|
37
|
+
console.warn(
|
|
38
|
+
'MixpanelReactNativeSessionReplay: TurboModule not available, falling back to NativeModules'
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Fallback to NativeModules for old architecture or if TurboModule fails
|
|
44
|
+
if (!MixpanelReactNativeSessionReplay) {
|
|
45
|
+
MixpanelReactNativeSessionReplay =
|
|
46
|
+
NativeModules.MixpanelReactNativeSessionReplay;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// If still not available, provide helpful error message
|
|
50
|
+
if (!MixpanelReactNativeSessionReplay) {
|
|
51
|
+
const errorMessage =
|
|
52
|
+
`The package '@mixpanel/react-native-session-replay' doesn't seem to be linked. Make sure:\n\n` +
|
|
53
|
+
"- You have installed the package using 'yarn add @mixpanel/react-native-session-replay' or 'npm install @mixpanel/react-native-session-replay'.\n" +
|
|
54
|
+
'- You have rebuilt the app after installing the package.\n' +
|
|
55
|
+
"- For iOS: You have run 'pod install' in the 'ios' directory and opened the .xcworkspace file in Xcode.\n" +
|
|
56
|
+
'- For Android: You have synced your project with Gradle files and rebuilt the app.\n' +
|
|
57
|
+
'- If you are using Expo, this package is not compatible with Expo Go.\n';
|
|
58
|
+
|
|
59
|
+
throw new Error(errorMessage);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export default MixpanelReactNativeSessionReplay as Spec;
|
package/src/index.tsx
CHANGED
|
@@ -129,8 +129,6 @@ export class MPSessionReplayConfig {
|
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
export { MixpanelSessionReplayView } from './MixpanelSessionReplayView';
|
|
133
|
-
|
|
134
132
|
/**
|
|
135
133
|
* Initializes the Mixpanel Session Replay system with the provided configuration.
|
|
136
134
|
*
|
|
@@ -143,7 +141,7 @@ export { MixpanelSessionReplayView } from './MixpanelSessionReplayView';
|
|
|
143
141
|
* @throws An error if the token or distinctId is missing or invalid, or if the configuration is invalid,
|
|
144
142
|
* or if the initialization fails.
|
|
145
143
|
*/
|
|
146
|
-
|
|
144
|
+
async function initialize(
|
|
147
145
|
token: string,
|
|
148
146
|
distinctId: string,
|
|
149
147
|
config: MPSessionReplayConfig
|
|
@@ -175,7 +173,7 @@ export async function initialize(
|
|
|
175
173
|
* This controls sampling of sessions. The `recordingSessionsPercent` value from the config is ignored when calling this method.
|
|
176
174
|
* @default 100 (record all sessions)
|
|
177
175
|
*/
|
|
178
|
-
|
|
176
|
+
async function startRecording(
|
|
179
177
|
recordingSessionsPercent: number = 100
|
|
180
178
|
): Promise<void> {
|
|
181
179
|
return MixpanelReactNativeSessionReplay.startRecording(
|
|
@@ -188,7 +186,7 @@ export async function startRecording(
|
|
|
188
186
|
*
|
|
189
187
|
* This method stops recording, clears relevant session state, and uploads pending events.
|
|
190
188
|
*/
|
|
191
|
-
|
|
189
|
+
async function stopRecording(): Promise<void> {
|
|
192
190
|
return MixpanelReactNativeSessionReplay.stopRecording();
|
|
193
191
|
}
|
|
194
192
|
|
|
@@ -197,7 +195,7 @@ export async function stopRecording(): Promise<void> {
|
|
|
197
195
|
*
|
|
198
196
|
* @returns A promise that resolves to `true` if recording is active, `false` otherwise.
|
|
199
197
|
*/
|
|
200
|
-
|
|
198
|
+
async function isRecording(): Promise<boolean> {
|
|
201
199
|
return MixpanelReactNativeSessionReplay.isRecording();
|
|
202
200
|
}
|
|
203
201
|
|
|
@@ -211,10 +209,33 @@ export async function isRecording(): Promise<boolean> {
|
|
|
211
209
|
* @param distinctId - The distinct ID of the user.
|
|
212
210
|
* @throws An error if the distinctId is missing or invalid.
|
|
213
211
|
*/
|
|
214
|
-
|
|
212
|
+
async function identify(distinctId: string): Promise<void> {
|
|
215
213
|
if (!distinctId || typeof distinctId !== 'string') {
|
|
216
214
|
throw new Error('distinctId is required and must be a string');
|
|
217
215
|
}
|
|
218
216
|
|
|
219
217
|
return MixpanelReactNativeSessionReplay.identify(distinctId);
|
|
220
218
|
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Gets the current replay ID.
|
|
222
|
+
*
|
|
223
|
+
* Returns the unique identifier for the current replay session, or null if no replay is active.
|
|
224
|
+
* This ID can be used to correlate session replays with other analytics data.
|
|
225
|
+
*
|
|
226
|
+
* @returns A promise that resolves to the replay ID string or null if no replay is active.
|
|
227
|
+
*/
|
|
228
|
+
async function getReplayId(): Promise<string | null> {
|
|
229
|
+
return MixpanelReactNativeSessionReplay.getReplayId();
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export { MPSessionReplayView } from './MixpanelSessionReplayView';
|
|
233
|
+
|
|
234
|
+
export const MPSessionReplay = {
|
|
235
|
+
initialize,
|
|
236
|
+
startRecording,
|
|
237
|
+
stopRecording,
|
|
238
|
+
isRecording,
|
|
239
|
+
identify,
|
|
240
|
+
getReplayId,
|
|
241
|
+
};
|