@datadog/mobile-react-native-session-replay 2.0.2-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.
Files changed (77) hide show
  1. package/DatadogSDKReactNativeSessionReplay.podspec +41 -0
  2. package/README.md +3 -0
  3. package/android/build.gradle +239 -0
  4. package/android/detekt.yml +572 -0
  5. package/android/gradle.properties +5 -0
  6. package/android/src/main/AndroidManifest.xml +11 -0
  7. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/DatadogSDKReactNativeSessionReplayPackage.kt +46 -0
  8. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/DdSessionReplayImplementation.kt +57 -0
  9. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/NoopTextPropertiesResolver.kt +22 -0
  10. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/ReactNativeSessionReplayExtensionSupport.kt +77 -0
  11. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/ReactTextPropertiesResolver.kt +196 -0
  12. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/SessionReplaySDKWrapper.kt +24 -0
  13. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/SessionReplayWrapper.kt +22 -0
  14. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/ShadowNodeWrapper.kt +70 -0
  15. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/TextPropertiesResolver.kt +20 -0
  16. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/extensions/LongExt.kt +15 -0
  17. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactMaskInputTextMapper.kt +54 -0
  18. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactMaskTextMapper.kt +55 -0
  19. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactTextMapper.kt +54 -0
  20. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactViewGroupMapper.kt +58 -0
  21. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/utils/ColorUtils.kt +22 -0
  22. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/utils/DrawableUtils.kt +35 -0
  23. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/utils/ReactViewBackgroundDrawableUtils.kt +66 -0
  24. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/utils/ReflectionUtils.kt +30 -0
  25. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/utils/TextViewUtils.kt +40 -0
  26. package/android/src/newarch/kotlin/com/datadog/reactnative/sessionreplay/DdSessionReplay.kt +33 -0
  27. package/android/src/oldarch/kotlin/com/datadog/reactnative/sessionreplay/DdSessionReplay.kt +34 -0
  28. package/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/DdSessionReplayImplementationTest.kt +105 -0
  29. package/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/ReactNativeSessionReplayExtensionSupportTest.kt +127 -0
  30. package/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/ReactTextPropertiesResolverTest.kt +271 -0
  31. package/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactViewGroupMapperTest.kt +131 -0
  32. package/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/utils/ColorUtilsTest.kt +42 -0
  33. package/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/utils/DrawableUtilsTest.kt +101 -0
  34. package/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/utils/TextViewUtilsTest.kt +109 -0
  35. package/android/src/test/kotlin/com/datadog/reactnative/tools/unit/GenericAssert.kt +69 -0
  36. package/android/src/test/kotlin/com/datadog/reactnative/tools/unit/MapExt.kt +29 -0
  37. package/android/src/test/kotlin/com/datadog/reactnative/tools/unit/ReflectUtils.kt +266 -0
  38. package/android/src/test/kotlin/com/datadog/reactnative/tools/unit/forge/BaseConfigurator.kt +24 -0
  39. package/android/src/test/kotlin/com/datadog/reactnative/tools/unit/forge/ForgeConfigurator.kt +24 -0
  40. package/android/src/test/kotlin/com/datadog/reactnative/tools/unit/forge/TextWireframeForgeryFactory.kt +64 -0
  41. package/android/src/test/kotlin/com/datadog/reactnative/tools/unit/forge/Throwable.kt +31 -0
  42. package/android/src/test/kotlin/com/datadog/reactnative/tools/unit/forge/ThrowableForgeryFactory.kt +21 -0
  43. package/android/src/test/kotlin/com/datadog/reactnative/tools/unit/forge/WireframeClipForgeryFactory.kt +25 -0
  44. package/android/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker +1 -0
  45. package/ios/DatadogSDKReactNativeSessionReplay.xcodeproj/project.pbxproj +272 -0
  46. package/ios/DatadogSDKReactNativeSessionReplay.xcodeproj/project.xcworkspace/contents.xcworkspacedata +4 -0
  47. package/ios/Sources/DatadogSDKReactNativeSessionReplay.h +8 -0
  48. package/ios/Sources/DdSessionReplay.h +24 -0
  49. package/ios/Sources/DdSessionReplay.mm +53 -0
  50. package/ios/Sources/DdSessionReplayImplementation.swift +70 -0
  51. package/ios/Sources/RCTTextViewRecorder.swift +157 -0
  52. package/lib/commonjs/SessionReplay.js +66 -0
  53. package/lib/commonjs/SessionReplay.js.map +1 -0
  54. package/lib/commonjs/index.js +26 -0
  55. package/lib/commonjs/index.js.map +1 -0
  56. package/lib/commonjs/nativeModulesTypes.js +2 -0
  57. package/lib/commonjs/nativeModulesTypes.js.map +1 -0
  58. package/lib/commonjs/specs/NativeDdSessionReplay.js +20 -0
  59. package/lib/commonjs/specs/NativeDdSessionReplay.js.map +1 -0
  60. package/lib/module/SessionReplay.js +53 -0
  61. package/lib/module/SessionReplay.js.map +1 -0
  62. package/lib/module/index.js +8 -0
  63. package/lib/module/index.js.map +1 -0
  64. package/lib/module/nativeModulesTypes.js +2 -0
  65. package/lib/module/nativeModulesTypes.js.map +1 -0
  66. package/lib/module/specs/NativeDdSessionReplay.js +14 -0
  67. package/lib/module/specs/NativeDdSessionReplay.js.map +1 -0
  68. package/lib/typescript/SessionReplay.d.ts +34 -0
  69. package/lib/typescript/index.d.ts +2 -0
  70. package/lib/typescript/nativeModulesTypes.d.ts +18 -0
  71. package/lib/typescript/specs/NativeDdSessionReplay.d.ts +15 -0
  72. package/package.json +90 -0
  73. package/src/SessionReplay.ts +84 -0
  74. package/src/__tests__/SessionReplay.test.ts +49 -0
  75. package/src/index.ts +13 -0
  76. package/src/nativeModulesTypes.ts +29 -0
  77. package/src/specs/NativeDdSessionReplay.ts +28 -0
