@datadog/mobile-react-native-session-replay 2.4.2-alpha.0 → 2.4.4-alpha.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 +6 -6
- package/android/gradle.properties +1 -1
- package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/DdSessionReplayImplementation.kt +26 -11
- package/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/DdSessionReplayImplementationTest.kt +54 -5
- package/ios/Sources/RCTTextViewRecorder.swift +1 -1
- package/package.json +1 -1
|
@@ -19,7 +19,7 @@ Pod::Spec.new do |s|
|
|
|
19
19
|
s.dependency "React-Core"
|
|
20
20
|
|
|
21
21
|
# /!\ Remember to keep the version in sync with DatadogSDKReactNative.podspec
|
|
22
|
-
s.dependency 'DatadogSessionReplay', '~> 2.
|
|
22
|
+
s.dependency 'DatadogSessionReplay', '~> 2.18.0'
|
|
23
23
|
s.dependency 'DatadogSDKReactNative'
|
|
24
24
|
|
|
25
25
|
s.test_spec 'Tests' do |test_spec|
|
package/android/build.gradle
CHANGED
|
@@ -12,7 +12,7 @@ buildscript {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
dependencies {
|
|
15
|
-
classpath 'com.android.tools.build:gradle:7.
|
|
15
|
+
classpath 'com.android.tools.build:gradle:7.3.1'
|
|
16
16
|
// noinspection DifferentKotlinGradleVersion
|
|
17
17
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
18
18
|
classpath "org.jlleitschuh.gradle:ktlint-gradle:11.5.1"
|
|
@@ -96,15 +96,19 @@ def getExtOrIntegerDefault(name) {
|
|
|
96
96
|
android {
|
|
97
97
|
compileSdkVersion getExtOrIntegerDefault('compileSdkVersion')
|
|
98
98
|
buildToolsVersion getExtOrDefault('buildToolsVersion')
|
|
99
|
+
|
|
99
100
|
def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
|
|
101
|
+
|
|
100
102
|
if (agpVersion.tokenize('.')[0].toInteger() >= 7) {
|
|
101
103
|
namespace = "com.datadog.reactnative.sessionreplay"
|
|
102
104
|
}
|
|
105
|
+
|
|
103
106
|
if (agpVersion.tokenize('.')[0].toInteger() >= 8) {
|
|
104
107
|
buildFeatures {
|
|
105
108
|
buildConfig = true
|
|
106
109
|
}
|
|
107
110
|
}
|
|
111
|
+
|
|
108
112
|
if (agpVersion.tokenize('.')[0].toInteger() < 8) {
|
|
109
113
|
compileOptions {
|
|
110
114
|
sourceCompatibility JavaVersion.VERSION_11
|
|
@@ -150,10 +154,6 @@ android {
|
|
|
150
154
|
lintOptions {
|
|
151
155
|
disable 'GradleCompatible'
|
|
152
156
|
}
|
|
153
|
-
compileOptions {
|
|
154
|
-
sourceCompatibility JavaVersion.VERSION_11
|
|
155
|
-
targetCompatibility JavaVersion.VERSION_11
|
|
156
|
-
}
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
repositories {
|
|
@@ -188,7 +188,7 @@ dependencies {
|
|
|
188
188
|
api "com.facebook.react:react-android:$reactNativeVersion"
|
|
189
189
|
}
|
|
190
190
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
191
|
-
implementation "com.datadoghq:dd-sdk-android-session-replay:2.
|
|
191
|
+
implementation "com.datadoghq:dd-sdk-android-session-replay:2.14.0"
|
|
192
192
|
implementation project(path: ':datadog_mobile-react-native')
|
|
193
193
|
|
|
194
194
|
testImplementation "org.junit.platform:junit-platform-launcher:1.6.2"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
DatadogSDKReactNativeSessionReplay_kotlinVersion=1.
|
|
1
|
+
DatadogSDKReactNativeSessionReplay_kotlinVersion=1.8.21
|
|
2
2
|
DatadogSDKReactNativeSessionReplay_compileSdkVersion=33
|
|
3
3
|
DatadogSDKReactNativeSessionReplay_buildToolsVersion=33.0.0
|
|
4
4
|
DatadogSDKReactNativeSessionReplay_targetSdkVersion=33
|
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
|
|
7
7
|
package com.datadog.reactnative.sessionreplay
|
|
8
8
|
|
|
9
|
-
import com.datadog.android.Datadog
|
|
10
9
|
import com.datadog.android.api.feature.FeatureSdkCore
|
|
10
|
+
import com.datadog.android.sessionreplay.ImagePrivacy
|
|
11
11
|
import com.datadog.android.sessionreplay.SessionReplayConfiguration
|
|
12
|
-
import com.datadog.android.sessionreplay.
|
|
12
|
+
import com.datadog.android.sessionreplay.TextAndInputPrivacy
|
|
13
|
+
import com.datadog.android.sessionreplay.TouchPrivacy
|
|
13
14
|
import com.datadog.reactnative.DatadogSDKWrapperStorage
|
|
14
15
|
import com.facebook.react.bridge.Promise
|
|
15
16
|
import com.facebook.react.bridge.ReactContext
|
|
@@ -34,7 +35,7 @@ class DdSessionReplayImplementation(
|
|
|
34
35
|
val sdkCore = DatadogSDKWrapperStorage.getSdkCore() as FeatureSdkCore
|
|
35
36
|
val logger = sdkCore.internalLogger
|
|
36
37
|
val configuration = SessionReplayConfiguration.Builder(replaySampleRate.toFloat())
|
|
37
|
-
.
|
|
38
|
+
.configurePrivacy(defaultPrivacyLevel)
|
|
38
39
|
.addExtensionSupport(ReactNativeSessionReplayExtensionSupport(reactContext, logger))
|
|
39
40
|
|
|
40
41
|
if (customEndpoint != "") {
|
|
@@ -45,16 +46,30 @@ class DdSessionReplayImplementation(
|
|
|
45
46
|
promise.resolve(null)
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
@Deprecated("Privacy should be set with separate properties mapped to " +
|
|
50
|
+
"`setImagePrivacy`, `setTouchPrivacy`, `setTextAndInputPrivacy`, but they are" +
|
|
51
|
+
" currently unavailable.")
|
|
52
|
+
private fun SessionReplayConfiguration.Builder.configurePrivacy(
|
|
53
|
+
defaultPrivacyLevel: String
|
|
54
|
+
): SessionReplayConfiguration.Builder {
|
|
55
|
+
when (defaultPrivacyLevel.lowercase(Locale.US)) {
|
|
56
|
+
"mask" -> {
|
|
57
|
+
this.setTextAndInputPrivacy(TextAndInputPrivacy.MASK_ALL)
|
|
58
|
+
this.setImagePrivacy(ImagePrivacy.MASK_ALL)
|
|
59
|
+
this.setTouchPrivacy(TouchPrivacy.HIDE)
|
|
60
|
+
}
|
|
61
|
+
"mask_user_input" -> {
|
|
62
|
+
this.setTextAndInputPrivacy(TextAndInputPrivacy.MASK_ALL_INPUTS)
|
|
63
|
+
this.setImagePrivacy(ImagePrivacy.MASK_NONE)
|
|
64
|
+
this.setTouchPrivacy(TouchPrivacy.HIDE)
|
|
65
|
+
}
|
|
66
|
+
"allow" -> {
|
|
67
|
+
this.setTextAndInputPrivacy(TextAndInputPrivacy.MASK_SENSITIVE_INPUTS)
|
|
68
|
+
this.setImagePrivacy(ImagePrivacy.MASK_NONE)
|
|
69
|
+
this.setTouchPrivacy(TouchPrivacy.SHOW)
|
|
55
70
|
}
|
|
56
71
|
}
|
|
57
|
-
|
|
72
|
+
return this
|
|
58
73
|
}
|
|
59
74
|
|
|
60
75
|
companion object {
|
|
@@ -6,17 +6,20 @@
|
|
|
6
6
|
|
|
7
7
|
package com.datadog.reactnative.sessionreplay
|
|
8
8
|
|
|
9
|
+
import com.datadog.android.sessionreplay.ImagePrivacy
|
|
9
10
|
import com.datadog.android.sessionreplay.SessionReplayConfiguration
|
|
10
11
|
import com.datadog.android.sessionreplay.SessionReplayPrivacy
|
|
12
|
+
import com.datadog.android.sessionreplay.TextAndInputPrivacy
|
|
13
|
+
import com.datadog.android.sessionreplay.TouchPrivacy
|
|
11
14
|
import com.datadog.tools.unit.GenericAssert.Companion.assertThat
|
|
12
15
|
import com.facebook.react.bridge.NativeModule
|
|
13
16
|
import com.facebook.react.bridge.Promise
|
|
14
17
|
import com.facebook.react.bridge.ReactContext
|
|
15
18
|
import com.facebook.react.uimanager.UIManagerModule
|
|
16
19
|
import fr.xgouchet.elmyr.annotation.DoubleForgery
|
|
17
|
-
import fr.xgouchet.elmyr.annotation.Forgery
|
|
18
20
|
import fr.xgouchet.elmyr.annotation.StringForgery
|
|
19
21
|
import fr.xgouchet.elmyr.junit5.ForgeExtension
|
|
22
|
+
import java.util.Locale
|
|
20
23
|
import org.junit.jupiter.api.AfterEach
|
|
21
24
|
import org.junit.jupiter.api.BeforeEach
|
|
22
25
|
import org.junit.jupiter.api.Test
|
|
@@ -67,10 +70,33 @@ internal class DdSessionReplayImplementationTest {
|
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
@Test
|
|
70
|
-
fun `M enable session replay W
|
|
73
|
+
fun `M enable session replay W privacy = ALLOW`(
|
|
71
74
|
@DoubleForgery(min = 0.0, max = 100.0) replaySampleRate: Double,
|
|
72
|
-
@Forgery privacy: SessionReplayPrivacy,
|
|
73
75
|
@StringForgery(regex = ".+") customEndpoint: String
|
|
76
|
+
) {
|
|
77
|
+
testSessionReplayEnable("ALLOW", replaySampleRate, customEndpoint)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@Test
|
|
81
|
+
fun `M enable session replay W privacy = MASK`(
|
|
82
|
+
@DoubleForgery(min = 0.0, max = 100.0) replaySampleRate: Double,
|
|
83
|
+
@StringForgery(regex = ".+") customEndpoint: String
|
|
84
|
+
) {
|
|
85
|
+
testSessionReplayEnable("MASK", replaySampleRate, customEndpoint)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@Test
|
|
89
|
+
fun `M enable session replay W privacy = MASK_USER_INPUT`(
|
|
90
|
+
@DoubleForgery(min = 0.0, max = 100.0) replaySampleRate: Double,
|
|
91
|
+
@StringForgery(regex = ".+") customEndpoint: String
|
|
92
|
+
) {
|
|
93
|
+
testSessionReplayEnable("MASK_USER_INPUT", replaySampleRate, customEndpoint)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private fun testSessionReplayEnable(
|
|
97
|
+
privacy: String,
|
|
98
|
+
replaySampleRate: Double,
|
|
99
|
+
customEndpoint: String
|
|
74
100
|
) {
|
|
75
101
|
// Given
|
|
76
102
|
val sessionReplayConfigCaptor = argumentCaptor<SessionReplayConfiguration>()
|
|
@@ -78,7 +104,7 @@ internal class DdSessionReplayImplementationTest {
|
|
|
78
104
|
// When
|
|
79
105
|
testedSessionReplay.enable(
|
|
80
106
|
replaySampleRate,
|
|
81
|
-
privacy
|
|
107
|
+
privacy,
|
|
82
108
|
customEndpoint,
|
|
83
109
|
mockPromise
|
|
84
110
|
)
|
|
@@ -87,8 +113,31 @@ internal class DdSessionReplayImplementationTest {
|
|
|
87
113
|
verify(mockSessionReplay).enable(sessionReplayConfigCaptor.capture(), any())
|
|
88
114
|
assertThat(sessionReplayConfigCaptor.firstValue)
|
|
89
115
|
.hasFieldEqualTo("sampleRate", replaySampleRate.toFloat())
|
|
90
|
-
.hasFieldEqualTo("privacy", privacy)
|
|
91
116
|
.hasFieldEqualTo("customEndpointUrl", customEndpoint)
|
|
117
|
+
|
|
118
|
+
when (privacy.lowercase(Locale.US)) {
|
|
119
|
+
"mask_user_input" -> {
|
|
120
|
+
assertThat(sessionReplayConfigCaptor.firstValue)
|
|
121
|
+
.hasFieldEqualTo("textAndInputPrivacy", TextAndInputPrivacy.MASK_ALL_INPUTS)
|
|
122
|
+
.hasFieldEqualTo("imagePrivacy", ImagePrivacy.MASK_NONE)
|
|
123
|
+
.hasFieldEqualTo("touchPrivacy", TouchPrivacy.HIDE)
|
|
124
|
+
}
|
|
125
|
+
"allow" -> {
|
|
126
|
+
assertThat(sessionReplayConfigCaptor.firstValue)
|
|
127
|
+
.hasFieldEqualTo(
|
|
128
|
+
"textAndInputPrivacy",
|
|
129
|
+
TextAndInputPrivacy.MASK_SENSITIVE_INPUTS
|
|
130
|
+
)
|
|
131
|
+
.hasFieldEqualTo("imagePrivacy", ImagePrivacy.MASK_NONE)
|
|
132
|
+
.hasFieldEqualTo("touchPrivacy", TouchPrivacy.SHOW)
|
|
133
|
+
}
|
|
134
|
+
else -> {
|
|
135
|
+
assertThat(sessionReplayConfigCaptor.firstValue)
|
|
136
|
+
.hasFieldEqualTo("textAndInputPrivacy", TextAndInputPrivacy.MASK_ALL)
|
|
137
|
+
.hasFieldEqualTo("imagePrivacy", ImagePrivacy.MASK_ALL)
|
|
138
|
+
.hasFieldEqualTo("touchPrivacy", TouchPrivacy.HIDE)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
92
141
|
}
|
|
93
142
|
|
|
94
143
|
@Test
|
|
@@ -11,7 +11,7 @@ import React
|
|
|
11
11
|
|
|
12
12
|
internal class RCTTextViewRecorder: SessionReplayNodeRecorder {
|
|
13
13
|
internal var textObfuscator: (SessionReplayViewTreeRecordingContext) -> SessionReplayTextObfuscating = { context in
|
|
14
|
-
return context.recorder.
|
|
14
|
+
return context.recorder.textAndInputPrivacy.staticTextObfuscator
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
internal var identifier = UUID()
|
package/package.json
CHANGED