@datadog/mobile-react-native-session-replay 2.14.1 → 3.0.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/DatadogSDKReactNativeSessionReplay.podspec +1 -1
- package/android/build.gradle +2 -2
- package/android/gradle.properties +1 -1
- package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/DdSessionReplayImplementation.kt +4 -4
- package/ios/Sources/DdSessionReplayImplementation.swift +5 -23
- package/ios/Sources/RCTTextViewRecorder.swift +25 -19
- package/lib/commonjs/SessionReplay.js +0 -22
- package/lib/commonjs/SessionReplay.js.map +1 -1
- package/lib/module/SessionReplay.js +0 -22
- package/lib/module/SessionReplay.js.map +1 -1
- package/lib/typescript/SessionReplay.d.ts +0 -8
- package/lib/typescript/SessionReplay.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/SessionReplay.ts +1 -40
- package/src/__tests__/SessionReplay.test.ts +1 -37
|
@@ -23,7 +23,7 @@ Pod::Spec.new do |s|
|
|
|
23
23
|
s.dependency "React-Core"
|
|
24
24
|
|
|
25
25
|
# /!\ Remember to keep the version in sync with DatadogSDKReactNative.podspec
|
|
26
|
-
s.dependency 'DatadogSessionReplay', '
|
|
26
|
+
s.dependency 'DatadogSessionReplay', '3.4.0'
|
|
27
27
|
s.dependency 'DatadogSDKReactNative'
|
|
28
28
|
|
|
29
29
|
s.test_spec 'Tests' do |test_spec|
|
package/android/build.gradle
CHANGED
|
@@ -216,8 +216,8 @@ dependencies {
|
|
|
216
216
|
api "com.facebook.react:react-android:$reactNativeVersion"
|
|
217
217
|
}
|
|
218
218
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
219
|
-
implementation "com.datadoghq:dd-sdk-android-session-replay:
|
|
220
|
-
implementation "com.datadoghq:dd-sdk-android-internal:
|
|
219
|
+
implementation "com.datadoghq:dd-sdk-android-session-replay:3.4.0"
|
|
220
|
+
implementation "com.datadoghq:dd-sdk-android-internal:3.4.0"
|
|
221
221
|
implementation project(path: ':datadog_mobile-react-native')
|
|
222
222
|
|
|
223
223
|
testImplementation "org.junit.platform:junit-platform-launcher:1.6.2"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
DatadogSDKReactNativeSessionReplay_kotlinVersion=1.8.21
|
|
2
2
|
DatadogSDKReactNativeSessionReplay_compileSdkVersion=33
|
|
3
|
-
DatadogSDKReactNativeSessionReplay_minSdkVersion=
|
|
3
|
+
DatadogSDKReactNativeSessionReplay_minSdkVersion=23
|
|
4
4
|
DatadogSDKReactNativeSessionReplay_buildToolsVersion=33.0.0
|
|
5
5
|
DatadogSDKReactNativeSessionReplay_targetSdkVersion=33
|
|
6
6
|
android.useAndroidX=true
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
package com.datadog.reactnative.sessionreplay
|
|
8
8
|
|
|
9
9
|
import android.annotation.SuppressLint
|
|
10
|
+
import com.datadog.android.Datadog
|
|
10
11
|
import com.datadog.android.api.feature.FeatureSdkCore
|
|
11
12
|
import com.datadog.android.sessionreplay.SessionReplayConfiguration
|
|
12
13
|
import com.datadog.android.sessionreplay._SessionReplayInternalProxy
|
|
13
|
-
import com.datadog.reactnative.DatadogSDKWrapperStorage
|
|
14
14
|
import com.datadog.reactnative.sessionreplay.utils.text.TextViewUtils
|
|
15
15
|
import com.facebook.react.bridge.Promise
|
|
16
16
|
import com.facebook.react.bridge.ReactContext
|
|
@@ -40,7 +40,7 @@ class DdSessionReplayImplementation(
|
|
|
40
40
|
startRecordingImmediately: Boolean,
|
|
41
41
|
promise: Promise
|
|
42
42
|
) {
|
|
43
|
-
val sdkCore =
|
|
43
|
+
val sdkCore = Datadog.getInstance() as FeatureSdkCore
|
|
44
44
|
val logger = sdkCore.internalLogger
|
|
45
45
|
val textViewUtils = TextViewUtils.create(reactContext, logger)
|
|
46
46
|
val internalCallback = ReactNativeInternalCallback(reactContext)
|
|
@@ -68,7 +68,7 @@ class DdSessionReplayImplementation(
|
|
|
68
68
|
*/
|
|
69
69
|
fun startRecording(promise: Promise) {
|
|
70
70
|
sessionReplayProvider().startRecording(
|
|
71
|
-
|
|
71
|
+
Datadog.getInstance() as FeatureSdkCore
|
|
72
72
|
)
|
|
73
73
|
promise.resolve(null)
|
|
74
74
|
}
|
|
@@ -78,7 +78,7 @@ class DdSessionReplayImplementation(
|
|
|
78
78
|
*/
|
|
79
79
|
fun stopRecording(promise: Promise) {
|
|
80
80
|
sessionReplayProvider().stopRecording(
|
|
81
|
-
|
|
81
|
+
Datadog.getInstance() as FeatureSdkCore
|
|
82
82
|
)
|
|
83
83
|
promise.resolve(null)
|
|
84
84
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import Foundation
|
|
8
8
|
@_spi(Internal) import DatadogSessionReplay
|
|
9
|
+
import DatadogCore
|
|
9
10
|
import DatadogInternal
|
|
10
11
|
import DatadogSDKReactNative
|
|
11
12
|
import React
|
|
@@ -66,8 +67,6 @@ public class DdSessionReplayImplementation: NSObject {
|
|
|
66
67
|
customEndpoint: customEndpointURL
|
|
67
68
|
)
|
|
68
69
|
|
|
69
|
-
// let bundle = Bundle(for: DdSessionReplayImplementation.self)
|
|
70
|
-
|
|
71
70
|
var svgMap: [String: SVGData] = [:]
|
|
72
71
|
|
|
73
72
|
if let bundle = Bundle.ddSessionReplayResources,
|
|
@@ -92,38 +91,21 @@ public class DdSessionReplayImplementation: NSObject {
|
|
|
92
91
|
fabricWrapper: fabricWrapper
|
|
93
92
|
)
|
|
94
93
|
])
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
sessionReplay.enable(
|
|
98
|
-
with: sessionReplayConfiguration,
|
|
99
|
-
in: core
|
|
100
|
-
)
|
|
101
|
-
} else {
|
|
102
|
-
consolePrint("Core instance was not found when initializing Session Replay.", .critical)
|
|
103
|
-
}
|
|
94
|
+
|
|
95
|
+
sessionReplay.enable(with: sessionReplayConfiguration, in: CoreRegistry.default)
|
|
104
96
|
|
|
105
97
|
resolve(nil)
|
|
106
98
|
}
|
|
107
99
|
|
|
108
100
|
@objc
|
|
109
101
|
public func startRecording(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
|
|
110
|
-
|
|
111
|
-
sessionReplay.startRecording(in: core)
|
|
112
|
-
} else {
|
|
113
|
-
consolePrint("Core instance was not found when calling startRecording in Session Replay.", .critical)
|
|
114
|
-
}
|
|
115
|
-
|
|
102
|
+
sessionReplay.startRecording(in: CoreRegistry.default)
|
|
116
103
|
resolve(nil)
|
|
117
104
|
}
|
|
118
105
|
|
|
119
106
|
@objc
|
|
120
107
|
public func stopRecording(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
|
|
121
|
-
|
|
122
|
-
sessionReplay.stopRecording(in: core)
|
|
123
|
-
} else {
|
|
124
|
-
consolePrint("Core instance was not found when calling stopRecording in Session Replay.", .critical)
|
|
125
|
-
}
|
|
126
|
-
|
|
108
|
+
sessionReplay.stopRecording(in: CoreRegistry.default)
|
|
127
109
|
resolve(nil)
|
|
128
110
|
}
|
|
129
111
|
|
|
@@ -4,15 +4,17 @@
|
|
|
4
4
|
* Copyright 2019-Present Datadog, Inc.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import
|
|
8
|
-
@_spi(Internal)
|
|
9
|
-
import DatadogSessionReplay
|
|
7
|
+
@_spi(Internal) import DatadogSessionReplay
|
|
10
8
|
import React
|
|
9
|
+
import UIKit
|
|
11
10
|
|
|
12
11
|
internal class RCTTextViewRecorder: SessionReplayNodeRecorder {
|
|
13
|
-
internal var textObfuscator:
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
internal var textObfuscator:
|
|
13
|
+
(SessionReplayViewTreeRecordingContext, SessionReplayViewAttributes) ->
|
|
14
|
+
SessionReplayTextObfuscating = { context, viewAttributes in
|
|
15
|
+
return viewAttributes.resolveTextAndInputPrivacyLevel(in: context)
|
|
16
|
+
.staticTextObfuscator
|
|
17
|
+
}
|
|
16
18
|
|
|
17
19
|
internal var identifier = UUID()
|
|
18
20
|
|
|
@@ -30,7 +32,8 @@ internal class RCTTextViewRecorder: SessionReplayNodeRecorder {
|
|
|
30
32
|
in context: SessionReplayViewTreeRecordingContext
|
|
31
33
|
) -> SessionReplayNodeSemantics? {
|
|
32
34
|
guard
|
|
33
|
-
let textProperties = fabricWrapper.tryToExtractTextProperties(from: view)
|
|
35
|
+
let textProperties = fabricWrapper.tryToExtractTextProperties(from: view)
|
|
36
|
+
?? tryToExtractTextProperties(view: view)
|
|
34
37
|
else {
|
|
35
38
|
return view is RCTTextView ? SessionReplayInvisibleElement.constant : nil
|
|
36
39
|
}
|
|
@@ -46,9 +49,11 @@ internal class RCTTextViewRecorder: SessionReplayNodeRecorder {
|
|
|
46
49
|
contentRect: textProperties.contentRect
|
|
47
50
|
)
|
|
48
51
|
|
|
49
|
-
return SessionReplaySpecificElement(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
return SessionReplaySpecificElement(
|
|
53
|
+
subtreeStrategy: .ignore,
|
|
54
|
+
nodes: [
|
|
55
|
+
SessionReplayNode(viewAttributes: attributes, wireframesBuilder: builder)
|
|
56
|
+
])
|
|
52
57
|
}
|
|
53
58
|
|
|
54
59
|
internal func tryToExtractTextFromSubViews(
|
|
@@ -80,7 +85,7 @@ internal class RCTTextViewRecorder: SessionReplayNodeRecorder {
|
|
|
80
85
|
|
|
81
86
|
let timeout: TimeInterval = 0.2
|
|
82
87
|
let semaphore = DispatchSemaphore(value: 0)
|
|
83
|
-
|
|
88
|
+
|
|
84
89
|
// We need to access the shadow view from the UIManager queue, but we're currently on the main thread.
|
|
85
90
|
// Calling `.sync` from the main thread to the UIManager queue is unsafe, because the UIManager queue
|
|
86
91
|
// may already be executing a layout operation that in turn requires the main thread (e.g. measuring a native view).
|
|
@@ -91,7 +96,7 @@ internal class RCTTextViewRecorder: SessionReplayNodeRecorder {
|
|
|
91
96
|
shadowView = self.uiManager.shadowView(forReactTag: tag) as? RCTTextShadowView
|
|
92
97
|
semaphore.signal()
|
|
93
98
|
}
|
|
94
|
-
|
|
99
|
+
|
|
95
100
|
let waitResult = semaphore.wait(timeout: .now() + timeout)
|
|
96
101
|
if waitResult == .timedOut {
|
|
97
102
|
return nil
|
|
@@ -137,17 +142,17 @@ internal struct RCTTextViewWireframesBuilder: SessionReplayNodeWireframesBuilder
|
|
|
137
142
|
// Clipping should be 0 to avoid the text from overflowing when the
|
|
138
143
|
// numberOfLines prop is used.
|
|
139
144
|
// To apply clip(0 0 0 0) we set a negative clipping (which has no effect).
|
|
140
|
-
// TODO: RUM-2354 remove this when clip(0 0 0 0) is applied
|
|
145
|
+
// TODO: RUM-2354 remove this when clip(0 0 0 0) is applied
|
|
141
146
|
private var clip: SRContentClip {
|
|
142
|
-
let top = -1.0
|
|
147
|
+
let top = -1.0
|
|
143
148
|
let left = 0.0
|
|
144
149
|
let bottom = 0.0
|
|
145
150
|
let right = 0.0
|
|
146
151
|
return SRContentClip.create(
|
|
147
|
-
bottom: Int64(
|
|
148
|
-
left: Int64(
|
|
149
|
-
right: Int64(
|
|
150
|
-
top: Int64(
|
|
152
|
+
bottom: Int64.ddWithNoOverflow(bottom),
|
|
153
|
+
left: Int64.ddWithNoOverflow(left),
|
|
154
|
+
right: Int64.ddWithNoOverflow(right),
|
|
155
|
+
top: Int64.ddWithNoOverflow(top)
|
|
151
156
|
)
|
|
152
157
|
}
|
|
153
158
|
|
|
@@ -180,7 +185,8 @@ internal struct RCTTextViewWireframesBuilder: SessionReplayNodeWireframesBuilder
|
|
|
180
185
|
// Text alignment is top for all RCTTextView and RCTParagraphComponentView components.
|
|
181
186
|
textAlignment: .init(systemTextAlignment: textAlignment, vertical: .top),
|
|
182
187
|
textColor: textColor.cgColor,
|
|
183
|
-
fontOverride: SessionReplayWireframesBuilder.FontOverride(
|
|
188
|
+
fontOverride: SessionReplayWireframesBuilder.FontOverride(
|
|
189
|
+
size: fontSize.isNaN ? RCTTextPropertiesDefaultFontSize : fontSize),
|
|
184
190
|
borderColor: attributes.layerBorderColor,
|
|
185
191
|
borderWidth: attributes.layerBorderWidth,
|
|
186
192
|
backgroundColor: attributes.backgroundColor,
|
|
@@ -63,7 +63,6 @@ let TextAndInputPrivacyLevel = exports.TextAndInputPrivacyLevel = /*#__PURE__*/f
|
|
|
63
63
|
*/
|
|
64
64
|
const DEFAULTS = {
|
|
65
65
|
replaySampleRate: 100,
|
|
66
|
-
defaultPrivacyLevel: SessionReplayPrivacy.MASK,
|
|
67
66
|
customEndpoint: '',
|
|
68
67
|
imagePrivacyLevel: ImagePrivacyLevel.MASK_ALL,
|
|
69
68
|
touchPrivacyLevel: TouchPrivacyLevel.HIDE,
|
|
@@ -92,27 +91,6 @@ class SessionReplayWrapper {
|
|
|
92
91
|
touchPrivacyLevel: configuration.touchPrivacyLevel ?? DEFAULTS.touchPrivacyLevel,
|
|
93
92
|
textAndInputPrivacyLevel: configuration.textAndInputPrivacyLevel ?? DEFAULTS.textAndInputPrivacyLevel
|
|
94
93
|
};
|
|
95
|
-
|
|
96
|
-
// Legacy Default Privacy Level property handling
|
|
97
|
-
if (configuration.defaultPrivacyLevel) {
|
|
98
|
-
switch (configuration.defaultPrivacyLevel) {
|
|
99
|
-
case SessionReplayPrivacy.MASK:
|
|
100
|
-
privacyConfig.imagePrivacyLevel = ImagePrivacyLevel.MASK_ALL;
|
|
101
|
-
privacyConfig.touchPrivacyLevel = TouchPrivacyLevel.HIDE;
|
|
102
|
-
privacyConfig.textAndInputPrivacyLevel = TextAndInputPrivacyLevel.MASK_ALL;
|
|
103
|
-
break;
|
|
104
|
-
case SessionReplayPrivacy.MASK_USER_INPUT:
|
|
105
|
-
privacyConfig.imagePrivacyLevel = ImagePrivacyLevel.MASK_NONE;
|
|
106
|
-
privacyConfig.touchPrivacyLevel = TouchPrivacyLevel.HIDE;
|
|
107
|
-
privacyConfig.textAndInputPrivacyLevel = TextAndInputPrivacyLevel.MASK_ALL_INPUTS;
|
|
108
|
-
break;
|
|
109
|
-
case SessionReplayPrivacy.ALLOW:
|
|
110
|
-
privacyConfig.imagePrivacyLevel = ImagePrivacyLevel.MASK_NONE;
|
|
111
|
-
privacyConfig.touchPrivacyLevel = TouchPrivacyLevel.SHOW;
|
|
112
|
-
privacyConfig.textAndInputPrivacyLevel = TextAndInputPrivacyLevel.MASK_SENSITIVE_INPUTS;
|
|
113
|
-
break;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
94
|
return {
|
|
117
95
|
...baseConfig,
|
|
118
96
|
...privacyConfig
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["SessionReplayPrivacy","exports","ImagePrivacyLevel","TouchPrivacyLevel","TextAndInputPrivacyLevel","DEFAULTS","replaySampleRate","
|
|
1
|
+
{"version":3,"names":["SessionReplayPrivacy","exports","ImagePrivacyLevel","TouchPrivacyLevel","TextAndInputPrivacyLevel","DEFAULTS","replaySampleRate","customEndpoint","imagePrivacyLevel","MASK_ALL","touchPrivacyLevel","HIDE","textAndInputPrivacyLevel","startRecordingImmediately","SessionReplayWrapper","nativeSessionReplay","require","default","buildConfiguration","configuration","baseConfig","undefined","privacyConfig","enable","startRecording","stopRecording","SessionReplay"],"sourceRoot":"../../src","sources":["SessionReplay.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -60,7 +60,6 @@ export let TextAndInputPrivacyLevel = /*#__PURE__*/function (TextAndInputPrivacy
|
|
|
60
60
|
|
|
61
61
|
const DEFAULTS = {
|
|
62
62
|
replaySampleRate: 100,
|
|
63
|
-
defaultPrivacyLevel: SessionReplayPrivacy.MASK,
|
|
64
63
|
customEndpoint: '',
|
|
65
64
|
imagePrivacyLevel: ImagePrivacyLevel.MASK_ALL,
|
|
66
65
|
touchPrivacyLevel: TouchPrivacyLevel.HIDE,
|
|
@@ -89,27 +88,6 @@ export class SessionReplayWrapper {
|
|
|
89
88
|
touchPrivacyLevel: configuration.touchPrivacyLevel ?? DEFAULTS.touchPrivacyLevel,
|
|
90
89
|
textAndInputPrivacyLevel: configuration.textAndInputPrivacyLevel ?? DEFAULTS.textAndInputPrivacyLevel
|
|
91
90
|
};
|
|
92
|
-
|
|
93
|
-
// Legacy Default Privacy Level property handling
|
|
94
|
-
if (configuration.defaultPrivacyLevel) {
|
|
95
|
-
switch (configuration.defaultPrivacyLevel) {
|
|
96
|
-
case SessionReplayPrivacy.MASK:
|
|
97
|
-
privacyConfig.imagePrivacyLevel = ImagePrivacyLevel.MASK_ALL;
|
|
98
|
-
privacyConfig.touchPrivacyLevel = TouchPrivacyLevel.HIDE;
|
|
99
|
-
privacyConfig.textAndInputPrivacyLevel = TextAndInputPrivacyLevel.MASK_ALL;
|
|
100
|
-
break;
|
|
101
|
-
case SessionReplayPrivacy.MASK_USER_INPUT:
|
|
102
|
-
privacyConfig.imagePrivacyLevel = ImagePrivacyLevel.MASK_NONE;
|
|
103
|
-
privacyConfig.touchPrivacyLevel = TouchPrivacyLevel.HIDE;
|
|
104
|
-
privacyConfig.textAndInputPrivacyLevel = TextAndInputPrivacyLevel.MASK_ALL_INPUTS;
|
|
105
|
-
break;
|
|
106
|
-
case SessionReplayPrivacy.ALLOW:
|
|
107
|
-
privacyConfig.imagePrivacyLevel = ImagePrivacyLevel.MASK_NONE;
|
|
108
|
-
privacyConfig.touchPrivacyLevel = TouchPrivacyLevel.SHOW;
|
|
109
|
-
privacyConfig.textAndInputPrivacyLevel = TextAndInputPrivacyLevel.MASK_SENSITIVE_INPUTS;
|
|
110
|
-
break;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
91
|
return {
|
|
114
92
|
...baseConfig,
|
|
115
93
|
...privacyConfig
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["SessionReplayPrivacy","ImagePrivacyLevel","TouchPrivacyLevel","TextAndInputPrivacyLevel","DEFAULTS","replaySampleRate","
|
|
1
|
+
{"version":3,"names":["SessionReplayPrivacy","ImagePrivacyLevel","TouchPrivacyLevel","TextAndInputPrivacyLevel","DEFAULTS","replaySampleRate","customEndpoint","imagePrivacyLevel","MASK_ALL","touchPrivacyLevel","HIDE","textAndInputPrivacyLevel","startRecordingImmediately","SessionReplayWrapper","nativeSessionReplay","require","default","buildConfiguration","configuration","baseConfig","undefined","privacyConfig","enable","startRecording","stopRecording","SessionReplay"],"sourceRoot":"../../src","sources":["SessionReplay.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -78,14 +78,6 @@ export interface SessionReplayConfiguration {
|
|
|
78
78
|
* Default: `true`.
|
|
79
79
|
*/
|
|
80
80
|
startRecordingImmediately?: boolean;
|
|
81
|
-
/**
|
|
82
|
-
* Defines the way sensitive content (e.g. text) should be masked.
|
|
83
|
-
*
|
|
84
|
-
* Default `SessionReplayPrivacy.MASK`.
|
|
85
|
-
* @deprecated Use {@link imagePrivacyLevel}, {@link touchPrivacyLevel} and {@link textAndInputPrivacyLevel} instead.
|
|
86
|
-
* Note: setting this property (`defaultPrivacyLevel`) will override the individual privacy levels.
|
|
87
|
-
*/
|
|
88
|
-
defaultPrivacyLevel?: SessionReplayPrivacy;
|
|
89
81
|
}
|
|
90
82
|
export declare class SessionReplayWrapper {
|
|
91
83
|
private nativeSessionReplay;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionReplay.d.ts","sourceRoot":"","sources":["../../src/SessionReplay.ts"],"names":[],"mappings":"AAQA,oBAAY,oBAAoB;IAC5B,IAAI,SAAS;IACb,KAAK,UAAU;IACf,eAAe,oBAAoB;CACtC;AAED,oBAAY,iBAAiB;IACzB;;;;OAIG;IACH,qBAAqB,0BAA0B;IAC/C;;OAEG;IACH,QAAQ,aAAa;IACrB;;OAEG;IACH,SAAS,cAAc;CAC1B;AAED,oBAAY,iBAAiB;IACzB;;OAEG;IACH,IAAI,SAAS;IACb;;OAEG;IACH,IAAI,SAAS;CAChB;AAED,oBAAY,wBAAwB;IAChC;;OAEG;IACH,qBAAqB,0BAA0B;IAC/C;;OAEG;IACH,eAAe,oBAAoB;IACnC;;OAEG;IACH,QAAQ,aAAa;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACvC;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IAEtC;;OAEG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IAEtC;;OAEG;IACH,wBAAwB,CAAC,EAAE,wBAAwB,CAAC;IAEpD;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"SessionReplay.d.ts","sourceRoot":"","sources":["../../src/SessionReplay.ts"],"names":[],"mappings":"AAQA,oBAAY,oBAAoB;IAC5B,IAAI,SAAS;IACb,KAAK,UAAU;IACf,eAAe,oBAAoB;CACtC;AAED,oBAAY,iBAAiB;IACzB;;;;OAIG;IACH,qBAAqB,0BAA0B;IAC/C;;OAEG;IACH,QAAQ,aAAa;IACrB;;OAEG;IACH,SAAS,cAAc;CAC1B;AAED,oBAAY,iBAAiB;IACzB;;OAEG;IACH,IAAI,SAAS;IACb;;OAEG;IACH,IAAI,SAAS;CAChB;AAED,oBAAY,wBAAwB;IAChC;;OAEG;IACH,qBAAqB,0BAA0B;IAC/C;;OAEG;IACH,eAAe,oBAAoB;IACnC;;OAEG;IACH,QAAQ,aAAa;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACvC;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IAEtC;;OAEG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IAEtC;;OAEG;IACH,wBAAwB,CAAC,EAAE,wBAAwB,CAAC;IAEpD;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACvC;AA0BD,qBAAa,oBAAoB;IAE7B,OAAO,CAAC,mBAAmB,CACd;IAEb,OAAO,CAAC,kBAAkB,CAsCxB;IAEF;;;OAGG;IACH,MAAM,mBAAoB,0BAA0B,KAAG,QAAQ,IAAI,CAAC,CAkBlE;IAEF;;OAEG;IACH,cAAc,QAAO,QAAQ,IAAI,CAAC,CAEhC;IAEF;;OAEG;IACH,aAAa,QAAO,QAAQ,IAAI,CAAC,CAE/B;CACL;AAED,eAAO,MAAM,aAAa,sBAA6B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datadog/mobile-react-native-session-replay",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "A client-side React Native module to enable session replay with Datadog",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"datadog",
|
|
@@ -96,5 +96,5 @@
|
|
|
96
96
|
"dependencies": {
|
|
97
97
|
"chokidar": "^4.0.3"
|
|
98
98
|
},
|
|
99
|
-
"gitHead": "
|
|
99
|
+
"gitHead": "2a8f57a6b7fa68cfa8a03ae202d65ecc64e3e42d"
|
|
100
100
|
}
|
package/src/SessionReplay.ts
CHANGED
|
@@ -95,15 +95,6 @@ export interface SessionReplayConfiguration {
|
|
|
95
95
|
* Default: `true`.
|
|
96
96
|
*/
|
|
97
97
|
startRecordingImmediately?: boolean;
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Defines the way sensitive content (e.g. text) should be masked.
|
|
101
|
-
*
|
|
102
|
-
* Default `SessionReplayPrivacy.MASK`.
|
|
103
|
-
* @deprecated Use {@link imagePrivacyLevel}, {@link touchPrivacyLevel} and {@link textAndInputPrivacyLevel} instead.
|
|
104
|
-
* Note: setting this property (`defaultPrivacyLevel`) will override the individual privacy levels.
|
|
105
|
-
*/
|
|
106
|
-
defaultPrivacyLevel?: SessionReplayPrivacy;
|
|
107
98
|
}
|
|
108
99
|
|
|
109
100
|
type InternalBaseSessionReplayConfiguration = {
|
|
@@ -121,11 +112,8 @@ type InternalPrivacySessionReplayConfiguration = {
|
|
|
121
112
|
type InternalSessionReplayConfiguration = InternalBaseSessionReplayConfiguration &
|
|
122
113
|
InternalPrivacySessionReplayConfiguration;
|
|
123
114
|
|
|
124
|
-
const DEFAULTS: InternalSessionReplayConfiguration
|
|
125
|
-
defaultPrivacyLevel: SessionReplayPrivacy;
|
|
126
|
-
} = {
|
|
115
|
+
const DEFAULTS: InternalSessionReplayConfiguration = {
|
|
127
116
|
replaySampleRate: 100,
|
|
128
|
-
defaultPrivacyLevel: SessionReplayPrivacy.MASK,
|
|
129
117
|
customEndpoint: '',
|
|
130
118
|
imagePrivacyLevel: ImagePrivacyLevel.MASK_ALL,
|
|
131
119
|
touchPrivacyLevel: TouchPrivacyLevel.HIDE,
|
|
@@ -175,33 +163,6 @@ export class SessionReplayWrapper {
|
|
|
175
163
|
DEFAULTS.textAndInputPrivacyLevel
|
|
176
164
|
};
|
|
177
165
|
|
|
178
|
-
// Legacy Default Privacy Level property handling
|
|
179
|
-
if (configuration.defaultPrivacyLevel) {
|
|
180
|
-
switch (configuration.defaultPrivacyLevel) {
|
|
181
|
-
case SessionReplayPrivacy.MASK:
|
|
182
|
-
privacyConfig.imagePrivacyLevel =
|
|
183
|
-
ImagePrivacyLevel.MASK_ALL;
|
|
184
|
-
privacyConfig.touchPrivacyLevel = TouchPrivacyLevel.HIDE;
|
|
185
|
-
privacyConfig.textAndInputPrivacyLevel =
|
|
186
|
-
TextAndInputPrivacyLevel.MASK_ALL;
|
|
187
|
-
break;
|
|
188
|
-
case SessionReplayPrivacy.MASK_USER_INPUT:
|
|
189
|
-
privacyConfig.imagePrivacyLevel =
|
|
190
|
-
ImagePrivacyLevel.MASK_NONE;
|
|
191
|
-
privacyConfig.touchPrivacyLevel = TouchPrivacyLevel.HIDE;
|
|
192
|
-
privacyConfig.textAndInputPrivacyLevel =
|
|
193
|
-
TextAndInputPrivacyLevel.MASK_ALL_INPUTS;
|
|
194
|
-
break;
|
|
195
|
-
case SessionReplayPrivacy.ALLOW:
|
|
196
|
-
privacyConfig.imagePrivacyLevel =
|
|
197
|
-
ImagePrivacyLevel.MASK_NONE;
|
|
198
|
-
privacyConfig.touchPrivacyLevel = TouchPrivacyLevel.SHOW;
|
|
199
|
-
privacyConfig.textAndInputPrivacyLevel =
|
|
200
|
-
TextAndInputPrivacyLevel.MASK_SENSITIVE_INPUTS;
|
|
201
|
-
break;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
166
|
return { ...baseConfig, ...privacyConfig };
|
|
206
167
|
};
|
|
207
168
|
|
|
@@ -9,7 +9,6 @@ import { NativeModules } from 'react-native';
|
|
|
9
9
|
import {
|
|
10
10
|
ImagePrivacyLevel,
|
|
11
11
|
SessionReplay,
|
|
12
|
-
SessionReplayPrivacy,
|
|
13
12
|
TextAndInputPrivacyLevel,
|
|
14
13
|
TouchPrivacyLevel
|
|
15
14
|
} from '../SessionReplay';
|
|
@@ -41,27 +40,9 @@ describe('SessionReplay', () => {
|
|
|
41
40
|
);
|
|
42
41
|
});
|
|
43
42
|
|
|
44
|
-
it('calls native session replay with provided configuration { w
|
|
43
|
+
it('calls native session replay with provided configuration { w custom endpoint }', () => {
|
|
45
44
|
SessionReplay.enable({
|
|
46
45
|
replaySampleRate: 100,
|
|
47
|
-
defaultPrivacyLevel: SessionReplayPrivacy.ALLOW,
|
|
48
|
-
customEndpoint: 'https://session-replay.example.com'
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
expect(NativeModules.DdSessionReplay.enable).toHaveBeenCalledWith(
|
|
52
|
-
100,
|
|
53
|
-
'https://session-replay.example.com',
|
|
54
|
-
'MASK_NONE',
|
|
55
|
-
'SHOW',
|
|
56
|
-
'MASK_SENSITIVE_INPUTS',
|
|
57
|
-
true
|
|
58
|
-
);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('calls native session replay with provided configuration { w defaultPrivacyLevel = MASK }', () => {
|
|
62
|
-
SessionReplay.enable({
|
|
63
|
-
replaySampleRate: 100,
|
|
64
|
-
defaultPrivacyLevel: SessionReplayPrivacy.MASK,
|
|
65
46
|
customEndpoint: 'https://session-replay.example.com'
|
|
66
47
|
});
|
|
67
48
|
|
|
@@ -75,23 +56,6 @@ describe('SessionReplay', () => {
|
|
|
75
56
|
);
|
|
76
57
|
});
|
|
77
58
|
|
|
78
|
-
it('calls native session replay with provided configuration { w defaultPrivacyLevel = MASK_USER_INPUT }', () => {
|
|
79
|
-
SessionReplay.enable({
|
|
80
|
-
replaySampleRate: 100,
|
|
81
|
-
defaultPrivacyLevel: SessionReplayPrivacy.MASK_USER_INPUT,
|
|
82
|
-
customEndpoint: 'https://session-replay.example.com'
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
expect(NativeModules.DdSessionReplay.enable).toHaveBeenCalledWith(
|
|
86
|
-
100,
|
|
87
|
-
'https://session-replay.example.com',
|
|
88
|
-
'MASK_NONE',
|
|
89
|
-
'HIDE',
|
|
90
|
-
'MASK_ALL_INPUTS',
|
|
91
|
-
true
|
|
92
|
-
);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
59
|
it('calls native session replay with provided configuration { w random privacy levels }', () => {
|
|
96
60
|
const TIMES = 20;
|
|
97
61
|
|