@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.
- package/LICENSE +1 -2
- package/README.md +216 -155
- package/SessionRecorderNative.podspec +9 -14
- package/android/build.gradle +21 -41
- package/android/gradle.properties +4 -4
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/multiplayer/sessionrecordernative/SessionRecorderNativeConfig.kt +52 -0
- package/android/src/main/java/com/multiplayer/sessionrecordernative/SessionRecorderNativeModule.kt +860 -0
- package/android/src/main/java/com/multiplayer/sessionrecordernative/SessionRecorderNativeModuleSpec.kt +51 -0
- package/android/src/main/java/com/multiplayer/sessionrecordernative/SessionRecorderNativePackage.kt +33 -0
- package/android/src/main/java/com/multiplayer/sessionrecordernative/model/TargetInfo.kt +9 -0
- package/android/src/main/java/com/multiplayer/sessionrecordernative/util/ViewUtils.kt +72 -0
- package/android/src/main/java/com/xxx/XxxModule.kt +23 -0
- package/ios/GestureTargetFinder.swift +50 -0
- package/ios/SessionRecorderNative.podspec +4 -2
- package/ios/SessionRecorderNative.swift +10 -1
- package/ios/SessionRecorderNativeSpec.swift +55 -0
- package/ios/Xxx.h +5 -0
- package/ios/Xxx.mm +21 -0
- package/lib/module/components/ScreenRecorderView/ScreenRecorderView.js +23 -0
- package/lib/module/components/ScreenRecorderView/ScreenRecorderView.js.map +1 -0
- package/lib/module/components/ScreenRecorderView/index.js +4 -0
- package/lib/module/components/ScreenRecorderView/index.js.map +1 -0
- package/lib/module/components/SessionRecorderWidget/ErrorBanner.js +64 -0
- package/lib/module/components/SessionRecorderWidget/ErrorBanner.js.map +1 -0
- package/lib/module/components/SessionRecorderWidget/FinalPopover.js +74 -0
- package/lib/module/components/SessionRecorderWidget/FinalPopover.js.map +1 -0
- package/lib/module/components/SessionRecorderWidget/FloatingButton.js +191 -0
- package/lib/module/components/SessionRecorderWidget/FloatingButton.js.map +1 -0
- package/lib/module/components/SessionRecorderWidget/InitialPopover.js +138 -0
- package/lib/module/components/SessionRecorderWidget/InitialPopover.js.map +1 -0
- package/lib/module/components/SessionRecorderWidget/ModalContainer.js +177 -0
- package/lib/module/components/SessionRecorderWidget/ModalContainer.js.map +1 -0
- package/lib/module/components/SessionRecorderWidget/ModalHeader.js +27 -0
- package/lib/module/components/SessionRecorderWidget/ModalHeader.js.map +1 -0
- package/lib/module/components/SessionRecorderWidget/SessionRecorderWidget.js +133 -0
- package/lib/module/components/SessionRecorderWidget/SessionRecorderWidget.js.map +1 -0
- package/lib/module/components/SessionRecorderWidget/icons.js +93 -0
- package/lib/module/components/SessionRecorderWidget/icons.js.map +1 -0
- package/lib/module/components/SessionRecorderWidget/index.js +5 -0
- package/lib/module/components/SessionRecorderWidget/index.js.map +1 -0
- package/lib/module/components/SessionRecorderWidget/styles.js +173 -0
- package/lib/module/components/SessionRecorderWidget/styles.js.map +1 -0
- package/lib/module/components/index.js +5 -0
- package/lib/module/components/index.js.map +1 -0
- package/lib/module/config/constants.js +42 -0
- package/lib/module/config/constants.js.map +1 -0
- package/lib/module/config/defaults.js +81 -0
- package/lib/module/config/defaults.js.map +1 -0
- package/lib/module/config/index.js +9 -0
- package/lib/module/config/index.js.map +1 -0
- package/lib/module/config/masking.js +35 -0
- package/lib/module/config/masking.js.map +1 -0
- package/lib/module/config/session-recorder.js +44 -0
- package/lib/module/config/session-recorder.js.map +1 -0
- package/lib/module/config/validators.js +28 -0
- package/lib/module/config/validators.js.map +1 -0
- package/lib/module/config/widget.js +35 -0
- package/lib/module/config/widget.js.map +1 -0
- package/lib/module/context/SessionRecorderContext.js +93 -0
- package/lib/module/context/SessionRecorderContext.js.map +1 -0
- package/lib/module/context/SessionRecorderStore.js +12 -0
- package/lib/module/context/SessionRecorderStore.js.map +1 -0
- package/lib/module/context/useSessionRecorderStore.js +20 -0
- package/lib/module/context/useSessionRecorderStore.js.map +1 -0
- package/lib/module/context/useStoreSelector.js +27 -0
- package/lib/module/context/useStoreSelector.js.map +1 -0
- package/lib/module/index.js +13 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/native/SessionRecorderNative.js +74 -0
- package/lib/module/native/SessionRecorderNative.js.map +1 -0
- package/lib/module/native/index.js +4 -0
- package/lib/module/native/index.js.map +1 -0
- package/lib/module/otel/helpers.js +218 -0
- package/lib/module/otel/helpers.js.map +1 -0
- package/lib/module/otel/index.js +95 -0
- package/lib/module/otel/index.js.map +1 -0
- package/lib/module/otel/instrumentations/index.js +102 -0
- package/lib/module/otel/instrumentations/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/patch/index.js +4 -0
- package/lib/module/patch/index.js.map +1 -0
- package/lib/module/patch/xhr.js +116 -0
- package/lib/module/patch/xhr.js.map +1 -0
- package/lib/module/recorder/eventExporter.js +130 -0
- package/lib/module/recorder/eventExporter.js.map +1 -0
- package/lib/module/recorder/gestureRecorder.js +641 -0
- package/lib/module/recorder/gestureRecorder.js.map +1 -0
- package/lib/module/recorder/index.js +168 -0
- package/lib/module/recorder/index.js.map +1 -0
- package/lib/module/recorder/navigationTracker.js +228 -0
- package/lib/module/recorder/navigationTracker.js.map +1 -0
- package/lib/module/recorder/screenRecorder.js +495 -0
- package/lib/module/recorder/screenRecorder.js.map +1 -0
- package/lib/module/services/api.service.js +149 -0
- package/lib/module/services/api.service.js.map +1 -0
- package/lib/module/services/network.service.js +178 -0
- package/lib/module/services/network.service.js.map +1 -0
- package/lib/module/services/screenMaskingService.js +107 -0
- package/lib/module/services/screenMaskingService.js.map +1 -0
- package/lib/module/services/storage.service.js +179 -0
- package/lib/module/services/storage.service.js.map +1 -0
- package/lib/module/session-recorder.js +541 -0
- package/lib/module/session-recorder.js.map +1 -0
- package/lib/module/types/configs.js +4 -0
- package/lib/module/types/configs.js.map +1 -0
- package/lib/module/types/expo-constants.d.js +2 -0
- package/lib/module/types/expo-constants.d.js.map +1 -0
- package/lib/module/types/index.js +11 -0
- package/lib/module/types/index.js.map +1 -0
- package/lib/module/types/session-recorder.js +68 -0
- package/lib/module/types/session-recorder.js.map +1 -0
- package/lib/module/types/session.js +9 -0
- package/lib/module/types/session.js.map +1 -0
- package/lib/module/utils/app-metadata.js +28 -0
- package/lib/module/utils/app-metadata.js.map +1 -0
- package/lib/module/utils/constants.optional.expo.js +6 -0
- package/lib/module/utils/constants.optional.expo.js.map +1 -0
- package/lib/module/utils/constants.optional.js +8 -0
- package/lib/module/utils/constants.optional.js.map +1 -0
- package/lib/module/utils/createStore.js +27 -0
- package/lib/module/utils/createStore.js.map +1 -0
- package/lib/module/utils/index.js +11 -0
- package/lib/module/utils/index.js.map +1 -0
- package/lib/module/utils/logger.js +193 -0
- package/lib/module/utils/logger.js.map +1 -0
- package/lib/module/utils/platform.js +340 -0
- package/lib/module/utils/platform.js.map +1 -0
- package/lib/module/utils/request-utils.js +58 -0
- package/lib/module/utils/request-utils.js.map +1 -0
- package/lib/module/utils/rrweb-events.js +276 -0
- package/lib/module/utils/rrweb-events.js.map +1 -0
- package/lib/module/utils/session.js +21 -0
- package/lib/module/utils/session.js.map +1 -0
- package/lib/module/utils/shallowEqual.js +17 -0
- package/lib/module/utils/shallowEqual.js.map +1 -0
- package/lib/module/utils/time.js +17 -0
- package/lib/module/utils/time.js.map +1 -0
- package/lib/module/utils/type-utils.js +69 -0
- package/lib/module/utils/type-utils.js.map +1 -0
- package/lib/module/version.js +4 -0
- package/lib/module/version.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/components/ScreenRecorderView/ScreenRecorderView.d.ts +6 -0
- package/lib/typescript/src/components/ScreenRecorderView/ScreenRecorderView.d.ts.map +1 -0
- package/lib/typescript/src/components/ScreenRecorderView/index.d.ts +2 -0
- package/lib/typescript/src/components/ScreenRecorderView/index.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/components/SessionRecorderWidget/ErrorBanner.d.ts +1 -0
- package/lib/typescript/src/components/SessionRecorderWidget/ErrorBanner.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/components/SessionRecorderWidget/FinalPopover.d.ts +2 -1
- package/lib/typescript/src/components/SessionRecorderWidget/FinalPopover.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/components/SessionRecorderWidget/FloatingButton.d.ts +1 -0
- package/lib/typescript/src/components/SessionRecorderWidget/FloatingButton.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/components/SessionRecorderWidget/InitialPopover.d.ts +2 -1
- package/lib/typescript/src/components/SessionRecorderWidget/InitialPopover.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/components/SessionRecorderWidget/ModalContainer.d.ts +1 -0
- package/lib/typescript/src/components/SessionRecorderWidget/ModalContainer.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/components/SessionRecorderWidget/ModalHeader.d.ts +1 -0
- package/lib/typescript/src/components/SessionRecorderWidget/ModalHeader.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/components/SessionRecorderWidget/SessionRecorderWidget.d.ts +1 -0
- package/lib/typescript/src/components/SessionRecorderWidget/SessionRecorderWidget.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/components/SessionRecorderWidget/icons.d.ts +1 -0
- package/lib/typescript/src/components/SessionRecorderWidget/icons.d.ts.map +1 -0
- package/lib/typescript/src/components/SessionRecorderWidget/index.d.ts +3 -0
- package/lib/typescript/src/components/SessionRecorderWidget/index.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/components/SessionRecorderWidget/styles.d.ts +4 -3
- package/lib/typescript/src/components/SessionRecorderWidget/styles.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/components/index.d.ts +1 -0
- package/lib/typescript/src/components/index.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/config/constants.d.ts +1 -0
- package/lib/typescript/src/config/constants.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/config/defaults.d.ts +2 -1
- package/lib/typescript/src/config/defaults.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/config/index.d.ts +1 -0
- package/lib/typescript/src/config/index.d.ts.map +1 -0
- package/lib/typescript/src/config/masking.d.ts +3 -0
- package/lib/typescript/src/config/masking.d.ts.map +1 -0
- package/lib/typescript/src/config/session-recorder.d.ts +3 -0
- package/lib/typescript/src/config/session-recorder.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/config/validators.d.ts +1 -0
- package/lib/typescript/src/config/validators.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/config/widget.d.ts +2 -1
- package/lib/typescript/src/config/widget.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/context/SessionRecorderContext.d.ts +3 -2
- package/lib/typescript/src/context/SessionRecorderContext.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/context/SessionRecorderStore.d.ts +2 -1
- package/lib/typescript/src/context/SessionRecorderStore.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/context/useSessionRecorderStore.d.ts +2 -1
- package/lib/typescript/src/context/useSessionRecorderStore.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/context/useStoreSelector.d.ts +2 -1
- package/lib/typescript/src/context/useStoreSelector.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/native/SessionRecorderNative.d.ts +21 -3
- package/lib/typescript/src/native/SessionRecorderNative.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/native/index.d.ts +1 -0
- package/lib/typescript/src/native/index.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/otel/helpers.d.ts +3 -2
- package/lib/typescript/src/otel/helpers.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/otel/index.d.ts +2 -2
- package/lib/typescript/src/otel/index.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/otel/instrumentations/index.d.ts +2 -1
- package/lib/typescript/src/otel/instrumentations/index.d.ts.map +1 -0
- package/lib/typescript/src/patch/index.d.ts +2 -0
- package/lib/typescript/src/patch/index.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/patch/xhr.d.ts +1 -0
- package/lib/typescript/src/patch/xhr.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/recorder/eventExporter.d.ts +2 -1
- package/lib/typescript/src/recorder/eventExporter.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/recorder/gestureRecorder.d.ts +3 -2
- package/lib/typescript/src/recorder/gestureRecorder.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/recorder/index.d.ts +3 -2
- package/lib/typescript/src/recorder/index.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/recorder/navigationTracker.d.ts +2 -1
- package/lib/typescript/src/recorder/navigationTracker.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/recorder/screenRecorder.d.ts +4 -4
- package/lib/typescript/src/recorder/screenRecorder.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/services/api.service.d.ts +2 -1
- package/lib/typescript/src/services/api.service.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/services/network.service.d.ts +1 -0
- package/lib/typescript/src/services/network.service.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/services/screenMaskingService.d.ts +2 -1
- package/lib/typescript/src/services/screenMaskingService.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/services/storage.service.d.ts +2 -1
- package/lib/typescript/src/services/storage.service.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/session-recorder.d.ts +3 -2
- package/lib/typescript/src/session-recorder.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/types/configs.d.ts +3 -2
- package/lib/typescript/src/types/configs.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/types/index.d.ts +1 -0
- package/lib/typescript/src/types/index.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/types/session-recorder.d.ts +3 -2
- package/lib/typescript/src/types/session-recorder.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/types/session.d.ts +1 -0
- package/lib/typescript/src/types/session.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/app-metadata.d.ts +1 -0
- package/lib/typescript/src/utils/app-metadata.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/constants.optional.d.ts +1 -0
- package/lib/typescript/src/utils/constants.optional.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/constants.optional.expo.d.ts +1 -0
- package/lib/typescript/src/utils/constants.optional.expo.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/createStore.d.ts +1 -0
- package/lib/typescript/src/utils/createStore.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/index.d.ts +1 -0
- package/lib/typescript/src/utils/index.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/logger.d.ts +1 -0
- package/lib/typescript/src/utils/logger.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/platform.d.ts +2 -1
- package/lib/typescript/src/utils/platform.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/request-utils.d.ts +1 -0
- package/lib/typescript/src/utils/request-utils.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/rrweb-events.d.ts +2 -1
- package/lib/typescript/src/utils/rrweb-events.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/session.d.ts +1 -0
- package/lib/typescript/src/utils/session.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/shallowEqual.d.ts +1 -0
- package/lib/typescript/src/utils/shallowEqual.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/time.d.ts +1 -0
- package/lib/typescript/src/utils/time.d.ts.map +1 -0
- package/{dist → lib/typescript/src}/utils/type-utils.d.ts +1 -0
- package/lib/typescript/src/utils/type-utils.d.ts.map +1 -0
- package/lib/typescript/src/version.d.ts +2 -0
- package/lib/typescript/src/version.d.ts.map +1 -0
- package/package.json +140 -39
- package/src/components/ScreenRecorderView/ScreenRecorderView.tsx +20 -0
- package/src/components/SessionRecorderWidget/ErrorBanner.tsx +58 -0
- package/src/components/SessionRecorderWidget/FinalPopover.tsx +96 -0
- package/src/components/SessionRecorderWidget/FloatingButton.tsx +176 -0
- package/src/components/SessionRecorderWidget/InitialPopover.tsx +167 -0
- package/src/components/SessionRecorderWidget/ModalContainer.tsx +189 -0
- package/src/components/SessionRecorderWidget/ModalHeader.tsx +24 -0
- package/src/components/SessionRecorderWidget/SessionRecorderWidget.tsx +136 -0
- package/src/components/SessionRecorderWidget/icons.tsx +52 -0
- package/{dist/components/SessionRecorderWidget/index.d.ts → src/components/SessionRecorderWidget/index.ts} +1 -0
- package/src/components/SessionRecorderWidget/styles.ts +169 -0
- package/src/components/index.ts +2 -0
- package/src/config/constants.ts +68 -0
- package/src/config/defaults.ts +101 -0
- package/src/config/index.ts +6 -0
- package/src/config/masking.ts +34 -0
- package/src/config/session-recorder.ts +59 -0
- package/src/config/validators.ts +31 -0
- package/src/config/widget.ts +38 -0
- package/src/context/SessionRecorderContext.tsx +138 -0
- package/src/context/SessionRecorderStore.ts +21 -0
- package/src/context/useSessionRecorderStore.ts +27 -0
- package/src/context/useStoreSelector.ts +34 -0
- package/src/index.ts +10 -0
- package/src/native/SessionRecorderNative.ts +164 -0
- package/src/native/index.ts +1 -0
- package/src/otel/helpers.ts +274 -0
- package/src/otel/index.ts +135 -0
- package/src/otel/instrumentations/index.ts +115 -0
- package/src/patch/index.ts +1 -0
- package/src/patch/xhr.ts +149 -0
- package/src/recorder/eventExporter.ts +155 -0
- package/src/recorder/gestureRecorder.ts +681 -0
- package/src/recorder/index.ts +190 -0
- package/src/recorder/navigationTracker.ts +245 -0
- package/src/recorder/screenRecorder.ts +549 -0
- package/src/services/api.service.ts +215 -0
- package/src/services/network.service.ts +182 -0
- package/src/services/screenMaskingService.ts +122 -0
- package/src/services/storage.service.ts +219 -0
- package/src/session-recorder.ts +591 -0
- package/src/types/configs.ts +96 -0
- package/src/types/expo-constants.d.ts +7 -0
- package/src/types/index.ts +29 -0
- package/src/types/session-recorder.ts +386 -0
- package/src/types/session.ts +65 -0
- package/src/utils/app-metadata.ts +31 -0
- package/src/utils/constants.optional.expo.ts +5 -0
- package/src/utils/constants.optional.ts +16 -0
- package/src/utils/createStore.ts +29 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/logger.ts +216 -0
- package/src/utils/platform.ts +370 -0
- package/src/utils/request-utils.ts +61 -0
- package/src/utils/rrweb-events.ts +316 -0
- package/src/utils/session.ts +19 -0
- package/src/utils/shallowEqual.ts +14 -0
- package/src/utils/time.ts +17 -0
- package/src/utils/type-utils.ts +75 -0
- package/src/version.ts +1 -0
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +0 -7
- package/android/gradlew +0 -249
- package/android/gradlew.bat +0 -92
- package/copy-react-native-dist.sh +0 -56
- package/dist/components/ScreenRecorderView/ScreenRecorderView.d.ts +0 -5
- package/dist/components/ScreenRecorderView/ScreenRecorderView.js +0 -1
- package/dist/components/ScreenRecorderView/ScreenRecorderView.js.map +0 -1
- package/dist/components/ScreenRecorderView/index.js +0 -1
- package/dist/components/ScreenRecorderView/index.js.map +0 -1
- package/dist/components/SessionRecorderWidget/ErrorBanner.js +0 -1
- package/dist/components/SessionRecorderWidget/ErrorBanner.js.map +0 -1
- package/dist/components/SessionRecorderWidget/FinalPopover.js +0 -1
- package/dist/components/SessionRecorderWidget/FinalPopover.js.map +0 -1
- package/dist/components/SessionRecorderWidget/FloatingButton.js +0 -1
- package/dist/components/SessionRecorderWidget/FloatingButton.js.map +0 -1
- package/dist/components/SessionRecorderWidget/InitialPopover.js +0 -1
- package/dist/components/SessionRecorderWidget/InitialPopover.js.map +0 -1
- package/dist/components/SessionRecorderWidget/ModalContainer.js +0 -1
- package/dist/components/SessionRecorderWidget/ModalContainer.js.map +0 -1
- package/dist/components/SessionRecorderWidget/ModalHeader.js +0 -1
- package/dist/components/SessionRecorderWidget/ModalHeader.js.map +0 -1
- package/dist/components/SessionRecorderWidget/SessionRecorderWidget.js +0 -1
- package/dist/components/SessionRecorderWidget/SessionRecorderWidget.js.map +0 -1
- package/dist/components/SessionRecorderWidget/icons.js +0 -1
- package/dist/components/SessionRecorderWidget/icons.js.map +0 -1
- package/dist/components/SessionRecorderWidget/index.js +0 -1
- package/dist/components/SessionRecorderWidget/index.js.map +0 -1
- package/dist/components/SessionRecorderWidget/styles.js +0 -1
- package/dist/components/SessionRecorderWidget/styles.js.map +0 -1
- package/dist/components/index.js +0 -1
- package/dist/components/index.js.map +0 -1
- package/dist/config/constants.js +0 -1
- package/dist/config/constants.js.map +0 -1
- package/dist/config/defaults.js +0 -1
- package/dist/config/defaults.js.map +0 -1
- package/dist/config/index.js +0 -1
- package/dist/config/index.js.map +0 -1
- package/dist/config/masking.d.ts +0 -2
- package/dist/config/masking.js +0 -1
- package/dist/config/masking.js.map +0 -1
- package/dist/config/session-recorder.d.ts +0 -2
- package/dist/config/session-recorder.js +0 -1
- package/dist/config/session-recorder.js.map +0 -1
- package/dist/config/validators.js +0 -1
- package/dist/config/validators.js.map +0 -1
- package/dist/config/widget.js +0 -1
- package/dist/config/widget.js.map +0 -1
- package/dist/context/SessionRecorderContext.js +0 -1
- package/dist/context/SessionRecorderContext.js.map +0 -1
- package/dist/context/SessionRecorderStore.js +0 -1
- package/dist/context/SessionRecorderStore.js.map +0 -1
- package/dist/context/useSessionRecorderStore.js +0 -1
- package/dist/context/useSessionRecorderStore.js.map +0 -1
- package/dist/context/useStoreSelector.js +0 -1
- package/dist/context/useStoreSelector.js.map +0 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +0 -1
- package/dist/native/GestureRecorderNative.d.ts +0 -57
- package/dist/native/GestureRecorderNative.js +0 -1
- package/dist/native/GestureRecorderNative.js.map +0 -1
- package/dist/native/GestureRecorderNativeTurboSpec.d.ts +0 -31
- package/dist/native/GestureRecorderNativeTurboSpec.js +0 -1
- package/dist/native/GestureRecorderNativeTurboSpec.js.map +0 -1
- package/dist/native/SessionRecorderNative.js +0 -1
- package/dist/native/SessionRecorderNative.js.map +0 -1
- package/dist/native/SessionRecorderNativeTurboSpec.d.ts +0 -17
- package/dist/native/SessionRecorderNativeTurboSpec.js +0 -1
- package/dist/native/SessionRecorderNativeTurboSpec.js.map +0 -1
- package/dist/native/index.js +0 -1
- package/dist/native/index.js.map +0 -1
- package/dist/otel/helpers.js +0 -1
- package/dist/otel/helpers.js.map +0 -1
- package/dist/otel/index.js +0 -1
- package/dist/otel/index.js.map +0 -1
- package/dist/otel/instrumentations/index.js +0 -1
- package/dist/otel/instrumentations/index.js.map +0 -1
- package/dist/patch/index.d.ts +0 -1
- package/dist/patch/index.js +0 -1
- package/dist/patch/index.js.map +0 -1
- package/dist/patch/xhr.js +0 -1
- package/dist/patch/xhr.js.map +0 -1
- package/dist/recorder/eventExporter.js +0 -1
- package/dist/recorder/eventExporter.js.map +0 -1
- package/dist/recorder/gestureRecorder.js +0 -1
- package/dist/recorder/gestureRecorder.js.map +0 -1
- package/dist/recorder/index.js +0 -1
- package/dist/recorder/index.js.map +0 -1
- package/dist/recorder/navigationTracker.js +0 -1
- package/dist/recorder/navigationTracker.js.map +0 -1
- package/dist/recorder/screenRecorder.js +0 -1
- package/dist/recorder/screenRecorder.js.map +0 -1
- package/dist/services/api.service.js +0 -1
- package/dist/services/api.service.js.map +0 -1
- package/dist/services/network.service.js +0 -1
- package/dist/services/network.service.js.map +0 -1
- package/dist/services/screenMaskingService.js +0 -1
- package/dist/services/screenMaskingService.js.map +0 -1
- package/dist/services/storage.service.js +0 -1
- package/dist/services/storage.service.js.map +0 -1
- package/dist/session-recorder.js +0 -1
- package/dist/session-recorder.js.map +0 -1
- package/dist/types/configs.js +0 -1
- package/dist/types/configs.js.map +0 -1
- package/dist/types/index.js +0 -1
- package/dist/types/index.js.map +0 -1
- package/dist/types/session-recorder.js +0 -1
- package/dist/types/session-recorder.js.map +0 -1
- package/dist/types/session.js +0 -1
- package/dist/types/session.js.map +0 -1
- package/dist/utils/app-metadata.js +0 -1
- package/dist/utils/app-metadata.js.map +0 -1
- package/dist/utils/constants.optional.expo.js +0 -1
- package/dist/utils/constants.optional.expo.js.map +0 -1
- package/dist/utils/constants.optional.js +0 -1
- package/dist/utils/constants.optional.js.map +0 -1
- package/dist/utils/createStore.js +0 -1
- package/dist/utils/createStore.js.map +0 -1
- package/dist/utils/index.js +0 -1
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/logger.js +0 -1
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/platform.js +0 -1
- package/dist/utils/platform.js.map +0 -1
- package/dist/utils/request-utils.js +0 -1
- package/dist/utils/request-utils.js.map +0 -1
- package/dist/utils/rrweb-events.js +0 -1
- package/dist/utils/rrweb-events.js.map +0 -1
- package/dist/utils/session.js +0 -1
- package/dist/utils/session.js.map +0 -1
- package/dist/utils/shallowEqual.js +0 -1
- package/dist/utils/shallowEqual.js.map +0 -1
- package/dist/utils/time.js +0 -1
- package/dist/utils/time.js.map +0 -1
- package/dist/utils/type-utils.js +0 -1
- package/dist/utils/type-utils.js.map +0 -1
- package/dist/version.d.ts +0 -1
- package/dist/version.js +0 -1
- package/dist/version.js.map +0 -1
- package/docs/AUTO_METADATA_DETECTION.md +0 -108
- /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
|
+
}
|