@multiplayer-app/session-recorder-react-native 1.0.1-beta.2 → 1.0.1-beta.4

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 (465) hide show
  1. package/LICENSE +1 -2
  2. package/README.md +216 -155
  3. package/SessionRecorderNative.podspec +9 -14
  4. package/android/build.gradle +21 -41
  5. package/android/gradle.properties +4 -4
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/java/com/multiplayer/sessionrecordernative/SessionRecorderNativeConfig.kt +52 -0
  8. package/android/src/main/java/com/multiplayer/sessionrecordernative/SessionRecorderNativeModule.kt +860 -0
  9. package/android/src/main/java/com/multiplayer/sessionrecordernative/SessionRecorderNativeModuleSpec.kt +51 -0
  10. package/android/src/main/java/com/multiplayer/sessionrecordernative/SessionRecorderNativePackage.kt +33 -0
  11. package/android/src/main/java/com/multiplayer/sessionrecordernative/model/TargetInfo.kt +9 -0
  12. package/android/src/main/java/com/multiplayer/sessionrecordernative/util/ViewUtils.kt +72 -0
  13. package/android/src/main/java/com/xxx/XxxModule.kt +23 -0
  14. package/ios/GestureTargetFinder.swift +50 -0
  15. package/ios/SessionRecorderNative.podspec +4 -2
  16. package/ios/SessionRecorderNative.swift +10 -1
  17. package/ios/SessionRecorderNativeSpec.swift +55 -0
  18. package/ios/Xxx.h +5 -0
  19. package/ios/Xxx.mm +21 -0
  20. package/lib/module/components/ScreenRecorderView/ScreenRecorderView.js +23 -0
  21. package/lib/module/components/ScreenRecorderView/ScreenRecorderView.js.map +1 -0
  22. package/lib/module/components/ScreenRecorderView/index.js +4 -0
  23. package/lib/module/components/ScreenRecorderView/index.js.map +1 -0
  24. package/lib/module/components/SessionRecorderWidget/ErrorBanner.js +64 -0
  25. package/lib/module/components/SessionRecorderWidget/ErrorBanner.js.map +1 -0
  26. package/lib/module/components/SessionRecorderWidget/FinalPopover.js +74 -0
  27. package/lib/module/components/SessionRecorderWidget/FinalPopover.js.map +1 -0
  28. package/lib/module/components/SessionRecorderWidget/FloatingButton.js +191 -0
  29. package/lib/module/components/SessionRecorderWidget/FloatingButton.js.map +1 -0
  30. package/lib/module/components/SessionRecorderWidget/InitialPopover.js +138 -0
  31. package/lib/module/components/SessionRecorderWidget/InitialPopover.js.map +1 -0
  32. package/lib/module/components/SessionRecorderWidget/ModalContainer.js +177 -0
  33. package/lib/module/components/SessionRecorderWidget/ModalContainer.js.map +1 -0
  34. package/lib/module/components/SessionRecorderWidget/ModalHeader.js +27 -0
  35. package/lib/module/components/SessionRecorderWidget/ModalHeader.js.map +1 -0
  36. package/lib/module/components/SessionRecorderWidget/SessionRecorderWidget.js +133 -0
  37. package/lib/module/components/SessionRecorderWidget/SessionRecorderWidget.js.map +1 -0
  38. package/lib/module/components/SessionRecorderWidget/icons.js +93 -0
  39. package/lib/module/components/SessionRecorderWidget/icons.js.map +1 -0
  40. package/lib/module/components/SessionRecorderWidget/index.js +5 -0
  41. package/lib/module/components/SessionRecorderWidget/index.js.map +1 -0
  42. package/lib/module/components/SessionRecorderWidget/styles.js +173 -0
  43. package/lib/module/components/SessionRecorderWidget/styles.js.map +1 -0
  44. package/lib/module/components/index.js +5 -0
  45. package/lib/module/components/index.js.map +1 -0
  46. package/lib/module/config/constants.js +42 -0
  47. package/lib/module/config/constants.js.map +1 -0
  48. package/lib/module/config/defaults.js +81 -0
  49. package/lib/module/config/defaults.js.map +1 -0
  50. package/lib/module/config/index.js +9 -0
  51. package/lib/module/config/index.js.map +1 -0
  52. package/lib/module/config/masking.js +35 -0
  53. package/lib/module/config/masking.js.map +1 -0
  54. package/lib/module/config/session-recorder.js +44 -0
  55. package/lib/module/config/session-recorder.js.map +1 -0
  56. package/lib/module/config/validators.js +28 -0
  57. package/lib/module/config/validators.js.map +1 -0
  58. package/lib/module/config/widget.js +35 -0
  59. package/lib/module/config/widget.js.map +1 -0
  60. package/lib/module/context/SessionRecorderContext.js +93 -0
  61. package/lib/module/context/SessionRecorderContext.js.map +1 -0
  62. package/lib/module/context/SessionRecorderStore.js +12 -0
  63. package/lib/module/context/SessionRecorderStore.js.map +1 -0
  64. package/lib/module/context/useSessionRecorderStore.js +20 -0
  65. package/lib/module/context/useSessionRecorderStore.js.map +1 -0
  66. package/lib/module/context/useStoreSelector.js +27 -0
  67. package/lib/module/context/useStoreSelector.js.map +1 -0
  68. package/lib/module/index.js +13 -0
  69. package/lib/module/index.js.map +1 -0
  70. package/lib/module/native/SessionRecorderNative.js +74 -0
  71. package/lib/module/native/SessionRecorderNative.js.map +1 -0
  72. package/lib/module/native/index.js +4 -0
  73. package/lib/module/native/index.js.map +1 -0
  74. package/lib/module/otel/helpers.js +218 -0
  75. package/lib/module/otel/helpers.js.map +1 -0
  76. package/lib/module/otel/index.js +95 -0
  77. package/lib/module/otel/index.js.map +1 -0
  78. package/lib/module/otel/instrumentations/index.js +102 -0
  79. package/lib/module/otel/instrumentations/index.js.map +1 -0
  80. package/lib/module/package.json +1 -0
  81. package/lib/module/patch/index.js +4 -0
  82. package/lib/module/patch/index.js.map +1 -0
  83. package/lib/module/patch/xhr.js +116 -0
  84. package/lib/module/patch/xhr.js.map +1 -0
  85. package/lib/module/recorder/eventExporter.js +130 -0
  86. package/lib/module/recorder/eventExporter.js.map +1 -0
  87. package/lib/module/recorder/gestureRecorder.js +641 -0
  88. package/lib/module/recorder/gestureRecorder.js.map +1 -0
  89. package/lib/module/recorder/index.js +168 -0
  90. package/lib/module/recorder/index.js.map +1 -0
  91. package/lib/module/recorder/navigationTracker.js +228 -0
  92. package/lib/module/recorder/navigationTracker.js.map +1 -0
  93. package/lib/module/recorder/screenRecorder.js +495 -0
  94. package/lib/module/recorder/screenRecorder.js.map +1 -0
  95. package/lib/module/services/api.service.js +149 -0
  96. package/lib/module/services/api.service.js.map +1 -0
  97. package/lib/module/services/network.service.js +178 -0
  98. package/lib/module/services/network.service.js.map +1 -0
  99. package/lib/module/services/screenMaskingService.js +107 -0
  100. package/lib/module/services/screenMaskingService.js.map +1 -0
  101. package/lib/module/services/storage.service.js +179 -0
  102. package/lib/module/services/storage.service.js.map +1 -0
  103. package/lib/module/session-recorder.js +541 -0
  104. package/lib/module/session-recorder.js.map +1 -0
  105. package/lib/module/types/configs.js +4 -0
  106. package/lib/module/types/configs.js.map +1 -0
  107. package/lib/module/types/expo-constants.d.js +2 -0
  108. package/lib/module/types/expo-constants.d.js.map +1 -0
  109. package/lib/module/types/index.js +11 -0
  110. package/lib/module/types/index.js.map +1 -0
  111. package/lib/module/types/session-recorder.js +68 -0
  112. package/lib/module/types/session-recorder.js.map +1 -0
  113. package/lib/module/types/session.js +9 -0
  114. package/lib/module/types/session.js.map +1 -0
  115. package/lib/module/utils/app-metadata.js +28 -0
  116. package/lib/module/utils/app-metadata.js.map +1 -0
  117. package/lib/module/utils/constants.optional.expo.js +6 -0
  118. package/lib/module/utils/constants.optional.expo.js.map +1 -0
  119. package/lib/module/utils/constants.optional.js +8 -0
  120. package/lib/module/utils/constants.optional.js.map +1 -0
  121. package/lib/module/utils/createStore.js +27 -0
  122. package/lib/module/utils/createStore.js.map +1 -0
  123. package/lib/module/utils/index.js +11 -0
  124. package/lib/module/utils/index.js.map +1 -0
  125. package/lib/module/utils/logger.js +193 -0
  126. package/lib/module/utils/logger.js.map +1 -0
  127. package/lib/module/utils/platform.js +340 -0
  128. package/lib/module/utils/platform.js.map +1 -0
  129. package/lib/module/utils/request-utils.js +58 -0
  130. package/lib/module/utils/request-utils.js.map +1 -0
  131. package/lib/module/utils/rrweb-events.js +276 -0
  132. package/lib/module/utils/rrweb-events.js.map +1 -0
  133. package/lib/module/utils/session.js +21 -0
  134. package/lib/module/utils/session.js.map +1 -0
  135. package/lib/module/utils/shallowEqual.js +17 -0
  136. package/lib/module/utils/shallowEqual.js.map +1 -0
  137. package/lib/module/utils/time.js +17 -0
  138. package/lib/module/utils/time.js.map +1 -0
  139. package/lib/module/utils/type-utils.js +69 -0
  140. package/lib/module/utils/type-utils.js.map +1 -0
  141. package/lib/module/version.js +4 -0
  142. package/lib/module/version.js.map +1 -0
  143. package/lib/typescript/package.json +1 -0
  144. package/lib/typescript/src/components/ScreenRecorderView/ScreenRecorderView.d.ts +6 -0
  145. package/lib/typescript/src/components/ScreenRecorderView/ScreenRecorderView.d.ts.map +1 -0
  146. package/lib/typescript/src/components/ScreenRecorderView/index.d.ts +2 -0
  147. package/lib/typescript/src/components/ScreenRecorderView/index.d.ts.map +1 -0
  148. package/{dist → lib/typescript/src}/components/SessionRecorderWidget/ErrorBanner.d.ts +1 -0
  149. package/lib/typescript/src/components/SessionRecorderWidget/ErrorBanner.d.ts.map +1 -0
  150. package/{dist → lib/typescript/src}/components/SessionRecorderWidget/FinalPopover.d.ts +2 -1
  151. package/lib/typescript/src/components/SessionRecorderWidget/FinalPopover.d.ts.map +1 -0
  152. package/{dist → lib/typescript/src}/components/SessionRecorderWidget/FloatingButton.d.ts +1 -0
  153. package/lib/typescript/src/components/SessionRecorderWidget/FloatingButton.d.ts.map +1 -0
  154. package/{dist → lib/typescript/src}/components/SessionRecorderWidget/InitialPopover.d.ts +2 -1
  155. package/lib/typescript/src/components/SessionRecorderWidget/InitialPopover.d.ts.map +1 -0
  156. package/{dist → lib/typescript/src}/components/SessionRecorderWidget/ModalContainer.d.ts +1 -0
  157. package/lib/typescript/src/components/SessionRecorderWidget/ModalContainer.d.ts.map +1 -0
  158. package/{dist → lib/typescript/src}/components/SessionRecorderWidget/ModalHeader.d.ts +1 -0
  159. package/lib/typescript/src/components/SessionRecorderWidget/ModalHeader.d.ts.map +1 -0
  160. package/{dist → lib/typescript/src}/components/SessionRecorderWidget/SessionRecorderWidget.d.ts +1 -0
  161. package/lib/typescript/src/components/SessionRecorderWidget/SessionRecorderWidget.d.ts.map +1 -0
  162. package/{dist → lib/typescript/src}/components/SessionRecorderWidget/icons.d.ts +1 -0
  163. package/lib/typescript/src/components/SessionRecorderWidget/icons.d.ts.map +1 -0
  164. package/lib/typescript/src/components/SessionRecorderWidget/index.d.ts +3 -0
  165. package/lib/typescript/src/components/SessionRecorderWidget/index.d.ts.map +1 -0
  166. package/{dist → lib/typescript/src}/components/SessionRecorderWidget/styles.d.ts +4 -3
  167. package/lib/typescript/src/components/SessionRecorderWidget/styles.d.ts.map +1 -0
  168. package/{dist → lib/typescript/src}/components/index.d.ts +1 -0
  169. package/lib/typescript/src/components/index.d.ts.map +1 -0
  170. package/{dist → lib/typescript/src}/config/constants.d.ts +1 -0
  171. package/lib/typescript/src/config/constants.d.ts.map +1 -0
  172. package/{dist → lib/typescript/src}/config/defaults.d.ts +2 -1
  173. package/lib/typescript/src/config/defaults.d.ts.map +1 -0
  174. package/{dist → lib/typescript/src}/config/index.d.ts +1 -0
  175. package/lib/typescript/src/config/index.d.ts.map +1 -0
  176. package/lib/typescript/src/config/masking.d.ts +3 -0
  177. package/lib/typescript/src/config/masking.d.ts.map +1 -0
  178. package/lib/typescript/src/config/session-recorder.d.ts +3 -0
  179. package/lib/typescript/src/config/session-recorder.d.ts.map +1 -0
  180. package/{dist → lib/typescript/src}/config/validators.d.ts +1 -0
  181. package/lib/typescript/src/config/validators.d.ts.map +1 -0
  182. package/{dist → lib/typescript/src}/config/widget.d.ts +2 -1
  183. package/lib/typescript/src/config/widget.d.ts.map +1 -0
  184. package/{dist → lib/typescript/src}/context/SessionRecorderContext.d.ts +3 -2
  185. package/lib/typescript/src/context/SessionRecorderContext.d.ts.map +1 -0
  186. package/{dist → lib/typescript/src}/context/SessionRecorderStore.d.ts +2 -1
  187. package/lib/typescript/src/context/SessionRecorderStore.d.ts.map +1 -0
  188. package/{dist → lib/typescript/src}/context/useSessionRecorderStore.d.ts +2 -1
  189. package/lib/typescript/src/context/useSessionRecorderStore.d.ts.map +1 -0
  190. package/{dist → lib/typescript/src}/context/useStoreSelector.d.ts +2 -1
  191. package/lib/typescript/src/context/useStoreSelector.d.ts.map +1 -0
  192. package/{dist → lib/typescript/src}/index.d.ts +1 -0
  193. package/lib/typescript/src/index.d.ts.map +1 -0
  194. package/{dist → lib/typescript/src}/native/SessionRecorderNative.d.ts +21 -3
  195. package/lib/typescript/src/native/SessionRecorderNative.d.ts.map +1 -0
  196. package/{dist → lib/typescript/src}/native/index.d.ts +1 -0
  197. package/lib/typescript/src/native/index.d.ts.map +1 -0
  198. package/{dist → lib/typescript/src}/otel/helpers.d.ts +3 -2
  199. package/lib/typescript/src/otel/helpers.d.ts.map +1 -0
  200. package/{dist → lib/typescript/src}/otel/index.d.ts +2 -2
  201. package/lib/typescript/src/otel/index.d.ts.map +1 -0
  202. package/{dist → lib/typescript/src}/otel/instrumentations/index.d.ts +2 -1
  203. package/lib/typescript/src/otel/instrumentations/index.d.ts.map +1 -0
  204. package/lib/typescript/src/patch/index.d.ts +2 -0
  205. package/lib/typescript/src/patch/index.d.ts.map +1 -0
  206. package/{dist → lib/typescript/src}/patch/xhr.d.ts +1 -0
  207. package/lib/typescript/src/patch/xhr.d.ts.map +1 -0
  208. package/{dist → lib/typescript/src}/recorder/eventExporter.d.ts +2 -1
  209. package/lib/typescript/src/recorder/eventExporter.d.ts.map +1 -0
  210. package/{dist → lib/typescript/src}/recorder/gestureRecorder.d.ts +3 -2
  211. package/lib/typescript/src/recorder/gestureRecorder.d.ts.map +1 -0
  212. package/{dist → lib/typescript/src}/recorder/index.d.ts +3 -2
  213. package/lib/typescript/src/recorder/index.d.ts.map +1 -0
  214. package/{dist → lib/typescript/src}/recorder/navigationTracker.d.ts +2 -1
  215. package/lib/typescript/src/recorder/navigationTracker.d.ts.map +1 -0
  216. package/{dist → lib/typescript/src}/recorder/screenRecorder.d.ts +4 -4
  217. package/lib/typescript/src/recorder/screenRecorder.d.ts.map +1 -0
  218. package/{dist → lib/typescript/src}/services/api.service.d.ts +2 -1
  219. package/lib/typescript/src/services/api.service.d.ts.map +1 -0
  220. package/{dist → lib/typescript/src}/services/network.service.d.ts +1 -0
  221. package/lib/typescript/src/services/network.service.d.ts.map +1 -0
  222. package/{dist → lib/typescript/src}/services/screenMaskingService.d.ts +2 -1
  223. package/lib/typescript/src/services/screenMaskingService.d.ts.map +1 -0
  224. package/{dist → lib/typescript/src}/services/storage.service.d.ts +2 -1
  225. package/lib/typescript/src/services/storage.service.d.ts.map +1 -0
  226. package/{dist → lib/typescript/src}/session-recorder.d.ts +3 -2
  227. package/lib/typescript/src/session-recorder.d.ts.map +1 -0
  228. package/{dist → lib/typescript/src}/types/configs.d.ts +3 -2
  229. package/lib/typescript/src/types/configs.d.ts.map +1 -0
  230. package/{dist → lib/typescript/src}/types/index.d.ts +1 -0
  231. package/lib/typescript/src/types/index.d.ts.map +1 -0
  232. package/{dist → lib/typescript/src}/types/session-recorder.d.ts +3 -2
  233. package/lib/typescript/src/types/session-recorder.d.ts.map +1 -0
  234. package/{dist → lib/typescript/src}/types/session.d.ts +1 -0
  235. package/lib/typescript/src/types/session.d.ts.map +1 -0
  236. package/{dist → lib/typescript/src}/utils/app-metadata.d.ts +1 -0
  237. package/lib/typescript/src/utils/app-metadata.d.ts.map +1 -0
  238. package/{dist → lib/typescript/src}/utils/constants.optional.d.ts +1 -0
  239. package/lib/typescript/src/utils/constants.optional.d.ts.map +1 -0
  240. package/{dist → lib/typescript/src}/utils/constants.optional.expo.d.ts +1 -0
  241. package/lib/typescript/src/utils/constants.optional.expo.d.ts.map +1 -0
  242. package/{dist → lib/typescript/src}/utils/createStore.d.ts +1 -0
  243. package/lib/typescript/src/utils/createStore.d.ts.map +1 -0
  244. package/{dist → lib/typescript/src}/utils/index.d.ts +1 -0
  245. package/lib/typescript/src/utils/index.d.ts.map +1 -0
  246. package/{dist → lib/typescript/src}/utils/logger.d.ts +1 -0
  247. package/lib/typescript/src/utils/logger.d.ts.map +1 -0
  248. package/{dist → lib/typescript/src}/utils/platform.d.ts +2 -1
  249. package/lib/typescript/src/utils/platform.d.ts.map +1 -0
  250. package/{dist → lib/typescript/src}/utils/request-utils.d.ts +1 -0
  251. package/lib/typescript/src/utils/request-utils.d.ts.map +1 -0
  252. package/{dist → lib/typescript/src}/utils/rrweb-events.d.ts +2 -1
  253. package/lib/typescript/src/utils/rrweb-events.d.ts.map +1 -0
  254. package/{dist → lib/typescript/src}/utils/session.d.ts +1 -0
  255. package/lib/typescript/src/utils/session.d.ts.map +1 -0
  256. package/{dist → lib/typescript/src}/utils/shallowEqual.d.ts +1 -0
  257. package/lib/typescript/src/utils/shallowEqual.d.ts.map +1 -0
  258. package/{dist → lib/typescript/src}/utils/time.d.ts +1 -0
  259. package/lib/typescript/src/utils/time.d.ts.map +1 -0
  260. package/{dist → lib/typescript/src}/utils/type-utils.d.ts +1 -0
  261. package/lib/typescript/src/utils/type-utils.d.ts.map +1 -0
  262. package/lib/typescript/src/version.d.ts +2 -0
  263. package/lib/typescript/src/version.d.ts.map +1 -0
  264. package/package.json +140 -39
  265. package/src/components/ScreenRecorderView/ScreenRecorderView.tsx +20 -0
  266. package/src/components/SessionRecorderWidget/ErrorBanner.tsx +58 -0
  267. package/src/components/SessionRecorderWidget/FinalPopover.tsx +96 -0
  268. package/src/components/SessionRecorderWidget/FloatingButton.tsx +176 -0
  269. package/src/components/SessionRecorderWidget/InitialPopover.tsx +167 -0
  270. package/src/components/SessionRecorderWidget/ModalContainer.tsx +189 -0
  271. package/src/components/SessionRecorderWidget/ModalHeader.tsx +24 -0
  272. package/src/components/SessionRecorderWidget/SessionRecorderWidget.tsx +136 -0
  273. package/src/components/SessionRecorderWidget/icons.tsx +52 -0
  274. package/{dist/components/SessionRecorderWidget/index.d.ts → src/components/SessionRecorderWidget/index.ts} +1 -0
  275. package/src/components/SessionRecorderWidget/styles.ts +169 -0
  276. package/src/components/index.ts +2 -0
  277. package/src/config/constants.ts +68 -0
  278. package/src/config/defaults.ts +101 -0
  279. package/src/config/index.ts +6 -0
  280. package/src/config/masking.ts +34 -0
  281. package/src/config/session-recorder.ts +59 -0
  282. package/src/config/validators.ts +31 -0
  283. package/src/config/widget.ts +38 -0
  284. package/src/context/SessionRecorderContext.tsx +138 -0
  285. package/src/context/SessionRecorderStore.ts +21 -0
  286. package/src/context/useSessionRecorderStore.ts +27 -0
  287. package/src/context/useStoreSelector.ts +34 -0
  288. package/src/index.ts +10 -0
  289. package/src/native/SessionRecorderNative.ts +164 -0
  290. package/src/native/index.ts +1 -0
  291. package/src/otel/helpers.ts +274 -0
  292. package/src/otel/index.ts +135 -0
  293. package/src/otel/instrumentations/index.ts +115 -0
  294. package/src/patch/index.ts +1 -0
  295. package/src/patch/xhr.ts +149 -0
  296. package/src/recorder/eventExporter.ts +155 -0
  297. package/src/recorder/gestureRecorder.ts +681 -0
  298. package/src/recorder/index.ts +190 -0
  299. package/src/recorder/navigationTracker.ts +245 -0
  300. package/src/recorder/screenRecorder.ts +549 -0
  301. package/src/services/api.service.ts +215 -0
  302. package/src/services/network.service.ts +182 -0
  303. package/src/services/screenMaskingService.ts +122 -0
  304. package/src/services/storage.service.ts +219 -0
  305. package/src/session-recorder.ts +591 -0
  306. package/src/types/configs.ts +96 -0
  307. package/src/types/expo-constants.d.ts +7 -0
  308. package/src/types/index.ts +29 -0
  309. package/src/types/session-recorder.ts +386 -0
  310. package/src/types/session.ts +65 -0
  311. package/src/utils/app-metadata.ts +31 -0
  312. package/src/utils/constants.optional.expo.ts +5 -0
  313. package/src/utils/constants.optional.ts +16 -0
  314. package/src/utils/createStore.ts +29 -0
  315. package/src/utils/index.ts +8 -0
  316. package/src/utils/logger.ts +216 -0
  317. package/src/utils/platform.ts +370 -0
  318. package/src/utils/request-utils.ts +61 -0
  319. package/src/utils/rrweb-events.ts +316 -0
  320. package/src/utils/session.ts +19 -0
  321. package/src/utils/shallowEqual.ts +14 -0
  322. package/src/utils/time.ts +17 -0
  323. package/src/utils/type-utils.ts +75 -0
  324. package/src/version.ts +1 -0
  325. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  326. package/android/gradle/wrapper/gradle-wrapper.properties +0 -7
  327. package/android/gradlew +0 -249
  328. package/android/gradlew.bat +0 -92
  329. package/copy-react-native-dist.sh +0 -56
  330. package/dist/components/ScreenRecorderView/ScreenRecorderView.d.ts +0 -5
  331. package/dist/components/ScreenRecorderView/ScreenRecorderView.js +0 -1
  332. package/dist/components/ScreenRecorderView/ScreenRecorderView.js.map +0 -1
  333. package/dist/components/ScreenRecorderView/index.js +0 -1
  334. package/dist/components/ScreenRecorderView/index.js.map +0 -1
  335. package/dist/components/SessionRecorderWidget/ErrorBanner.js +0 -1
  336. package/dist/components/SessionRecorderWidget/ErrorBanner.js.map +0 -1
  337. package/dist/components/SessionRecorderWidget/FinalPopover.js +0 -1
  338. package/dist/components/SessionRecorderWidget/FinalPopover.js.map +0 -1
  339. package/dist/components/SessionRecorderWidget/FloatingButton.js +0 -1
  340. package/dist/components/SessionRecorderWidget/FloatingButton.js.map +0 -1
  341. package/dist/components/SessionRecorderWidget/InitialPopover.js +0 -1
  342. package/dist/components/SessionRecorderWidget/InitialPopover.js.map +0 -1
  343. package/dist/components/SessionRecorderWidget/ModalContainer.js +0 -1
  344. package/dist/components/SessionRecorderWidget/ModalContainer.js.map +0 -1
  345. package/dist/components/SessionRecorderWidget/ModalHeader.js +0 -1
  346. package/dist/components/SessionRecorderWidget/ModalHeader.js.map +0 -1
  347. package/dist/components/SessionRecorderWidget/SessionRecorderWidget.js +0 -1
  348. package/dist/components/SessionRecorderWidget/SessionRecorderWidget.js.map +0 -1
  349. package/dist/components/SessionRecorderWidget/icons.js +0 -1
  350. package/dist/components/SessionRecorderWidget/icons.js.map +0 -1
  351. package/dist/components/SessionRecorderWidget/index.js +0 -1
  352. package/dist/components/SessionRecorderWidget/index.js.map +0 -1
  353. package/dist/components/SessionRecorderWidget/styles.js +0 -1
  354. package/dist/components/SessionRecorderWidget/styles.js.map +0 -1
  355. package/dist/components/index.js +0 -1
  356. package/dist/components/index.js.map +0 -1
  357. package/dist/config/constants.js +0 -1
  358. package/dist/config/constants.js.map +0 -1
  359. package/dist/config/defaults.js +0 -1
  360. package/dist/config/defaults.js.map +0 -1
  361. package/dist/config/index.js +0 -1
  362. package/dist/config/index.js.map +0 -1
  363. package/dist/config/masking.d.ts +0 -2
  364. package/dist/config/masking.js +0 -1
  365. package/dist/config/masking.js.map +0 -1
  366. package/dist/config/session-recorder.d.ts +0 -2
  367. package/dist/config/session-recorder.js +0 -1
  368. package/dist/config/session-recorder.js.map +0 -1
  369. package/dist/config/validators.js +0 -1
  370. package/dist/config/validators.js.map +0 -1
  371. package/dist/config/widget.js +0 -1
  372. package/dist/config/widget.js.map +0 -1
  373. package/dist/context/SessionRecorderContext.js +0 -1
  374. package/dist/context/SessionRecorderContext.js.map +0 -1
  375. package/dist/context/SessionRecorderStore.js +0 -1
  376. package/dist/context/SessionRecorderStore.js.map +0 -1
  377. package/dist/context/useSessionRecorderStore.js +0 -1
  378. package/dist/context/useSessionRecorderStore.js.map +0 -1
  379. package/dist/context/useStoreSelector.js +0 -1
  380. package/dist/context/useStoreSelector.js.map +0 -1
  381. package/dist/index.js +0 -1
  382. package/dist/index.js.map +0 -1
  383. package/dist/native/GestureRecorderNative.d.ts +0 -57
  384. package/dist/native/GestureRecorderNative.js +0 -1
  385. package/dist/native/GestureRecorderNative.js.map +0 -1
  386. package/dist/native/GestureRecorderNativeTurboSpec.d.ts +0 -31
  387. package/dist/native/GestureRecorderNativeTurboSpec.js +0 -1
  388. package/dist/native/GestureRecorderNativeTurboSpec.js.map +0 -1
  389. package/dist/native/SessionRecorderNative.js +0 -1
  390. package/dist/native/SessionRecorderNative.js.map +0 -1
  391. package/dist/native/SessionRecorderNativeTurboSpec.d.ts +0 -17
  392. package/dist/native/SessionRecorderNativeTurboSpec.js +0 -1
  393. package/dist/native/SessionRecorderNativeTurboSpec.js.map +0 -1
  394. package/dist/native/index.js +0 -1
  395. package/dist/native/index.js.map +0 -1
  396. package/dist/otel/helpers.js +0 -1
  397. package/dist/otel/helpers.js.map +0 -1
  398. package/dist/otel/index.js +0 -1
  399. package/dist/otel/index.js.map +0 -1
  400. package/dist/otel/instrumentations/index.js +0 -1
  401. package/dist/otel/instrumentations/index.js.map +0 -1
  402. package/dist/patch/index.d.ts +0 -1
  403. package/dist/patch/index.js +0 -1
  404. package/dist/patch/index.js.map +0 -1
  405. package/dist/patch/xhr.js +0 -1
  406. package/dist/patch/xhr.js.map +0 -1
  407. package/dist/recorder/eventExporter.js +0 -1
  408. package/dist/recorder/eventExporter.js.map +0 -1
  409. package/dist/recorder/gestureRecorder.js +0 -1
  410. package/dist/recorder/gestureRecorder.js.map +0 -1
  411. package/dist/recorder/index.js +0 -1
  412. package/dist/recorder/index.js.map +0 -1
  413. package/dist/recorder/navigationTracker.js +0 -1
  414. package/dist/recorder/navigationTracker.js.map +0 -1
  415. package/dist/recorder/screenRecorder.js +0 -1
  416. package/dist/recorder/screenRecorder.js.map +0 -1
  417. package/dist/services/api.service.js +0 -1
  418. package/dist/services/api.service.js.map +0 -1
  419. package/dist/services/network.service.js +0 -1
  420. package/dist/services/network.service.js.map +0 -1
  421. package/dist/services/screenMaskingService.js +0 -1
  422. package/dist/services/screenMaskingService.js.map +0 -1
  423. package/dist/services/storage.service.js +0 -1
  424. package/dist/services/storage.service.js.map +0 -1
  425. package/dist/session-recorder.js +0 -1
  426. package/dist/session-recorder.js.map +0 -1
  427. package/dist/types/configs.js +0 -1
  428. package/dist/types/configs.js.map +0 -1
  429. package/dist/types/index.js +0 -1
  430. package/dist/types/index.js.map +0 -1
  431. package/dist/types/session-recorder.js +0 -1
  432. package/dist/types/session-recorder.js.map +0 -1
  433. package/dist/types/session.js +0 -1
  434. package/dist/types/session.js.map +0 -1
  435. package/dist/utils/app-metadata.js +0 -1
  436. package/dist/utils/app-metadata.js.map +0 -1
  437. package/dist/utils/constants.optional.expo.js +0 -1
  438. package/dist/utils/constants.optional.expo.js.map +0 -1
  439. package/dist/utils/constants.optional.js +0 -1
  440. package/dist/utils/constants.optional.js.map +0 -1
  441. package/dist/utils/createStore.js +0 -1
  442. package/dist/utils/createStore.js.map +0 -1
  443. package/dist/utils/index.js +0 -1
  444. package/dist/utils/index.js.map +0 -1
  445. package/dist/utils/logger.js +0 -1
  446. package/dist/utils/logger.js.map +0 -1
  447. package/dist/utils/platform.js +0 -1
  448. package/dist/utils/platform.js.map +0 -1
  449. package/dist/utils/request-utils.js +0 -1
  450. package/dist/utils/request-utils.js.map +0 -1
  451. package/dist/utils/rrweb-events.js +0 -1
  452. package/dist/utils/rrweb-events.js.map +0 -1
  453. package/dist/utils/session.js +0 -1
  454. package/dist/utils/session.js.map +0 -1
  455. package/dist/utils/shallowEqual.js +0 -1
  456. package/dist/utils/shallowEqual.js.map +0 -1
  457. package/dist/utils/time.js +0 -1
  458. package/dist/utils/time.js.map +0 -1
  459. package/dist/utils/type-utils.js +0 -1
  460. package/dist/utils/type-utils.js.map +0 -1
  461. package/dist/version.d.ts +0 -1
  462. package/dist/version.js +0 -1
  463. package/dist/version.js.map +0 -1
  464. package/docs/AUTO_METADATA_DETECTION.md +0 -108
  465. /package/{dist/components/ScreenRecorderView/index.d.ts → src/components/ScreenRecorderView/index.ts} +0 -0