@@ -0,0 +1,272 @@
1
+ // !$*UTF8*$!
2
+ {
3
+ archiveVersion = 1;
4
+ classes = {
5
+ };
6
+ objectVersion = 46;
7
+ objects = {
8
+
9
+ /* Begin PBXCopyFilesBuildPhase section */
10
+ 58B511D91A9E6C8500147676 /* CopyFiles */ = {
11
+ isa = PBXCopyFilesBuildPhase;
12
+ buildActionMask = 2147483647;
13
+ dstPath = "include/$(PRODUCT_NAME)";
14
+ dstSubfolderSpec = 16;
15
+ files = (
16
+ );
17
+ runOnlyForDeploymentPostprocessing = 0;
18
+ };
19
+ /* End PBXCopyFilesBuildPhase section */
20
+
21
+ /* Begin PBXFileReference section */
22
+ 134814201AA4EA6300B7C361 /* libDatadogSDKReactNativeSessionReplay.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libDatadogSDKReactNativeSessionReplay.a; sourceTree = BUILT_PRODUCTS_DIR; };
23
+ F625545A26A82D430033052D /* Sources */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Sources; sourceTree = "<group>"; };
24
+ F625545B26A82D430033052D /* Tests */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Tests; sourceTree = "<group>"; };
25
+ /* End PBXFileReference section */
26
+
27
+ /* Begin PBXFrameworksBuildPhase section */
28
+ 58B511D81A9E6C8500147676 /* Frameworks */ = {
29
+ isa = PBXFrameworksBuildPhase;
30
+ buildActionMask = 2147483647;
31
+ files = (
32
+ );
33
+ runOnlyForDeploymentPostprocessing = 0;
34
+ };
35
+ /* End PBXFrameworksBuildPhase section */
36
+
37
+ /* Begin PBXGroup section */
38
+ 134814211AA4EA7D00B7C361 /* Products */ = {
39
+ isa = PBXGroup;
40
+ children = (
41
+ 134814201AA4EA6300B7C361 /* libDatadogSDKReactNativeSessionReplay.a */,
42
+ );
43
+ name = Products;
44
+ sourceTree = "<group>";
45
+ };
46
+ 58B511D21A9E6C8500147676 = {
47
+ isa = PBXGroup;
48
+ children = (
49
+ F625545A26A82D430033052D /* Sources */,
50
+ F625545B26A82D430033052D /* Tests */,
51
+ 134814211AA4EA7D00B7C361 /* Products */,
52
+ );
53
+ sourceTree = "<group>";
54
+ };
55
+ /* End PBXGroup section */
56
+
57
+ /* Begin PBXNativeTarget section */
58
+ 58B511DA1A9E6C8500147676 /* DatadogSDKReactNativeSessionReplay */ = {
59
+ isa = PBXNativeTarget;
60
+ buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "DatadogSDKReactNativeSessionReplay" */;
61
+ buildPhases = (
62
+ 58B511D71A9E6C8500147676 /* Sources */,
63
+ 58B511D81A9E6C8500147676 /* Frameworks */,
64
+ 58B511D91A9E6C8500147676 /* CopyFiles */,
65
+ );
66
+ buildRules = (
67
+ );
68
+ dependencies = (
69
+ );
70
+ name = DatadogSDKReactNativeSessionReplay;
71
+ productName = RCTDataManager;
72
+ productReference = 134814201AA4EA6300B7C361 /* libDatadogSDKReactNativeSessionReplay.a */;
73
+ productType = "com.apple.product-type.library.static";
74
+ };
75
+ /* End PBXNativeTarget section */
76
+
77
+ /* Begin PBXProject section */
78
+ 58B511D31A9E6C8500147676 /* Project object */ = {
79
+ isa = PBXProject;
80
+ attributes = {
81
+ LastUpgradeCheck = 0920;
82
+ ORGANIZATIONNAME = Facebook;
83
+ TargetAttributes = {
84
+ 58B511DA1A9E6C8500147676 = {
85
+ CreatedOnToolsVersion = 6.1.1;
86
+ };
87
+ };
88
+ };
89
+ buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "DatadogSDKReactNativeSessionReplay" */;
90
+ compatibilityVersion = "Xcode 3.2";
91
+ developmentRegion = English;
92
+ hasScannedForEncodings = 0;
93
+ knownRegions = (
94
+ English,
95
+ en,
96
+ );
97
+ mainGroup = 58B511D21A9E6C8500147676;
98
+ productRefGroup = 58B511D21A9E6C8500147676;
99
+ projectDirPath = "";
100
+ projectRoot = "";
101
+ targets = (
102
+ 58B511DA1A9E6C8500147676 /* DatadogSDKReactNativeSessionReplay */,
103
+ );
104
+ };
105
+ /* End PBXProject section */
106
+
107
+ /* Begin PBXSourcesBuildPhase section */
108
+ 58B511D71A9E6C8500147676 /* Sources */ = {
109
+ isa = PBXSourcesBuildPhase;
110
+ buildActionMask = 2147483647;
111
+ files = (
112
+ );
113
+ runOnlyForDeploymentPostprocessing = 0;
114
+ };
115
+ /* End PBXSourcesBuildPhase section */
116
+
117
+ /* Begin XCBuildConfiguration section */
118
+ 58B511ED1A9E6C8500147676 /* Debug */ = {
119
+ isa = XCBuildConfiguration;
120
+ buildSettings = {
121
+ ALWAYS_SEARCH_USER_PATHS = NO;
122
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
123
+ CLANG_CXX_LIBRARY = "libc++";
124
+ CLANG_ENABLE_MODULES = YES;
125
+ CLANG_ENABLE_OBJC_ARC = YES;
126
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
127
+ CLANG_WARN_BOOL_CONVERSION = YES;
128
+ CLANG_WARN_COMMA = YES;
129
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
130
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
131
+ CLANG_WARN_EMPTY_BODY = YES;
132
+ CLANG_WARN_ENUM_CONVERSION = YES;
133
+ CLANG_WARN_INFINITE_RECURSION = YES;
134
+ CLANG_WARN_INT_CONVERSION = YES;
135
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
136
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
137
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
138
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
139
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
140
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
141
+ CLANG_WARN_UNREACHABLE_CODE = YES;
142
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
143
+ COPY_PHASE_STRIP = NO;
144
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
145
+ ENABLE_TESTABILITY = YES;
146
+ GCC_C_LANGUAGE_STANDARD = gnu99;
147
+ GCC_DYNAMIC_NO_PIC = NO;
148
+ GCC_NO_COMMON_BLOCKS = YES;
149
+ GCC_OPTIMIZATION_LEVEL = 0;
150
+ GCC_PREPROCESSOR_DEFINITIONS = (
151
+ "DEBUG=1",
152
+ "$(inherited)",
153
+ );
154
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
155
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
156
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
157
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
158
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
159
+ GCC_WARN_UNUSED_FUNCTION = YES;
160
+ GCC_WARN_UNUSED_VARIABLE = YES;
161
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
162
+ MTL_ENABLE_DEBUG_INFO = YES;
163
+ ONLY_ACTIVE_ARCH = YES;
164
+ SDKROOT = iphoneos;
165
+ };
166
+ name = Debug;
167
+ };
168
+ 58B511EE1A9E6C8500147676 /* Release */ = {
169
+ isa = XCBuildConfiguration;
170
+ buildSettings = {
171
+ ALWAYS_SEARCH_USER_PATHS = NO;
172
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
173
+ CLANG_CXX_LIBRARY = "libc++";
174
+ CLANG_ENABLE_MODULES = YES;
175
+ CLANG_ENABLE_OBJC_ARC = YES;
176
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
177
+ CLANG_WARN_BOOL_CONVERSION = YES;
178
+ CLANG_WARN_COMMA = YES;
179
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
180
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
181
+ CLANG_WARN_EMPTY_BODY = YES;
182
+ CLANG_WARN_ENUM_CONVERSION = YES;
183
+ CLANG_WARN_INFINITE_RECURSION = YES;
184
+ CLANG_WARN_INT_CONVERSION = YES;
185
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
186
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
187
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
188
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
189
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
190
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
191
+ CLANG_WARN_UNREACHABLE_CODE = YES;
192
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
193
+ COPY_PHASE_STRIP = YES;
194
+ ENABLE_NS_ASSERTIONS = NO;
195
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
196
+ GCC_C_LANGUAGE_STANDARD = gnu99;
197
+ GCC_NO_COMMON_BLOCKS = YES;
198
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
199
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
200
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
201
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
202
+ GCC_WARN_UNUSED_FUNCTION = YES;
203
+ GCC_WARN_UNUSED_VARIABLE = YES;
204
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
205
+ MTL_ENABLE_DEBUG_INFO = NO;
206
+ SDKROOT = iphoneos;
207
+ VALIDATE_PRODUCT = YES;
208
+ };
209
+ name = Release;
210
+ };
211
+ 58B511F01A9E6C8500147676 /* Debug */ = {
212
+ isa = XCBuildConfiguration;
213
+ buildSettings = {
214
+ HEADER_SEARCH_PATHS = (
215
+ "$(inherited)",
216
+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
217
+ "$(SRCROOT)/../../../React/**",
218
+ "$(SRCROOT)/../../react-native/React/**",
219
+ );
220
+ LIBRARY_SEARCH_PATHS = "$(inherited)";
221
+ OTHER_LDFLAGS = "-ObjC";
222
+ PRODUCT_NAME = DatadogSDKReactNativeSessionReplay;
223
+ SKIP_INSTALL = YES;
224
+ SWIFT_OBJC_BRIDGING_HEADER = "DatadogSDKReactNativeSessionReplay-Bridging-Header.h";
225
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
226
+ SWIFT_VERSION = 5.0;
227
+ };
228
+ name = Debug;
229
+ };
230
+ 58B511F11A9E6C8500147676 /* Release */ = {
231
+ isa = XCBuildConfiguration;
232
+ buildSettings = {
233
+ HEADER_SEARCH_PATHS = (
234
+ "$(inherited)",
235
+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
236
+ "$(SRCROOT)/../../../React/**",
237
+ "$(SRCROOT)/../../react-native/React/**",
238
+ );
239
+ LIBRARY_SEARCH_PATHS = "$(inherited)";
240
+ OTHER_LDFLAGS = "-ObjC";
241
+ PRODUCT_NAME = DatadogSDKReactNativeSessionReplay;
242
+ SKIP_INSTALL = YES;
243
+ SWIFT_OBJC_BRIDGING_HEADER = "DatadogSDKReactNativeSessionReplay-Bridging-Header.h";
244
+ SWIFT_VERSION = 5.0;
245
+ };
246
+ name = Release;
247
+ };
248
+ /* End XCBuildConfiguration section */
249
+
250
+ /* Begin XCConfigurationList section */
251
+ 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "DatadogSDKReactNativeSessionReplay" */ = {
252
+ isa = XCConfigurationList;
253
+ buildConfigurations = (
254
+ 58B511ED1A9E6C8500147676 /* Debug */,
255
+ 58B511EE1A9E6C8500147676 /* Release */,
256
+ );
257
+ defaultConfigurationIsVisible = 0;
258
+ defaultConfigurationName = Release;
259
+ };
260
+ 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "DatadogSDKReactNativeSessionReplay" */ = {
261
+ isa = XCConfigurationList;
262
+ buildConfigurations = (
263
+ 58B511F01A9E6C8500147676 /* Debug */,
264
+ 58B511F11A9E6C8500147676 /* Release */,
265
+ );
266
+ defaultConfigurationIsVisible = 0;
267
+ defaultConfigurationName = Release;
268
+ };
269
+ /* End XCConfigurationList section */
270
+ };
271
+ rootObject = 58B511D31A9E6C8500147676 /* Project object */;
272
+ }
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Workspace
3
+ version = "1.0">
4
+ </Workspace>
@@ -0,0 +1,8 @@
1
+ /*
2
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
4
+ * Copyright 2016-Present Datadog, Inc.
5
+ */
6
+
7
+ // This file is imported in the auto-generated DatadogSDKReactNative-Swift.h header file.
8
+ // Deleting it could result in iOS builds failing.
@@ -0,0 +1,24 @@
1
+ /*
2
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
4
+ * Copyright 2016-Present Datadog, Inc.
5
+ */
6
+
7
+ #import <Foundation/Foundation.h>
8
+ @class DdSessionReplayImplementation;
9
+
10
+ #ifdef RCT_NEW_ARCH_ENABLED
11
+
12
+ #import <DatadogSDKReactNativeSessionReplay/DatadogSDKReactNativeSessionReplay.h>
13
+ @interface DdSessionReplay: NSObject <NativeDdSessionReplaySpec>
14
+
15
+ #else
16
+
17
+ #import <React/RCTBridgeModule.h>
18
+ @interface DdSessionReplay : NSObject <RCTBridgeModule>
19
+
20
+ #endif
21
+
22
+ @property (nonatomic, strong) DdSessionReplayImplementation* ddSessionReplayImplementation;
23
+
24
+ @end
@@ -0,0 +1,53 @@
1
+ /*
2
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
4
+ * Copyright 2016-Present Datadog, Inc.
5
+ */
6
+ // Import this first to prevent require cycles
7
+ #if __has_include("DatadogSDKReactNativeSessionReplay-Swift.h")
8
+ #import <DatadogSDKReactNativeSessionReplay-Swift.h>
9
+ #else
10
+ #import <DatadogSDKReactNativeSessionReplay/DatadogSDKReactNativeSessionReplay-Swift.h>
11
+ #endif
12
+ #import "DdSessionReplay.h"
13
+
14
+
15
+ @implementation DdSessionReplay
16
+
17
+ @synthesize bridge = _bridge;
18
+ RCT_EXPORT_MODULE()
19
+
20
+ RCT_REMAP_METHOD(enable, withEnableReplaySampleRate:(double)replaySampleRate
21
+ withDefaultPrivacyLevel:(NSString*)defaultPrivacyLevel
22
+ withResolver:(RCTPromiseResolveBlock)resolve
23
+ withRejecter:(RCTPromiseRejectBlock)reject)
24
+ {
25
+ [self enable:replaySampleRate defaultPrivacyLevel:defaultPrivacyLevel resolve:resolve reject:reject];
26
+ }
27
+
28
+ // Thanks to this guard, we won't compile this code when we build for the old architecture.
29
+ #ifdef RCT_NEW_ARCH_ENABLED
30
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
31
+ (const facebook::react::ObjCTurboModule::InitParams &)params
32
+ {
33
+ return std::make_shared<facebook::react::NativeDdSessionReplaySpecJSI>(params);
34
+ }
35
+ #endif
36
+
37
+ - (DdSessionReplayImplementation*)ddSessionReplayImplementation
38
+ {
39
+ if (_ddSessionReplayImplementation == nil) {
40
+ _ddSessionReplayImplementation = [[DdSessionReplayImplementation alloc] initWithBridge:_bridge];
41
+ }
42
+ return _ddSessionReplayImplementation;
43
+ }
44
+
45
+ + (BOOL)requiresMainQueueSetup {
46
+ return NO;
47
+ }
48
+
49
+ - (void)enable:(double)replaySampleRate defaultPrivacyLevel:(NSString *)defaultPrivacyLevel resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
50
+ [self.ddSessionReplayImplementation enableWithReplaySampleRate:replaySampleRate defaultPrivacyLevel:defaultPrivacyLevel resolve:resolve reject:reject];
51
+ }
52
+
53
+ @end
@@ -0,0 +1,70 @@
1
+ /*
2
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
4
+ * Copyright 2016-Present Datadog, Inc.
5
+ */
6
+
7
+ import Foundation
8
+ @_spi(Internal) import DatadogSessionReplay
9
+ import DatadogInternal
10
+ import React
11
+
12
+ @objc
13
+ public class DdSessionReplayImplementation: NSObject {
14
+ private lazy var sessionReplay: SessionReplayProtocol = sessionReplayProvider()
15
+ private let sessionReplayProvider: () -> SessionReplayProtocol
16
+ private let uiManager: RCTUIManager
17
+
18
+ internal init(sessionReplayProvider: @escaping () -> SessionReplayProtocol, uiManager: RCTUIManager) {
19
+ self.sessionReplayProvider = sessionReplayProvider
20
+ self.uiManager = uiManager
21
+ }
22
+
23
+ @objc
24
+ public convenience init(bridge: RCTBridge) {
25
+ self.init(
26
+ sessionReplayProvider: { NativeSessionReplay() },
27
+ uiManager: bridge.uiManager
28
+ )
29
+ }
30
+
31
+ @objc
32
+ public func enable(replaySampleRate: Double, defaultPrivacyLevel: String, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
33
+ var sessionReplayConfiguration = SessionReplay.Configuration(
34
+ replaySampleRate: Float(replaySampleRate),
35
+ defaultPrivacyLevel: buildPrivacyLevel(privacyLevel: defaultPrivacyLevel as NSString)
36
+ )
37
+
38
+ sessionReplayConfiguration.setAdditionalNodeRecorders([RCTTextViewRecorder(uiManager: self.uiManager)])
39
+
40
+ sessionReplay.enable(
41
+ with: sessionReplayConfiguration
42
+ )
43
+ resolve(nil)
44
+ }
45
+
46
+ func buildPrivacyLevel(privacyLevel: NSString) -> SessionReplay.Configuration.PrivacyLevel {
47
+ switch privacyLevel.lowercased {
48
+ case "mask":
49
+ return .mask
50
+ case "mask_user_input":
51
+ return .maskUserInput
52
+ case "allow":
53
+ return .allow
54
+ default:
55
+ return .mask
56
+ }
57
+ }
58
+ }
59
+
60
+ internal protocol SessionReplayProtocol {
61
+ func enable(
62
+ with configuration: SessionReplay.Configuration
63
+ )
64
+ }
65
+
66
+ internal class NativeSessionReplay: SessionReplayProtocol {
67
+ func enable(with configuration: DatadogSessionReplay.SessionReplay.Configuration) {
68
+ SessionReplay.enable(with: configuration)
69
+ }
70
+ }
@@ -0,0 +1,157 @@
1
+ /*
2
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
4
+ * Copyright 2019-Present Datadog, Inc.
5
+ */
6
+
7
+ import UIKit
8
+ @_spi(Internal)
9
+ import DatadogSessionReplay
10
+ import React
11
+
12
+ internal class RCTTextViewRecorder: SessionReplayNodeRecorder {
13
+ internal var textObfuscator: (SessionReplayViewTreeRecordingContext) -> SessionReplayTextObfuscating = { context in
14
+ return context.recorder.privacy.staticTextObfuscator
15
+ }
16
+
17
+ internal var identifier = UUID()
18
+
19
+ internal let uiManager: RCTUIManager
20
+
21
+ internal init(uiManager: RCTUIManager) {
22
+ self.uiManager = uiManager
23
+ }
24
+
25
+ internal func extractTextFromSubViews(
26
+ subviews: [RCTShadowView]?
27
+ ) -> String? {
28
+ if let subviews = subviews {
29
+ return subviews.compactMap { subview in
30
+ if let sub = subview as? RCTRawTextShadowView {
31
+ return sub.text
32
+ }
33
+ if let sub = subview as? RCTVirtualTextShadowView {
34
+ // We recursively get all subviews for nested Text components
35
+ return extractTextFromSubViews(subviews: sub.reactSubviews())
36
+ }
37
+ return nil
38
+ }.joined()
39
+ }
40
+ return nil
41
+ }
42
+
43
+ public func semantics(
44
+ of view: UIView,
45
+ with attributes: SessionReplayViewAttributes,
46
+ in context: SessionReplayViewTreeRecordingContext
47
+ ) -> SessionReplayNodeSemantics? {
48
+ guard let textView = view as? RCTTextView else {
49
+ return nil
50
+ }
51
+
52
+ var shadowView: RCTTextShadowView? = nil
53
+ let tag = textView.reactTag
54
+
55
+ RCTGetUIManagerQueue().sync {
56
+ shadowView = uiManager.shadowView(forReactTag: tag) as? RCTTextShadowView
57
+ }
58
+
59
+ if let shadow = shadowView {
60
+ // TODO: RUM-2173 check performance is ok
61
+ let text = extractTextFromSubViews(
62
+ subviews: shadow.reactSubviews()
63
+ )
64
+
65
+ let builder = RCTTextViewWireframesBuilder(
66
+ wireframeID: context.ids.nodeID(view: textView, nodeRecorder: self),
67
+ attributes: attributes,
68
+ text: text,
69
+ textAlignment: shadow.textAttributes.alignment,
70
+ textColor: shadow.textAttributes.foregroundColor?.cgColor,
71
+ textObfuscator: textObfuscator(context),
72
+ fontSize: shadow.textAttributes.fontSize,
73
+ contentRect: shadow.contentFrame
74
+ )
75
+ let node = SessionReplayNode(viewAttributes: attributes, wireframesBuilder: builder)
76
+ return SessionReplaySpecificElement(subtreeStrategy: .ignore, nodes: [node])
77
+ }
78
+ return SessionReplayInvisibleElement.constant
79
+ }
80
+ }
81
+
82
+ // Black color. This is the default for RN: https://github.com/facebook/react-native/blob/a5ee029cd02a636136058d82919480eeeb700067/packages/react-native/Libraries/Text/RCTTextAttributes.mm#L250
83
+ let DEFAULT_COLOR = UIColor.black.cgColor
84
+
85
+ // Default font size for RN: https://github.com/facebook/react-native/blob/16dff523b0a16d7fa9b651062c386885c2f48a6b/packages/react-native/React/Views/RCTFont.mm#L396
86
+ let DEFAULT_FONT_SIZE = CGFloat(14)
87
+
88
+ internal struct RCTTextViewWireframesBuilder: SessionReplayNodeWireframesBuilder {
89
+ let wireframeID: WireframeID
90
+ let attributes: SessionReplayViewAttributes
91
+ let text: String?
92
+ var textAlignment: NSTextAlignment
93
+ let textColor: CGColor?
94
+ let textObfuscator: SessionReplayTextObfuscating
95
+ let fontSize: CGFloat
96
+ let contentRect: CGRect
97
+
98
+ public var wireframeRect: CGRect {
99
+ attributes.frame
100
+ }
101
+
102
+ // Clipping should be 0 to avoid the text from overflowing when the
103
+ // numberOfLines prop is used.
104
+ // To apply clip(0 0 0 0) we set a negative clipping (which has no effect).
105
+ // TODO: RUM-2354 remove this when clip(0 0 0 0) is applied
106
+ private var clip: SRContentClip {
107
+ let top = -1.0
108
+ let left = 0.0
109
+ let bottom = 0.0
110
+ let right = 0.0
111
+ return SRContentClip.create(
112
+ bottom: Int64(withNoOverflow: bottom),
113
+ left: Int64(withNoOverflow: left),
114
+ right: Int64(withNoOverflow: right),
115
+ top: Int64(withNoOverflow: top)
116
+ )
117
+ }
118
+
119
+ private var relativeIntersectedRect: CGRect {
120
+ return CGRect(
121
+ x: attributes.frame.origin.x,
122
+ y: attributes.frame.origin.y,
123
+ width: max(contentRect.width, attributes.frame.width),
124
+ height: max(contentRect.height, attributes.frame.height)
125
+ )
126
+ }
127
+
128
+ private var textFrame: CGRect {
129
+ return CGRect(
130
+ x: attributes.frame.origin.x + contentRect.origin.x,
131
+ y: attributes.frame.origin.y + contentRect.origin.y,
132
+ width: contentRect.width,
133
+ height: contentRect.height
134
+ )
135
+ }
136
+
137
+ public func buildWireframes(with builder: SessionReplayWireframesBuilder) -> [SRWireframe] {
138
+ return [
139
+ builder.createTextWireframe(
140
+ id: wireframeID,
141
+ frame: relativeIntersectedRect,
142
+ text: textObfuscator.mask(text: text ?? ""),
143
+ textFrame: textFrame,
144
+ // Text alignment is top for all RCTTextView components.
145
+ textAlignment: .init(systemTextAlignment: textAlignment, vertical: .top),
146
+ clip: clip,
147
+ textColor: textColor ?? DEFAULT_COLOR,
148
+ fontOverride: SessionReplayWireframesBuilder.FontOverride(size: fontSize.isNaN ? DEFAULT_FONT_SIZE : fontSize),
149
+ borderColor: attributes.layerBorderColor,
150
+ borderWidth: attributes.layerBorderWidth,
151
+ backgroundColor: attributes.backgroundColor,
152
+ cornerRadius: attributes.layerCornerRadius,
153
+ opacity: attributes.alpha
154
+ )
155
+ ]
156
+ }
157
+ }
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.SessionReplay = exports.SessionReplayWrapper = exports.SessionReplayPrivacy = void 0;
7
+
8
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
9
+
10
+ /*
11
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
12
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
13
+ * Copyright 2016-Present Datadog, Inc.
14
+ */
15
+ let SessionReplayPrivacy;
16
+ /**
17
+ * The Session Replay configuration object.
18
+ */
19
+
20
+ exports.SessionReplayPrivacy = SessionReplayPrivacy;
21
+
22
+ (function (SessionReplayPrivacy) {
23
+ SessionReplayPrivacy["MASK"] = "MASK";
24
+ SessionReplayPrivacy["ALLOW"] = "ALLOW";
25
+ SessionReplayPrivacy["MASK_USER_INPUT"] = "MASK_USER_INPUT";
26
+ })(SessionReplayPrivacy || (exports.SessionReplayPrivacy = SessionReplayPrivacy = {}));
27
+
28
+ const DEFAULTS = {
29
+ replaySampleRate: 0,
30
+ defaultPrivacyLevel: SessionReplayPrivacy.MASK
31
+ };
32
+
33
+ class SessionReplayWrapper {
34
+ constructor() {
35
+ _defineProperty(this, "nativeSessionReplay", require('./specs/NativeDdSessionReplay').default);
36
+
37
+ _defineProperty(this, "buildConfiguration", configuration => {
38
+ if (!configuration) {
39
+ return DEFAULTS;
40
+ }
41
+
42
+ const {
43
+ replaySampleRate,
44
+ defaultPrivacyLevel
45
+ } = configuration;
46
+ return {
47
+ replaySampleRate: replaySampleRate !== undefined ? replaySampleRate : DEFAULTS.replaySampleRate,
48
+ defaultPrivacyLevel: defaultPrivacyLevel !== undefined ? defaultPrivacyLevel : DEFAULTS.defaultPrivacyLevel
49
+ };
50
+ });
51
+
52
+ _defineProperty(this, "enable", configuration => {
53
+ const {
54
+ replaySampleRate,
55
+ defaultPrivacyLevel
56
+ } = this.buildConfiguration(configuration);
57
+ return this.nativeSessionReplay.enable(replaySampleRate, defaultPrivacyLevel);
58
+ });
59
+ }
60
+
61
+ }
62
+
63
+ exports.SessionReplayWrapper = SessionReplayWrapper;
64
+ const SessionReplay = new SessionReplayWrapper();
65
+ exports.SessionReplay = SessionReplay;
66
+ //# sourceMappingURL=SessionReplay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["SessionReplay.ts"],"names":["SessionReplayPrivacy","DEFAULTS","replaySampleRate","defaultPrivacyLevel","MASK","SessionReplayWrapper","require","default","configuration","undefined","buildConfiguration","nativeSessionReplay","enable","SessionReplay"],"mappings":";;;;;;;;;AAAA;AACA;AACA;AACA;AACA;IAIYA,oB;AAMZ;AACA;AACA;;;;WARYA,oB;AAAAA,EAAAA,oB;AAAAA,EAAAA,oB;AAAAA,EAAAA,oB;GAAAA,oB,oCAAAA,oB;;AA0BZ,MAAMC,QAAQ,GAAG;AACbC,EAAAA,gBAAgB,EAAE,CADL;AAEbC,EAAAA,mBAAmB,EAAEH,oBAAoB,CAACI;AAF7B,CAAjB;;AAKO,MAAMC,oBAAN,CAA2B;AAAA;AAAA,iDAEyBC,OAAO,CAAC,+BAAD,CAAP,CAClDC,OAHyB;;AAAA,gDAM1BC,aADyB,IAKxB;AACD,UAAI,CAACA,aAAL,EAAoB;AAChB,eAAOP,QAAP;AACH;;AACD,YAAM;AAAEC,QAAAA,gBAAF;AAAoBC,QAAAA;AAApB,UAA4CK,aAAlD;AACA,aAAO;AACHN,QAAAA,gBAAgB,EACZA,gBAAgB,KAAKO,SAArB,GACMP,gBADN,GAEMD,QAAQ,CAACC,gBAJhB;AAKHC,QAAAA,mBAAmB,EACfA,mBAAmB,KAAKM,SAAxB,GACMN,mBADN,GAEMF,QAAQ,CAACE;AARhB,OAAP;AAUH,KAzB6B;;AAAA,oCA+BpBK,aAAD,IAA+D;AACpE,YAAM;AACFN,QAAAA,gBADE;AAEFC,QAAAA;AAFE,UAGF,KAAKO,kBAAL,CAAwBF,aAAxB,CAHJ;AAKA,aAAO,KAAKG,mBAAL,CAAyBC,MAAzB,CACHV,gBADG,EAEHC,mBAFG,CAAP;AAIH,KAzC6B;AAAA;;AAAA;;;AA4C3B,MAAMU,aAAa,GAAG,IAAIR,oBAAJ,EAAtB","sourcesContent":["/*\n * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.\n * This product includes software developed at Datadog (https://www.datadoghq.com/).\n * Copyright 2016-Present Datadog, Inc.\n */\n\nimport type { NativeSessionReplayType } from './nativeModulesTypes';\n\nexport enum SessionReplayPrivacy {\n MASK = 'MASK',\n ALLOW = 'ALLOW',\n MASK_USER_INPUT = 'MASK_USER_INPUT'\n}\n\n/**\n * The Session Replay configuration object.\n */\nexport interface SessionReplayConfiguration {\n /**\n * The sampling rate for Session Replay.\n * It is applied in addition to the RUM session sample rate.\n * Range `0`-`100`.\n *\n * Default value is `20`.\n */\n replaySampleRate?: number;\n /**\n * Defines the way sensitive content (e.g. text) should be masked.\n *\n * Default `SessionReplayPrivacy.MASK`.\n */\n defaultPrivacyLevel?: SessionReplayPrivacy;\n}\n\nconst DEFAULTS = {\n replaySampleRate: 0,\n defaultPrivacyLevel: SessionReplayPrivacy.MASK\n};\n\nexport class SessionReplayWrapper {\n // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires\n private nativeSessionReplay: NativeSessionReplayType = require('./specs/NativeDdSessionReplay')\n .default;\n\n private buildConfiguration = (\n configuration?: SessionReplayConfiguration\n ): {\n replaySampleRate: number;\n defaultPrivacyLevel: SessionReplayPrivacy;\n } => {\n if (!configuration) {\n return DEFAULTS;\n }\n const { replaySampleRate, defaultPrivacyLevel } = configuration;\n return {\n replaySampleRate:\n replaySampleRate !== undefined\n ? replaySampleRate\n : DEFAULTS.replaySampleRate,\n defaultPrivacyLevel:\n defaultPrivacyLevel !== undefined\n ? defaultPrivacyLevel\n : DEFAULTS.defaultPrivacyLevel\n };\n };\n\n /**\n * Enable session replay and start recording session.\n * @param configuration: The session replay configuration.\n */\n enable = (configuration?: SessionReplayConfiguration): Promise<void> => {\n const {\n replaySampleRate,\n defaultPrivacyLevel\n } = this.buildConfiguration(configuration);\n\n return this.nativeSessionReplay.enable(\n replaySampleRate,\n defaultPrivacyLevel\n );\n };\n}\n\nexport const SessionReplay = new SessionReplayWrapper();\n"]}