@@ -0,0 +1,138 @@
1
+ import React, {
2
+ createContext,
3
+ useContext,
4
+ useEffect,
5
+ useCallback,
6
+ type PropsWithChildren,
7
+ } from 'react';
8
+ import { type SessionRecorderOptions, SessionState } from '../types';
9
+ import sessionRecorder from '../session-recorder';
10
+ import { ScreenRecorderView } from '../components/ScreenRecorderView';
11
+ import SessionRecorderWidget from '../components/SessionRecorderWidget';
12
+ import { SessionType } from '@multiplayer-app/session-recorder-common';
13
+ import {
14
+ sessionRecorderStore,
15
+ type SessionRecorderState,
16
+ } from './SessionRecorderStore';
17
+ import { useStoreSelector } from './useStoreSelector';
18
+
19
+ interface SessionRecorderContextType {
20
+ instance: typeof sessionRecorder;
21
+ openWidgetModal: () => void;
22
+ closeWidgetModal: () => void;
23
+ startSession: (sessionType?: SessionType) => Promise<void>;
24
+ stopSession: (comment?: string) => Promise<void>;
25
+ pauseSession: () => Promise<void>;
26
+ resumeSession: () => Promise<void>;
27
+ cancelSession: () => Promise<void>;
28
+ saveSession: () => Promise<void>;
29
+ }
30
+
31
+ const SessionRecorderContext = createContext<SessionRecorderContextType | null>(
32
+ null
33
+ );
34
+
35
+ export interface SessionRecorderProviderProps extends PropsWithChildren {
36
+ options?: SessionRecorderOptions;
37
+ }
38
+
39
+ export const SessionRecorderProvider: React.FC<
40
+ SessionRecorderProviderProps
41
+ > = ({ children, options }) => {
42
+ const isInitialized = useStoreSelector<SessionRecorderState, boolean>(
43
+ sessionRecorderStore,
44
+ (s) => s.isInitialized
45
+ );
46
+
47
+ useEffect(() => {
48
+ if (options) {
49
+ sessionRecorder.init(options);
50
+ }
51
+ sessionRecorderStore.setState({
52
+ isInitialized: sessionRecorder.isInitialized,
53
+ });
54
+ }, []);
55
+
56
+ useEffect(() => {
57
+ sessionRecorderStore.setState({
58
+ sessionState: sessionRecorder.sessionState,
59
+ sessionType: sessionRecorder.sessionType,
60
+ });
61
+ const onStateChange = (
62
+ sessionState: SessionState,
63
+ sessionType: SessionType
64
+ ) => {
65
+ sessionRecorderStore.setState({ sessionState, sessionType });
66
+ };
67
+ sessionRecorder.on('state-change', onStateChange);
68
+ return () => {
69
+ sessionRecorder.off('state-change', onStateChange);
70
+ };
71
+ }, []);
72
+
73
+ const startSession = useCallback(
74
+ (sessionType: SessionType = SessionType.PLAIN) => {
75
+ return sessionRecorder.start(sessionType);
76
+ },
77
+ []
78
+ );
79
+
80
+ const stopSession = useCallback((comment?: string) => {
81
+ return sessionRecorder.stop(comment);
82
+ }, []);
83
+
84
+ const pauseSession = useCallback(() => {
85
+ return sessionRecorder.pause();
86
+ }, []);
87
+
88
+ const resumeSession = useCallback(() => {
89
+ return sessionRecorder.resume();
90
+ }, []);
91
+
92
+ const cancelSession = useCallback(() => {
93
+ return sessionRecorder.cancel();
94
+ }, []);
95
+
96
+ const saveSession = useCallback(() => {
97
+ return sessionRecorder.save();
98
+ }, []);
99
+
100
+ const openWidgetModal = useCallback(() => {
101
+ sessionRecorderStore.setState({ isWidgetModalVisible: true });
102
+ }, []);
103
+
104
+ const closeWidgetModal = useCallback(() => {
105
+ sessionRecorderStore.setState({ isWidgetModalVisible: false });
106
+ }, []);
107
+
108
+ return (
109
+ <SessionRecorderContext.Provider
110
+ value={{
111
+ instance: sessionRecorder,
112
+ openWidgetModal,
113
+ closeWidgetModal,
114
+ startSession,
115
+ stopSession,
116
+ pauseSession,
117
+ resumeSession,
118
+ cancelSession,
119
+ saveSession,
120
+ }}
121
+ >
122
+ <ScreenRecorderView>{children}</ScreenRecorderView>
123
+ {isInitialized && !!sessionRecorder.config.widget.enabled && (
124
+ <SessionRecorderWidget />
125
+ )}
126
+ </SessionRecorderContext.Provider>
127
+ );
128
+ };
129
+
130
+ export const useSessionRecorder = (): SessionRecorderContextType => {
131
+ const context = useContext(SessionRecorderContext);
132
+ if (!context) {
133
+ throw new Error(
134
+ 'useSessionRecorder must be used within a SessionRecorderProvider'
135
+ );
136
+ }
137
+ return context;
138
+ };
@@ -0,0 +1,21 @@
1
+ import { createStore, type Store } from '../utils/createStore'
2
+ import { SessionType } from '@multiplayer-app/session-recorder-common'
3
+ import { SessionState } from '../types'
4
+
5
+ export type SessionRecorderState = {
6
+ isInitialized: boolean
7
+ sessionType: SessionType | null
8
+ sessionState: SessionState | null
9
+ isWidgetModalVisible: boolean
10
+ isOnline: boolean
11
+ error: string | null
12
+ }
13
+
14
+ export const sessionRecorderStore: Store<SessionRecorderState> = createStore<SessionRecorderState>({
15
+ isInitialized: false,
16
+ sessionType: null,
17
+ sessionState: null,
18
+ isWidgetModalVisible: false,
19
+ isOnline: true,
20
+ error: null,
21
+ })
@@ -0,0 +1,27 @@
1
+ import { SessionType } from "@multiplayer-app/session-recorder-common"
2
+ import { SessionState } from "../types"
3
+ import { useStoreSelector } from "./useStoreSelector"
4
+ import { type SessionRecorderState, sessionRecorderStore } from "./SessionRecorderStore"
5
+
6
+ export function useSessionRecorderStore<TSlice>(
7
+ selector: (s: SessionRecorderState) => TSlice,
8
+ equalityFn?: (a: TSlice, b: TSlice) => boolean
9
+ ): TSlice {
10
+ return useStoreSelector<SessionRecorderState, TSlice>(sessionRecorderStore, selector, equalityFn)
11
+ }
12
+
13
+ export function useSessionRecordingState() {
14
+ return useSessionRecorderStore<SessionState | null>((s) => s.sessionState)
15
+ }
16
+
17
+ export function useSessionType() {
18
+ return useSessionRecorderStore<SessionType | null>((s) => s.sessionType)
19
+ }
20
+
21
+ export function useIsInitialized() {
22
+ return useSessionRecorderStore<boolean>((s) => s.isInitialized)
23
+ }
24
+
25
+ export function useWidgetModalVisible() {
26
+ return useSessionRecorderStore<boolean>((s) => s.isWidgetModalVisible)
27
+ }
@@ -0,0 +1,34 @@
1
+ import { useEffect, useRef, useState } from 'react'
2
+ import { type Store } from '../utils/createStore'
3
+ import { shallowEqual } from '../utils/shallowEqual'
4
+
5
+ export function useStoreSelector<TState extends object, TSlice>(
6
+ store: Store<TState>,
7
+ selector: (state: TState) => TSlice,
8
+ equalityFn: (a: TSlice, b: TSlice) => boolean = Object.is,
9
+ ): TSlice {
10
+ const latestSelectorRef = useRef(selector)
11
+ const latestEqualityRef = useRef(equalityFn)
12
+ latestSelectorRef.current = selector
13
+ latestEqualityRef.current = equalityFn
14
+
15
+ const [slice, setSlice] = useState<TSlice>(() => latestSelectorRef.current(store.getState()))
16
+
17
+ useEffect(() => {
18
+ function handleChange(nextState: TState, prevState: TState) {
19
+ const nextSlice = latestSelectorRef.current(nextState)
20
+ const prevSlice = latestSelectorRef.current(prevState)
21
+ if (!latestEqualityRef.current(nextSlice, prevSlice)) {
22
+ setSlice(nextSlice)
23
+ }
24
+ }
25
+ const unsubscribe = store.subscribe(handleChange)
26
+ // Sync once in case changed between render and effect
27
+ handleChange(store.getState(), store.getState())
28
+ return unsubscribe
29
+ }, [store])
30
+
31
+ return slice
32
+ }
33
+
34
+ export const shallow = shallowEqual
package/src/index.ts ADDED
@@ -0,0 +1,10 @@
1
+ import './patch'
2
+ import SessionRecorder from './session-recorder'
3
+ export * from '@multiplayer-app/session-recorder-common'
4
+ export * from './context/SessionRecorderContext'
5
+ export * from './context/useSessionRecorderStore'
6
+
7
+ // Export the class for type checking
8
+ export { SessionRecorder }
9
+ // Export the instance as default
10
+ export default SessionRecorder
@@ -0,0 +1,164 @@
1
+
2
+ import { NativeEventEmitter, Platform, TurboModuleRegistry, type TurboModule } from 'react-native';
3
+
4
+ export interface Spec extends TurboModule {
5
+ /**
6
+ * Capture the current screen and apply masking to sensitive elements
7
+ * @returns Promise that resolves to base64 encoded image
8
+ */
9
+ captureAndMask(): Promise<string>
10
+
11
+ /**
12
+ * Capture the current screen and apply masking with custom options
13
+ * @param options Custom masking options
14
+ * @returns Promise that resolves to base64 encoded image
15
+ */
16
+ captureAndMaskWithOptions(options: MaskingOptions): Promise<string>
17
+
18
+ // Gesture recording APIs
19
+ startGestureRecording(): Promise<void>
20
+ stopGestureRecording(): Promise<void>
21
+ isGestureRecordingActive(): Promise<boolean>
22
+ setGestureCallback(callback: (event: any) => void): void
23
+ }
24
+
25
+ export interface MaskingOptions {
26
+ /** Quality of the captured image (0.1 to 1.0, default: 0.3 for smaller file size) */
27
+ quality?: number
28
+ /** Scale of the captured image (0.1 to 1.0, default: 1.0) */
29
+ scale?: number
30
+ /** Whether to mask text inputs (UITextField, UITextView, React Native text components) */
31
+ maskTextInputs?: boolean
32
+ /** Whether to mask images (UIImageView, React Native Image components) */
33
+ maskImages?: boolean
34
+ /** Whether to mask buttons (UIButton) */
35
+ maskButtons?: boolean
36
+ /** Whether to mask labels (UILabel) */
37
+ maskLabels?: boolean
38
+ /** Whether to mask web views (WKWebView) */
39
+ maskWebViews?: boolean
40
+ /** Whether to mask sandboxed views (system views that don't belong to current process) */
41
+ maskSandboxedViews?: boolean
42
+ }
43
+
44
+
45
+ export interface SessionRecorderNativeModule {
46
+ /**
47
+ * Capture the current screen and apply masking to sensitive elements
48
+ * @returns Promise that resolves to base64 encoded image
49
+ */
50
+ captureAndMask(): Promise<string>
51
+
52
+ /**
53
+ * Capture the current screen and apply masking with custom options
54
+ * @param options Custom masking options
55
+ * @returns Promise that resolves to base64 encoded image
56
+ */
57
+ captureAndMaskWithOptions(options: MaskingOptions): Promise<string>
58
+
59
+ // Gesture recording APIs
60
+ startGestureRecording(): Promise<void>
61
+ stopGestureRecording(): Promise<void>
62
+ isGestureRecordingActive(): Promise<boolean>
63
+ setGestureCallback(callback: (event: any) => void): void
64
+ }
65
+
66
+ // Check if we're on web platform
67
+ const isWeb = Platform.OS === 'web'
68
+
69
+ // Get the Turbo Module
70
+ let SessionRecorderNative: Spec | null = null
71
+ let eventEmitter: NativeEventEmitter | null = null
72
+
73
+ if (!isWeb) {
74
+ try {
75
+ SessionRecorderNative = TurboModuleRegistry.getEnforcing<Spec>('SessionRecorderNative')
76
+ eventEmitter = new NativeEventEmitter(SessionRecorderNative as any)
77
+ } catch (error) {
78
+ console.warn('Failed to access SessionRecorderNative Turbo Module:', error)
79
+ }
80
+ }
81
+
82
+ // Validate that the native module is available
83
+ if (!SessionRecorderNative && !isWeb) {
84
+ console.warn('SessionRecorderNative Turbo Module is not available. Auto-linking may not have completed yet.')
85
+ } else if (isWeb) {
86
+ console.info('SessionRecorderNative: Running on web platform, native module disabled')
87
+ }
88
+
89
+ // Create a safe wrapper that handles web platform
90
+ const SafeSessionRecorderNative: Spec = {
91
+ async captureAndMask(): Promise<string> {
92
+ if (isWeb || !SessionRecorderNative) {
93
+ throw new Error('SessionRecorderNative is not available on web platform')
94
+ }
95
+ return SessionRecorderNative.captureAndMask()
96
+ },
97
+
98
+ async captureAndMaskWithOptions(options: MaskingOptions): Promise<string> {
99
+ if (isWeb || !SessionRecorderNative) {
100
+ throw new Error('SessionRecorderNative is not available on web platform')
101
+ }
102
+ return SessionRecorderNative.captureAndMaskWithOptions(options)
103
+ },
104
+
105
+ async startGestureRecording(): Promise<void> {
106
+ if (isWeb || !SessionRecorderNative) {
107
+ throw new Error('SessionRecorderNative is not available on web platform')
108
+ }
109
+ return SessionRecorderNative.startGestureRecording()
110
+ },
111
+
112
+ async stopGestureRecording(): Promise<void> {
113
+ if (isWeb || !SessionRecorderNative) {
114
+ throw new Error('SessionRecorderNative is not available on web platform')
115
+ }
116
+ return SessionRecorderNative.stopGestureRecording()
117
+ },
118
+
119
+ async isGestureRecordingActive(): Promise<boolean> {
120
+ if (isWeb || !SessionRecorderNative) {
121
+ throw new Error('SessionRecorderNative is not available on web platform')
122
+ }
123
+ return SessionRecorderNative.isGestureRecordingActive()
124
+ },
125
+
126
+ setGestureCallback(callback: (event: any) => void): void {
127
+ if (isWeb || !SessionRecorderNative) {
128
+ throw new Error('SessionRecorderNative is not available on web platform')
129
+ }
130
+ // Native side will also invoke callback if provided; also subscribe to events here
131
+ try {
132
+ SessionRecorderNative.setGestureCallback(callback as any)
133
+ } catch { }
134
+ eventEmitter?.removeAllListeners('onGestureDetected')
135
+ eventEmitter?.addListener('onGestureDetected', callback)
136
+ }
137
+ }
138
+
139
+ export interface NativeGestureEvent {
140
+ type: 'tap' | 'pan_start' | 'pan_move' | 'pan_end' | 'long_press' | 'pinch' | 'swipe'
141
+ timestamp: number
142
+ x: number
143
+ y: number
144
+ target?: string
145
+ targetInfo?: {
146
+ identifier: string
147
+ label?: string
148
+ role?: string
149
+ testId?: string
150
+ text?: string
151
+ }
152
+ metadata?: {
153
+ pressure?: number
154
+ velocity?: number
155
+ scale?: number
156
+ direction?: string
157
+ distance?: number
158
+ }
159
+ }
160
+
161
+ export default SafeSessionRecorderNative
162
+
163
+ // Export event emitter for gesture events to maintain previous API
164
+ export const gestureEventEmitter = eventEmitter
@@ -0,0 +1 @@
1
+ export { default as SessionRecorderNative, gestureEventEmitter, type NativeGestureEvent } from './SessionRecorderNative'
@@ -0,0 +1,274 @@
1
+ import { type Span } from '@opentelemetry/api'
2
+ import {
3
+ MULTIPLAYER_TRACE_DEBUG_PREFIX,
4
+ MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX,
5
+ ATTR_MULTIPLAYER_HTTP_REQUEST_BODY,
6
+ ATTR_MULTIPLAYER_HTTP_REQUEST_HEADERS,
7
+ ATTR_MULTIPLAYER_HTTP_RESPONSE_BODY,
8
+ ATTR_MULTIPLAYER_HTTP_RESPONSE_HEADERS,
9
+ } from '@multiplayer-app/session-recorder-common'
10
+ import { logger } from '../utils'
11
+ import { type TracerReactNativeConfig } from '../types'
12
+
13
+
14
+
15
+ export interface HttpPayloadData {
16
+ requestBody?: any
17
+ responseBody?: any
18
+ requestHeaders?: Record<string, string>
19
+ responseHeaders?: Record<string, string>
20
+ }
21
+
22
+ export interface ProcessedHttpPayload {
23
+ requestBody?: string
24
+ responseBody?: string
25
+ requestHeaders?: string
26
+ responseHeaders?: string
27
+ }
28
+
29
+ /**
30
+ * Checks if the trace should be processed based on trace ID prefixes
31
+ */
32
+ export function shouldProcessTrace(traceId: string): boolean {
33
+ return (
34
+ traceId.startsWith(MULTIPLAYER_TRACE_DEBUG_PREFIX) ||
35
+ traceId.startsWith(MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX)
36
+ )
37
+ }
38
+
39
+ /**
40
+ * Processes request and response body based on trace type and configuration
41
+ */
42
+ export function processBody(
43
+ payload: HttpPayloadData,
44
+ config: TracerReactNativeConfig,
45
+ span: Span,
46
+ ): { requestBody?: string; responseBody?: string } {
47
+ const { captureBody, masking } = config
48
+ const traceId = span.spanContext().traceId
49
+
50
+ if (!captureBody) {
51
+ return {}
52
+ }
53
+
54
+ let { requestBody, responseBody } = payload
55
+
56
+ if (requestBody !== undefined && requestBody !== null) {
57
+ requestBody = JSON.parse(JSON.stringify(requestBody))
58
+ }
59
+ if (responseBody !== undefined && responseBody !== null) {
60
+ responseBody = JSON.parse(JSON.stringify(responseBody))
61
+ }
62
+
63
+ // Apply masking for debug traces
64
+ if (
65
+ traceId.startsWith(MULTIPLAYER_TRACE_DEBUG_PREFIX) ||
66
+ traceId.startsWith(MULTIPLAYER_TRACE_CONTINUOUS_DEBUG_PREFIX)
67
+ ) {
68
+ if (masking.isContentMaskingEnabled) {
69
+ requestBody = requestBody && masking.maskBody?.(requestBody, span)
70
+ responseBody = responseBody && masking.maskBody?.(responseBody, span)
71
+ }
72
+ }
73
+
74
+ // Convert to string if needed
75
+ if (typeof requestBody !== 'string') {
76
+ requestBody = JSON.stringify(requestBody)
77
+ }
78
+
79
+ if (typeof responseBody !== 'string') {
80
+ responseBody = JSON.stringify(responseBody)
81
+ }
82
+
83
+ return {
84
+ requestBody: requestBody?.length ? requestBody : undefined,
85
+ responseBody: responseBody?.length ? responseBody : undefined,
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Processes request and response headers based on configuration
91
+ */
92
+ export function processHeaders(
93
+ payload: HttpPayloadData,
94
+ config: TracerReactNativeConfig,
95
+ span: Span,
96
+ ): { requestHeaders?: string; responseHeaders?: string } {
97
+ const { captureHeaders, masking } = config
98
+
99
+ if (!captureHeaders) {
100
+ return {}
101
+ }
102
+
103
+ let { requestHeaders = {}, responseHeaders = {} } = payload
104
+
105
+ // Handle header filtering
106
+ if (
107
+ !masking.headersToInclude?.length &&
108
+ !masking.headersToExclude?.length
109
+ ) {
110
+ // Add null checks to prevent JSON.parse error when headers is undefined
111
+ if (requestHeaders !== undefined && requestHeaders !== null) {
112
+ requestHeaders = JSON.parse(JSON.stringify(requestHeaders))
113
+ }
114
+ if (responseHeaders !== undefined && responseHeaders !== null) {
115
+ responseHeaders = JSON.parse(JSON.stringify(responseHeaders))
116
+ }
117
+ } else {
118
+ if (masking.headersToInclude) {
119
+ const _requestHeaders: Record<string, string> = {}
120
+ const _responseHeaders: Record<string, string> = {}
121
+
122
+ for (const headerName of masking.headersToInclude) {
123
+ if (requestHeaders[headerName]) {
124
+ _requestHeaders[headerName] = requestHeaders[headerName]
125
+ }
126
+ if (responseHeaders[headerName]) {
127
+ _responseHeaders[headerName] = responseHeaders[headerName]
128
+ }
129
+ }
130
+
131
+ requestHeaders = _requestHeaders
132
+ responseHeaders = _responseHeaders
133
+ }
134
+
135
+ if (masking.headersToExclude?.length) {
136
+ for (const headerName of masking.headersToExclude) {
137
+ delete requestHeaders[headerName]
138
+ delete responseHeaders[headerName]
139
+ }
140
+ }
141
+ }
142
+
143
+ // Apply masking
144
+ const maskedRequestHeaders = masking.maskHeaders?.(requestHeaders, span) || requestHeaders
145
+ const maskedResponseHeaders = masking.maskHeaders?.(responseHeaders, span) || responseHeaders
146
+
147
+ // Convert to string
148
+ const requestHeadersStr = typeof maskedRequestHeaders === 'string'
149
+ ? maskedRequestHeaders
150
+ : JSON.stringify(maskedRequestHeaders)
151
+
152
+ const responseHeadersStr = typeof maskedResponseHeaders === 'string'
153
+ ? maskedResponseHeaders
154
+ : JSON.stringify(maskedResponseHeaders)
155
+
156
+ return {
157
+ requestHeaders: requestHeadersStr?.length ? requestHeadersStr : undefined,
158
+ responseHeaders: responseHeadersStr?.length ? responseHeadersStr : undefined,
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Processes HTTP payload (body and headers) and sets span attributes
164
+ */
165
+ export function processHttpPayload(
166
+ payload: HttpPayloadData,
167
+ config: TracerReactNativeConfig,
168
+ span: Span,
169
+ ): void {
170
+ const traceId = span.spanContext().traceId
171
+
172
+ if (!shouldProcessTrace(traceId)) {
173
+ return
174
+ }
175
+
176
+ const { requestBody, responseBody } = processBody(payload, config, span)
177
+ const { requestHeaders, responseHeaders } = processHeaders(payload, config, span)
178
+
179
+ // Set span attributes
180
+ if (requestBody) {
181
+ span.setAttribute(ATTR_MULTIPLAYER_HTTP_REQUEST_BODY, requestBody)
182
+ }
183
+
184
+ if (responseBody) {
185
+ span.setAttribute(ATTR_MULTIPLAYER_HTTP_RESPONSE_BODY, responseBody)
186
+ }
187
+
188
+ if (requestHeaders) {
189
+ span.setAttribute(ATTR_MULTIPLAYER_HTTP_REQUEST_HEADERS, requestHeaders)
190
+ }
191
+
192
+ if (responseHeaders) {
193
+ span.setAttribute(ATTR_MULTIPLAYER_HTTP_RESPONSE_HEADERS, responseHeaders)
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Converts Headers object to plain object
199
+ */
200
+ export function headersToObject(headers: Headers | Record<string, string> | Record<string, string | string[]> | string[][] | undefined): Record<string, string> {
201
+ const result: Record<string, string> = {}
202
+
203
+ if (!headers) {
204
+ return result
205
+ }
206
+
207
+ if (headers instanceof Headers) {
208
+ headers.forEach((value: string, key: string) => {
209
+ result[key] = value
210
+ })
211
+ } else if (Array.isArray(headers)) {
212
+ // Handle array of [key, value] pairs
213
+ for (const [key, value] of headers) {
214
+ if (typeof key === 'string' && typeof value === 'string') {
215
+ result[key] = value
216
+ }
217
+ }
218
+ } else if (typeof headers === 'object' && !Array.isArray(headers)) {
219
+ for (const [key, value] of Object.entries(headers)) {
220
+ if (typeof key === 'string' && typeof value === 'string') {
221
+ result[key] = value
222
+ }
223
+ }
224
+ }
225
+
226
+ return result
227
+ }
228
+
229
+ /**
230
+ * Extracts response body as string from Response object
231
+ */
232
+ export async function extractResponseBody(response: Response): Promise<string | null> {
233
+ if (!response.body) {
234
+ return null
235
+ }
236
+
237
+ try {
238
+ if (response.body instanceof ReadableStream) {
239
+ // Check if response body is already consumed
240
+ if (response.bodyUsed) {
241
+ return null
242
+ }
243
+
244
+ const responseClone = response.clone()
245
+ return responseClone.text()
246
+ } else {
247
+ return JSON.stringify(response.body)
248
+ }
249
+ } catch (error) {
250
+ // If cloning fails (body already consumed), return null
251
+ // eslint-disable-next-line no-console
252
+ logger.warn('DEBUGGER_LIB', 'Failed to extract response body', error)
253
+ return null
254
+ }
255
+ }
256
+
257
+ export const getExporterEndpoint = (exporterEndpoint: string): string => {
258
+ const hasPath = exporterEndpoint && (() => {
259
+ try {
260
+ const url = new URL(exporterEndpoint)
261
+ return url.pathname !== '/' && url.pathname !== ''
262
+ } catch {
263
+ return false
264
+ }
265
+ })()
266
+
267
+ if (hasPath) {
268
+ return exporterEndpoint
269
+ }
270
+
271
+ const trimmedExporterEndpoint = new URL(exporterEndpoint).origin
272
+
273
+ return `${trimmedExporterEndpoint}/v1/traces`
274
+ }