@scalebun/react-native 1.0.2 → 1.0.3
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 +21 -21
- package/README.md +65 -65
- package/android/build.gradle +86 -86
- package/android/consumer-rules.pro +28 -28
- package/android/src/main/AndroidManifest.xml +14 -14
- package/android/src/main/java/com/scalebun/core/crash/CrashStorage.kt +41 -41
- package/android/src/main/java/com/scalebun/core/crash/NativeCrashHandler.kt +79 -79
- package/android/src/main/java/com/scalebun/core/performance/ANRWatchdog.kt +100 -100
- package/android/src/main/java/com/scalebun/core/performance/AppStartCollector.kt +132 -132
- package/android/src/main/java/com/scalebun/core/performance/FrameMetricsCollector.kt +230 -230
- package/android/src/main/java/com/scalebun/core/performance/PerformanceCore.kt +165 -165
- package/android/src/main/java/com/scalebun/profiler/ProfilerModule.kt +398 -398
- package/android/src/main/java/com/scalebun/profiler/ProfilerPackage.kt +24 -24
- package/android/src/main/java/com/scalebun/profiler/collectors/CpuCollector.kt +161 -161
- package/android/src/main/java/com/scalebun/profiler/collectors/IncidentDetector.kt +223 -223
- package/android/src/main/java/com/scalebun/profiler/collectors/MemoryCollector.kt +157 -157
- package/android/src/main/java/com/scalebun/profiler/collectors/RenderCollector.kt +194 -194
- package/android/src/main/java/com/scalebun/profiler/collectors/SamplerScheduler.kt +218 -218
- package/android/src/main/java/com/scalebun/profiler/collectors/ThreadCollector.kt +142 -142
- package/android/src/main/java/com/scalebun/replaysdk/ReplaySdkModule.kt +966 -966
- package/android/src/main/java/com/scalebun/replaysdk/ReplaySdkPackage.kt +24 -24
- package/android/src/main/java/com/scalebun/replaysdk/capture/CaptureReason.kt +47 -47
- package/android/src/main/java/com/scalebun/replaysdk/capture/FrameCaptureManager.kt +508 -508
- package/android/src/main/java/com/scalebun/replaysdk/capture/FrameCaptureScheduler.kt +187 -187
- package/android/src/main/java/com/scalebun/replaysdk/capture/UiStabilityDetector.kt +214 -214
- package/android/src/main/java/com/scalebun/replaysdk/core/ReplayConfig.kt +144 -144
- package/android/src/main/java/com/scalebun/replaysdk/core/ReplayLogger.kt +31 -31
- package/android/src/main/java/com/scalebun/replaysdk/core/SessionIdGenerator.kt +15 -15
- package/android/src/main/java/com/scalebun/replaysdk/models/ReplayModels.kt +88 -88
- package/android/src/main/java/com/scalebun/replaysdk/outbox/NativeOutbox.kt +541 -541
- package/android/src/main/java/com/scalebun/replaysdk/outbox/OutboxUploader.kt +407 -407
- package/android/src/main/java/com/scalebun/replaysdk/privacy/PrivacyMaskProcessor.kt +126 -126
- package/android/src/main/java/com/scalebun/replaysdk/session/SessionManager.kt +281 -281
- package/android/src/main/java/com/scalebun/replaysdk/storage/ReplayStorage.kt +136 -136
- package/android/src/main/java/com/scalebun/replaysdk/timeline/TimelineCollector.kt +28 -28
- package/android/src/main/java/com/scalebun/replaysdk/tracking/InteractionTracker.kt +419 -419
- package/android/src/main/java/com/scalebun/replaysdk/tracking/ScreenTracker.kt +20 -20
- package/android/src/main/java/com/scalebun/replaysdk/transport/ReplayTransport.kt +99 -99
- package/android/src/main/java/com/scalebun/replaysdk/voice/VoiceRecorder.kt +121 -121
- package/android/src/main/java/com/scalebun/replaysdk/voice/VoiceTranscriber.kt +104 -104
- package/android/src/main/java/com/scalebun/rn/ScaleBunPackage.kt +113 -113
- package/android/src/main/java/com/scalebun/rn/crash/ScaleBunCrashModule.kt +100 -100
- package/android/src/main/java/com/scalebun/rn/crash/ScaleBunCrashPackage.kt +22 -22
- package/android/src/main/java/com/scalebun/rn/engage/ScaleBunEngageModule.kt +579 -579
- package/android/src/main/java/com/scalebun/rn/engage/ScaleBunEngagePackage.kt +22 -22
- package/android/src/main/java/com/scalebun/rn/engage/ScaleBunNotificationPresenter.kt +110 -110
- package/android/src/main/java/com/scalebun/rn/ota/BundleDownloader.kt +170 -0
- package/android/src/main/java/com/scalebun/rn/ota/ScaleBunOtaModule.kt +284 -136
- package/android/src/main/java/com/scalebun/rn/ota/SlotManager.kt +311 -285
- package/android/src/main/java/com/scalebun/rn/performance/PerformanceModule.kt +206 -206
- package/android/src/main/java/com/scalebun/rn/referrer/ScaleBunInstallReferrerModule.kt +77 -77
- package/android/src/main/java/com/scalebun/rn/storage/ScaleBunStorageModule.kt +68 -68
- package/android/src/main/java/com/scalebun/storage/KvFileStore.kt +174 -174
- package/android/src/newarch/java/com/scalebun/profiler/ProfilerSpec.kt +12 -12
- package/android/src/newarch/java/com/scalebun/replaysdk/ReplaySdkSpec.kt +12 -12
- package/android/src/newarch/java/com/scalebun/rn/crash/ScaleBunCrashSpec.kt +15 -15
- package/android/src/newarch/java/com/scalebun/rn/ota/ScaleBunOtaSpec.kt +16 -16
- package/android/src/newarch/java/com/scalebun/rn/performance/PerformanceSpec.kt +12 -12
- package/android/src/newarch/java/com/scalebun/rn/referrer/ScaleBunInstallReferrerSpec.kt +14 -14
- package/android/src/newarch/java/com/scalebun/rn/storage/ScaleBunStorageSpec.kt +16 -16
- package/android/src/oldarch/java/com/scalebun/profiler/ProfilerSpec.kt +34 -34
- package/android/src/oldarch/java/com/scalebun/replaysdk/ReplaySdkSpec.kt +76 -76
- package/android/src/oldarch/java/com/scalebun/rn/crash/ScaleBunCrashSpec.kt +21 -21
- package/android/src/oldarch/java/com/scalebun/rn/ota/ScaleBunOtaSpec.kt +31 -25
- package/android/src/oldarch/java/com/scalebun/rn/performance/PerformanceSpec.kt +27 -27
- package/android/src/oldarch/java/com/scalebun/rn/referrer/ScaleBunInstallReferrerSpec.kt +18 -18
- package/android/src/oldarch/java/com/scalebun/rn/storage/ScaleBunStorageSpec.kt +26 -26
- package/bin/lib/iosCodemod.js +266 -266
- package/bin/scalebun.js +640 -640
- package/ios/Capture/InteractionTracker.swift +191 -191
- package/ios/Capture/PrivacyMaskProcessor.swift +158 -158
- package/ios/Capture/ScreenshotCaptureManager.swift +315 -315
- package/ios/Capture/WindowResolver.swift +63 -63
- package/ios/Core/ReplayConfig.swift +100 -100
- package/ios/Core/ReplayLogger.swift +22 -22
- package/ios/Core/SessionIdGenerator.swift +18 -18
- package/ios/Crash/ScaleBunCrashBridge.mm +63 -63
- package/ios/Crash/ScaleBunCrashHandler.swift +67 -67
- package/ios/Crash/ScaleBunCrashModule.swift +69 -69
- package/ios/Crash/ScaleBunCrashSignalBridge.h +18 -18
- package/ios/Crash/ScaleBunCrashSignalBridge.m +131 -131
- package/ios/Crash/ScaleBunCrashStorage.swift +46 -46
- package/ios/Engage/ScaleBunEngageBridge.m +32 -32
- package/ios/Engage/ScaleBunEngageModule.swift +250 -250
- package/ios/Engage/ScaleBunPushNotificationCenter.swift +185 -185
- package/ios/Ota/BundleDownloader.swift +182 -0
- package/ios/Ota/OtaSlotManager.swift +290 -264
- package/ios/Ota/ScaleBunOtaBridge.mm +77 -68
- package/ios/Ota/ScaleBunOtaEventsModule.swift +61 -0
- package/ios/Ota/ScaleBunOtaModule.swift +176 -123
- package/ios/Outbox/NativeOutbox.swift +598 -598
- package/ios/Outbox/OutboxUploader.swift +431 -431
- package/ios/Performance/ScaleBunPerformanceBridge.m +32 -32
- package/ios/Performance/ScaleBunPerformanceModule.swift +290 -290
- package/ios/PrivacyInfo.xcprivacy +97 -97
- package/ios/Profiler/ScaleBunProfilerBridge.m +55 -55
- package/ios/Profiler/ScaleBunProfilerModule.swift +972 -972
- package/ios/ReplaySdk-Bridging-Header.h +2 -2
- package/ios/ReplaySdk.swift +608 -608
- package/ios/ReplaySdkBridge.m +94 -94
- package/ios/Session/SessionManager.swift +203 -203
- package/ios/Skan/ScaleBunSkanBridge.m +14 -14
- package/ios/Skan/ScaleBunSkanModule.swift +61 -61
- package/ios/Storage/ReplayStorage.swift +61 -61
- package/ios/Storage/ScaleBunKvFileStore.swift +125 -125
- package/ios/Storage/ScaleBunStorageBridge.mm +72 -72
- package/ios/Storage/ScaleBunStorageModule.swift +57 -57
- package/ios/Transport/ReplayTransport.swift +70 -70
- package/ios/VoiceRecorder.swift +145 -145
- package/lib/commonjs/analytics/EventTracker.js +34 -34
- package/lib/commonjs/analytics/EventTracker.js.map +1 -1
- package/lib/commonjs/analytics/automaticEvents.js +7 -7
- package/lib/commonjs/analytics/automaticEvents.js.map +1 -1
- package/lib/commonjs/analytics/batching.js +24 -24
- package/lib/commonjs/analytics/batching.js.map +1 -1
- package/lib/commonjs/analytics/eventLane.js +13 -13
- package/lib/commonjs/analytics/eventLane.js.map +1 -1
- package/lib/commonjs/bootstrap/FeatureRegistry.js +17 -17
- package/lib/commonjs/bootstrap/FeatureRegistry.js.map +1 -1
- package/lib/commonjs/bootstrap/SDKBootstrapper.js +64 -42
- package/lib/commonjs/bootstrap/SDKBootstrapper.js.map +1 -1
- package/lib/commonjs/bucketing/fnv1a32.js +10 -10
- package/lib/commonjs/bucketing/fnv1a32.js.map +1 -1
- package/lib/commonjs/compat/codepush.js +6 -6
- package/lib/commonjs/compat/codepush.js.map +1 -1
- package/lib/commonjs/config/ConfigManager.js +20 -20
- package/lib/commonjs/config/ConfigManager.js.map +1 -1
- package/lib/commonjs/config/configTypes.js.map +1 -1
- package/lib/commonjs/core/architecture.js +23 -23
- package/lib/commonjs/core/architecture.js.map +1 -1
- package/lib/commonjs/core/clock/now.js +2 -2
- package/lib/commonjs/core/clock/now.js.map +1 -1
- package/lib/commonjs/core/config/defaults.js.map +1 -1
- package/lib/commonjs/core/config/schema.js +102 -102
- package/lib/commonjs/core/config/schema.js.map +1 -1
- package/lib/commonjs/core/constants/endpoints.js +7 -7
- package/lib/commonjs/core/constants/endpoints.js.map +1 -1
- package/lib/commonjs/core/constants/timings.js +5 -5
- package/lib/commonjs/core/constants/timings.js.map +1 -1
- package/lib/commonjs/core/constants/version.js +4 -4
- package/lib/commonjs/core/constants/version.js.map +1 -1
- package/lib/commonjs/core/context/app.js.map +1 -1
- package/lib/commonjs/core/context/device.js.map +1 -1
- package/lib/commonjs/core/context/session.js.map +1 -1
- package/lib/commonjs/core/context/user.js.map +1 -1
- package/lib/commonjs/core/contracts/IFeature.js.map +1 -1
- package/lib/commonjs/core/di/container.js.map +1 -1
- package/lib/commonjs/core/encoding/base64.js +9 -9
- package/lib/commonjs/core/encoding/base64.js.map +1 -1
- package/lib/commonjs/core/id/deviceId.js +4 -4
- package/lib/commonjs/core/id/deviceId.js.map +1 -1
- package/lib/commonjs/core/id/sessionId.js.map +1 -1
- package/lib/commonjs/core/lifecycle/appLifecycle.js.map +1 -1
- package/lib/commonjs/core/lifecycle/crashSafe.js +3 -3
- package/lib/commonjs/core/lifecycle/crashSafe.js.map +1 -1
- package/lib/commonjs/core/logger/errorClassification.js +30 -30
- package/lib/commonjs/core/logger/errorClassification.js.map +1 -1
- package/lib/commonjs/core/logger/internalLogger.js.map +1 -1
- package/lib/commonjs/core/logger/levels.js.map +1 -1
- package/lib/commonjs/crypto/hmacSha256.js +6 -6
- package/lib/commonjs/crypto/hmacSha256.js.map +1 -1
- package/lib/commonjs/debug/bootstrap.js +26 -26
- package/lib/commonjs/debug/bootstrap.js.map +1 -1
- package/lib/commonjs/debug/commands.js +10 -10
- package/lib/commonjs/debug/commands.js.map +1 -1
- package/lib/commonjs/debug/configBuilder.js +6 -6
- package/lib/commonjs/debug/configBuilder.js.map +1 -1
- package/lib/commonjs/debug/exportBridge.js +17 -17
- package/lib/commonjs/debug/exportBridge.js.map +1 -1
- package/lib/commonjs/debug/hostResolver.js +10 -10
- package/lib/commonjs/debug/hostResolver.js.map +1 -1
- package/lib/commonjs/debug/index.js.map +1 -1
- package/lib/commonjs/debug/metrics.js.map +1 -1
- package/lib/commonjs/debug/perf.js +11 -11
- package/lib/commonjs/debug/perf.js.map +1 -1
- package/lib/commonjs/debug/perfWiring.js +10 -10
- package/lib/commonjs/debug/perfWiring.js.map +1 -1
- package/lib/commonjs/debug/protocol.js.map +1 -1
- package/lib/commonjs/debug/redaction.js +26 -26
- package/lib/commonjs/debug/redaction.js.map +1 -1
- package/lib/commonjs/debug/replayWiring.js +11 -11
- package/lib/commonjs/debug/replayWiring.js.map +1 -1
- package/lib/commonjs/debug/screenTracking.js +7 -7
- package/lib/commonjs/debug/screenTracking.js.map +1 -1
- package/lib/commonjs/debug/sessionWiring.js +8 -8
- package/lib/commonjs/debug/sessionWiring.js.map +1 -1
- package/lib/commonjs/debug/stream.js +26 -26
- package/lib/commonjs/debug/stream.js.map +1 -1
- package/lib/commonjs/debug/transport.js +24 -24
- package/lib/commonjs/debug/transport.js.map +1 -1
- package/lib/commonjs/features/bugreport/index.js.map +1 -1
- package/lib/commonjs/features/crash/CrashFeature.js +27 -9
- package/lib/commonjs/features/crash/CrashFeature.js.map +1 -1
- package/lib/commonjs/features/crash/CrashReporter.js +28 -28
- package/lib/commonjs/features/crash/CrashReporter.js.map +1 -1
- package/lib/commonjs/features/crash/NativeCrashFeature.js +7 -7
- package/lib/commonjs/features/crash/NativeCrashFeature.js.map +1 -1
- package/lib/commonjs/features/crash/capture.js.map +1 -1
- package/lib/commonjs/features/crash/globalHandler.js +11 -11
- package/lib/commonjs/features/crash/globalHandler.js.map +1 -1
- package/lib/commonjs/features/crash/index.js.map +1 -1
- package/lib/commonjs/features/crash/nativeCrashBridge.js +19 -19
- package/lib/commonjs/features/crash/nativeCrashBridge.js.map +1 -1
- package/lib/commonjs/features/crash/rejectionHandler.js +123 -0
- package/lib/commonjs/features/crash/rejectionHandler.js.map +1 -0
- package/lib/commonjs/features/engage/EngageAnchor.js +3 -3
- package/lib/commonjs/features/engage/EngageAnchor.js.map +1 -1
- package/lib/commonjs/features/engage/EngageArchetypeRenderers.js +19 -19
- package/lib/commonjs/features/engage/EngageArchetypeRenderers.js.map +1 -1
- package/lib/commonjs/features/engage/EngageInAppView.js +35 -35
- package/lib/commonjs/features/engage/EngageInAppView.js.map +1 -1
- package/lib/commonjs/features/engage/EngageInlinePlacement.js +7 -7
- package/lib/commonjs/features/engage/EngageInlinePlacement.js.map +1 -1
- package/lib/commonjs/features/engage/EngagePromptProvider.js +88 -86
- package/lib/commonjs/features/engage/EngagePromptProvider.js.map +1 -1
- package/lib/commonjs/features/engage/EngagePromptView.js +18 -18
- package/lib/commonjs/features/engage/EngagePromptView.js.map +1 -1
- package/lib/commonjs/features/engage/EngageTransport.js +79 -79
- package/lib/commonjs/features/engage/EngageTransport.js.map +1 -1
- package/lib/commonjs/features/engage/EngageVariantContent.js +10 -10
- package/lib/commonjs/features/engage/EngageVariantContent.js.map +1 -1
- package/lib/commonjs/features/engage/__test-support__/reactNativeStub.js +7 -7
- package/lib/commonjs/features/engage/__test-support__/reactNativeStub.js.map +1 -1
- package/lib/commonjs/features/engage/attachmentCapture.js +12 -12
- package/lib/commonjs/features/engage/attachmentCapture.js.map +1 -1
- package/lib/commonjs/features/engage/captureVoiceAttachment.js +20 -20
- package/lib/commonjs/features/engage/captureVoiceAttachment.js.map +1 -1
- package/lib/commonjs/features/engage/engageCoachmarkTour.js +4 -4
- package/lib/commonjs/features/engage/engageCoachmarkTour.js.map +1 -1
- package/lib/commonjs/features/engage/engageGameLogic.js.map +1 -1
- package/lib/commonjs/features/engage/engageMediaSizing.js +15 -15
- package/lib/commonjs/features/engage/engageMediaSizing.js.map +1 -1
- package/lib/commonjs/features/engage/engageMultiStepSheet.js +6 -6
- package/lib/commonjs/features/engage/engageMultiStepSheet.js.map +1 -1
- package/lib/commonjs/features/engage/engageOutcome.js +6 -6
- package/lib/commonjs/features/engage/engageOutcome.js.map +1 -1
- package/lib/commonjs/features/engage/engagePushTokenBridge.js +20 -20
- package/lib/commonjs/features/engage/engagePushTokenBridge.js.map +1 -1
- package/lib/commonjs/features/engage/engageShakeBridge.js +16 -16
- package/lib/commonjs/features/engage/engageShakeBridge.js.map +1 -1
- package/lib/commonjs/features/engage/engageSignals.js.map +1 -1
- package/lib/commonjs/features/engage/engageStoreReviewBridge.js +19 -19
- package/lib/commonjs/features/engage/engageStoreReviewBridge.js.map +1 -1
- package/lib/commonjs/features/engage/engageTestSeenStore.js +29 -29
- package/lib/commonjs/features/engage/engageTestSeenStore.js.map +1 -1
- package/lib/commonjs/features/engage/engageThrottle.js +117 -86
- package/lib/commonjs/features/engage/engageThrottle.js.map +1 -1
- package/lib/commonjs/features/engage/engageTriggerEngine.js +7 -7
- package/lib/commonjs/features/engage/engageTriggerEngine.js.map +1 -1
- package/lib/commonjs/features/engage/engageTypes.js +33 -33
- package/lib/commonjs/features/engage/engageTypes.js.map +1 -1
- package/lib/commonjs/features/engage/engageVariantResolver.js +13 -13
- package/lib/commonjs/features/engage/engageVariantResolver.js.map +1 -1
- package/lib/commonjs/features/engage/engageWindowInsets.js +10 -10
- package/lib/commonjs/features/engage/engageWindowInsets.js.map +1 -1
- package/lib/commonjs/features/engage/gestureTriggerDetector.js.map +1 -1
- package/lib/commonjs/features/engage/transcription/TranscriptionProvider.js +16 -16
- package/lib/commonjs/features/engage/transcription/TranscriptionProvider.js.map +1 -1
- package/lib/commonjs/features/install-referrer/installReferrer.js +26 -26
- package/lib/commonjs/features/install-referrer/installReferrer.js.map +1 -1
- package/lib/commonjs/features/journey/ScaleBunDebugRoot.js +28 -28
- package/lib/commonjs/features/journey/ScaleBunDebugRoot.js.map +1 -1
- package/lib/commonjs/features/journey/ScaleBunFlatList.js +15 -15
- package/lib/commonjs/features/journey/ScaleBunFlatList.js.map +1 -1
- package/lib/commonjs/features/journey/ScaleBunImpression.js +22 -22
- package/lib/commonjs/features/journey/ScaleBunImpression.js.map +1 -1
- package/lib/commonjs/features/journey/ScaleBunScrollView.js +20 -20
- package/lib/commonjs/features/journey/ScaleBunScrollView.js.map +1 -1
- package/lib/commonjs/features/journey/ScaleBunSectionList.js +15 -15
- package/lib/commonjs/features/journey/ScaleBunSectionList.js.map +1 -1
- package/lib/commonjs/features/journey/calibrationContext.js +12 -12
- package/lib/commonjs/features/journey/calibrationContext.js.map +1 -1
- package/lib/commonjs/features/journey/gestureBuffer.js +9 -9
- package/lib/commonjs/features/journey/gestureBuffer.js.map +1 -1
- package/lib/commonjs/features/journey/gestureDetector.js +10 -10
- package/lib/commonjs/features/journey/gestureDetector.js.map +1 -1
- package/lib/commonjs/features/journey/impression.js +18 -18
- package/lib/commonjs/features/journey/impression.js.map +1 -1
- package/lib/commonjs/features/journey/journeyManager.js +6 -6
- package/lib/commonjs/features/journey/journeyManager.js.map +1 -1
- package/lib/commonjs/features/journey/journeyTypes.js +5 -5
- package/lib/commonjs/features/journey/journeyTypes.js.map +1 -1
- package/lib/commonjs/features/journey/navDetector.js +7 -7
- package/lib/commonjs/features/journey/navDetector.js.map +1 -1
- package/lib/commonjs/features/journey/screenshotHelper.js +7 -7
- package/lib/commonjs/features/journey/screenshotHelper.js.map +1 -1
- package/lib/commonjs/features/journey/targetRegistry.js +17 -17
- package/lib/commonjs/features/journey/targetRegistry.js.map +1 -1
- package/lib/commonjs/features/journey/touchTarget.js +29 -29
- package/lib/commonjs/features/journey/touchTarget.js.map +1 -1
- package/lib/commonjs/features/navigation/AutoScreenDetector.js +114 -71
- package/lib/commonjs/features/navigation/AutoScreenDetector.js.map +1 -1
- package/lib/commonjs/features/network/NetworkFeature.js +23 -23
- package/lib/commonjs/features/network/NetworkFeature.js.map +1 -1
- package/lib/commonjs/features/network/index.js +5 -5
- package/lib/commonjs/features/network/index.js.map +1 -1
- package/lib/commonjs/features/ota/OtaEventEmitter.js +21 -21
- package/lib/commonjs/features/ota/OtaEventEmitter.js.map +1 -1
- package/lib/commonjs/features/ota/OtaOrchestrator.js +535 -40
- package/lib/commonjs/features/ota/OtaOrchestrator.js.map +1 -1
- package/lib/commonjs/features/ota/OtaTypes.js.map +1 -1
- package/lib/commonjs/features/ota/environment.js +172 -0
- package/lib/commonjs/features/ota/environment.js.map +1 -0
- package/lib/commonjs/features/ota/retry.js +96 -0
- package/lib/commonjs/features/ota/retry.js.map +1 -0
- package/lib/commonjs/features/ota/signature.js +115 -0
- package/lib/commonjs/features/ota/signature.js.map +1 -0
- package/lib/commonjs/features/ota/useOtaUpdate.js +15 -15
- package/lib/commonjs/features/ota/useOtaUpdate.js.map +1 -1
- package/lib/commonjs/features/performance/PerformanceFeature.js +26 -26
- package/lib/commonjs/features/performance/PerformanceFeature.js.map +1 -1
- package/lib/commonjs/features/performance/collectors/AppLaunchCollector.js +13 -13
- package/lib/commonjs/features/performance/collectors/AppLaunchCollector.js.map +1 -1
- package/lib/commonjs/features/performance/collectors/AutoScreenLoadCollector.js +32 -32
- package/lib/commonjs/features/performance/collectors/AutoScreenLoadCollector.js.map +1 -1
- package/lib/commonjs/features/performance/collectors/CustomTraceCollector.js +13 -13
- package/lib/commonjs/features/performance/collectors/CustomTraceCollector.js.map +1 -1
- package/lib/commonjs/features/performance/collectors/FrameMetricsCollector.js +11 -11
- package/lib/commonjs/features/performance/collectors/FrameMetricsCollector.js.map +1 -1
- package/lib/commonjs/features/performance/collectors/JsStallCollector.js +12 -12
- package/lib/commonjs/features/performance/collectors/JsStallCollector.js.map +1 -1
- package/lib/commonjs/features/performance/collectors/NetworkPerfCollector.js +10 -10
- package/lib/commonjs/features/performance/collectors/NetworkPerfCollector.js.map +1 -1
- package/lib/commonjs/features/performance/collectors/ScreenLoadCollector.js +11 -11
- package/lib/commonjs/features/performance/collectors/ScreenLoadCollector.js.map +1 -1
- package/lib/commonjs/features/performance/collectors/UiHangCollector.js +5 -5
- package/lib/commonjs/features/performance/collectors/UiHangCollector.js.map +1 -1
- package/lib/commonjs/features/performance/config.js +11 -11
- package/lib/commonjs/features/performance/config.js.map +1 -1
- package/lib/commonjs/features/performance/getNativePerformanceModule.js +11 -11
- package/lib/commonjs/features/performance/getNativePerformanceModule.js.map +1 -1
- package/lib/commonjs/features/performance/index.js.map +1 -1
- package/lib/commonjs/features/performance/metrics/MetricsEngine.js +13 -13
- package/lib/commonjs/features/performance/metrics/MetricsEngine.js.map +1 -1
- package/lib/commonjs/features/performance/models.js +8 -8
- package/lib/commonjs/features/performance/models.js.map +1 -1
- package/lib/commonjs/features/performance/transport/PerformanceTransport.js +6 -6
- package/lib/commonjs/features/performance/transport/PerformanceTransport.js.map +1 -1
- package/lib/commonjs/features/profiler/ProfilerFeature.js +53 -53
- package/lib/commonjs/features/profiler/ProfilerFeature.js.map +1 -1
- package/lib/commonjs/features/profiler/config.js +15 -15
- package/lib/commonjs/features/profiler/config.js.map +1 -1
- package/lib/commonjs/features/profiler/contracts.js +22 -22
- package/lib/commonjs/features/profiler/contracts.js.map +1 -1
- package/lib/commonjs/features/profiler/index.js.map +1 -1
- package/lib/commonjs/features/profiler/models.js +44 -44
- package/lib/commonjs/features/profiler/models.js.map +1 -1
- package/lib/commonjs/features/profiler/transport/ProfilerTransport.js +9 -9
- package/lib/commonjs/features/profiler/transport/ProfilerTransport.js.map +1 -1
- package/lib/commonjs/features/replay/bridge/adapters/bridgeAdapter.js +17 -17
- package/lib/commonjs/features/replay/bridge/adapters/bridgeAdapter.js.map +1 -1
- package/lib/commonjs/features/replay/bridge/eventEmitter.js +8 -8
- package/lib/commonjs/features/replay/bridge/eventEmitter.js.map +1 -1
- package/lib/commonjs/features/replay/bridge/nativeModule.js +20 -20
- package/lib/commonjs/features/replay/bridge/nativeModule.js.map +1 -1
- package/lib/commonjs/features/replay/core/clock/clock.js +6 -6
- package/lib/commonjs/features/replay/core/clock/clock.js.map +1 -1
- package/lib/commonjs/features/replay/core/config/defaults.js +2 -2
- package/lib/commonjs/features/replay/core/config/defaults.js.map +1 -1
- package/lib/commonjs/features/replay/core/config/validator.js +5 -5
- package/lib/commonjs/features/replay/core/config/validator.js.map +1 -1
- package/lib/commonjs/features/replay/core/env/environmentDetector.js +10 -10
- package/lib/commonjs/features/replay/core/env/environmentDetector.js.map +1 -1
- package/lib/commonjs/features/replay/core/errors/safeCall.js +4 -4
- package/lib/commonjs/features/replay/core/errors/safeCall.js.map +1 -1
- package/lib/commonjs/features/replay/core/ids/sessionId.js +5 -5
- package/lib/commonjs/features/replay/core/ids/sessionId.js.map +1 -1
- package/lib/commonjs/features/replay/core/logger/logger.js +5 -5
- package/lib/commonjs/features/replay/core/logger/logger.js.map +1 -1
- package/lib/commonjs/features/replay/core/privacy/privacyTypes.js +4 -4
- package/lib/commonjs/features/replay/core/privacy/privacyTypes.js.map +1 -1
- package/lib/commonjs/features/replay/core/queue/boundedQueue.js +5 -5
- package/lib/commonjs/features/replay/core/queue/boundedQueue.js.map +1 -1
- package/lib/commonjs/features/replay/integrations/alert/alertInstrumentation.js +59 -59
- package/lib/commonjs/features/replay/integrations/alert/alertInstrumentation.js.map +1 -1
- package/lib/commonjs/features/replay/integrations/logs/consoleIntegration.js +19 -19
- package/lib/commonjs/features/replay/integrations/logs/consoleIntegration.js.map +1 -1
- package/lib/commonjs/features/replay/integrations/network/networkAdapter.js +30 -30
- package/lib/commonjs/features/replay/integrations/network/networkAdapter.js.map +1 -1
- package/lib/commonjs/features/replay/integrations/react-navigation/navigationIntegration.js +19 -19
- package/lib/commonjs/features/replay/integrations/react-navigation/navigationIntegration.js.map +1 -1
- package/lib/commonjs/features/replay/integrations/touch/ReplayRoot.js +16 -16
- package/lib/commonjs/features/replay/integrations/touch/ReplayRoot.js.map +1 -1
- package/lib/commonjs/features/replay/pipeline/batching/batchManager.js +5 -5
- package/lib/commonjs/features/replay/pipeline/batching/batchManager.js.map +1 -1
- package/lib/commonjs/features/replay/pipeline/envelope/envelopeBuilder.js +5 -5
- package/lib/commonjs/features/replay/pipeline/envelope/envelopeBuilder.js.map +1 -1
- package/lib/commonjs/features/replay/pipeline/retry/retryPolicy.js +4 -4
- package/lib/commonjs/features/replay/pipeline/retry/retryPolicy.js.map +1 -1
- package/lib/commonjs/features/replay/pipeline/transport/transportTypes.js +7 -7
- package/lib/commonjs/features/replay/pipeline/transport/transportTypes.js.map +1 -1
- package/lib/commonjs/features/replay/public/api.js +21 -21
- package/lib/commonjs/features/replay/public/api.js.map +1 -1
- package/lib/commonjs/features/replay/public/enums.js +5 -5
- package/lib/commonjs/features/replay/public/enums.js.map +1 -1
- package/lib/commonjs/features/replay/public/types.js.map +1 -1
- package/lib/commonjs/features/replay/replay/breadcrumbs/breadcrumbCollector.js +5 -5
- package/lib/commonjs/features/replay/replay/breadcrumbs/breadcrumbCollector.js.map +1 -1
- package/lib/commonjs/features/replay/replay/frames/frameModels.js +4 -4
- package/lib/commonjs/features/replay/replay/frames/frameModels.js.map +1 -1
- package/lib/commonjs/features/replay/replay/session/sessionOrchestrator.js +10 -10
- package/lib/commonjs/features/replay/replay/session/sessionOrchestrator.js.map +1 -1
- package/lib/commonjs/features/replay/replay/timeline/timelineModels.js +4 -4
- package/lib/commonjs/features/replay/replay/timeline/timelineModels.js.map +1 -1
- package/lib/commonjs/features/replay/transport/BackendReplayTransport.js +13 -13
- package/lib/commonjs/features/replay/transport/BackendReplayTransport.js.map +1 -1
- package/lib/commonjs/features/replay/transport/CompositeReplayTransport.js +8 -8
- package/lib/commonjs/features/replay/transport/CompositeReplayTransport.js.map +1 -1
- package/lib/commonjs/features/replay/transport/DesktopReplayTransport.js +14 -14
- package/lib/commonjs/features/replay/transport/DesktopReplayTransport.js.map +1 -1
- package/lib/commonjs/features/replay/transport/ReplayTransport.js.map +1 -1
- package/lib/commonjs/features/session/BackendSessionAdapter.js +358 -153
- package/lib/commonjs/features/session/BackendSessionAdapter.js.map +1 -1
- package/lib/commonjs/features/session/DesktopSessionTransport.js +14 -14
- package/lib/commonjs/features/session/DesktopSessionTransport.js.map +1 -1
- package/lib/commonjs/features/session/JourneyEventPipeline.js +19 -19
- package/lib/commonjs/features/session/JourneyEventPipeline.js.map +1 -1
- package/lib/commonjs/features/session/ReplayCaptureManager.js +123 -123
- package/lib/commonjs/features/session/ReplayCaptureManager.js.map +1 -1
- package/lib/commonjs/features/session/ScrollTracker.js +17 -17
- package/lib/commonjs/features/session/ScrollTracker.js.map +1 -1
- package/lib/commonjs/features/session/SessionManager.js +143 -143
- package/lib/commonjs/features/session/SessionManager.js.map +1 -1
- package/lib/commonjs/features/session/SyncDecisionEngine.js +23 -23
- package/lib/commonjs/features/session/SyncDecisionEngine.js.map +1 -1
- package/lib/commonjs/features/session/index.js.map +1 -1
- package/lib/commonjs/features/session/nativeCapture.js +5 -5
- package/lib/commonjs/features/session/nativeCapture.js.map +1 -1
- package/lib/commonjs/features/session/outboxFrameCapture.js +15 -15
- package/lib/commonjs/features/session/outboxFrameCapture.js.map +1 -1
- package/lib/commonjs/features/session/sessionTypes.js +44 -44
- package/lib/commonjs/features/session/sessionTypes.js.map +1 -1
- package/lib/commonjs/features/skan/skanBridge.js +11 -11
- package/lib/commonjs/features/skan/skanBridge.js.map +1 -1
- package/lib/commonjs/features/skan/skanConversionManager.js +23 -23
- package/lib/commonjs/features/skan/skanConversionManager.js.map +1 -1
- package/lib/commonjs/index.js +7 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/integrations/fetch/fetchInterceptor.js +21 -21
- package/lib/commonjs/integrations/fetch/fetchInterceptor.js.map +1 -1
- package/lib/commonjs/integrations/navigation/screenTracker.js.map +1 -1
- package/lib/commonjs/integrations/network/bodyCapture.js +69 -69
- package/lib/commonjs/integrations/network/bodyCapture.js.map +1 -1
- package/lib/commonjs/integrations/xhr/xhrInterceptor.js +24 -24
- package/lib/commonjs/integrations/xhr/xhrInterceptor.js.map +1 -1
- package/lib/commonjs/metro/index.js +37 -37
- package/lib/commonjs/metro/index.js.map +1 -1
- package/lib/commonjs/metro/optionalDependencyStub.js.map +1 -1
- package/lib/commonjs/metro/optionalModules.js +16 -16
- package/lib/commonjs/metro/optionalModules.js.map +1 -1
- package/lib/commonjs/pipeline/dispatcher/dispatcher.js.map +1 -1
- package/lib/commonjs/pipeline/envelope/envelope.js.map +1 -1
- package/lib/commonjs/pipeline/envelope/serializer.js.map +1 -1
- package/lib/commonjs/pipeline/processors/dedupe.js.map +1 -1
- package/lib/commonjs/pipeline/processors/enrich.js.map +1 -1
- package/lib/commonjs/pipeline/processors/sampling.js.map +1 -1
- package/lib/commonjs/pipeline/processors/sanitize.js.map +1 -1
- package/lib/commonjs/pipeline/queue/flushQueue.js +4 -4
- package/lib/commonjs/pipeline/queue/flushQueue.js.map +1 -1
- package/lib/commonjs/pipeline/queue/memoryQueue.js.map +1 -1
- package/lib/commonjs/pipeline/queue/persistentQueue.js +80 -80
- package/lib/commonjs/pipeline/queue/persistentQueue.js.map +1 -1
- package/lib/commonjs/pipeline/queue/queuePolicy.js.map +1 -1
- package/lib/commonjs/pipeline/scheduler/flushScheduler.js.map +1 -1
- package/lib/commonjs/pipeline/scheduler/retryPolicy.js +2 -2
- package/lib/commonjs/pipeline/scheduler/retryPolicy.js.map +1 -1
- package/lib/commonjs/public/ScaleBunErrorBoundary.js +79 -0
- package/lib/commonjs/public/ScaleBunErrorBoundary.js.map +1 -0
- package/lib/commonjs/public/ScaleBunFacade.js +274 -274
- package/lib/commonjs/public/ScaleBunFacade.js.map +1 -1
- package/lib/commonjs/public/ScaleBunProvider.js +3 -3
- package/lib/commonjs/public/ScaleBunProvider.js.map +1 -1
- package/lib/commonjs/public/typedTracker.js +36 -36
- package/lib/commonjs/public/typedTracker.js.map +1 -1
- package/lib/commonjs/public/types.js.map +1 -1
- package/lib/commonjs/push/PushManager.js +21 -21
- package/lib/commonjs/push/PushManager.js.map +1 -1
- package/lib/commonjs/push/adapters/ManualAdapter.js +14 -14
- package/lib/commonjs/push/adapters/ManualAdapter.js.map +1 -1
- package/lib/commonjs/push/adapters/NativeBridgeAdapter.js +17 -17
- package/lib/commonjs/push/adapters/NativeBridgeAdapter.js.map +1 -1
- package/lib/commonjs/push/adapters/NoopAdapter.js +5 -5
- package/lib/commonjs/push/adapters/NoopAdapter.js.map +1 -1
- package/lib/commonjs/push/adapters/RNFirebaseMessagingAdapter.js +17 -17
- package/lib/commonjs/push/adapters/RNFirebaseMessagingAdapter.js.map +1 -1
- package/lib/commonjs/push/adapters/loadMessaging.js +12 -12
- package/lib/commonjs/push/adapters/loadMessaging.js.map +1 -1
- package/lib/commonjs/push/adapters/loadNotifee.js +12 -12
- package/lib/commonjs/push/adapters/loadNotifee.js.map +1 -1
- package/lib/commonjs/push/adapters/selectAdapter.js +14 -14
- package/lib/commonjs/push/adapters/selectAdapter.js.map +1 -1
- package/lib/commonjs/push/detect/capabilities.js +19 -19
- package/lib/commonjs/push/detect/capabilities.js.map +1 -1
- package/lib/commonjs/push/index.js.map +1 -1
- package/lib/commonjs/push/native/nativeNotifications.js +32 -32
- package/lib/commonjs/push/native/nativeNotifications.js.map +1 -1
- package/lib/commonjs/push/types.js.map +1 -1
- package/lib/commonjs/specs/NativeReplaySdk.js +18 -18
- package/lib/commonjs/specs/NativeReplaySdk.js.map +1 -1
- package/lib/commonjs/specs/NativeScaleBunCrash.js +19 -19
- package/lib/commonjs/specs/NativeScaleBunCrash.js.map +1 -1
- package/lib/commonjs/specs/NativeScaleBunInstallReferrer.js +14 -14
- package/lib/commonjs/specs/NativeScaleBunInstallReferrer.js.map +1 -1
- package/lib/commonjs/specs/NativeScaleBunOta.js +21 -21
- package/lib/commonjs/specs/NativeScaleBunOta.js.map +1 -1
- package/lib/commonjs/specs/NativeScaleBunPerformance.js +15 -15
- package/lib/commonjs/specs/NativeScaleBunPerformance.js.map +1 -1
- package/lib/commonjs/specs/NativeScaleBunProfiler.js +16 -16
- package/lib/commonjs/specs/NativeScaleBunProfiler.js.map +1 -1
- package/lib/commonjs/specs/NativeScaleBunStorage.js +29 -29
- package/lib/commonjs/specs/NativeScaleBunStorage.js.map +1 -1
- package/lib/commonjs/storage/StorageBackend.js +83 -83
- package/lib/commonjs/storage/StorageBackend.js.map +1 -1
- package/lib/commonjs/storage/db/sqlite.js.map +1 -1
- package/lib/commonjs/storage/files/fileStore.js.map +1 -1
- package/lib/commonjs/transport/auth/sdkSession.js.map +1 -1
- package/lib/commonjs/transport/backoff/exponentialJitter.js +2 -2
- package/lib/commonjs/transport/backoff/exponentialJitter.js.map +1 -1
- package/lib/commonjs/transport/http/endpoints.js.map +1 -1
- package/lib/commonjs/transport/http/httpClient.js +3 -3
- package/lib/commonjs/transport/http/httpClient.js.map +1 -1
- package/lib/commonjs/transport/rateLimit/retryAfter.js.map +1 -1
- package/lib/commonjs/transport/signing/requestSigner.js.map +1 -1
- package/lib/commonjs/vendor/protocol/index.js +74 -74
- package/lib/commonjs/vendor/protocol/index.js.map +1 -1
- package/lib/commonjs/vendor/protocol/internal/validation.js +23 -23
- package/lib/commonjs/vendor/protocol/internal/validation.js.map +1 -1
- package/lib/commonjs/vendor/sdk-contracts/bridge.js.map +1 -1
- package/lib/commonjs/vendor/sdk-contracts/config.js.map +1 -1
- package/lib/commonjs/vendor/sdk-contracts/events.js.map +1 -1
- package/lib/commonjs/vendor/sdk-contracts/features.js.map +1 -1
- package/lib/commonjs/vendor/sdk-contracts/index.js.map +1 -1
- package/lib/commonjs/vendor/sdk-contracts/platform.js.map +1 -1
- package/lib/commonjs/vendor/sdk-contracts/session-boundary.js.map +1 -1
- package/lib/commonjs/vendor/sdk-contracts/session.js.map +1 -1
- package/lib/commonjs/vendor/vendor.manifest +10 -10
- package/lib/module/analytics/EventTracker.js +34 -34
- package/lib/module/analytics/EventTracker.js.map +1 -1
- package/lib/module/analytics/automaticEvents.js +7 -7
- package/lib/module/analytics/automaticEvents.js.map +1 -1
- package/lib/module/analytics/batching.js +24 -24
- package/lib/module/analytics/batching.js.map +1 -1
- package/lib/module/analytics/eventLane.js +13 -13
- package/lib/module/analytics/eventLane.js.map +1 -1
- package/lib/module/bootstrap/FeatureRegistry.js +17 -17
- package/lib/module/bootstrap/FeatureRegistry.js.map +1 -1
- package/lib/module/bootstrap/SDKBootstrapper.js +64 -42
- package/lib/module/bootstrap/SDKBootstrapper.js.map +1 -1
- package/lib/module/bucketing/fnv1a32.js +10 -10
- package/lib/module/bucketing/fnv1a32.js.map +1 -1
- package/lib/module/compat/codepush.js +6 -6
- package/lib/module/compat/codepush.js.map +1 -1
- package/lib/module/config/ConfigManager.js +20 -20
- package/lib/module/config/ConfigManager.js.map +1 -1
- package/lib/module/config/configTypes.js.map +1 -1
- package/lib/module/core/architecture.js +23 -23
- package/lib/module/core/architecture.js.map +1 -1
- package/lib/module/core/clock/now.js +2 -2
- package/lib/module/core/clock/now.js.map +1 -1
- package/lib/module/core/config/defaults.js.map +1 -1
- package/lib/module/core/config/schema.js +102 -102
- package/lib/module/core/config/schema.js.map +1 -1
- package/lib/module/core/constants/endpoints.js +7 -7
- package/lib/module/core/constants/endpoints.js.map +1 -1
- package/lib/module/core/constants/timings.js +5 -5
- package/lib/module/core/constants/timings.js.map +1 -1
- package/lib/module/core/constants/version.js +4 -4
- package/lib/module/core/constants/version.js.map +1 -1
- package/lib/module/core/context/app.js.map +1 -1
- package/lib/module/core/context/device.js.map +1 -1
- package/lib/module/core/context/session.js.map +1 -1
- package/lib/module/core/context/user.js.map +1 -1
- package/lib/module/core/contracts/IFeature.js.map +1 -1
- package/lib/module/core/di/container.js.map +1 -1
- package/lib/module/core/encoding/base64.js +9 -9
- package/lib/module/core/encoding/base64.js.map +1 -1
- package/lib/module/core/id/deviceId.js +4 -4
- package/lib/module/core/id/deviceId.js.map +1 -1
- package/lib/module/core/id/sessionId.js.map +1 -1
- package/lib/module/core/lifecycle/appLifecycle.js.map +1 -1
- package/lib/module/core/lifecycle/crashSafe.js +3 -3
- package/lib/module/core/lifecycle/crashSafe.js.map +1 -1
- package/lib/module/core/logger/errorClassification.js +30 -30
- package/lib/module/core/logger/errorClassification.js.map +1 -1
- package/lib/module/core/logger/internalLogger.js.map +1 -1
- package/lib/module/core/logger/levels.js.map +1 -1
- package/lib/module/crypto/hmacSha256.js +6 -6
- package/lib/module/crypto/hmacSha256.js.map +1 -1
- package/lib/module/debug/bootstrap.js +26 -26
- package/lib/module/debug/bootstrap.js.map +1 -1
- package/lib/module/debug/commands.js +10 -10
- package/lib/module/debug/commands.js.map +1 -1
- package/lib/module/debug/configBuilder.js +6 -6
- package/lib/module/debug/configBuilder.js.map +1 -1
- package/lib/module/debug/exportBridge.js +17 -17
- package/lib/module/debug/exportBridge.js.map +1 -1
- package/lib/module/debug/hostResolver.js +10 -10
- package/lib/module/debug/hostResolver.js.map +1 -1
- package/lib/module/debug/index.js +5 -5
- package/lib/module/debug/index.js.map +1 -1
- package/lib/module/debug/metrics.js.map +1 -1
- package/lib/module/debug/perf.js +11 -11
- package/lib/module/debug/perf.js.map +1 -1
- package/lib/module/debug/perfWiring.js +10 -10
- package/lib/module/debug/perfWiring.js.map +1 -1
- package/lib/module/debug/protocol.js +11 -11
- package/lib/module/debug/protocol.js.map +1 -1
- package/lib/module/debug/redaction.js +26 -26
- package/lib/module/debug/redaction.js.map +1 -1
- package/lib/module/debug/replayWiring.js +11 -11
- package/lib/module/debug/replayWiring.js.map +1 -1
- package/lib/module/debug/screenTracking.js +7 -7
- package/lib/module/debug/screenTracking.js.map +1 -1
- package/lib/module/debug/sessionWiring.js +8 -8
- package/lib/module/debug/sessionWiring.js.map +1 -1
- package/lib/module/debug/stream.js +26 -26
- package/lib/module/debug/stream.js.map +1 -1
- package/lib/module/debug/transport.js +24 -24
- package/lib/module/debug/transport.js.map +1 -1
- package/lib/module/features/bugreport/index.js.map +1 -1
- package/lib/module/features/crash/CrashFeature.js +27 -9
- package/lib/module/features/crash/CrashFeature.js.map +1 -1
- package/lib/module/features/crash/CrashReporter.js +28 -28
- package/lib/module/features/crash/CrashReporter.js.map +1 -1
- package/lib/module/features/crash/NativeCrashFeature.js +7 -7
- package/lib/module/features/crash/NativeCrashFeature.js.map +1 -1
- package/lib/module/features/crash/capture.js.map +1 -1
- package/lib/module/features/crash/globalHandler.js +11 -11
- package/lib/module/features/crash/globalHandler.js.map +1 -1
- package/lib/module/features/crash/index.js.map +1 -1
- package/lib/module/features/crash/nativeCrashBridge.js +19 -19
- package/lib/module/features/crash/nativeCrashBridge.js.map +1 -1
- package/lib/module/features/crash/rejectionHandler.js +116 -0
- package/lib/module/features/crash/rejectionHandler.js.map +1 -0
- package/lib/module/features/engage/EngageAnchor.js +3 -3
- package/lib/module/features/engage/EngageAnchor.js.map +1 -1
- package/lib/module/features/engage/EngageArchetypeRenderers.js +19 -19
- package/lib/module/features/engage/EngageArchetypeRenderers.js.map +1 -1
- package/lib/module/features/engage/EngageInAppView.js +35 -35
- package/lib/module/features/engage/EngageInAppView.js.map +1 -1
- package/lib/module/features/engage/EngageInlinePlacement.js +7 -7
- package/lib/module/features/engage/EngageInlinePlacement.js.map +1 -1
- package/lib/module/features/engage/EngagePromptProvider.js +88 -86
- package/lib/module/features/engage/EngagePromptProvider.js.map +1 -1
- package/lib/module/features/engage/EngagePromptView.js +18 -18
- package/lib/module/features/engage/EngagePromptView.js.map +1 -1
- package/lib/module/features/engage/EngageTransport.js +79 -79
- package/lib/module/features/engage/EngageTransport.js.map +1 -1
- package/lib/module/features/engage/EngageVariantContent.js +10 -10
- package/lib/module/features/engage/EngageVariantContent.js.map +1 -1
- package/lib/module/features/engage/__test-support__/reactNativeStub.js +7 -7
- package/lib/module/features/engage/__test-support__/reactNativeStub.js.map +1 -1
- package/lib/module/features/engage/attachmentCapture.js +12 -12
- package/lib/module/features/engage/attachmentCapture.js.map +1 -1
- package/lib/module/features/engage/captureVoiceAttachment.js +20 -20
- package/lib/module/features/engage/captureVoiceAttachment.js.map +1 -1
- package/lib/module/features/engage/engageCoachmarkTour.js +4 -4
- package/lib/module/features/engage/engageCoachmarkTour.js.map +1 -1
- package/lib/module/features/engage/engageGameLogic.js.map +1 -1
- package/lib/module/features/engage/engageMediaSizing.js +15 -15
- package/lib/module/features/engage/engageMediaSizing.js.map +1 -1
- package/lib/module/features/engage/engageMultiStepSheet.js +6 -6
- package/lib/module/features/engage/engageMultiStepSheet.js.map +1 -1
- package/lib/module/features/engage/engageOutcome.js +6 -6
- package/lib/module/features/engage/engageOutcome.js.map +1 -1
- package/lib/module/features/engage/engagePushTokenBridge.js +20 -20
- package/lib/module/features/engage/engagePushTokenBridge.js.map +1 -1
- package/lib/module/features/engage/engageShakeBridge.js +16 -16
- package/lib/module/features/engage/engageShakeBridge.js.map +1 -1
- package/lib/module/features/engage/engageSignals.js.map +1 -1
- package/lib/module/features/engage/engageStoreReviewBridge.js +19 -19
- package/lib/module/features/engage/engageStoreReviewBridge.js.map +1 -1
- package/lib/module/features/engage/engageTestSeenStore.js +29 -29
- package/lib/module/features/engage/engageTestSeenStore.js.map +1 -1
- package/lib/module/features/engage/engageThrottle.js +117 -86
- package/lib/module/features/engage/engageThrottle.js.map +1 -1
- package/lib/module/features/engage/engageTriggerEngine.js +7 -7
- package/lib/module/features/engage/engageTriggerEngine.js.map +1 -1
- package/lib/module/features/engage/engageTypes.js +33 -33
- package/lib/module/features/engage/engageTypes.js.map +1 -1
- package/lib/module/features/engage/engageVariantResolver.js +13 -13
- package/lib/module/features/engage/engageVariantResolver.js.map +1 -1
- package/lib/module/features/engage/engageWindowInsets.js +10 -10
- package/lib/module/features/engage/engageWindowInsets.js.map +1 -1
- package/lib/module/features/engage/gestureTriggerDetector.js.map +1 -1
- package/lib/module/features/engage/transcription/TranscriptionProvider.js +16 -16
- package/lib/module/features/engage/transcription/TranscriptionProvider.js.map +1 -1
- package/lib/module/features/install-referrer/installReferrer.js +26 -26
- package/lib/module/features/install-referrer/installReferrer.js.map +1 -1
- package/lib/module/features/journey/ScaleBunDebugRoot.js +28 -28
- package/lib/module/features/journey/ScaleBunDebugRoot.js.map +1 -1
- package/lib/module/features/journey/ScaleBunFlatList.js +15 -15
- package/lib/module/features/journey/ScaleBunFlatList.js.map +1 -1
- package/lib/module/features/journey/ScaleBunImpression.js +22 -22
- package/lib/module/features/journey/ScaleBunImpression.js.map +1 -1
- package/lib/module/features/journey/ScaleBunScrollView.js +20 -20
- package/lib/module/features/journey/ScaleBunScrollView.js.map +1 -1
- package/lib/module/features/journey/ScaleBunSectionList.js +15 -15
- package/lib/module/features/journey/ScaleBunSectionList.js.map +1 -1
- package/lib/module/features/journey/calibrationContext.js +12 -12
- package/lib/module/features/journey/calibrationContext.js.map +1 -1
- package/lib/module/features/journey/gestureBuffer.js +9 -9
- package/lib/module/features/journey/gestureBuffer.js.map +1 -1
- package/lib/module/features/journey/gestureDetector.js +10 -10
- package/lib/module/features/journey/gestureDetector.js.map +1 -1
- package/lib/module/features/journey/impression.js +18 -18
- package/lib/module/features/journey/impression.js.map +1 -1
- package/lib/module/features/journey/journeyManager.js +6 -6
- package/lib/module/features/journey/journeyManager.js.map +1 -1
- package/lib/module/features/journey/journeyTypes.js +5 -5
- package/lib/module/features/journey/journeyTypes.js.map +1 -1
- package/lib/module/features/journey/navDetector.js +7 -7
- package/lib/module/features/journey/navDetector.js.map +1 -1
- package/lib/module/features/journey/screenshotHelper.js +7 -7
- package/lib/module/features/journey/screenshotHelper.js.map +1 -1
- package/lib/module/features/journey/targetRegistry.js +17 -17
- package/lib/module/features/journey/targetRegistry.js.map +1 -1
- package/lib/module/features/journey/touchTarget.js +29 -29
- package/lib/module/features/journey/touchTarget.js.map +1 -1
- package/lib/module/features/navigation/AutoScreenDetector.js +114 -71
- package/lib/module/features/navigation/AutoScreenDetector.js.map +1 -1
- package/lib/module/features/network/NetworkFeature.js +23 -23
- package/lib/module/features/network/NetworkFeature.js.map +1 -1
- package/lib/module/features/network/index.js +5 -5
- package/lib/module/features/network/index.js.map +1 -1
- package/lib/module/features/ota/OtaEventEmitter.js +21 -21
- package/lib/module/features/ota/OtaEventEmitter.js.map +1 -1
- package/lib/module/features/ota/OtaOrchestrator.js +536 -41
- package/lib/module/features/ota/OtaOrchestrator.js.map +1 -1
- package/lib/module/features/ota/OtaTypes.js.map +1 -1
- package/lib/module/features/ota/environment.js +165 -0
- package/lib/module/features/ota/environment.js.map +1 -0
- package/lib/module/features/ota/retry.js +87 -0
- package/lib/module/features/ota/retry.js.map +1 -0
- package/lib/module/features/ota/signature.js +109 -0
- package/lib/module/features/ota/signature.js.map +1 -0
- package/lib/module/features/ota/useOtaUpdate.js +15 -15
- package/lib/module/features/ota/useOtaUpdate.js.map +1 -1
- package/lib/module/features/performance/PerformanceFeature.js +26 -26
- package/lib/module/features/performance/PerformanceFeature.js.map +1 -1
- package/lib/module/features/performance/collectors/AppLaunchCollector.js +13 -13
- package/lib/module/features/performance/collectors/AppLaunchCollector.js.map +1 -1
- package/lib/module/features/performance/collectors/AutoScreenLoadCollector.js +32 -32
- package/lib/module/features/performance/collectors/AutoScreenLoadCollector.js.map +1 -1
- package/lib/module/features/performance/collectors/CustomTraceCollector.js +13 -13
- package/lib/module/features/performance/collectors/CustomTraceCollector.js.map +1 -1
- package/lib/module/features/performance/collectors/FrameMetricsCollector.js +11 -11
- package/lib/module/features/performance/collectors/FrameMetricsCollector.js.map +1 -1
- package/lib/module/features/performance/collectors/JsStallCollector.js +12 -12
- package/lib/module/features/performance/collectors/JsStallCollector.js.map +1 -1
- package/lib/module/features/performance/collectors/NetworkPerfCollector.js +10 -10
- package/lib/module/features/performance/collectors/NetworkPerfCollector.js.map +1 -1
- package/lib/module/features/performance/collectors/ScreenLoadCollector.js +11 -11
- package/lib/module/features/performance/collectors/ScreenLoadCollector.js.map +1 -1
- package/lib/module/features/performance/collectors/UiHangCollector.js +5 -5
- package/lib/module/features/performance/collectors/UiHangCollector.js.map +1 -1
- package/lib/module/features/performance/config.js +11 -11
- package/lib/module/features/performance/config.js.map +1 -1
- package/lib/module/features/performance/getNativePerformanceModule.js +11 -11
- package/lib/module/features/performance/getNativePerformanceModule.js.map +1 -1
- package/lib/module/features/performance/index.js +2 -2
- package/lib/module/features/performance/index.js.map +1 -1
- package/lib/module/features/performance/metrics/MetricsEngine.js +13 -13
- package/lib/module/features/performance/metrics/MetricsEngine.js.map +1 -1
- package/lib/module/features/performance/models.js +8 -8
- package/lib/module/features/performance/models.js.map +1 -1
- package/lib/module/features/performance/transport/PerformanceTransport.js +6 -6
- package/lib/module/features/performance/transport/PerformanceTransport.js.map +1 -1
- package/lib/module/features/profiler/ProfilerFeature.js +53 -53
- package/lib/module/features/profiler/ProfilerFeature.js.map +1 -1
- package/lib/module/features/profiler/config.js +15 -15
- package/lib/module/features/profiler/config.js.map +1 -1
- package/lib/module/features/profiler/contracts.js +22 -22
- package/lib/module/features/profiler/contracts.js.map +1 -1
- package/lib/module/features/profiler/index.js +4 -4
- package/lib/module/features/profiler/index.js.map +1 -1
- package/lib/module/features/profiler/models.js +44 -44
- package/lib/module/features/profiler/models.js.map +1 -1
- package/lib/module/features/profiler/transport/ProfilerTransport.js +9 -9
- package/lib/module/features/profiler/transport/ProfilerTransport.js.map +1 -1
- package/lib/module/features/replay/bridge/adapters/bridgeAdapter.js +17 -17
- package/lib/module/features/replay/bridge/adapters/bridgeAdapter.js.map +1 -1
- package/lib/module/features/replay/bridge/eventEmitter.js +8 -8
- package/lib/module/features/replay/bridge/eventEmitter.js.map +1 -1
- package/lib/module/features/replay/bridge/nativeModule.js +20 -20
- package/lib/module/features/replay/bridge/nativeModule.js.map +1 -1
- package/lib/module/features/replay/core/clock/clock.js +6 -6
- package/lib/module/features/replay/core/clock/clock.js.map +1 -1
- package/lib/module/features/replay/core/config/defaults.js +2 -2
- package/lib/module/features/replay/core/config/defaults.js.map +1 -1
- package/lib/module/features/replay/core/config/validator.js +5 -5
- package/lib/module/features/replay/core/config/validator.js.map +1 -1
- package/lib/module/features/replay/core/env/environmentDetector.js +10 -10
- package/lib/module/features/replay/core/env/environmentDetector.js.map +1 -1
- package/lib/module/features/replay/core/errors/safeCall.js +4 -4
- package/lib/module/features/replay/core/errors/safeCall.js.map +1 -1
- package/lib/module/features/replay/core/ids/sessionId.js +5 -5
- package/lib/module/features/replay/core/ids/sessionId.js.map +1 -1
- package/lib/module/features/replay/core/logger/logger.js +5 -5
- package/lib/module/features/replay/core/logger/logger.js.map +1 -1
- package/lib/module/features/replay/core/privacy/privacyTypes.js +4 -4
- package/lib/module/features/replay/core/privacy/privacyTypes.js.map +1 -1
- package/lib/module/features/replay/core/queue/boundedQueue.js +5 -5
- package/lib/module/features/replay/core/queue/boundedQueue.js.map +1 -1
- package/lib/module/features/replay/integrations/alert/alertInstrumentation.js +59 -59
- package/lib/module/features/replay/integrations/alert/alertInstrumentation.js.map +1 -1
- package/lib/module/features/replay/integrations/logs/consoleIntegration.js +19 -19
- package/lib/module/features/replay/integrations/logs/consoleIntegration.js.map +1 -1
- package/lib/module/features/replay/integrations/network/networkAdapter.js +30 -30
- package/lib/module/features/replay/integrations/network/networkAdapter.js.map +1 -1
- package/lib/module/features/replay/integrations/react-navigation/navigationIntegration.js +19 -19
- package/lib/module/features/replay/integrations/react-navigation/navigationIntegration.js.map +1 -1
- package/lib/module/features/replay/integrations/touch/ReplayRoot.js +16 -16
- package/lib/module/features/replay/integrations/touch/ReplayRoot.js.map +1 -1
- package/lib/module/features/replay/pipeline/batching/batchManager.js +5 -5
- package/lib/module/features/replay/pipeline/batching/batchManager.js.map +1 -1
- package/lib/module/features/replay/pipeline/envelope/envelopeBuilder.js +5 -5
- package/lib/module/features/replay/pipeline/envelope/envelopeBuilder.js.map +1 -1
- package/lib/module/features/replay/pipeline/retry/retryPolicy.js +4 -4
- package/lib/module/features/replay/pipeline/retry/retryPolicy.js.map +1 -1
- package/lib/module/features/replay/pipeline/transport/transportTypes.js +7 -7
- package/lib/module/features/replay/pipeline/transport/transportTypes.js.map +1 -1
- package/lib/module/features/replay/public/api.js +21 -21
- package/lib/module/features/replay/public/api.js.map +1 -1
- package/lib/module/features/replay/public/enums.js +5 -5
- package/lib/module/features/replay/public/enums.js.map +1 -1
- package/lib/module/features/replay/public/types.js.map +1 -1
- package/lib/module/features/replay/replay/breadcrumbs/breadcrumbCollector.js +5 -5
- package/lib/module/features/replay/replay/breadcrumbs/breadcrumbCollector.js.map +1 -1
- package/lib/module/features/replay/replay/frames/frameModels.js +4 -4
- package/lib/module/features/replay/replay/frames/frameModels.js.map +1 -1
- package/lib/module/features/replay/replay/session/sessionOrchestrator.js +10 -10
- package/lib/module/features/replay/replay/session/sessionOrchestrator.js.map +1 -1
- package/lib/module/features/replay/replay/timeline/timelineModels.js +4 -4
- package/lib/module/features/replay/replay/timeline/timelineModels.js.map +1 -1
- package/lib/module/features/replay/transport/BackendReplayTransport.js +13 -13
- package/lib/module/features/replay/transport/BackendReplayTransport.js.map +1 -1
- package/lib/module/features/replay/transport/CompositeReplayTransport.js +8 -8
- package/lib/module/features/replay/transport/CompositeReplayTransport.js.map +1 -1
- package/lib/module/features/replay/transport/DesktopReplayTransport.js +14 -14
- package/lib/module/features/replay/transport/DesktopReplayTransport.js.map +1 -1
- package/lib/module/features/replay/transport/ReplayTransport.js.map +1 -1
- package/lib/module/features/session/BackendSessionAdapter.js +357 -153
- package/lib/module/features/session/BackendSessionAdapter.js.map +1 -1
- package/lib/module/features/session/DesktopSessionTransport.js +14 -14
- package/lib/module/features/session/DesktopSessionTransport.js.map +1 -1
- package/lib/module/features/session/JourneyEventPipeline.js +19 -19
- package/lib/module/features/session/JourneyEventPipeline.js.map +1 -1
- package/lib/module/features/session/ReplayCaptureManager.js +123 -123
- package/lib/module/features/session/ReplayCaptureManager.js.map +1 -1
- package/lib/module/features/session/ScrollTracker.js +17 -17
- package/lib/module/features/session/ScrollTracker.js.map +1 -1
- package/lib/module/features/session/SessionManager.js +143 -143
- package/lib/module/features/session/SessionManager.js.map +1 -1
- package/lib/module/features/session/SyncDecisionEngine.js +23 -23
- package/lib/module/features/session/SyncDecisionEngine.js.map +1 -1
- package/lib/module/features/session/index.js +5 -5
- package/lib/module/features/session/index.js.map +1 -1
- package/lib/module/features/session/nativeCapture.js +5 -5
- package/lib/module/features/session/nativeCapture.js.map +1 -1
- package/lib/module/features/session/outboxFrameCapture.js +15 -15
- package/lib/module/features/session/outboxFrameCapture.js.map +1 -1
- package/lib/module/features/session/sessionTypes.js +44 -44
- package/lib/module/features/session/sessionTypes.js.map +1 -1
- package/lib/module/features/skan/skanBridge.js +11 -11
- package/lib/module/features/skan/skanBridge.js.map +1 -1
- package/lib/module/features/skan/skanConversionManager.js +23 -23
- package/lib/module/features/skan/skanConversionManager.js.map +1 -1
- package/lib/module/index.js +16 -10
- package/lib/module/index.js.map +1 -1
- package/lib/module/integrations/fetch/fetchInterceptor.js +21 -21
- package/lib/module/integrations/fetch/fetchInterceptor.js.map +1 -1
- package/lib/module/integrations/navigation/screenTracker.js.map +1 -1
- package/lib/module/integrations/network/bodyCapture.js +69 -69
- package/lib/module/integrations/network/bodyCapture.js.map +1 -1
- package/lib/module/integrations/xhr/xhrInterceptor.js +24 -24
- package/lib/module/integrations/xhr/xhrInterceptor.js.map +1 -1
- package/lib/module/metro/index.js +37 -37
- package/lib/module/metro/index.js.map +1 -1
- package/lib/module/metro/optionalDependencyStub.js +11 -11
- package/lib/module/metro/optionalDependencyStub.js.map +1 -1
- package/lib/module/metro/optionalModules.js +16 -16
- package/lib/module/metro/optionalModules.js.map +1 -1
- package/lib/module/pipeline/dispatcher/dispatcher.js.map +1 -1
- package/lib/module/pipeline/envelope/envelope.js.map +1 -1
- package/lib/module/pipeline/envelope/serializer.js.map +1 -1
- package/lib/module/pipeline/processors/dedupe.js.map +1 -1
- package/lib/module/pipeline/processors/enrich.js.map +1 -1
- package/lib/module/pipeline/processors/sampling.js.map +1 -1
- package/lib/module/pipeline/processors/sanitize.js.map +1 -1
- package/lib/module/pipeline/queue/flushQueue.js +4 -4
- package/lib/module/pipeline/queue/flushQueue.js.map +1 -1
- package/lib/module/pipeline/queue/memoryQueue.js.map +1 -1
- package/lib/module/pipeline/queue/persistentQueue.js +80 -80
- package/lib/module/pipeline/queue/persistentQueue.js.map +1 -1
- package/lib/module/pipeline/queue/queuePolicy.js.map +1 -1
- package/lib/module/pipeline/scheduler/flushScheduler.js.map +1 -1
- package/lib/module/pipeline/scheduler/retryPolicy.js +2 -2
- package/lib/module/pipeline/scheduler/retryPolicy.js.map +1 -1
- package/lib/module/public/ScaleBunErrorBoundary.js +70 -0
- package/lib/module/public/ScaleBunErrorBoundary.js.map +1 -0
- package/lib/module/public/ScaleBunFacade.js +274 -274
- package/lib/module/public/ScaleBunFacade.js.map +1 -1
- package/lib/module/public/ScaleBunProvider.js +3 -3
- package/lib/module/public/ScaleBunProvider.js.map +1 -1
- package/lib/module/public/typedTracker.js +36 -36
- package/lib/module/public/typedTracker.js.map +1 -1
- package/lib/module/public/types.js.map +1 -1
- package/lib/module/push/PushManager.js +21 -21
- package/lib/module/push/PushManager.js.map +1 -1
- package/lib/module/push/adapters/ManualAdapter.js +14 -14
- package/lib/module/push/adapters/ManualAdapter.js.map +1 -1
- package/lib/module/push/adapters/NativeBridgeAdapter.js +17 -17
- package/lib/module/push/adapters/NativeBridgeAdapter.js.map +1 -1
- package/lib/module/push/adapters/NoopAdapter.js +5 -5
- package/lib/module/push/adapters/NoopAdapter.js.map +1 -1
- package/lib/module/push/adapters/RNFirebaseMessagingAdapter.js +17 -17
- package/lib/module/push/adapters/RNFirebaseMessagingAdapter.js.map +1 -1
- package/lib/module/push/adapters/loadMessaging.js +12 -12
- package/lib/module/push/adapters/loadMessaging.js.map +1 -1
- package/lib/module/push/adapters/loadNotifee.js +12 -12
- package/lib/module/push/adapters/loadNotifee.js.map +1 -1
- package/lib/module/push/adapters/selectAdapter.js +14 -14
- package/lib/module/push/adapters/selectAdapter.js.map +1 -1
- package/lib/module/push/detect/capabilities.js +19 -19
- package/lib/module/push/detect/capabilities.js.map +1 -1
- package/lib/module/push/index.js +3 -3
- package/lib/module/push/index.js.map +1 -1
- package/lib/module/push/native/nativeNotifications.js +32 -32
- package/lib/module/push/native/nativeNotifications.js.map +1 -1
- package/lib/module/push/types.js.map +1 -1
- package/lib/module/specs/NativeReplaySdk.js +18 -18
- package/lib/module/specs/NativeReplaySdk.js.map +1 -1
- package/lib/module/specs/NativeScaleBunCrash.js +19 -19
- package/lib/module/specs/NativeScaleBunCrash.js.map +1 -1
- package/lib/module/specs/NativeScaleBunInstallReferrer.js +14 -14
- package/lib/module/specs/NativeScaleBunInstallReferrer.js.map +1 -1
- package/lib/module/specs/NativeScaleBunOta.js +21 -21
- package/lib/module/specs/NativeScaleBunOta.js.map +1 -1
- package/lib/module/specs/NativeScaleBunPerformance.js +15 -15
- package/lib/module/specs/NativeScaleBunPerformance.js.map +1 -1
- package/lib/module/specs/NativeScaleBunProfiler.js +16 -16
- package/lib/module/specs/NativeScaleBunProfiler.js.map +1 -1
- package/lib/module/specs/NativeScaleBunStorage.js +29 -29
- package/lib/module/specs/NativeScaleBunStorage.js.map +1 -1
- package/lib/module/storage/StorageBackend.js +83 -83
- package/lib/module/storage/StorageBackend.js.map +1 -1
- package/lib/module/storage/db/sqlite.js.map +1 -1
- package/lib/module/storage/files/fileStore.js.map +1 -1
- package/lib/module/transport/auth/sdkSession.js.map +1 -1
- package/lib/module/transport/backoff/exponentialJitter.js +2 -2
- package/lib/module/transport/backoff/exponentialJitter.js.map +1 -1
- package/lib/module/transport/http/endpoints.js.map +1 -1
- package/lib/module/transport/http/httpClient.js +3 -3
- package/lib/module/transport/http/httpClient.js.map +1 -1
- package/lib/module/transport/rateLimit/retryAfter.js.map +1 -1
- package/lib/module/transport/signing/requestSigner.js.map +1 -1
- package/lib/module/vendor/protocol/index.js +74 -74
- package/lib/module/vendor/protocol/index.js.map +1 -1
- package/lib/module/vendor/protocol/internal/validation.js +23 -23
- package/lib/module/vendor/protocol/internal/validation.js.map +1 -1
- package/lib/module/vendor/sdk-contracts/bridge.js.map +1 -1
- package/lib/module/vendor/sdk-contracts/config.js.map +1 -1
- package/lib/module/vendor/sdk-contracts/events.js.map +1 -1
- package/lib/module/vendor/sdk-contracts/features.js.map +1 -1
- package/lib/module/vendor/sdk-contracts/index.js.map +1 -1
- package/lib/module/vendor/sdk-contracts/platform.js.map +1 -1
- package/lib/module/vendor/sdk-contracts/session-boundary.js.map +1 -1
- package/lib/module/vendor/sdk-contracts/session.js.map +1 -1
- package/lib/module/vendor/vendor.manifest +10 -10
- package/lib/typescript/bootstrap/SDKBootstrapper.d.ts.map +1 -1
- package/lib/typescript/features/crash/CrashFeature.d.ts.map +1 -1
- package/lib/typescript/features/crash/rejectionHandler.d.ts +46 -0
- package/lib/typescript/features/crash/rejectionHandler.d.ts.map +1 -0
- package/lib/typescript/features/engage/EngagePromptProvider.d.ts.map +1 -1
- package/lib/typescript/features/engage/engageThrottle.d.ts +24 -4
- package/lib/typescript/features/engage/engageThrottle.d.ts.map +1 -1
- package/lib/typescript/features/engage/engageTypes.d.ts +6 -0
- package/lib/typescript/features/engage/engageTypes.d.ts.map +1 -1
- package/lib/typescript/features/navigation/AutoScreenDetector.d.ts +9 -0
- package/lib/typescript/features/navigation/AutoScreenDetector.d.ts.map +1 -1
- package/lib/typescript/features/ota/OtaOrchestrator.d.ts +67 -1
- package/lib/typescript/features/ota/OtaOrchestrator.d.ts.map +1 -1
- package/lib/typescript/features/ota/OtaTypes.d.ts +42 -0
- package/lib/typescript/features/ota/OtaTypes.d.ts.map +1 -1
- package/lib/typescript/features/ota/environment.d.ts +99 -0
- package/lib/typescript/features/ota/environment.d.ts.map +1 -0
- package/lib/typescript/features/ota/retry.d.ts +53 -0
- package/lib/typescript/features/ota/retry.d.ts.map +1 -0
- package/lib/typescript/features/ota/signature.d.ts +66 -0
- package/lib/typescript/features/ota/signature.d.ts.map +1 -0
- package/lib/typescript/features/session/BackendSessionAdapter.d.ts +93 -2
- package/lib/typescript/features/session/BackendSessionAdapter.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +6 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/public/ScaleBunErrorBoundary.d.ts +44 -0
- package/lib/typescript/public/ScaleBunErrorBoundary.d.ts.map +1 -0
- package/lib/typescript/specs/NativeScaleBunOta.d.ts +11 -0
- package/lib/typescript/specs/NativeScaleBunOta.d.ts.map +1 -1
- package/package.json +12 -14
- package/react-native.config.js +24 -24
- package/scalebun-react-native.podspec +37 -37
- package/src/analytics/EventTracker.ts +462 -462
- package/src/analytics/automaticEvents.ts +105 -105
- package/src/analytics/batching.ts +54 -54
- package/src/analytics/eventLane.ts +26 -26
- package/src/bootstrap/FeatureRegistry.ts +81 -81
- package/src/bootstrap/SDKBootstrapper.ts +609 -585
- package/src/bucketing/fnv1a32.ts +40 -40
- package/src/compat/codepush.ts +118 -118
- package/src/config/ConfigManager.ts +167 -167
- package/src/config/configTypes.ts +32 -32
- package/src/core/architecture.ts +39 -39
- package/src/core/clock/now.ts +6 -6
- package/src/core/config/schema.ts +231 -231
- package/src/core/constants/endpoints.ts +9 -9
- package/src/core/constants/timings.ts +23 -23
- package/src/core/constants/version.ts +6 -6
- package/src/core/context/user.ts +26 -26
- package/src/core/contracts/IFeature.ts +53 -53
- package/src/core/di/container.ts +26 -26
- package/src/core/encoding/base64.ts +46 -46
- package/src/core/id/deviceId.ts +51 -51
- package/src/core/lifecycle/appLifecycle.ts +33 -33
- package/src/core/lifecycle/crashSafe.ts +29 -29
- package/src/core/logger/errorClassification.ts +108 -108
- package/src/core/logger/internalLogger.ts +65 -65
- package/src/crypto/hmacSha256.ts +106 -106
- package/src/debug/bootstrap.ts +366 -366
- package/src/debug/commands.ts +597 -597
- package/src/debug/configBuilder.ts +56 -56
- package/src/debug/exportBridge.ts +153 -153
- package/src/debug/hostResolver.ts +34 -34
- package/src/debug/index.ts +25 -25
- package/src/debug/metrics.ts +29 -29
- package/src/debug/perf.ts +212 -212
- package/src/debug/perfWiring.ts +119 -119
- package/src/debug/protocol.ts +58 -58
- package/src/debug/redaction.ts +290 -290
- package/src/debug/replayWiring.ts +147 -147
- package/src/debug/screenTracking.ts +55 -55
- package/src/debug/sessionWiring.ts +59 -59
- package/src/debug/stream.ts +561 -561
- package/src/debug/transport.ts +439 -439
- package/src/features/crash/CrashFeature.ts +71 -52
- package/src/features/crash/CrashReporter.ts +140 -140
- package/src/features/crash/NativeCrashFeature.ts +42 -42
- package/src/features/crash/capture.ts +21 -21
- package/src/features/crash/globalHandler.ts +39 -39
- package/src/features/crash/index.ts +8 -8
- package/src/features/crash/nativeCrashBridge.ts +132 -132
- package/src/features/crash/rejectionHandler.ts +134 -0
- package/src/features/engage/EngageAnchor.tsx +159 -159
- package/src/features/engage/EngageArchetypeRenderers.tsx +3716 -3716
- package/src/features/engage/EngageInAppView.tsx +2678 -2678
- package/src/features/engage/EngageInlinePlacement.tsx +169 -169
- package/src/features/engage/EngagePromptProvider.tsx +1272 -1270
- package/src/features/engage/EngagePromptView.tsx +1364 -1364
- package/src/features/engage/EngageTransport.ts +668 -668
- package/src/features/engage/EngageVariantContent.tsx +1483 -1483
- package/src/features/engage/__test-support__/reactNativeStub.js +40 -40
- package/src/features/engage/attachmentCapture.ts +45 -45
- package/src/features/engage/captureVoiceAttachment.ts +81 -81
- package/src/features/engage/engageCoachmarkTour.ts +120 -120
- package/src/features/engage/engageGameLogic.ts +347 -347
- package/src/features/engage/engageMediaSizing.ts +76 -76
- package/src/features/engage/engageMultiStepSheet.ts +53 -53
- package/src/features/engage/engageOutcome.ts +157 -157
- package/src/features/engage/engagePushTokenBridge.ts +84 -84
- package/src/features/engage/engageShakeBridge.ts +67 -67
- package/src/features/engage/engageSignals.ts +40 -40
- package/src/features/engage/engageStoreReviewBridge.ts +48 -48
- package/src/features/engage/engageTestSeenStore.ts +95 -95
- package/src/features/engage/engageThrottle.ts +478 -440
- package/src/features/engage/engageTriggerEngine.ts +335 -335
- package/src/features/engage/engageTypes.ts +697 -691
- package/src/features/engage/engageVariantResolver.ts +364 -364
- package/src/features/engage/engageWindowInsets.ts +108 -108
- package/src/features/engage/gestureTriggerDetector.ts +83 -83
- package/src/features/engage/transcription/TranscriptionProvider.ts +68 -68
- package/src/features/install-referrer/installReferrer.ts +112 -112
- package/src/features/journey/ScaleBunDebugRoot.tsx +726 -726
- package/src/features/journey/ScaleBunFlatList.tsx +39 -39
- package/src/features/journey/ScaleBunImpression.tsx +109 -109
- package/src/features/journey/ScaleBunScrollView.tsx +72 -72
- package/src/features/journey/ScaleBunSectionList.tsx +39 -39
- package/src/features/journey/calibrationContext.ts +53 -53
- package/src/features/journey/gestureBuffer.ts +59 -59
- package/src/features/journey/gestureDetector.ts +162 -162
- package/src/features/journey/impression.ts +92 -92
- package/src/features/journey/journeyManager.ts +466 -466
- package/src/features/journey/journeyTypes.ts +215 -215
- package/src/features/journey/navDetector.ts +149 -149
- package/src/features/journey/screenshotHelper.ts +137 -137
- package/src/features/journey/targetRegistry.ts +43 -43
- package/src/features/journey/touchTarget.ts +128 -128
- package/src/features/navigation/AutoScreenDetector.ts +503 -448
- package/src/features/network/NetworkFeature.ts +144 -144
- package/src/features/network/index.ts +31 -31
- package/src/features/ota/OtaEventEmitter.ts +128 -128
- package/src/features/ota/OtaOrchestrator.ts +894 -323
- package/src/features/ota/OtaTypes.ts +118 -62
- package/src/features/ota/environment.ts +199 -0
- package/src/features/ota/retry.ts +123 -0
- package/src/features/ota/signature.ts +123 -0
- package/src/features/ota/useOtaUpdate.ts +134 -134
- package/src/features/performance/PerformanceFeature.ts +584 -584
- package/src/features/performance/collectors/AppLaunchCollector.ts +117 -117
- package/src/features/performance/collectors/AutoScreenLoadCollector.ts +258 -258
- package/src/features/performance/collectors/CustomTraceCollector.ts +116 -116
- package/src/features/performance/collectors/FrameMetricsCollector.ts +119 -119
- package/src/features/performance/collectors/JsStallCollector.ts +165 -165
- package/src/features/performance/collectors/NetworkPerfCollector.ts +69 -69
- package/src/features/performance/collectors/ScreenLoadCollector.ts +95 -95
- package/src/features/performance/collectors/UiHangCollector.ts +98 -98
- package/src/features/performance/config.ts +136 -136
- package/src/features/performance/getNativePerformanceModule.ts +38 -38
- package/src/features/performance/index.ts +28 -28
- package/src/features/performance/metrics/MetricsEngine.ts +152 -152
- package/src/features/performance/models.ts +235 -235
- package/src/features/performance/transport/PerformanceTransport.ts +143 -143
- package/src/features/profiler/ProfilerFeature.ts +661 -661
- package/src/features/profiler/config.ts +230 -230
- package/src/features/profiler/contracts.ts +176 -176
- package/src/features/profiler/index.ts +45 -45
- package/src/features/profiler/models.ts +430 -430
- package/src/features/profiler/transport/ProfilerTransport.ts +93 -93
- package/src/features/replay/bridge/adapters/bridgeAdapter.ts +230 -230
- package/src/features/replay/bridge/eventEmitter.ts +176 -176
- package/src/features/replay/bridge/nativeModule.ts +241 -241
- package/src/features/replay/core/clock/clock.ts +38 -38
- package/src/features/replay/core/config/defaults.ts +66 -66
- package/src/features/replay/core/config/validator.ts +113 -113
- package/src/features/replay/core/env/environmentDetector.ts +21 -21
- package/src/features/replay/core/errors/safeCall.ts +34 -34
- package/src/features/replay/core/ids/sessionId.ts +44 -44
- package/src/features/replay/core/logger/logger.ts +40 -40
- package/src/features/replay/core/privacy/privacyTypes.ts +41 -41
- package/src/features/replay/core/queue/boundedQueue.ts +71 -71
- package/src/features/replay/integrations/alert/alertInstrumentation.ts +277 -277
- package/src/features/replay/integrations/logs/consoleIntegration.ts +116 -116
- package/src/features/replay/integrations/network/networkAdapter.ts +128 -128
- package/src/features/replay/integrations/react-navigation/navigationIntegration.ts +89 -89
- package/src/features/replay/integrations/touch/ReplayRoot.tsx +114 -114
- package/src/features/replay/pipeline/batching/batchManager.ts +133 -133
- package/src/features/replay/pipeline/envelope/envelopeBuilder.ts +66 -66
- package/src/features/replay/pipeline/retry/retryPolicy.ts +62 -62
- package/src/features/replay/pipeline/transport/transportTypes.ts +85 -85
- package/src/features/replay/public/api.ts +364 -364
- package/src/features/replay/public/enums.ts +78 -78
- package/src/features/replay/public/types.ts +297 -297
- package/src/features/replay/replay/breadcrumbs/breadcrumbCollector.ts +115 -115
- package/src/features/replay/replay/frames/frameModels.ts +45 -45
- package/src/features/replay/replay/session/sessionOrchestrator.ts +286 -286
- package/src/features/replay/replay/timeline/timelineModels.ts +129 -129
- package/src/features/replay/transport/BackendReplayTransport.ts +215 -215
- package/src/features/replay/transport/CompositeReplayTransport.ts +82 -82
- package/src/features/replay/transport/DesktopReplayTransport.ts +140 -140
- package/src/features/replay/transport/ReplayTransport.ts +84 -84
- package/src/features/session/BackendSessionAdapter.ts +1441 -1233
- package/src/features/session/DesktopSessionTransport.ts +128 -128
- package/src/features/session/JourneyEventPipeline.ts +273 -273
- package/src/features/session/ReplayCaptureManager.ts +946 -946
- package/src/features/session/ScrollTracker.ts +166 -166
- package/src/features/session/SessionManager.ts +1209 -1209
- package/src/features/session/SyncDecisionEngine.ts +117 -117
- package/src/features/session/index.ts +88 -88
- package/src/features/session/nativeCapture.ts +38 -38
- package/src/features/session/outboxFrameCapture.ts +74 -74
- package/src/features/session/sessionTypes.ts +491 -491
- package/src/features/skan/skanBridge.ts +61 -61
- package/src/features/skan/skanConversionManager.ts +173 -173
- package/src/index.ts +197 -191
- package/src/integrations/fetch/fetchInterceptor.ts +182 -182
- package/src/integrations/network/bodyCapture.ts +328 -328
- package/src/integrations/xhr/xhrInterceptor.ts +231 -231
- package/src/metro/index.ts +164 -164
- package/src/metro/optionalDependencyStub.ts +13 -13
- package/src/metro/optionalModules.ts +27 -27
- package/src/pipeline/dispatcher/dispatcher.ts +22 -22
- package/src/pipeline/envelope/envelope.ts +31 -31
- package/src/pipeline/envelope/serializer.ts +14 -14
- package/src/pipeline/processors/enrich.ts +11 -11
- package/src/pipeline/processors/sanitize.ts +23 -23
- package/src/pipeline/queue/flushQueue.ts +144 -144
- package/src/pipeline/queue/memoryQueue.ts +31 -31
- package/src/pipeline/queue/persistentQueue.ts +414 -414
- package/src/pipeline/scheduler/flushScheduler.ts +47 -47
- package/src/pipeline/scheduler/retryPolicy.ts +8 -8
- package/src/public/ScaleBunErrorBoundary.tsx +79 -0
- package/src/public/ScaleBunFacade.ts +1479 -1479
- package/src/public/ScaleBunProvider.tsx +91 -91
- package/src/public/typedTracker.ts +123 -123
- package/src/public/types.ts +312 -312
- package/src/push/PushManager.ts +318 -318
- package/src/push/adapters/ManualAdapter.ts +100 -100
- package/src/push/adapters/NativeBridgeAdapter.ts +142 -142
- package/src/push/adapters/NoopAdapter.ts +46 -46
- package/src/push/adapters/RNFirebaseMessagingAdapter.ts +271 -271
- package/src/push/adapters/loadMessaging.ts +24 -24
- package/src/push/adapters/loadNotifee.ts +29 -29
- package/src/push/adapters/selectAdapter.ts +176 -176
- package/src/push/detect/capabilities.ts +124 -124
- package/src/push/index.ts +22 -22
- package/src/push/native/nativeNotifications.ts +216 -216
- package/src/push/types.ts +159 -159
- package/src/specs/NativeReplaySdk.ts +99 -99
- package/src/specs/NativeScaleBunCrash.ts +36 -36
- package/src/specs/NativeScaleBunInstallReferrer.ts +29 -29
- package/src/specs/NativeScaleBunOta.ts +97 -85
- package/src/specs/NativeScaleBunPerformance.ts +34 -34
- package/src/specs/NativeScaleBunProfiler.ts +41 -41
- package/src/specs/NativeScaleBunStorage.ts +59 -59
- package/src/storage/StorageBackend.ts +272 -272
- package/src/transport/auth/sdkSession.ts +27 -27
- package/src/transport/backoff/exponentialJitter.ts +9 -9
- package/src/transport/http/endpoints.ts +33 -33
- package/src/transport/http/httpClient.ts +73 -73
- package/src/vendor/protocol/index.ts +391 -391
- package/src/vendor/protocol/internal/validation.ts +497 -497
- package/src/vendor/sdk-contracts/bridge.ts +162 -162
- package/src/vendor/sdk-contracts/config.ts +192 -192
- package/src/vendor/sdk-contracts/events.ts +50 -50
- package/src/vendor/sdk-contracts/features.ts +42 -42
- package/src/vendor/sdk-contracts/index.ts +98 -98
- package/src/vendor/sdk-contracts/platform.ts +42 -42
- package/src/vendor/sdk-contracts/session-boundary.ts +55 -55
- package/src/vendor/sdk-contracts/session.ts +225 -225
- package/src/vendor/vendor.manifest +10 -10
- package/android/build/generated/source/buildConfig/debug/com/scalebun/sdk/BuildConfig.java +0 -12
- package/android/build/generated/source/codegen/java/com/scalebun/spec/NativeReplaySdkSpec.java +0 -208
- package/android/build/generated/source/codegen/java/com/scalebun/spec/NativeScaleBunCrashSpec.java +0 -46
- package/android/build/generated/source/codegen/java/com/scalebun/spec/NativeScaleBunInstallReferrerSpec.java +0 -38
- package/android/build/generated/source/codegen/java/com/scalebun/spec/NativeScaleBunOtaSpec.java +0 -63
- package/android/build/generated/source/codegen/java/com/scalebun/spec/NativeScaleBunPerformanceSpec.java +0 -70
- package/android/build/generated/source/codegen/java/com/scalebun/spec/NativeScaleBunProfilerSpec.java +0 -96
- package/android/build/generated/source/codegen/java/com/scalebun/spec/NativeScaleBunStorageSpec.java +0 -50
- package/android/build/generated/source/codegen/jni/CMakeLists.txt +0 -28
- package/android/build/generated/source/codegen/jni/ScaleBunSpec-generated.cpp +0 -554
- package/android/build/generated/source/codegen/jni/ScaleBunSpec.h +0 -79
- package/android/build/generated/source/codegen/jni/react/renderer/components/ScaleBunSpec/ComponentDescriptors.cpp +0 -22
- package/android/build/generated/source/codegen/jni/react/renderer/components/ScaleBunSpec/ComponentDescriptors.h +0 -24
- package/android/build/generated/source/codegen/jni/react/renderer/components/ScaleBunSpec/EventEmitters.cpp +0 -16
- package/android/build/generated/source/codegen/jni/react/renderer/components/ScaleBunSpec/EventEmitters.h +0 -17
- package/android/build/generated/source/codegen/jni/react/renderer/components/ScaleBunSpec/Props.cpp +0 -19
- package/android/build/generated/source/codegen/jni/react/renderer/components/ScaleBunSpec/Props.h +0 -18
- package/android/build/generated/source/codegen/jni/react/renderer/components/ScaleBunSpec/ScaleBunSpecJSI-generated.cpp +0 -595
- package/android/build/generated/source/codegen/jni/react/renderer/components/ScaleBunSpec/ScaleBunSpecJSI.h +0 -1070
- package/android/build/generated/source/codegen/jni/react/renderer/components/ScaleBunSpec/ShadowNodes.cpp +0 -17
- package/android/build/generated/source/codegen/jni/react/renderer/components/ScaleBunSpec/ShadowNodes.h +0 -23
- package/android/build/generated/source/codegen/jni/react/renderer/components/ScaleBunSpec/States.cpp +0 -16
- package/android/build/generated/source/codegen/jni/react/renderer/components/ScaleBunSpec/States.h +0 -20
- package/android/build/generated/source/codegen/schema.json +0 -1
- package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +0 -20
- package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json +0 -18
- package/android/build/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties +0 -6
- package/android/build/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json +0 -1
- package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar +0 -0
- package/android/build/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt +0 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +0 -1
- package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +0 -2
- package/android/build/intermediates/incremental/mergeDebugAssets/merger.xml +0 -2
- package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +0 -2
- package/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +0 -2
- package/android/build/intermediates/java_res/debug/processDebugJavaRes/out/META-INF/scalebun_react-native_debug.kotlin_module +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/scalebun/sdk/BuildConfig.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/scalebun/spec/NativeReplaySdkSpec.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/scalebun/spec/NativeScaleBunCrashSpec.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/scalebun/spec/NativeScaleBunInstallReferrerSpec.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/scalebun/spec/NativeScaleBunOtaSpec.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/scalebun/spec/NativeScaleBunPerformanceSpec.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/scalebun/spec/NativeScaleBunProfilerSpec.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/scalebun/spec/NativeScaleBunStorageSpec.class +0 -0
- package/android/build/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt +0 -2
- package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +0 -24
- package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +0 -20
- package/android/build/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json +0 -1
- package/android/build/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt +0 -1
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/META-INF/scalebun_react-native_debug.kotlin_module +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/core/crash/CrashStorage.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/core/crash/NativeCrashHandler$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/core/crash/NativeCrashHandler.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/core/performance/ANRWatchdog$HangInfo.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/core/performance/ANRWatchdog.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/core/performance/AppStartCollector$AppStartInfo.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/core/performance/AppStartCollector$Breakdown.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/core/performance/AppStartCollector$start$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/core/performance/AppStartCollector.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/core/performance/FrameMetricsCollector$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/core/performance/FrameMetricsCollector$FrameMetricsSnapshot.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/core/performance/FrameMetricsCollector$start$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/core/performance/FrameMetricsCollector$startChoreographerFallback$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/core/performance/FrameMetricsCollector.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/core/performance/PerformanceCore$Listener.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/core/performance/PerformanceCore.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/profiler/ProfilerModule$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/profiler/ProfilerModule.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/profiler/ProfilerPackage.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/profiler/ProfilerSpec.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/profiler/collectors/CpuCollector.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/profiler/collectors/IncidentDetector.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/profiler/collectors/MemoryCollector.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/profiler/collectors/RenderCollector$frameCallback$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/profiler/collectors/RenderCollector.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/profiler/collectors/SamplerScheduler.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/profiler/collectors/SamplerSchedulerKt.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/profiler/collectors/ThreadCollector$WhenMappings.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/profiler/collectors/ThreadCollector.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/ReplaySdkModule$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/ReplaySdkModule$registerConnectivity$cb$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/ReplaySdkModule.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/ReplaySdkPackage.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/ReplaySdkSpec.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/capture/CaptureReason$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/capture/CaptureReason.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/capture/FrameCaptureManager$startFrequencyTimer$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/capture/FrameCaptureManager.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/capture/FrameCaptureScheduler$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/capture/FrameCaptureScheduler$FrameRequest.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/capture/FrameCaptureScheduler.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/capture/UiStabilityDetector$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/capture/UiStabilityDetector$SettleWatch.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/capture/UiStabilityDetector$StabilityWatch.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/capture/UiStabilityDetector.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/core/CaptureMode$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/core/CaptureMode.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/core/ReplayConfig$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/core/ReplayConfig.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/core/ReplayLogger.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/core/ScreenshotQuality$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/core/ScreenshotQuality.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/core/SessionIdGenerator.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/core/SessionState.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/models/ReplayFrame.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/models/ReplaySession.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/models/TimelineEvent.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/outbox/NativeOutbox$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/outbox/NativeOutbox$enforceLimits$lambda$37$$inlined$sortedBy$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/outbox/NativeOutbox.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/outbox/OutboxUploader$NetResult$NetworkError.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/outbox/OutboxUploader$NetResult$Response.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/outbox/OutboxUploader$NetResult.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/outbox/OutboxUploader$Outcome.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/outbox/OutboxUploader$WhenMappings.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/outbox/OutboxUploader.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/privacy/PrivacyMaskProcessor.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/session/SessionManager.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/storage/ReplayStorage$enforceStorageLimit$$inlined$sortedBy$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/storage/ReplayStorage.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/timeline/TimelineCollector.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/tracking/DialogTouchObserver$start$runnable$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/tracking/DialogTouchObserver.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/tracking/InteractionTracker.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/tracking/NativeTouchInterceptor.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/tracking/ScreenTracker.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/transport/ReplayTransport$UploadResult.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/transport/ReplayTransport$upload$2.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/transport/ReplayTransport.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/voice/VoiceRecorder$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/voice/VoiceRecorder$Result.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/voice/VoiceRecorder.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/voice/VoiceTranscriber$TranscriptResult.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/voice/VoiceTranscriber$listener$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/replaysdk/voice/VoiceTranscriber.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/ScaleBunPackage$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/ScaleBunPackage.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/crash/ScaleBunCrashModule$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/crash/ScaleBunCrashModule.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/crash/ScaleBunCrashPackage.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/crash/ScaleBunCrashSpec.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/engage/ScaleBunEngageModule$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/engage/ScaleBunEngageModule$WindowInsetEdges.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/engage/ScaleBunEngageModule$shakeListener$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/engage/ScaleBunEngageModule.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/engage/ScaleBunEngagePackage.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/engage/ScaleBunNotificationPresenter.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/ota/ScaleBunOtaModule$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/ota/ScaleBunOtaModule.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/ota/ScaleBunOtaSpec.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/ota/SlotManager$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/ota/SlotManager.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/performance/PerformanceModule$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/performance/PerformanceModule$coreListener$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/performance/PerformanceModule.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/performance/PerformanceSpec.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/referrer/ScaleBunInstallReferrerModule$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/referrer/ScaleBunInstallReferrerModule$getInstallReferrer$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/referrer/ScaleBunInstallReferrerModule.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/referrer/ScaleBunInstallReferrerSpec.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/storage/ScaleBunStorageModule$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/storage/ScaleBunStorageModule.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/rn/storage/ScaleBunStorageSpec.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/sdk/BuildConfig.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/spec/NativeReplaySdkSpec.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/spec/NativeScaleBunCrashSpec.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/spec/NativeScaleBunInstallReferrerSpec.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/spec/NativeScaleBunOtaSpec.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/spec/NativeScaleBunPerformanceSpec.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/spec/NativeScaleBunProfilerSpec.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/spec/NativeScaleBunStorageSpec.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/storage/KvFileStore$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/scalebun/storage/KvFileStore.class +0 -0
- package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt +0 -1
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.s +0 -1
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab +0 -2
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.s +0 -1
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
- package/android/build/outputs/logs/manifest-merger-debug-report.txt +0 -25
- package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
- package/android/build/tmp/kotlin-classes/debug/META-INF/scalebun_react-native_debug.kotlin_module +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/core/crash/CrashStorage.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/core/crash/NativeCrashHandler$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/core/crash/NativeCrashHandler.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/core/performance/ANRWatchdog$HangInfo.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/core/performance/ANRWatchdog.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/core/performance/AppStartCollector$AppStartInfo.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/core/performance/AppStartCollector$Breakdown.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/core/performance/AppStartCollector$start$1.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/core/performance/AppStartCollector.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/core/performance/FrameMetricsCollector$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/core/performance/FrameMetricsCollector$FrameMetricsSnapshot.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/core/performance/FrameMetricsCollector$start$1.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/core/performance/FrameMetricsCollector$startChoreographerFallback$1.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/core/performance/FrameMetricsCollector.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/core/performance/PerformanceCore$Listener.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/core/performance/PerformanceCore.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/profiler/ProfilerModule$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/profiler/ProfilerModule.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/profiler/ProfilerPackage.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/profiler/ProfilerSpec.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/profiler/collectors/CpuCollector.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/profiler/collectors/IncidentDetector.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/profiler/collectors/MemoryCollector.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/profiler/collectors/RenderCollector$frameCallback$1.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/profiler/collectors/RenderCollector.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/profiler/collectors/SamplerScheduler.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/profiler/collectors/SamplerSchedulerKt.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/profiler/collectors/ThreadCollector$WhenMappings.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/profiler/collectors/ThreadCollector.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/ReplaySdkModule$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/ReplaySdkModule$registerConnectivity$cb$1.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/ReplaySdkModule.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/ReplaySdkPackage.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/ReplaySdkSpec.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/capture/CaptureReason$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/capture/CaptureReason.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/capture/FrameCaptureManager$startFrequencyTimer$1.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/capture/FrameCaptureManager.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/capture/FrameCaptureScheduler$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/capture/FrameCaptureScheduler$FrameRequest.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/capture/FrameCaptureScheduler.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/capture/UiStabilityDetector$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/capture/UiStabilityDetector$SettleWatch.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/capture/UiStabilityDetector$StabilityWatch.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/capture/UiStabilityDetector.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/core/CaptureMode$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/core/CaptureMode.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/core/ReplayConfig$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/core/ReplayConfig.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/core/ReplayLogger.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/core/ScreenshotQuality$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/core/ScreenshotQuality.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/core/SessionIdGenerator.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/core/SessionState.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/models/ReplayFrame.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/models/ReplaySession.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/models/TimelineEvent.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/outbox/NativeOutbox$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/outbox/NativeOutbox$enforceLimits$lambda$37$$inlined$sortedBy$1.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/outbox/NativeOutbox.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/outbox/OutboxUploader$NetResult$NetworkError.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/outbox/OutboxUploader$NetResult$Response.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/outbox/OutboxUploader$NetResult.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/outbox/OutboxUploader$Outcome.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/outbox/OutboxUploader$WhenMappings.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/outbox/OutboxUploader.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/privacy/PrivacyMaskProcessor.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/session/SessionManager.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/storage/ReplayStorage$enforceStorageLimit$$inlined$sortedBy$1.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/storage/ReplayStorage.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/timeline/TimelineCollector.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/tracking/DialogTouchObserver$start$runnable$1.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/tracking/DialogTouchObserver.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/tracking/InteractionTracker.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/tracking/NativeTouchInterceptor.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/tracking/ScreenTracker.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/transport/ReplayTransport$UploadResult.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/transport/ReplayTransport$upload$2.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/transport/ReplayTransport.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/voice/VoiceRecorder$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/voice/VoiceRecorder$Result.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/voice/VoiceRecorder.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/voice/VoiceTranscriber$TranscriptResult.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/voice/VoiceTranscriber$listener$1.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/replaysdk/voice/VoiceTranscriber.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/ScaleBunPackage$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/ScaleBunPackage.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/crash/ScaleBunCrashModule$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/crash/ScaleBunCrashModule.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/crash/ScaleBunCrashPackage.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/crash/ScaleBunCrashSpec.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/engage/ScaleBunEngageModule$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/engage/ScaleBunEngageModule$WindowInsetEdges.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/engage/ScaleBunEngageModule$shakeListener$1.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/engage/ScaleBunEngageModule.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/engage/ScaleBunEngagePackage.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/engage/ScaleBunNotificationPresenter.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/ota/ScaleBunOtaModule$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/ota/ScaleBunOtaModule.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/ota/ScaleBunOtaSpec.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/ota/SlotManager$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/ota/SlotManager.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/performance/PerformanceModule$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/performance/PerformanceModule$coreListener$1.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/performance/PerformanceModule.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/performance/PerformanceSpec.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/referrer/ScaleBunInstallReferrerModule$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/referrer/ScaleBunInstallReferrerModule$getInstallReferrer$1.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/referrer/ScaleBunInstallReferrerModule.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/referrer/ScaleBunInstallReferrerSpec.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/storage/ScaleBunStorageModule$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/storage/ScaleBunStorageModule.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/rn/storage/ScaleBunStorageSpec.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/storage/KvFileStore$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/scalebun/storage/KvFileStore.class +0 -0
|
@@ -1,1270 +1,1272 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ScaleBun SDK — Engage Prompt Provider (campaign renderer core, D4)
|
|
3
|
-
*
|
|
4
|
-
* Wraps the host app and owns the campaign-render lifecycle for the shared
|
|
5
|
-
* cross-platform JS overlay:
|
|
6
|
-
* 1. on a trigger (app-controlled via `showEngagePrompt()` and/or the campaign's
|
|
7
|
-
* own `trigger` from config), calls `facade.engage.fetchConfig()`,
|
|
8
|
-
* 2. runs the throttle/decision core (`selectCampaignToRender`) to pick which
|
|
9
|
-
* campaign — if any — is eligible, honoring frequency caps,
|
|
10
|
-
* 3. mounts the parameterized `EngagePromptView` (Open/Closed: NPS now,
|
|
11
|
-
* ratings/feedback/survey later via the renderer registry),
|
|
12
|
-
* 4. on submit → `facade.engage.submitResponse({ surveyId, score, text })`
|
|
13
|
-
* (transport stamps `responseId` UUID + `schemaVersion` per contract),
|
|
14
|
-
* records the impression as completed, and emits an in-app dismiss/submit
|
|
15
|
-
* tracking event,
|
|
16
|
-
* 5. on dismiss → `facade.engage.trackEvent` with a `dismiss` event.
|
|
17
|
-
*
|
|
18
|
-
* The provider depends only on the `engage` namespace shape — NOT the whole
|
|
19
|
-
* facade — so it stays decoupled and testable, and reuses the existing transport
|
|
20
|
-
* (no second HTTP path).
|
|
21
|
-
*
|
|
22
|
-
* IN-APP MESSAGES (the second Engage family, §2.4/§2.5) are surfaced by this SAME
|
|
23
|
-
* provider — NOT a parallel one. `showInAppMessage()` fetches the config, picks an
|
|
24
|
-
* eligible message from `inAppMessages[]` (shared throttle store), and mounts the
|
|
25
|
-
* config-driven `EngageInAppView` (banner/modal/overlay). Events: `impression` on
|
|
26
|
-
* show, `click` on CTA tap (the resolved deep link is surfaced to the host via
|
|
27
|
-
* `onInAppDeepLink` — the SDK never opens URLs), `dismiss` on close.
|
|
28
|
-
*
|
|
29
|
-
* PRECEDENCE (campaign vs in-app): a campaign prompt wins the screen. If a
|
|
30
|
-
* campaign prompt is already visible, `showInAppMessage()` is a no-op (returns
|
|
31
|
-
* false) and the mounted in-app view is hidden while a campaign is up, so the two
|
|
32
|
-
* families never fight for the screen.
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
import React, {
|
|
36
|
-
createContext,
|
|
37
|
-
useContext,
|
|
38
|
-
useCallback,
|
|
39
|
-
useEffect,
|
|
40
|
-
useMemo,
|
|
41
|
-
useRef,
|
|
42
|
-
useState,
|
|
43
|
-
type ReactNode,
|
|
44
|
-
type ReactElement,
|
|
45
|
-
} from 'react';
|
|
46
|
-
import { Linking, Platform } from 'react-native';
|
|
47
|
-
import { logger } from '../../core/logger/internalLogger';
|
|
48
|
-
import { installEngageTriggerEngine } from './engageTriggerEngine';
|
|
49
|
-
import { appLifecycle } from '../../core/lifecycle/appLifecycle';
|
|
50
|
-
import { getDeviceId } from '../../core/id/deviceId';
|
|
51
|
-
import { ReplaySdk } from '../replay/public/api';
|
|
52
|
-
import { SessionManager } from '../session/SessionManager';
|
|
53
|
-
import {
|
|
54
|
-
EngagePromptView,
|
|
55
|
-
type EngagePromptResult,
|
|
56
|
-
type EngageSubmitStatus,
|
|
57
|
-
type RatingPromptConfig,
|
|
58
|
-
} from './EngagePromptView';
|
|
59
|
-
import { EngageInAppView, type InAppMechanicInteraction } from './EngageInAppView';
|
|
60
|
-
import { EngageAnchorProvider } from './EngageAnchor';
|
|
61
|
-
import {
|
|
62
|
-
EngageInlinePlacementProvider,
|
|
63
|
-
createEngageInlinePlacementRegistry,
|
|
64
|
-
resolveEngageInlinePlacement,
|
|
65
|
-
type EngageInlineDelivery,
|
|
66
|
-
} from './EngageInlinePlacement';
|
|
67
|
-
import { resolveInAppPresentation } from './engageVariantResolver';
|
|
68
|
-
import { shouldTrackInAppCta } from './engageOutcome';
|
|
69
|
-
import type { SubmitStage } from './EngageTransport';
|
|
70
|
-
import {
|
|
71
|
-
EngageThrottleStore,
|
|
72
|
-
selectCampaignToRender,
|
|
73
|
-
selectInAppToRender,
|
|
74
|
-
selectInAppVariant,
|
|
75
|
-
selectLatestUnseenTest,
|
|
76
|
-
testRunIdOf,
|
|
77
|
-
} from './engageThrottle';
|
|
78
|
-
import { EngageTestSeenStore } from './engageTestSeenStore';
|
|
79
|
-
import type {
|
|
80
|
-
EngageAttachmentDraft,
|
|
81
|
-
EngageCampaignConfig,
|
|
82
|
-
EngageCampaignType,
|
|
83
|
-
EngageConfigContext,
|
|
84
|
-
EngageConfigResponse,
|
|
85
|
-
EngageEventInput,
|
|
86
|
-
InAppGameRequestHandler,
|
|
87
|
-
EngageResponseInput,
|
|
88
|
-
InAppMessageConfig,
|
|
89
|
-
InAppRenderSpec,
|
|
90
|
-
InAppVariantId,
|
|
91
|
-
RatingFunnelEventDims,
|
|
92
|
-
RatingFunnelEventInput,
|
|
93
|
-
RatingFunnelEventType,
|
|
94
|
-
SurveyAnswer,
|
|
95
|
-
SurveyImpressionInput,
|
|
96
|
-
} from './engageTypes';
|
|
97
|
-
|
|
98
|
-
/** Client-generated UUID for app-rating idempotency (D8: `clientRatingId`). */
|
|
99
|
-
function ratingUuid(): string {
|
|
100
|
-
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
101
|
-
const r = (Math.random() * 16) | 0;
|
|
102
|
-
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
103
|
-
return v.toString(16);
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/** Preserve a multi-question survey answer in the keyed wire shape (§1.4). */
|
|
108
|
-
export function toWireAnswers(
|
|
109
|
-
answers: SurveyAnswer[],
|
|
110
|
-
): { key: string; value: string | number | string[] }[] {
|
|
111
|
-
return answers.map((a) => ({
|
|
112
|
-
key: a.key,
|
|
113
|
-
value: a.value,
|
|
114
|
-
}));
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Resolve the canonical session id for response linkage (contract §1/§7).
|
|
119
|
-
* Primary source is `SessionManager.currentSessionId` — the always-on analytics
|
|
120
|
-
* session id (`rs-…`) that the replay recording attaches to (and that `/sessions/:id`
|
|
121
|
-
* keys on). `ReplaySdk.sessionId` (the orchestrator's recording id) is only set
|
|
122
|
-
* while a recording is mid-flight and reads `null` at submit time, so it is a
|
|
123
|
-
* fallback, not the primary. Returns `undefined` (not `null`) so the optional wire
|
|
124
|
-
* field is simply omitted when no session is active.
|
|
125
|
-
*/
|
|
126
|
-
function currentSessionId(): string | undefined {
|
|
127
|
-
return (
|
|
128
|
-
SessionManager.getExistingInstance()?.currentSessionId ??
|
|
129
|
-
ReplaySdk.sessionId ??
|
|
130
|
-
undefined
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* The host app version for by-version analytics (contract §1). Read from the
|
|
136
|
-
* SAME synchronous source the SDK's rating lane already uses
|
|
137
|
-
* (`SessionManager.currentSessionMetadata.appVersion`, populated from native
|
|
138
|
-
* device info) — NOT hardcoded, and NOT the SDK build version. `undefined` when
|
|
139
|
-
* no session metadata is available yet, so the optional field is omitted.
|
|
140
|
-
*/
|
|
141
|
-
function currentAppVersion(): string | undefined {
|
|
142
|
-
return SessionManager.getExistingInstance()?.currentSessionMetadata?.appVersion ?? undefined;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Device platform as the `'android' | 'ios'` wire union (contract §1). Shared JS
|
|
147
|
-
* path — NOT platform-gated — so Android and iOS both stamp their own value.
|
|
148
|
-
* `Platform.OS` also yields `'windows' | 'macos' | 'web'`; those are out of the
|
|
149
|
-
* SDK's mobile scope and intentionally collapse to `undefined` (field omitted).
|
|
150
|
-
*/
|
|
151
|
-
function currentPlatform(): 'android' | 'ios' | undefined {
|
|
152
|
-
return Platform.OS === 'android' || Platform.OS === 'ios' ? Platform.OS : undefined;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Build the config-serve context (contract §1.3 query). ALWAYS carries `deviceId`
|
|
157
|
-
* — the backend keys per-device test previews on it, so omitting it would hide a
|
|
158
|
-
* "Send Test" preview from the very device it was queued for (T1). `platform`/
|
|
159
|
-
* `appVersion` ride along for server-side targeting; both honest, both omitted when
|
|
160
|
-
* unresolved. A caller-supplied `context` (manual show) overrides field-by-field.
|
|
161
|
-
*/
|
|
162
|
-
function buildConfigContext(
|
|
163
|
-
engage: EngageRendererFacade,
|
|
164
|
-
override?: EngageConfigContext,
|
|
165
|
-
): EngageConfigContext {
|
|
166
|
-
const identifiedUserId = engage.getIdentifiedUserId?.();
|
|
167
|
-
return {
|
|
168
|
-
deviceId: getDeviceId(),
|
|
169
|
-
...(currentPlatform() ? { platform: currentPlatform() } : {}),
|
|
170
|
-
...(currentAppVersion() ? { appVersion: currentAppVersion() } : {}),
|
|
171
|
-
...(identifiedUserId ? { endUserId: identifiedUserId } : {}),
|
|
172
|
-
...override,
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Build the rating-funnel breakdown dimensions (ratings-rebuild CONTRACT §1.2 `dims`)
|
|
178
|
-
* from the SAME live session metadata the response builder reads — NOT hardcoded.
|
|
179
|
-
* Only honest, present values are included; `country`/`locale`/`acquisitionSource`
|
|
180
|
-
* are intentionally omitted here (no on-device source yet) so the backend reports
|
|
181
|
-
* them as absent rather than fabricated.
|
|
182
|
-
*/
|
|
183
|
-
function currentRatingDims(): RatingFunnelEventDims {
|
|
184
|
-
const meta = SessionManager.getExistingInstance()?.currentSessionMetadata;
|
|
185
|
-
const platform = currentPlatform();
|
|
186
|
-
return {
|
|
187
|
-
...(platform ? { platform } : {}),
|
|
188
|
-
...(meta?.appVersion ? { appVersion: meta.appVersion } : {}),
|
|
189
|
-
...(meta?.osVersion ? { osVersion: meta.osVersion } : {}),
|
|
190
|
-
...(meta?.deviceModel ? { deviceModel: meta.deviceModel } : {}),
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* The slice of the SDK facade the renderer consumes (the `engage` namespace).
|
|
196
|
-
* Matching this shape — rather than importing the facade — keeps the renderer a
|
|
197
|
-
* pure consumer of the foundation transport and trivially testable.
|
|
198
|
-
*/
|
|
199
|
-
export interface EngageRendererFacade {
|
|
200
|
-
/** External user id last supplied through ScaleBun.identify(). */
|
|
201
|
-
getIdentifiedUserId?: () => string | undefined;
|
|
202
|
-
fetchConfig: (context?: EngageConfigContext) => Promise<EngageConfigResponse | null>;
|
|
203
|
-
trackCoachmarkEvent?: (name: string, properties: Record<string, unknown>) => void;
|
|
204
|
-
submitResponse: (input: EngageResponseInput) => void;
|
|
205
|
-
/**
|
|
206
|
-
* [P3-e] Submit a response with native attachments (screenshot/voice). Optional
|
|
207
|
-
* so a host wired to an older facade still renders prompts (media silently
|
|
208
|
-
* degrades to a plain response).
|
|
209
|
-
*/
|
|
210
|
-
submitResponseWithAttachments?: (
|
|
211
|
-
input: EngageResponseInput,
|
|
212
|
-
attachments: EngageAttachmentDraft[],
|
|
213
|
-
) => void;
|
|
214
|
-
/**
|
|
215
|
-
* [Slice D5] CONFIRMED submit used by the reusable submitting→success→error state
|
|
216
|
-
* machine: resolves only on real server persistence, rejects on failure, idempotent
|
|
217
|
-
* on `responseId`. Optional so an older facade still renders prompts (falls back to
|
|
218
|
-
* the fire-and-forget lanes, which resolve immediately).
|
|
219
|
-
*/
|
|
220
|
-
submitResponseConfirmed?: (
|
|
221
|
-
input: EngageResponseInput,
|
|
222
|
-
attachments: EngageAttachmentDraft[],
|
|
223
|
-
opts: { responseId: string; onStage?: (stage: SubmitStage) => void },
|
|
224
|
-
) => Promise<void>;
|
|
225
|
-
trackEvent: (input: EngageEventInput) => void;
|
|
226
|
-
trackSurveyImpression?: (input: SurveyImpressionInput) => void;
|
|
227
|
-
/**
|
|
228
|
-
* Force-flush queued in-app events immediately (bypassing the batch threshold/timer).
|
|
229
|
-
* Called right after a TEST preview's impression/dismiss ACK so the backend consumes
|
|
230
|
-
* the one-shot preview row before the app can be backgrounded/killed — otherwise a
|
|
231
|
-
* still-`delivered` row re-serves on the next reopen. Optional: an older facade simply
|
|
232
|
-
* relies on the periodic flush (eventual consistency).
|
|
233
|
-
*/
|
|
234
|
-
flushEvents?: () => void;
|
|
235
|
-
/**
|
|
236
|
-
* Submit a 1–5 app-store rating via the EXISTING rating lane (NOT
|
|
237
|
-
* submitResponse — D1 keeps app-ratings a distinct funnel). The provider
|
|
238
|
-
* passes a client `clientRatingId` for idempotency (D8). Optional so a host
|
|
239
|
-
* that never shows RATING_PROMPT need not supply it.
|
|
240
|
-
*/
|
|
241
|
-
submitRating?: (input: {
|
|
242
|
-
rating: number;
|
|
243
|
-
comment?: string;
|
|
244
|
-
source?: 'in_app' | 'prompt' | 'manual';
|
|
245
|
-
clientRatingId?: string;
|
|
246
|
-
}) => unknown;
|
|
247
|
-
/**
|
|
248
|
-
* Emit a rating-funnel tracking fact (ratings-rebuild CONTRACT §1.2) — eligible/
|
|
249
|
-
* shown/dismissed/selected/redirect. NOT a campaign response (D1). Optional so an
|
|
250
|
-
* older facade still renders rating prompts (the funnel just goes uninstrumented).
|
|
251
|
-
*/
|
|
252
|
-
emitRatingEvent?: (input: RatingFunnelEventInput) => void;
|
|
253
|
-
/**
|
|
254
|
-
* Trigger the native in-app review sheet (D5). Resolves `true` only when the OS
|
|
255
|
-
* flow ran/resolved after a positive route, so the provider emits
|
|
256
|
-
* `store_redirect_clicked` solely on a `true` result. Optional/fail-soft.
|
|
257
|
-
*/
|
|
258
|
-
requestStoreReview?: () => Promise<boolean>;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* Host-app RATING_PROMPT routing config. The store deeplink is NEVER hardcoded —
|
|
263
|
-
* the host supplies either a static `storeUrl` or an `onHighRating` callback (e.g.
|
|
264
|
-
* `Linking.openURL(...)` / native `requestReview()`), and an `onLowRating` for the
|
|
265
|
-
* feedback hand-off. The provider only decides WHICH callback to invoke.
|
|
266
|
-
*/
|
|
267
|
-
export interface EngageRatingRouting extends RatingPromptConfig {
|
|
268
|
-
/** App-store deeplink opened on a high rating (host owns the navigation). */
|
|
269
|
-
storeUrl?: string;
|
|
270
|
-
/** Called on a high rating (>= threshold). Receives the resolved store URL if set. */
|
|
271
|
-
onHighRating?: (info: { rating: number; campaign: EngageCampaignConfig; storeUrl?: string }) => void;
|
|
272
|
-
/** Called on a low rating when routing to feedback (host opens its form). */
|
|
273
|
-
onLowRating?: (info: { rating: number; campaign: EngageCampaignConfig }) => void;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
export interface ShowEngagePromptOptions {
|
|
277
|
-
/** Restrict to specific campaign types. Defaults to `['NPS']` (NPS-first slice). */
|
|
278
|
-
types?: EngageCampaignType[];
|
|
279
|
-
/** Match a campaign's `targetScreen` to the current screen. */
|
|
280
|
-
screen?: string;
|
|
281
|
-
/**
|
|
282
|
-
* Restrict to campaigns whose `trigger` equals this value (behavioral-trigger
|
|
283
|
-
* path, e.g. `'screen_exit'`). Omitted ⇒ trigger-agnostic (manual fire).
|
|
284
|
-
*/
|
|
285
|
-
trigger?: string;
|
|
286
|
-
/** Event name for `custom_event` / `after_purchase` (matches `triggerConfig.event`). */
|
|
287
|
-
event?: string;
|
|
288
|
-
/** Action label for `failed_action` (matches `triggerConfig.action`). */
|
|
289
|
-
action?: string;
|
|
290
|
-
/** Fired `time_in_app` threshold, used to select only that configured timer. */
|
|
291
|
-
seconds?: number;
|
|
292
|
-
/** App/user context forwarded to the config fetch for server-side targeting. */
|
|
293
|
-
context?: EngageConfigContext;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
export interface ShowInAppMessageOptions {
|
|
297
|
-
/** Match a message's `targetScreen` to the current screen. */
|
|
298
|
-
screen?: string;
|
|
299
|
-
/**
|
|
300
|
-
* Restrict to messages whose `trigger` equals this value (behavioral-trigger
|
|
301
|
-
* path, e.g. `'session_start'`). Omitted ⇒ trigger-agnostic (manual host call).
|
|
302
|
-
*/
|
|
303
|
-
trigger?: string;
|
|
304
|
-
/** Fired business/custom event name, matched against `message.eventName`. */
|
|
305
|
-
event?: string;
|
|
306
|
-
/** Fired action value for forward-compatible action-specific messages. */
|
|
307
|
-
action?: string;
|
|
308
|
-
/** Fired `time_delay` threshold, used to select only that configured message. */
|
|
309
|
-
seconds?: number;
|
|
310
|
-
/** App/user context forwarded to the config fetch for server-side targeting. */
|
|
311
|
-
context?: EngageConfigContext;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* The host's deep-link sink for an in-app CTA tap. The SDK NEVER opens a URL — it
|
|
316
|
-
* hands the resolved `deepLink` (and full message/cta) to the host, which decides
|
|
317
|
-
* how to navigate (e.g. `Linking.openURL` / a router push). Only fired for a CTA
|
|
318
|
-
* whose `action` resolves to a link with a `deepLink`.
|
|
319
|
-
*/
|
|
320
|
-
export type InAppDeepLinkHandler = (info: {
|
|
321
|
-
message: InAppMessageConfig;
|
|
322
|
-
cta: NonNullable<InAppRenderSpec['cta']>;
|
|
323
|
-
deepLink: string;
|
|
324
|
-
}) => void;
|
|
325
|
-
|
|
326
|
-
/** Imperative controller a host app uses to trigger a prompt / in-app message. */
|
|
327
|
-
export interface EngagePromptController {
|
|
328
|
-
/** Fetch config, pick an eligible campaign, and show it. Returns whether one was shown. */
|
|
329
|
-
showEngagePrompt: (options?: ShowEngagePromptOptions) => Promise<boolean>;
|
|
330
|
-
/** Dismiss the currently visible prompt (no response submitted). */
|
|
331
|
-
dismissEngagePrompt: () => void;
|
|
332
|
-
/**
|
|
333
|
-
* Fetch config, pick an eligible in-app message (`inAppMessages[]`), and show
|
|
334
|
-
* it. Returns whether one was shown. PRECEDENCE: a campaign prompt already on
|
|
335
|
-
* screen wins — an in-app message is NOT shown over it (see provider doc).
|
|
336
|
-
*/
|
|
337
|
-
showInAppMessage: (options?: ShowInAppMessageOptions) => Promise<boolean>;
|
|
338
|
-
/** Dismiss the currently visible in-app message (emits a `dismiss` event). */
|
|
339
|
-
dismissInAppMessage: () => void;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
const EngagePromptContext = createContext<EngagePromptController | null>(null);
|
|
343
|
-
|
|
344
|
-
export interface EngagePromptProviderProps {
|
|
345
|
-
/** The SDK facade's `engage` namespace (e.g. `ScaleBun.engage`). */
|
|
346
|
-
engage: EngageRendererFacade;
|
|
347
|
-
/** Default campaign types to consider. Defaults to NPS-first. */
|
|
348
|
-
defaultTypes?: EngageCampaignType[];
|
|
349
|
-
/**
|
|
350
|
-
* RATING_PROMPT routing config (host-supplied). The app-store deeplink and
|
|
351
|
-
* feedback hand-off are NEVER hardcoded in the SDK — supplied here.
|
|
352
|
-
*/
|
|
353
|
-
ratingRouting?: EngageRatingRouting;
|
|
354
|
-
/**
|
|
355
|
-
* Host sink for an in-app message CTA deep link. The SDK never opens URLs —
|
|
356
|
-
* it surfaces the resolved `deepLink` here for the host to navigate. Optional:
|
|
357
|
-
* a host that never uses link-action CTAs need not supply it.
|
|
358
|
-
*/
|
|
359
|
-
onInAppDeepLink?: InAppDeepLinkHandler;
|
|
360
|
-
/**
|
|
361
|
-
* Required when a production gamified campaign is used. The SDK calls this
|
|
362
|
-
* only at play/load/check-in/quiz resolution time; the host's authenticated
|
|
363
|
-
* backend owns eligibility, granting, and the returned result.
|
|
364
|
-
*/
|
|
365
|
-
onInAppGameRequest?: InAppGameRequestHandler;
|
|
366
|
-
/**
|
|
367
|
-
* DEV/TEST ONLY — poll interval (ms) for queued test previews while the app is
|
|
368
|
-
* already foregrounded. `checkForPreview` runs on mount + every AppState→active,
|
|
369
|
-
* which covers "reopen the app". But if you press "Send Test" while the app is
|
|
370
|
-
* ALREADY open and in the foreground, there is no background→foreground edge to
|
|
371
|
-
* trigger a refetch. Setting e.g. `previewPollMs={4000}` makes a warm, foreground
|
|
372
|
-
* app pick up a Send Test within a few seconds with no app switch. Leave UNSET in
|
|
373
|
-
* production (0/undefined ⇒ no polling — the foreground/cold-start fetch is enough).
|
|
374
|
-
*/
|
|
375
|
-
previewPollMs?: number;
|
|
376
|
-
children: ReactNode;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
const DEFAULT_TYPES: EngageCampaignType[] = ['NPS'];
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* Provider that mounts the shared overlay and exposes the imperative controller
|
|
383
|
-
* via `useEngagePrompt()`.
|
|
384
|
-
*/
|
|
385
|
-
export function EngagePromptProvider({
|
|
386
|
-
engage,
|
|
387
|
-
defaultTypes,
|
|
388
|
-
ratingRouting,
|
|
389
|
-
onInAppDeepLink,
|
|
390
|
-
onInAppGameRequest,
|
|
391
|
-
previewPollMs,
|
|
392
|
-
children,
|
|
393
|
-
}: EngagePromptProviderProps): ReactElement {
|
|
394
|
-
const [active, setActive] = useState<EngageCampaignConfig | null>(null);
|
|
395
|
-
const [activeInApp, setActiveInApp] = useState<InAppMessageConfig | null>(null);
|
|
396
|
-
const [inlineFallbackMessageId, setInlineFallbackMessageId] = useState<string | null>(null);
|
|
397
|
-
const [inlinePlacementRevision, setInlinePlacementRevision] = useState(0);
|
|
398
|
-
const inlinePlacementRegistry = useMemo(createEngageInlinePlacementRegistry, []);
|
|
399
|
-
const shownInAppMessageIdRef = useRef<string | null>(null);
|
|
400
|
-
// Resolved A/B arm for the active in-app message (D8/J6). Held in a ref: it is
|
|
401
|
-
// render-stable metadata (the chosen `spec` drives the view, the `variant` id
|
|
402
|
-
// rides the lifecycle events) and must not perturb the precedence that keys off
|
|
403
|
-
// `activeInApp`. `null` when no message is active (or it has no experiment).
|
|
404
|
-
const activeInAppVariantRef = useRef<
|
|
405
|
-
{ variant: InAppVariantId; spec: InAppRenderSpec } | null
|
|
406
|
-
>(null);
|
|
407
|
-
// Show-time screen of the currently-active campaign prompt (contract §1
|
|
408
|
-
// `screen`). Held in a ref alongside `active` — it is render-irrelevant
|
|
409
|
-
// metadata read only at submit, so it needs no re-render and must not perturb
|
|
410
|
-
// the campaign-vs-in-app precedence which keys off `active`/`activeInApp`.
|
|
411
|
-
const activeScreenRef = useRef<string | undefined>(undefined);
|
|
412
|
-
const surveyStartedRef = useRef<string | null>(null);
|
|
413
|
-
// [T1] Test previews bypass the throttle store and the backend re-serves them on
|
|
414
|
-
// EVERY config poll until TTL — great for "reopen the app and see it again", but it
|
|
415
|
-
// means a dismissed preview would re-appear on the next warm poll. This session set
|
|
416
|
-
// records previews the user already closed (dismiss/CTA) so we don't re-show the SAME
|
|
417
|
-
// one. It is in-memory only: a cold restart clears it, so reopening the app still
|
|
418
|
-
// shows the queued test (the intended QA behavior).
|
|
419
|
-
const consumedPreviewIds = useRef<Set<string>>(new Set());
|
|
420
|
-
// [T1] Persistent dedupe for ONE-SHOT test delivery — survives cold restarts (unlike
|
|
421
|
-
// consumedPreviewIds above). A testRunId is recorded here AFTER it actually renders, so
|
|
422
|
-
// reopening the app does NOT re-show a test the device already displayed. This is the
|
|
423
|
-
// fix for "close/open and the old test re-appears, and they stack up". Separate from the
|
|
424
|
-
// throttle store so production frequency caps never block a fresh test and vice-versa.
|
|
425
|
-
const seenTestsRef = useRef<EngageTestSeenStore | null>(null);
|
|
426
|
-
if (seenTestsRef.current === null) {
|
|
427
|
-
seenTestsRef.current = new EngageTestSeenStore();
|
|
428
|
-
}
|
|
429
|
-
// One persistent throttle store for the provider lifetime — SHARED by campaigns
|
|
430
|
-
// and in-app messages so both honor the same per-id frequency caps.
|
|
431
|
-
const storeRef = useRef<EngageThrottleStore | null>(null);
|
|
432
|
-
if (storeRef.current === null) {
|
|
433
|
-
storeRef.current = new EngageThrottleStore();
|
|
434
|
-
}
|
|
435
|
-
const types = defaultTypes ?? DEFAULT_TYPES;
|
|
436
|
-
|
|
437
|
-
// ─── Reusable submit state machine (Slice D5) ────────────────────────────
|
|
438
|
-
// ONE machine for EVERY question type. `responseIdRef` is the idempotency key,
|
|
439
|
-
// generated once per prompt and REUSED on retry so a re-send can't duplicate.
|
|
440
|
-
// `submitCtxRef` holds the campaign+result so retry re-runs the same submit.
|
|
441
|
-
const [submitStatus, setSubmitStatus] = useState<EngageSubmitStatus>({ phase: 'idle' });
|
|
442
|
-
const responseIdRef = useRef<string | null>(null);
|
|
443
|
-
const submitCtxRef = useRef<{ campaign: EngageCampaignConfig; result: EngagePromptResult } | null>(null);
|
|
444
|
-
const successTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
445
|
-
|
|
446
|
-
const resetSubmit = useCallback((): void => {
|
|
447
|
-
if (successTimerRef.current) {
|
|
448
|
-
clearTimeout(successTimerRef.current);
|
|
449
|
-
successTimerRef.current = null;
|
|
450
|
-
}
|
|
451
|
-
responseIdRef.current = null;
|
|
452
|
-
submitCtxRef.current = null;
|
|
453
|
-
setSubmitStatus({ phase: 'idle' });
|
|
454
|
-
}, []);
|
|
455
|
-
|
|
456
|
-
// Single campaign tracking lane (mirrors trackInApp). `impression` on show,
|
|
457
|
-
// `completion` on submit, `dismiss` on close — the §2.5 analytics events that
|
|
458
|
-
// back the response-rate / completion KPIs (P3-e #2). Distinct from the local
|
|
459
|
-
// throttle store, which only counts impressions for frequency caps.
|
|
460
|
-
const trackCampaign = useCallback(
|
|
461
|
-
(campaign: EngageCampaignConfig, eventType: 'impression' | 'completion' | 'dismiss') => {
|
|
462
|
-
try {
|
|
463
|
-
engage.trackEvent({
|
|
464
|
-
campaignId: campaign.id,
|
|
465
|
-
channel: 'inapp',
|
|
466
|
-
type: eventType,
|
|
467
|
-
deviceId: getDeviceId(),
|
|
468
|
-
});
|
|
469
|
-
} catch (err) {
|
|
470
|
-
logger.debug('[Engage] trackEvent failed:', (err as Error)?.message);
|
|
471
|
-
}
|
|
472
|
-
},
|
|
473
|
-
[engage],
|
|
474
|
-
);
|
|
475
|
-
|
|
476
|
-
const trackSurveyStage = useCallback(
|
|
477
|
-
(campaign: EngageCampaignConfig, stage: 'shown' | 'started'): void => {
|
|
478
|
-
if (campaign.type === 'RATING_PROMPT' || campaign.type === 'RATINGS_PROMPT') return;
|
|
479
|
-
try {
|
|
480
|
-
engage.trackSurveyImpression?.({
|
|
481
|
-
surveyId: campaign.id,
|
|
482
|
-
stage,
|
|
483
|
-
sessionId: currentSessionId(),
|
|
484
|
-
deviceId: getDeviceId(),
|
|
485
|
-
platform: currentPlatform(),
|
|
486
|
-
appVersion: currentAppVersion(),
|
|
487
|
-
screen: activeScreenRef.current,
|
|
488
|
-
});
|
|
489
|
-
} catch (err) {
|
|
490
|
-
logger.debug('[Engage] survey impression failed:', (err as Error)?.message);
|
|
491
|
-
}
|
|
492
|
-
},
|
|
493
|
-
[engage],
|
|
494
|
-
);
|
|
495
|
-
|
|
496
|
-
const isRatingType = (type: EngageCampaignType): boolean =>
|
|
497
|
-
type === 'RATING_PROMPT' || type === 'RATINGS_PROMPT';
|
|
498
|
-
|
|
499
|
-
// Rating-funnel emit lane (ratings-rebuild CONTRACT §1.2). Distinct from
|
|
500
|
-
// trackCampaign (the §2.5 in-app analytics lane) and from submitRating (the D1
|
|
501
|
-
// app-rating lane): these are dimensioned FACTS feeding the Overview funnel and
|
|
502
|
-
// are NEVER counted as responses. `stars` rides only on `rating_selected`.
|
|
503
|
-
const emitRatingFunnel = useCallback(
|
|
504
|
-
(
|
|
505
|
-
campaign: EngageCampaignConfig,
|
|
506
|
-
type: RatingFunnelEventType,
|
|
507
|
-
extra?: { stars?: number },
|
|
508
|
-
): void => {
|
|
509
|
-
try {
|
|
510
|
-
engage.emitRatingEvent?.({
|
|
511
|
-
type,
|
|
512
|
-
sessionId: currentSessionId(),
|
|
513
|
-
userId: engage.getIdentifiedUserId?.(),
|
|
514
|
-
promptId: campaign.id,
|
|
515
|
-
triggerId: campaign.trigger,
|
|
516
|
-
...(extra?.stars !== undefined ? { stars: extra.stars } : {}),
|
|
517
|
-
dims: currentRatingDims(),
|
|
518
|
-
});
|
|
519
|
-
} catch (err) {
|
|
520
|
-
logger.debug('[Engage] emitRatingEvent failed:', (err as Error)?.message);
|
|
521
|
-
}
|
|
522
|
-
},
|
|
523
|
-
[engage],
|
|
524
|
-
);
|
|
525
|
-
|
|
526
|
-
const dismissEngagePrompt = useCallback((): void => {
|
|
527
|
-
setActive((current) => {
|
|
528
|
-
if (current) {
|
|
529
|
-
trackCampaign(current, 'dismiss');
|
|
530
|
-
// Rating funnel: a close without a selection is a funnel drop.
|
|
531
|
-
if (isRatingType(current.type)) emitRatingFunnel(current, 'rating_prompt_dismissed');
|
|
532
|
-
}
|
|
533
|
-
return null;
|
|
534
|
-
});
|
|
535
|
-
activeScreenRef.current = undefined;
|
|
536
|
-
surveyStartedRef.current = null;
|
|
537
|
-
resetSubmit();
|
|
538
|
-
}, [trackCampaign, resetSubmit, emitRatingFunnel]);
|
|
539
|
-
|
|
540
|
-
// The actual submit run — used by both the first submit and a retry. Reads
|
|
541
|
-
// `submitCtxRef` + `responseIdRef` so a retry re-sends with the SAME idempotency
|
|
542
|
-
// key. Resolves to `success` ONLY on confirmed persistence; `error` on failure.
|
|
543
|
-
const runSubmit = useCallback(async (): Promise<void> => {
|
|
544
|
-
const ctx = submitCtxRef.current;
|
|
545
|
-
if (!ctx) return;
|
|
546
|
-
const { campaign, result } = ctx;
|
|
547
|
-
const store = storeRef.current;
|
|
548
|
-
const responseId = responseIdRef.current ?? (responseIdRef.current = ratingUuid());
|
|
549
|
-
|
|
550
|
-
setSubmitStatus({ phase: 'submitting', stage: 'saving' });
|
|
551
|
-
try {
|
|
552
|
-
if (isRatingType(campaign.type)) {
|
|
553
|
-
// RATING_PROMPT submits via the EXISTING app-rating lane (D1), NOT
|
|
554
|
-
// submitResponse, with a client clientRatingId for idempotency. Awaited
|
|
555
|
-
// so the loading state reflects the real round-trip.
|
|
556
|
-
const rating = typeof result.score === 'number' ? result.score : 0;
|
|
557
|
-
await Promise.resolve(
|
|
558
|
-
engage.submitRating?.({ rating, source: 'prompt', clientRatingId: responseId }),
|
|
559
|
-
);
|
|
560
|
-
// Funnel: user picked 1–5★ (carries stars). Emitted regardless of route.
|
|
561
|
-
emitRatingFunnel(campaign, 'rating_selected', { stars: rating });
|
|
562
|
-
// Routing decided by the view (`route`), executed against host-supplied
|
|
563
|
-
// callbacks/URL — the deeplink is never hardcoded.
|
|
564
|
-
if (result.route === 'store') {
|
|
565
|
-
// D5: prefer the genuinely-native in-app review sheet. `store_redirect_clicked`
|
|
566
|
-
// fires ONLY when an actual store route resolves (native review ran, or a
|
|
567
|
-
// host-supplied deeplink/callback executed) — never speculatively.
|
|
568
|
-
let redirected = false;
|
|
569
|
-
if (engage.requestStoreReview) {
|
|
570
|
-
redirected = await engage.requestStoreReview();
|
|
571
|
-
}
|
|
572
|
-
const storeUrl = campaign.storeUrl ?? ratingRouting?.storeUrl;
|
|
573
|
-
if (ratingRouting?.onHighRating) {
|
|
574
|
-
ratingRouting.onHighRating({ rating, campaign, storeUrl });
|
|
575
|
-
redirected = true;
|
|
576
|
-
} else if (!redirected && storeUrl) {
|
|
577
|
-
redirected = await Linking.openURL(storeUrl).then(() => true).catch(() => false);
|
|
578
|
-
}
|
|
579
|
-
if (redirected) emitRatingFunnel(campaign, 'store_redirect_clicked');
|
|
580
|
-
} else if (result.route === 'feedback') {
|
|
581
|
-
ratingRouting?.onLowRating?.({ rating, campaign });
|
|
582
|
-
}
|
|
583
|
-
} else {
|
|
584
|
-
// [v2] response context (contract §1): session linkage + originating
|
|
585
|
-
// screen + platform + app version. All optional; omitted when unresolved.
|
|
586
|
-
// We send ONLY the new response fact + the sessionId; replay/errors/network
|
|
587
|
-
// are NOT re-sent — the read side joins them by sessionId.
|
|
588
|
-
const input: EngageResponseInput = Array.isArray(result.answers)
|
|
589
|
-
? {
|
|
590
|
-
surveyId: campaign.id,
|
|
591
|
-
text: result.reason,
|
|
592
|
-
answers: toWireAnswers(result.answers),
|
|
593
|
-
deviceId: getDeviceId(),
|
|
594
|
-
sessionId: currentSessionId(),
|
|
595
|
-
screen: activeScreenRef.current,
|
|
596
|
-
platform: currentPlatform(),
|
|
597
|
-
appVersion: currentAppVersion(),
|
|
598
|
-
}
|
|
599
|
-
: {
|
|
600
|
-
surveyId: campaign.id,
|
|
601
|
-
score: result.score,
|
|
602
|
-
text: result.reason,
|
|
603
|
-
tags: result.tags,
|
|
604
|
-
deviceId: getDeviceId(),
|
|
605
|
-
sessionId: currentSessionId(),
|
|
606
|
-
screen: activeScreenRef.current,
|
|
607
|
-
platform: currentPlatform(),
|
|
608
|
-
appVersion: currentAppVersion(),
|
|
609
|
-
};
|
|
610
|
-
|
|
611
|
-
const drafts = result.attachments ?? [];
|
|
612
|
-
if (engage.submitResponseConfirmed) {
|
|
613
|
-
// Confirmed lane: awaits real persistence (presign+PUT bytes → response
|
|
614
|
-
// POST), reports stages, idempotent on responseId, throws on failure.
|
|
615
|
-
await engage.submitResponseConfirmed(input, drafts, {
|
|
616
|
-
responseId,
|
|
617
|
-
onStage: (stage) => setSubmitStatus({ phase: 'submitting', stage }),
|
|
618
|
-
});
|
|
619
|
-
} else if (drafts.length > 0 && engage.submitResponseWithAttachments) {
|
|
620
|
-
// Fallback (older facade): fire-and-forget — resolves immediately.
|
|
621
|
-
engage.submitResponseWithAttachments(input, drafts);
|
|
622
|
-
} else {
|
|
623
|
-
engage.submitResponse(input);
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
store?.markCompleted(campaign.id);
|
|
628
|
-
trackCampaign(campaign, 'completion');
|
|
629
|
-
setSubmitStatus({ phase: 'success' });
|
|
630
|
-
// Brief success beat, then close + reset.
|
|
631
|
-
successTimerRef.current = setTimeout(() => {
|
|
632
|
-
setActive(null);
|
|
633
|
-
activeScreenRef.current = undefined;
|
|
634
|
-
resetSubmit();
|
|
635
|
-
}, 1100);
|
|
636
|
-
} catch (err) {
|
|
637
|
-
logger.warn('[Engage] submit failed:', (err as Error)?.message);
|
|
638
|
-
setSubmitStatus({ phase: 'error', message: (err as Error)?.message });
|
|
639
|
-
}
|
|
640
|
-
}, [engage, trackCampaign, ratingRouting, resetSubmit, emitRatingFunnel]);
|
|
641
|
-
|
|
642
|
-
const handleSubmit = useCallback(
|
|
643
|
-
(campaign: EngageCampaignConfig, result: EngagePromptResult): void => {
|
|
644
|
-
// Guard double-submit: ignore re-fires once a submit is in flight or done.
|
|
645
|
-
if (submitCtxRef.current && responseIdRef.current) return;
|
|
646
|
-
submitCtxRef.current = { campaign, result };
|
|
647
|
-
void runSubmit();
|
|
648
|
-
},
|
|
649
|
-
[runSubmit],
|
|
650
|
-
);
|
|
651
|
-
|
|
652
|
-
const closeAfterSubmit = useCallback((): void => {
|
|
653
|
-
setActive(null);
|
|
654
|
-
activeScreenRef.current = undefined;
|
|
655
|
-
resetSubmit();
|
|
656
|
-
}, [resetSubmit]);
|
|
657
|
-
|
|
658
|
-
const showEngagePrompt = useCallback(
|
|
659
|
-
async (options?: ShowEngagePromptOptions): Promise<boolean> => {
|
|
660
|
-
const store = storeRef.current;
|
|
661
|
-
if (!store) return false;
|
|
662
|
-
try {
|
|
663
|
-
const config = await engage.fetchConfig(options?.context);
|
|
664
|
-
if (!config || !Array.isArray(config.campaigns)) return false;
|
|
665
|
-
|
|
666
|
-
const campaign = selectCampaignToRender(config.campaigns, store, {
|
|
667
|
-
// A behavioral-trigger fire (`options.trigger`) is type-agnostic:
|
|
668
|
-
// the trigger itself selects the campaign, so don't layer the
|
|
669
|
-
// NPS-first default on top (it would drop FEEDBACK/CSAT/etc.).
|
|
670
|
-
// Manual fires keep the provider default unless overridden.
|
|
671
|
-
types: options?.types ?? (options?.trigger ? undefined : types),
|
|
672
|
-
screen: options?.screen,
|
|
673
|
-
trigger: options?.trigger,
|
|
674
|
-
seconds: options?.seconds,
|
|
675
|
-
event: options?.event,
|
|
676
|
-
action: options?.action,
|
|
677
|
-
});
|
|
678
|
-
if (!campaign) {
|
|
679
|
-
logger.debug('[Engage] no eligible campaign to render');
|
|
680
|
-
return false;
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
// Record the impression up front so throttle counts it even if the
|
|
684
|
-
// user backgrounds the app before submitting.
|
|
685
|
-
store.recordImpression(campaign.id);
|
|
686
|
-
// Emit the §2.5 impression event (P3-e #2) so the dashboard's
|
|
687
|
-
// response-rate / completion KPIs have a real denominator — the
|
|
688
|
-
// prompt path previously only counted impressions locally.
|
|
689
|
-
trackCampaign(campaign, 'impression');
|
|
690
|
-
// Rating funnel (CONTRACT §1.1): selection passed the throttle/anti-
|
|
691
|
-
// annoyance gate (→ eligible) and we are about to render (→ shown).
|
|
692
|
-
if (isRatingType(campaign.type)) {
|
|
693
|
-
emitRatingFunnel(campaign, 'rating_prompt_eligible');
|
|
694
|
-
emitRatingFunnel(campaign, 'rating_prompt_shown');
|
|
695
|
-
}
|
|
696
|
-
// Stamp the show-time screen alongside the active campaign so
|
|
697
|
-
// handleSubmit can attribute the response to its originating screen.
|
|
698
|
-
activeScreenRef.current = options?.screen;
|
|
699
|
-
surveyStartedRef.current = null;
|
|
700
|
-
trackSurveyStage(campaign, 'shown');
|
|
701
|
-
resetSubmit();
|
|
702
|
-
setActive(campaign);
|
|
703
|
-
return true;
|
|
704
|
-
} catch (err) {
|
|
705
|
-
logger.warn('[Engage] showEngagePrompt failed:', (err as Error)?.message);
|
|
706
|
-
return false;
|
|
707
|
-
}
|
|
708
|
-
},
|
|
709
|
-
[engage, types, trackCampaign, trackSurveyStage, emitRatingFunnel],
|
|
710
|
-
);
|
|
711
|
-
|
|
712
|
-
// ─── In-app message lifecycle (the second Engage family, §2.4/§2.5) ──────
|
|
713
|
-
// Reuses the SAME transport (`trackEvent`), the SAME throttle store, and the
|
|
714
|
-
// SAME provider — NOT a parallel provider. Events: impression on show, click
|
|
715
|
-
// on CTA tap, completion on a finished tour, dismiss on close/skip.
|
|
716
|
-
|
|
717
|
-
const trackInApp = useCallback(
|
|
718
|
-
(
|
|
719
|
-
message: InAppMessageConfig,
|
|
720
|
-
eventType:
|
|
721
|
-
| 'impression'
|
|
722
|
-
| 'completion'
|
|
723
|
-
| 'click'
|
|
724
|
-
| 'dismiss'
|
|
725
|
-
| 'interaction'
|
|
726
|
-
| 'render_degraded'
|
|
727
|
-
| 'render_failed'
|
|
728
|
-
| 'cta_open_failed',
|
|
729
|
-
extraMeta?: Record<string, unknown>,
|
|
730
|
-
): void => {
|
|
731
|
-
try {
|
|
732
|
-
// A/B attribution (D8/J6): when the active message resolved to an
|
|
733
|
-
// experiment arm, tag every lifecycle event with the chosen variant
|
|
734
|
-
// via the existing optional `meta` field — NO event-schema change
|
|
735
|
-
// (EngageEventUpload already carries `meta`; the backend EngageEvent
|
|
736
|
-
// accepts it). Plain (non-experiment) messages send no variant key.
|
|
737
|
-
const variant = activeInAppVariantRef.current?.variant;
|
|
738
|
-
// [T1] Test-preview tagging: a preview-flagged message stamps
|
|
739
|
-
// `previewId` + `isTest` + `source` so (a) the backend CONSUMES the
|
|
740
|
-
// matching preview row on the impression and (b) production KPIs
|
|
741
|
-
// exclude the traffic. Normal campaign messages omit all of it.
|
|
742
|
-
const isPreview = message.preview === true || message.isTest === true;
|
|
743
|
-
const meta = {
|
|
744
|
-
...(variant ? { variant } : {}),
|
|
745
|
-
// testRunId correlates a specific "Send Test" run to its render/click/
|
|
746
|
-
// dismiss in the dashboard; rides the existing meta field (no schema churn).
|
|
747
|
-
...(message.testRunId ? { testRunId: message.testRunId } : {}),
|
|
748
|
-
...(extraMeta ?? {}),
|
|
749
|
-
};
|
|
750
|
-
engage.trackEvent({
|
|
751
|
-
campaignId: message.id,
|
|
752
|
-
channel: 'inapp',
|
|
753
|
-
type: eventType,
|
|
754
|
-
deviceId: getDeviceId(),
|
|
755
|
-
...(message.previewId ? { previewId: message.previewId } : {}),
|
|
756
|
-
...(isPreview ? { isTest: true, source: 'test_preview' } : {}),
|
|
757
|
-
...(variant ? { variantId: variant } : {}),
|
|
758
|
-
...(Object.keys(meta).length > 0 ? { meta } : {}),
|
|
759
|
-
});
|
|
760
|
-
} catch (err) {
|
|
761
|
-
logger.debug('[Engage] in-app trackEvent failed:', (err as Error)?.message);
|
|
762
|
-
}
|
|
763
|
-
},
|
|
764
|
-
[engage],
|
|
765
|
-
);
|
|
766
|
-
|
|
767
|
-
// [T1] In-app message actually mounted on screen. The impression event IS the test
|
|
768
|
-
// ACK to the backend (which consumes the preview row → 'rendered'). We ALSO persist the
|
|
769
|
-
// testRunId locally so a cold restart can't re-show it before the ACK is processed
|
|
770
|
-
// server-side — the one-shot guarantee survives a flaky/slow network.
|
|
771
|
-
const handleInAppShow = useCallback(
|
|
772
|
-
(message: InAppMessageConfig): void => {
|
|
773
|
-
// A slot can be replaced or degrade to an overlay while the same message
|
|
774
|
-
// remains active. Treat that as one mount lifecycle, not two impressions.
|
|
775
|
-
if (shownInAppMessageIdRef.current === message.id) return;
|
|
776
|
-
shownInAppMessageIdRef.current = message.id;
|
|
777
|
-
trackInApp(message, 'impression');
|
|
778
|
-
if (message.preview === true || message.isTest === true) {
|
|
779
|
-
const runId = message.testRunId ?? message.previewId ?? message.id;
|
|
780
|
-
seenTestsRef.current?.markSeen(runId);
|
|
781
|
-
// Eager-flush so the backend consumes the one-shot preview row NOW — a fast
|
|
782
|
-
// close→kill→reopen must not re-serve a still-`delivered` test.
|
|
783
|
-
engage.flushEvents?.();
|
|
784
|
-
logger.debug(`[Engage] test ${runId} render displayed — ACK sent (impression), flushed`);
|
|
785
|
-
}
|
|
786
|
-
},
|
|
787
|
-
[trackInApp, engage],
|
|
788
|
-
);
|
|
789
|
-
|
|
790
|
-
const finalizeInAppMessage = useCallback((eventType: 'dismiss' | 'completion'): void => {
|
|
791
|
-
setActiveInApp((current) => {
|
|
792
|
-
if (current) {
|
|
793
|
-
const isTest = current.preview === true || current.isTest === true;
|
|
794
|
-
const runId = current.testRunId ?? current.previewId ?? current.id;
|
|
795
|
-
logger.debug(`[Engage] in-app ${eventType}${isTest ? ` (test ${runId})` : ''}`);
|
|
796
|
-
trackInApp(current, eventType);
|
|
797
|
-
if (isTest) {
|
|
798
|
-
consumedPreviewIds.current.add(current.previewId ?? current.id);
|
|
799
|
-
seenTestsRef.current?.markSeen(runId);
|
|
800
|
-
engage.flushEvents?.();
|
|
801
|
-
logger.debug(`[Engage] test ${runId} ${eventType} persisted + ACK flushed`);
|
|
802
|
-
} else {
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
if (cta
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
//
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
//
|
|
887
|
-
//
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
//
|
|
955
|
-
//
|
|
956
|
-
//
|
|
957
|
-
//
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
//
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
//
|
|
979
|
-
//
|
|
980
|
-
//
|
|
981
|
-
//
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
const
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
//
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
//
|
|
1020
|
-
//
|
|
1021
|
-
//
|
|
1022
|
-
//
|
|
1023
|
-
//
|
|
1024
|
-
//
|
|
1025
|
-
//
|
|
1026
|
-
//
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
const
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
const
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
engage.trackCoachmarkEvent?.('$
|
|
1097
|
-
} else if (interaction.
|
|
1098
|
-
engage.trackCoachmarkEvent?.('$
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
{
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
*
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* ScaleBun SDK — Engage Prompt Provider (campaign renderer core, D4)
|
|
3
|
+
*
|
|
4
|
+
* Wraps the host app and owns the campaign-render lifecycle for the shared
|
|
5
|
+
* cross-platform JS overlay:
|
|
6
|
+
* 1. on a trigger (app-controlled via `showEngagePrompt()` and/or the campaign's
|
|
7
|
+
* own `trigger` from config), calls `facade.engage.fetchConfig()`,
|
|
8
|
+
* 2. runs the throttle/decision core (`selectCampaignToRender`) to pick which
|
|
9
|
+
* campaign — if any — is eligible, honoring frequency caps,
|
|
10
|
+
* 3. mounts the parameterized `EngagePromptView` (Open/Closed: NPS now,
|
|
11
|
+
* ratings/feedback/survey later via the renderer registry),
|
|
12
|
+
* 4. on submit → `facade.engage.submitResponse({ surveyId, score, text })`
|
|
13
|
+
* (transport stamps `responseId` UUID + `schemaVersion` per contract),
|
|
14
|
+
* records the impression as completed, and emits an in-app dismiss/submit
|
|
15
|
+
* tracking event,
|
|
16
|
+
* 5. on dismiss → `facade.engage.trackEvent` with a `dismiss` event.
|
|
17
|
+
*
|
|
18
|
+
* The provider depends only on the `engage` namespace shape — NOT the whole
|
|
19
|
+
* facade — so it stays decoupled and testable, and reuses the existing transport
|
|
20
|
+
* (no second HTTP path).
|
|
21
|
+
*
|
|
22
|
+
* IN-APP MESSAGES (the second Engage family, §2.4/§2.5) are surfaced by this SAME
|
|
23
|
+
* provider — NOT a parallel one. `showInAppMessage()` fetches the config, picks an
|
|
24
|
+
* eligible message from `inAppMessages[]` (shared throttle store), and mounts the
|
|
25
|
+
* config-driven `EngageInAppView` (banner/modal/overlay). Events: `impression` on
|
|
26
|
+
* show, `click` on CTA tap (the resolved deep link is surfaced to the host via
|
|
27
|
+
* `onInAppDeepLink` — the SDK never opens URLs), `dismiss` on close.
|
|
28
|
+
*
|
|
29
|
+
* PRECEDENCE (campaign vs in-app): a campaign prompt wins the screen. If a
|
|
30
|
+
* campaign prompt is already visible, `showInAppMessage()` is a no-op (returns
|
|
31
|
+
* false) and the mounted in-app view is hidden while a campaign is up, so the two
|
|
32
|
+
* families never fight for the screen.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import React, {
|
|
36
|
+
createContext,
|
|
37
|
+
useContext,
|
|
38
|
+
useCallback,
|
|
39
|
+
useEffect,
|
|
40
|
+
useMemo,
|
|
41
|
+
useRef,
|
|
42
|
+
useState,
|
|
43
|
+
type ReactNode,
|
|
44
|
+
type ReactElement,
|
|
45
|
+
} from 'react';
|
|
46
|
+
import { Linking, Platform } from 'react-native';
|
|
47
|
+
import { logger } from '../../core/logger/internalLogger';
|
|
48
|
+
import { installEngageTriggerEngine } from './engageTriggerEngine';
|
|
49
|
+
import { appLifecycle } from '../../core/lifecycle/appLifecycle';
|
|
50
|
+
import { getDeviceId } from '../../core/id/deviceId';
|
|
51
|
+
import { ReplaySdk } from '../replay/public/api';
|
|
52
|
+
import { SessionManager } from '../session/SessionManager';
|
|
53
|
+
import {
|
|
54
|
+
EngagePromptView,
|
|
55
|
+
type EngagePromptResult,
|
|
56
|
+
type EngageSubmitStatus,
|
|
57
|
+
type RatingPromptConfig,
|
|
58
|
+
} from './EngagePromptView';
|
|
59
|
+
import { EngageInAppView, type InAppMechanicInteraction } from './EngageInAppView';
|
|
60
|
+
import { EngageAnchorProvider } from './EngageAnchor';
|
|
61
|
+
import {
|
|
62
|
+
EngageInlinePlacementProvider,
|
|
63
|
+
createEngageInlinePlacementRegistry,
|
|
64
|
+
resolveEngageInlinePlacement,
|
|
65
|
+
type EngageInlineDelivery,
|
|
66
|
+
} from './EngageInlinePlacement';
|
|
67
|
+
import { resolveInAppPresentation } from './engageVariantResolver';
|
|
68
|
+
import { shouldTrackInAppCta } from './engageOutcome';
|
|
69
|
+
import type { SubmitStage } from './EngageTransport';
|
|
70
|
+
import {
|
|
71
|
+
EngageThrottleStore,
|
|
72
|
+
selectCampaignToRender,
|
|
73
|
+
selectInAppToRender,
|
|
74
|
+
selectInAppVariant,
|
|
75
|
+
selectLatestUnseenTest,
|
|
76
|
+
testRunIdOf,
|
|
77
|
+
} from './engageThrottle';
|
|
78
|
+
import { EngageTestSeenStore } from './engageTestSeenStore';
|
|
79
|
+
import type {
|
|
80
|
+
EngageAttachmentDraft,
|
|
81
|
+
EngageCampaignConfig,
|
|
82
|
+
EngageCampaignType,
|
|
83
|
+
EngageConfigContext,
|
|
84
|
+
EngageConfigResponse,
|
|
85
|
+
EngageEventInput,
|
|
86
|
+
InAppGameRequestHandler,
|
|
87
|
+
EngageResponseInput,
|
|
88
|
+
InAppMessageConfig,
|
|
89
|
+
InAppRenderSpec,
|
|
90
|
+
InAppVariantId,
|
|
91
|
+
RatingFunnelEventDims,
|
|
92
|
+
RatingFunnelEventInput,
|
|
93
|
+
RatingFunnelEventType,
|
|
94
|
+
SurveyAnswer,
|
|
95
|
+
SurveyImpressionInput,
|
|
96
|
+
} from './engageTypes';
|
|
97
|
+
|
|
98
|
+
/** Client-generated UUID for app-rating idempotency (D8: `clientRatingId`). */
|
|
99
|
+
function ratingUuid(): string {
|
|
100
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
101
|
+
const r = (Math.random() * 16) | 0;
|
|
102
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
103
|
+
return v.toString(16);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Preserve a multi-question survey answer in the keyed wire shape (§1.4). */
|
|
108
|
+
export function toWireAnswers(
|
|
109
|
+
answers: SurveyAnswer[],
|
|
110
|
+
): { key: string; value: string | number | string[] }[] {
|
|
111
|
+
return answers.map((a) => ({
|
|
112
|
+
key: a.key,
|
|
113
|
+
value: a.value,
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Resolve the canonical session id for response linkage (contract §1/§7).
|
|
119
|
+
* Primary source is `SessionManager.currentSessionId` — the always-on analytics
|
|
120
|
+
* session id (`rs-…`) that the replay recording attaches to (and that `/sessions/:id`
|
|
121
|
+
* keys on). `ReplaySdk.sessionId` (the orchestrator's recording id) is only set
|
|
122
|
+
* while a recording is mid-flight and reads `null` at submit time, so it is a
|
|
123
|
+
* fallback, not the primary. Returns `undefined` (not `null`) so the optional wire
|
|
124
|
+
* field is simply omitted when no session is active.
|
|
125
|
+
*/
|
|
126
|
+
function currentSessionId(): string | undefined {
|
|
127
|
+
return (
|
|
128
|
+
SessionManager.getExistingInstance()?.currentSessionId ??
|
|
129
|
+
ReplaySdk.sessionId ??
|
|
130
|
+
undefined
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The host app version for by-version analytics (contract §1). Read from the
|
|
136
|
+
* SAME synchronous source the SDK's rating lane already uses
|
|
137
|
+
* (`SessionManager.currentSessionMetadata.appVersion`, populated from native
|
|
138
|
+
* device info) — NOT hardcoded, and NOT the SDK build version. `undefined` when
|
|
139
|
+
* no session metadata is available yet, so the optional field is omitted.
|
|
140
|
+
*/
|
|
141
|
+
function currentAppVersion(): string | undefined {
|
|
142
|
+
return SessionManager.getExistingInstance()?.currentSessionMetadata?.appVersion ?? undefined;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Device platform as the `'android' | 'ios'` wire union (contract §1). Shared JS
|
|
147
|
+
* path — NOT platform-gated — so Android and iOS both stamp their own value.
|
|
148
|
+
* `Platform.OS` also yields `'windows' | 'macos' | 'web'`; those are out of the
|
|
149
|
+
* SDK's mobile scope and intentionally collapse to `undefined` (field omitted).
|
|
150
|
+
*/
|
|
151
|
+
function currentPlatform(): 'android' | 'ios' | undefined {
|
|
152
|
+
return Platform.OS === 'android' || Platform.OS === 'ios' ? Platform.OS : undefined;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Build the config-serve context (contract §1.3 query). ALWAYS carries `deviceId`
|
|
157
|
+
* — the backend keys per-device test previews on it, so omitting it would hide a
|
|
158
|
+
* "Send Test" preview from the very device it was queued for (T1). `platform`/
|
|
159
|
+
* `appVersion` ride along for server-side targeting; both honest, both omitted when
|
|
160
|
+
* unresolved. A caller-supplied `context` (manual show) overrides field-by-field.
|
|
161
|
+
*/
|
|
162
|
+
function buildConfigContext(
|
|
163
|
+
engage: EngageRendererFacade,
|
|
164
|
+
override?: EngageConfigContext,
|
|
165
|
+
): EngageConfigContext {
|
|
166
|
+
const identifiedUserId = engage.getIdentifiedUserId?.();
|
|
167
|
+
return {
|
|
168
|
+
deviceId: getDeviceId(),
|
|
169
|
+
...(currentPlatform() ? { platform: currentPlatform() } : {}),
|
|
170
|
+
...(currentAppVersion() ? { appVersion: currentAppVersion() } : {}),
|
|
171
|
+
...(identifiedUserId ? { endUserId: identifiedUserId } : {}),
|
|
172
|
+
...override,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Build the rating-funnel breakdown dimensions (ratings-rebuild CONTRACT §1.2 `dims`)
|
|
178
|
+
* from the SAME live session metadata the response builder reads — NOT hardcoded.
|
|
179
|
+
* Only honest, present values are included; `country`/`locale`/`acquisitionSource`
|
|
180
|
+
* are intentionally omitted here (no on-device source yet) so the backend reports
|
|
181
|
+
* them as absent rather than fabricated.
|
|
182
|
+
*/
|
|
183
|
+
function currentRatingDims(): RatingFunnelEventDims {
|
|
184
|
+
const meta = SessionManager.getExistingInstance()?.currentSessionMetadata;
|
|
185
|
+
const platform = currentPlatform();
|
|
186
|
+
return {
|
|
187
|
+
...(platform ? { platform } : {}),
|
|
188
|
+
...(meta?.appVersion ? { appVersion: meta.appVersion } : {}),
|
|
189
|
+
...(meta?.osVersion ? { osVersion: meta.osVersion } : {}),
|
|
190
|
+
...(meta?.deviceModel ? { deviceModel: meta.deviceModel } : {}),
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* The slice of the SDK facade the renderer consumes (the `engage` namespace).
|
|
196
|
+
* Matching this shape — rather than importing the facade — keeps the renderer a
|
|
197
|
+
* pure consumer of the foundation transport and trivially testable.
|
|
198
|
+
*/
|
|
199
|
+
export interface EngageRendererFacade {
|
|
200
|
+
/** External user id last supplied through ScaleBun.identify(). */
|
|
201
|
+
getIdentifiedUserId?: () => string | undefined;
|
|
202
|
+
fetchConfig: (context?: EngageConfigContext) => Promise<EngageConfigResponse | null>;
|
|
203
|
+
trackCoachmarkEvent?: (name: string, properties: Record<string, unknown>) => void;
|
|
204
|
+
submitResponse: (input: EngageResponseInput) => void;
|
|
205
|
+
/**
|
|
206
|
+
* [P3-e] Submit a response with native attachments (screenshot/voice). Optional
|
|
207
|
+
* so a host wired to an older facade still renders prompts (media silently
|
|
208
|
+
* degrades to a plain response).
|
|
209
|
+
*/
|
|
210
|
+
submitResponseWithAttachments?: (
|
|
211
|
+
input: EngageResponseInput,
|
|
212
|
+
attachments: EngageAttachmentDraft[],
|
|
213
|
+
) => void;
|
|
214
|
+
/**
|
|
215
|
+
* [Slice D5] CONFIRMED submit used by the reusable submitting→success→error state
|
|
216
|
+
* machine: resolves only on real server persistence, rejects on failure, idempotent
|
|
217
|
+
* on `responseId`. Optional so an older facade still renders prompts (falls back to
|
|
218
|
+
* the fire-and-forget lanes, which resolve immediately).
|
|
219
|
+
*/
|
|
220
|
+
submitResponseConfirmed?: (
|
|
221
|
+
input: EngageResponseInput,
|
|
222
|
+
attachments: EngageAttachmentDraft[],
|
|
223
|
+
opts: { responseId: string; onStage?: (stage: SubmitStage) => void },
|
|
224
|
+
) => Promise<void>;
|
|
225
|
+
trackEvent: (input: EngageEventInput) => void;
|
|
226
|
+
trackSurveyImpression?: (input: SurveyImpressionInput) => void;
|
|
227
|
+
/**
|
|
228
|
+
* Force-flush queued in-app events immediately (bypassing the batch threshold/timer).
|
|
229
|
+
* Called right after a TEST preview's impression/dismiss ACK so the backend consumes
|
|
230
|
+
* the one-shot preview row before the app can be backgrounded/killed — otherwise a
|
|
231
|
+
* still-`delivered` row re-serves on the next reopen. Optional: an older facade simply
|
|
232
|
+
* relies on the periodic flush (eventual consistency).
|
|
233
|
+
*/
|
|
234
|
+
flushEvents?: () => void;
|
|
235
|
+
/**
|
|
236
|
+
* Submit a 1–5 app-store rating via the EXISTING rating lane (NOT
|
|
237
|
+
* submitResponse — D1 keeps app-ratings a distinct funnel). The provider
|
|
238
|
+
* passes a client `clientRatingId` for idempotency (D8). Optional so a host
|
|
239
|
+
* that never shows RATING_PROMPT need not supply it.
|
|
240
|
+
*/
|
|
241
|
+
submitRating?: (input: {
|
|
242
|
+
rating: number;
|
|
243
|
+
comment?: string;
|
|
244
|
+
source?: 'in_app' | 'prompt' | 'manual';
|
|
245
|
+
clientRatingId?: string;
|
|
246
|
+
}) => unknown;
|
|
247
|
+
/**
|
|
248
|
+
* Emit a rating-funnel tracking fact (ratings-rebuild CONTRACT §1.2) — eligible/
|
|
249
|
+
* shown/dismissed/selected/redirect. NOT a campaign response (D1). Optional so an
|
|
250
|
+
* older facade still renders rating prompts (the funnel just goes uninstrumented).
|
|
251
|
+
*/
|
|
252
|
+
emitRatingEvent?: (input: RatingFunnelEventInput) => void;
|
|
253
|
+
/**
|
|
254
|
+
* Trigger the native in-app review sheet (D5). Resolves `true` only when the OS
|
|
255
|
+
* flow ran/resolved after a positive route, so the provider emits
|
|
256
|
+
* `store_redirect_clicked` solely on a `true` result. Optional/fail-soft.
|
|
257
|
+
*/
|
|
258
|
+
requestStoreReview?: () => Promise<boolean>;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Host-app RATING_PROMPT routing config. The store deeplink is NEVER hardcoded —
|
|
263
|
+
* the host supplies either a static `storeUrl` or an `onHighRating` callback (e.g.
|
|
264
|
+
* `Linking.openURL(...)` / native `requestReview()`), and an `onLowRating` for the
|
|
265
|
+
* feedback hand-off. The provider only decides WHICH callback to invoke.
|
|
266
|
+
*/
|
|
267
|
+
export interface EngageRatingRouting extends RatingPromptConfig {
|
|
268
|
+
/** App-store deeplink opened on a high rating (host owns the navigation). */
|
|
269
|
+
storeUrl?: string;
|
|
270
|
+
/** Called on a high rating (>= threshold). Receives the resolved store URL if set. */
|
|
271
|
+
onHighRating?: (info: { rating: number; campaign: EngageCampaignConfig; storeUrl?: string }) => void;
|
|
272
|
+
/** Called on a low rating when routing to feedback (host opens its form). */
|
|
273
|
+
onLowRating?: (info: { rating: number; campaign: EngageCampaignConfig }) => void;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export interface ShowEngagePromptOptions {
|
|
277
|
+
/** Restrict to specific campaign types. Defaults to `['NPS']` (NPS-first slice). */
|
|
278
|
+
types?: EngageCampaignType[];
|
|
279
|
+
/** Match a campaign's `targetScreen` to the current screen. */
|
|
280
|
+
screen?: string;
|
|
281
|
+
/**
|
|
282
|
+
* Restrict to campaigns whose `trigger` equals this value (behavioral-trigger
|
|
283
|
+
* path, e.g. `'screen_exit'`). Omitted ⇒ trigger-agnostic (manual fire).
|
|
284
|
+
*/
|
|
285
|
+
trigger?: string;
|
|
286
|
+
/** Event name for `custom_event` / `after_purchase` (matches `triggerConfig.event`). */
|
|
287
|
+
event?: string;
|
|
288
|
+
/** Action label for `failed_action` (matches `triggerConfig.action`). */
|
|
289
|
+
action?: string;
|
|
290
|
+
/** Fired `time_in_app` threshold, used to select only that configured timer. */
|
|
291
|
+
seconds?: number;
|
|
292
|
+
/** App/user context forwarded to the config fetch for server-side targeting. */
|
|
293
|
+
context?: EngageConfigContext;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export interface ShowInAppMessageOptions {
|
|
297
|
+
/** Match a message's `targetScreen` to the current screen. */
|
|
298
|
+
screen?: string;
|
|
299
|
+
/**
|
|
300
|
+
* Restrict to messages whose `trigger` equals this value (behavioral-trigger
|
|
301
|
+
* path, e.g. `'session_start'`). Omitted ⇒ trigger-agnostic (manual host call).
|
|
302
|
+
*/
|
|
303
|
+
trigger?: string;
|
|
304
|
+
/** Fired business/custom event name, matched against `message.eventName`. */
|
|
305
|
+
event?: string;
|
|
306
|
+
/** Fired action value for forward-compatible action-specific messages. */
|
|
307
|
+
action?: string;
|
|
308
|
+
/** Fired `time_delay` threshold, used to select only that configured message. */
|
|
309
|
+
seconds?: number;
|
|
310
|
+
/** App/user context forwarded to the config fetch for server-side targeting. */
|
|
311
|
+
context?: EngageConfigContext;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* The host's deep-link sink for an in-app CTA tap. The SDK NEVER opens a URL — it
|
|
316
|
+
* hands the resolved `deepLink` (and full message/cta) to the host, which decides
|
|
317
|
+
* how to navigate (e.g. `Linking.openURL` / a router push). Only fired for a CTA
|
|
318
|
+
* whose `action` resolves to a link with a `deepLink`.
|
|
319
|
+
*/
|
|
320
|
+
export type InAppDeepLinkHandler = (info: {
|
|
321
|
+
message: InAppMessageConfig;
|
|
322
|
+
cta: NonNullable<InAppRenderSpec['cta']>;
|
|
323
|
+
deepLink: string;
|
|
324
|
+
}) => void;
|
|
325
|
+
|
|
326
|
+
/** Imperative controller a host app uses to trigger a prompt / in-app message. */
|
|
327
|
+
export interface EngagePromptController {
|
|
328
|
+
/** Fetch config, pick an eligible campaign, and show it. Returns whether one was shown. */
|
|
329
|
+
showEngagePrompt: (options?: ShowEngagePromptOptions) => Promise<boolean>;
|
|
330
|
+
/** Dismiss the currently visible prompt (no response submitted). */
|
|
331
|
+
dismissEngagePrompt: () => void;
|
|
332
|
+
/**
|
|
333
|
+
* Fetch config, pick an eligible in-app message (`inAppMessages[]`), and show
|
|
334
|
+
* it. Returns whether one was shown. PRECEDENCE: a campaign prompt already on
|
|
335
|
+
* screen wins — an in-app message is NOT shown over it (see provider doc).
|
|
336
|
+
*/
|
|
337
|
+
showInAppMessage: (options?: ShowInAppMessageOptions) => Promise<boolean>;
|
|
338
|
+
/** Dismiss the currently visible in-app message (emits a `dismiss` event). */
|
|
339
|
+
dismissInAppMessage: () => void;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const EngagePromptContext = createContext<EngagePromptController | null>(null);
|
|
343
|
+
|
|
344
|
+
export interface EngagePromptProviderProps {
|
|
345
|
+
/** The SDK facade's `engage` namespace (e.g. `ScaleBun.engage`). */
|
|
346
|
+
engage: EngageRendererFacade;
|
|
347
|
+
/** Default campaign types to consider. Defaults to NPS-first. */
|
|
348
|
+
defaultTypes?: EngageCampaignType[];
|
|
349
|
+
/**
|
|
350
|
+
* RATING_PROMPT routing config (host-supplied). The app-store deeplink and
|
|
351
|
+
* feedback hand-off are NEVER hardcoded in the SDK — supplied here.
|
|
352
|
+
*/
|
|
353
|
+
ratingRouting?: EngageRatingRouting;
|
|
354
|
+
/**
|
|
355
|
+
* Host sink for an in-app message CTA deep link. The SDK never opens URLs —
|
|
356
|
+
* it surfaces the resolved `deepLink` here for the host to navigate. Optional:
|
|
357
|
+
* a host that never uses link-action CTAs need not supply it.
|
|
358
|
+
*/
|
|
359
|
+
onInAppDeepLink?: InAppDeepLinkHandler;
|
|
360
|
+
/**
|
|
361
|
+
* Required when a production gamified campaign is used. The SDK calls this
|
|
362
|
+
* only at play/load/check-in/quiz resolution time; the host's authenticated
|
|
363
|
+
* backend owns eligibility, granting, and the returned result.
|
|
364
|
+
*/
|
|
365
|
+
onInAppGameRequest?: InAppGameRequestHandler;
|
|
366
|
+
/**
|
|
367
|
+
* DEV/TEST ONLY — poll interval (ms) for queued test previews while the app is
|
|
368
|
+
* already foregrounded. `checkForPreview` runs on mount + every AppState→active,
|
|
369
|
+
* which covers "reopen the app". But if you press "Send Test" while the app is
|
|
370
|
+
* ALREADY open and in the foreground, there is no background→foreground edge to
|
|
371
|
+
* trigger a refetch. Setting e.g. `previewPollMs={4000}` makes a warm, foreground
|
|
372
|
+
* app pick up a Send Test within a few seconds with no app switch. Leave UNSET in
|
|
373
|
+
* production (0/undefined ⇒ no polling — the foreground/cold-start fetch is enough).
|
|
374
|
+
*/
|
|
375
|
+
previewPollMs?: number;
|
|
376
|
+
children: ReactNode;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const DEFAULT_TYPES: EngageCampaignType[] = ['NPS'];
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Provider that mounts the shared overlay and exposes the imperative controller
|
|
383
|
+
* via `useEngagePrompt()`.
|
|
384
|
+
*/
|
|
385
|
+
export function EngagePromptProvider({
|
|
386
|
+
engage,
|
|
387
|
+
defaultTypes,
|
|
388
|
+
ratingRouting,
|
|
389
|
+
onInAppDeepLink,
|
|
390
|
+
onInAppGameRequest,
|
|
391
|
+
previewPollMs,
|
|
392
|
+
children,
|
|
393
|
+
}: EngagePromptProviderProps): ReactElement {
|
|
394
|
+
const [active, setActive] = useState<EngageCampaignConfig | null>(null);
|
|
395
|
+
const [activeInApp, setActiveInApp] = useState<InAppMessageConfig | null>(null);
|
|
396
|
+
const [inlineFallbackMessageId, setInlineFallbackMessageId] = useState<string | null>(null);
|
|
397
|
+
const [inlinePlacementRevision, setInlinePlacementRevision] = useState(0);
|
|
398
|
+
const inlinePlacementRegistry = useMemo(createEngageInlinePlacementRegistry, []);
|
|
399
|
+
const shownInAppMessageIdRef = useRef<string | null>(null);
|
|
400
|
+
// Resolved A/B arm for the active in-app message (D8/J6). Held in a ref: it is
|
|
401
|
+
// render-stable metadata (the chosen `spec` drives the view, the `variant` id
|
|
402
|
+
// rides the lifecycle events) and must not perturb the precedence that keys off
|
|
403
|
+
// `activeInApp`. `null` when no message is active (or it has no experiment).
|
|
404
|
+
const activeInAppVariantRef = useRef<
|
|
405
|
+
{ variant: InAppVariantId; spec: InAppRenderSpec } | null
|
|
406
|
+
>(null);
|
|
407
|
+
// Show-time screen of the currently-active campaign prompt (contract §1
|
|
408
|
+
// `screen`). Held in a ref alongside `active` — it is render-irrelevant
|
|
409
|
+
// metadata read only at submit, so it needs no re-render and must not perturb
|
|
410
|
+
// the campaign-vs-in-app precedence which keys off `active`/`activeInApp`.
|
|
411
|
+
const activeScreenRef = useRef<string | undefined>(undefined);
|
|
412
|
+
const surveyStartedRef = useRef<string | null>(null);
|
|
413
|
+
// [T1] Test previews bypass the throttle store and the backend re-serves them on
|
|
414
|
+
// EVERY config poll until TTL — great for "reopen the app and see it again", but it
|
|
415
|
+
// means a dismissed preview would re-appear on the next warm poll. This session set
|
|
416
|
+
// records previews the user already closed (dismiss/CTA) so we don't re-show the SAME
|
|
417
|
+
// one. It is in-memory only: a cold restart clears it, so reopening the app still
|
|
418
|
+
// shows the queued test (the intended QA behavior).
|
|
419
|
+
const consumedPreviewIds = useRef<Set<string>>(new Set());
|
|
420
|
+
// [T1] Persistent dedupe for ONE-SHOT test delivery — survives cold restarts (unlike
|
|
421
|
+
// consumedPreviewIds above). A testRunId is recorded here AFTER it actually renders, so
|
|
422
|
+
// reopening the app does NOT re-show a test the device already displayed. This is the
|
|
423
|
+
// fix for "close/open and the old test re-appears, and they stack up". Separate from the
|
|
424
|
+
// throttle store so production frequency caps never block a fresh test and vice-versa.
|
|
425
|
+
const seenTestsRef = useRef<EngageTestSeenStore | null>(null);
|
|
426
|
+
if (seenTestsRef.current === null) {
|
|
427
|
+
seenTestsRef.current = new EngageTestSeenStore();
|
|
428
|
+
}
|
|
429
|
+
// One persistent throttle store for the provider lifetime — SHARED by campaigns
|
|
430
|
+
// and in-app messages so both honor the same per-id frequency caps.
|
|
431
|
+
const storeRef = useRef<EngageThrottleStore | null>(null);
|
|
432
|
+
if (storeRef.current === null) {
|
|
433
|
+
storeRef.current = new EngageThrottleStore();
|
|
434
|
+
}
|
|
435
|
+
const types = defaultTypes ?? DEFAULT_TYPES;
|
|
436
|
+
|
|
437
|
+
// ─── Reusable submit state machine (Slice D5) ────────────────────────────
|
|
438
|
+
// ONE machine for EVERY question type. `responseIdRef` is the idempotency key,
|
|
439
|
+
// generated once per prompt and REUSED on retry so a re-send can't duplicate.
|
|
440
|
+
// `submitCtxRef` holds the campaign+result so retry re-runs the same submit.
|
|
441
|
+
const [submitStatus, setSubmitStatus] = useState<EngageSubmitStatus>({ phase: 'idle' });
|
|
442
|
+
const responseIdRef = useRef<string | null>(null);
|
|
443
|
+
const submitCtxRef = useRef<{ campaign: EngageCampaignConfig; result: EngagePromptResult } | null>(null);
|
|
444
|
+
const successTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
445
|
+
|
|
446
|
+
const resetSubmit = useCallback((): void => {
|
|
447
|
+
if (successTimerRef.current) {
|
|
448
|
+
clearTimeout(successTimerRef.current);
|
|
449
|
+
successTimerRef.current = null;
|
|
450
|
+
}
|
|
451
|
+
responseIdRef.current = null;
|
|
452
|
+
submitCtxRef.current = null;
|
|
453
|
+
setSubmitStatus({ phase: 'idle' });
|
|
454
|
+
}, []);
|
|
455
|
+
|
|
456
|
+
// Single campaign tracking lane (mirrors trackInApp). `impression` on show,
|
|
457
|
+
// `completion` on submit, `dismiss` on close — the §2.5 analytics events that
|
|
458
|
+
// back the response-rate / completion KPIs (P3-e #2). Distinct from the local
|
|
459
|
+
// throttle store, which only counts impressions for frequency caps.
|
|
460
|
+
const trackCampaign = useCallback(
|
|
461
|
+
(campaign: EngageCampaignConfig, eventType: 'impression' | 'completion' | 'dismiss') => {
|
|
462
|
+
try {
|
|
463
|
+
engage.trackEvent({
|
|
464
|
+
campaignId: campaign.id,
|
|
465
|
+
channel: 'inapp',
|
|
466
|
+
type: eventType,
|
|
467
|
+
deviceId: getDeviceId(),
|
|
468
|
+
});
|
|
469
|
+
} catch (err) {
|
|
470
|
+
logger.debug('[Engage] trackEvent failed:', (err as Error)?.message);
|
|
471
|
+
}
|
|
472
|
+
},
|
|
473
|
+
[engage],
|
|
474
|
+
);
|
|
475
|
+
|
|
476
|
+
const trackSurveyStage = useCallback(
|
|
477
|
+
(campaign: EngageCampaignConfig, stage: 'shown' | 'started'): void => {
|
|
478
|
+
if (campaign.type === 'RATING_PROMPT' || campaign.type === 'RATINGS_PROMPT') return;
|
|
479
|
+
try {
|
|
480
|
+
engage.trackSurveyImpression?.({
|
|
481
|
+
surveyId: campaign.id,
|
|
482
|
+
stage,
|
|
483
|
+
sessionId: currentSessionId(),
|
|
484
|
+
deviceId: getDeviceId(),
|
|
485
|
+
platform: currentPlatform(),
|
|
486
|
+
appVersion: currentAppVersion(),
|
|
487
|
+
screen: activeScreenRef.current,
|
|
488
|
+
});
|
|
489
|
+
} catch (err) {
|
|
490
|
+
logger.debug('[Engage] survey impression failed:', (err as Error)?.message);
|
|
491
|
+
}
|
|
492
|
+
},
|
|
493
|
+
[engage],
|
|
494
|
+
);
|
|
495
|
+
|
|
496
|
+
const isRatingType = (type: EngageCampaignType): boolean =>
|
|
497
|
+
type === 'RATING_PROMPT' || type === 'RATINGS_PROMPT';
|
|
498
|
+
|
|
499
|
+
// Rating-funnel emit lane (ratings-rebuild CONTRACT §1.2). Distinct from
|
|
500
|
+
// trackCampaign (the §2.5 in-app analytics lane) and from submitRating (the D1
|
|
501
|
+
// app-rating lane): these are dimensioned FACTS feeding the Overview funnel and
|
|
502
|
+
// are NEVER counted as responses. `stars` rides only on `rating_selected`.
|
|
503
|
+
const emitRatingFunnel = useCallback(
|
|
504
|
+
(
|
|
505
|
+
campaign: EngageCampaignConfig,
|
|
506
|
+
type: RatingFunnelEventType,
|
|
507
|
+
extra?: { stars?: number },
|
|
508
|
+
): void => {
|
|
509
|
+
try {
|
|
510
|
+
engage.emitRatingEvent?.({
|
|
511
|
+
type,
|
|
512
|
+
sessionId: currentSessionId(),
|
|
513
|
+
userId: engage.getIdentifiedUserId?.(),
|
|
514
|
+
promptId: campaign.id,
|
|
515
|
+
triggerId: campaign.trigger,
|
|
516
|
+
...(extra?.stars !== undefined ? { stars: extra.stars } : {}),
|
|
517
|
+
dims: currentRatingDims(),
|
|
518
|
+
});
|
|
519
|
+
} catch (err) {
|
|
520
|
+
logger.debug('[Engage] emitRatingEvent failed:', (err as Error)?.message);
|
|
521
|
+
}
|
|
522
|
+
},
|
|
523
|
+
[engage],
|
|
524
|
+
);
|
|
525
|
+
|
|
526
|
+
const dismissEngagePrompt = useCallback((): void => {
|
|
527
|
+
setActive((current) => {
|
|
528
|
+
if (current) {
|
|
529
|
+
trackCampaign(current, 'dismiss');
|
|
530
|
+
// Rating funnel: a close without a selection is a funnel drop.
|
|
531
|
+
if (isRatingType(current.type)) emitRatingFunnel(current, 'rating_prompt_dismissed');
|
|
532
|
+
}
|
|
533
|
+
return null;
|
|
534
|
+
});
|
|
535
|
+
activeScreenRef.current = undefined;
|
|
536
|
+
surveyStartedRef.current = null;
|
|
537
|
+
resetSubmit();
|
|
538
|
+
}, [trackCampaign, resetSubmit, emitRatingFunnel]);
|
|
539
|
+
|
|
540
|
+
// The actual submit run — used by both the first submit and a retry. Reads
|
|
541
|
+
// `submitCtxRef` + `responseIdRef` so a retry re-sends with the SAME idempotency
|
|
542
|
+
// key. Resolves to `success` ONLY on confirmed persistence; `error` on failure.
|
|
543
|
+
const runSubmit = useCallback(async (): Promise<void> => {
|
|
544
|
+
const ctx = submitCtxRef.current;
|
|
545
|
+
if (!ctx) return;
|
|
546
|
+
const { campaign, result } = ctx;
|
|
547
|
+
const store = storeRef.current;
|
|
548
|
+
const responseId = responseIdRef.current ?? (responseIdRef.current = ratingUuid());
|
|
549
|
+
|
|
550
|
+
setSubmitStatus({ phase: 'submitting', stage: 'saving' });
|
|
551
|
+
try {
|
|
552
|
+
if (isRatingType(campaign.type)) {
|
|
553
|
+
// RATING_PROMPT submits via the EXISTING app-rating lane (D1), NOT
|
|
554
|
+
// submitResponse, with a client clientRatingId for idempotency. Awaited
|
|
555
|
+
// so the loading state reflects the real round-trip.
|
|
556
|
+
const rating = typeof result.score === 'number' ? result.score : 0;
|
|
557
|
+
await Promise.resolve(
|
|
558
|
+
engage.submitRating?.({ rating, source: 'prompt', clientRatingId: responseId }),
|
|
559
|
+
);
|
|
560
|
+
// Funnel: user picked 1–5★ (carries stars). Emitted regardless of route.
|
|
561
|
+
emitRatingFunnel(campaign, 'rating_selected', { stars: rating });
|
|
562
|
+
// Routing decided by the view (`route`), executed against host-supplied
|
|
563
|
+
// callbacks/URL — the deeplink is never hardcoded.
|
|
564
|
+
if (result.route === 'store') {
|
|
565
|
+
// D5: prefer the genuinely-native in-app review sheet. `store_redirect_clicked`
|
|
566
|
+
// fires ONLY when an actual store route resolves (native review ran, or a
|
|
567
|
+
// host-supplied deeplink/callback executed) — never speculatively.
|
|
568
|
+
let redirected = false;
|
|
569
|
+
if (engage.requestStoreReview) {
|
|
570
|
+
redirected = await engage.requestStoreReview();
|
|
571
|
+
}
|
|
572
|
+
const storeUrl = campaign.storeUrl ?? ratingRouting?.storeUrl;
|
|
573
|
+
if (ratingRouting?.onHighRating) {
|
|
574
|
+
ratingRouting.onHighRating({ rating, campaign, storeUrl });
|
|
575
|
+
redirected = true;
|
|
576
|
+
} else if (!redirected && storeUrl) {
|
|
577
|
+
redirected = await Linking.openURL(storeUrl).then(() => true).catch(() => false);
|
|
578
|
+
}
|
|
579
|
+
if (redirected) emitRatingFunnel(campaign, 'store_redirect_clicked');
|
|
580
|
+
} else if (result.route === 'feedback') {
|
|
581
|
+
ratingRouting?.onLowRating?.({ rating, campaign });
|
|
582
|
+
}
|
|
583
|
+
} else {
|
|
584
|
+
// [v2] response context (contract §1): session linkage + originating
|
|
585
|
+
// screen + platform + app version. All optional; omitted when unresolved.
|
|
586
|
+
// We send ONLY the new response fact + the sessionId; replay/errors/network
|
|
587
|
+
// are NOT re-sent — the read side joins them by sessionId.
|
|
588
|
+
const input: EngageResponseInput = Array.isArray(result.answers)
|
|
589
|
+
? {
|
|
590
|
+
surveyId: campaign.id,
|
|
591
|
+
text: result.reason,
|
|
592
|
+
answers: toWireAnswers(result.answers),
|
|
593
|
+
deviceId: getDeviceId(),
|
|
594
|
+
sessionId: currentSessionId(),
|
|
595
|
+
screen: activeScreenRef.current,
|
|
596
|
+
platform: currentPlatform(),
|
|
597
|
+
appVersion: currentAppVersion(),
|
|
598
|
+
}
|
|
599
|
+
: {
|
|
600
|
+
surveyId: campaign.id,
|
|
601
|
+
score: result.score,
|
|
602
|
+
text: result.reason,
|
|
603
|
+
tags: result.tags,
|
|
604
|
+
deviceId: getDeviceId(),
|
|
605
|
+
sessionId: currentSessionId(),
|
|
606
|
+
screen: activeScreenRef.current,
|
|
607
|
+
platform: currentPlatform(),
|
|
608
|
+
appVersion: currentAppVersion(),
|
|
609
|
+
};
|
|
610
|
+
|
|
611
|
+
const drafts = result.attachments ?? [];
|
|
612
|
+
if (engage.submitResponseConfirmed) {
|
|
613
|
+
// Confirmed lane: awaits real persistence (presign+PUT bytes → response
|
|
614
|
+
// POST), reports stages, idempotent on responseId, throws on failure.
|
|
615
|
+
await engage.submitResponseConfirmed(input, drafts, {
|
|
616
|
+
responseId,
|
|
617
|
+
onStage: (stage) => setSubmitStatus({ phase: 'submitting', stage }),
|
|
618
|
+
});
|
|
619
|
+
} else if (drafts.length > 0 && engage.submitResponseWithAttachments) {
|
|
620
|
+
// Fallback (older facade): fire-and-forget — resolves immediately.
|
|
621
|
+
engage.submitResponseWithAttachments(input, drafts);
|
|
622
|
+
} else {
|
|
623
|
+
engage.submitResponse(input);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
store?.markCompleted(campaign.id);
|
|
628
|
+
trackCampaign(campaign, 'completion');
|
|
629
|
+
setSubmitStatus({ phase: 'success' });
|
|
630
|
+
// Brief success beat, then close + reset.
|
|
631
|
+
successTimerRef.current = setTimeout(() => {
|
|
632
|
+
setActive(null);
|
|
633
|
+
activeScreenRef.current = undefined;
|
|
634
|
+
resetSubmit();
|
|
635
|
+
}, 1100);
|
|
636
|
+
} catch (err) {
|
|
637
|
+
logger.warn('[Engage] submit failed:', (err as Error)?.message);
|
|
638
|
+
setSubmitStatus({ phase: 'error', message: (err as Error)?.message });
|
|
639
|
+
}
|
|
640
|
+
}, [engage, trackCampaign, ratingRouting, resetSubmit, emitRatingFunnel]);
|
|
641
|
+
|
|
642
|
+
const handleSubmit = useCallback(
|
|
643
|
+
(campaign: EngageCampaignConfig, result: EngagePromptResult): void => {
|
|
644
|
+
// Guard double-submit: ignore re-fires once a submit is in flight or done.
|
|
645
|
+
if (submitCtxRef.current && responseIdRef.current) return;
|
|
646
|
+
submitCtxRef.current = { campaign, result };
|
|
647
|
+
void runSubmit();
|
|
648
|
+
},
|
|
649
|
+
[runSubmit],
|
|
650
|
+
);
|
|
651
|
+
|
|
652
|
+
const closeAfterSubmit = useCallback((): void => {
|
|
653
|
+
setActive(null);
|
|
654
|
+
activeScreenRef.current = undefined;
|
|
655
|
+
resetSubmit();
|
|
656
|
+
}, [resetSubmit]);
|
|
657
|
+
|
|
658
|
+
const showEngagePrompt = useCallback(
|
|
659
|
+
async (options?: ShowEngagePromptOptions): Promise<boolean> => {
|
|
660
|
+
const store = storeRef.current;
|
|
661
|
+
if (!store) return false;
|
|
662
|
+
try {
|
|
663
|
+
const config = await engage.fetchConfig(options?.context);
|
|
664
|
+
if (!config || !Array.isArray(config.campaigns)) return false;
|
|
665
|
+
|
|
666
|
+
const campaign = selectCampaignToRender(config.campaigns, store, {
|
|
667
|
+
// A behavioral-trigger fire (`options.trigger`) is type-agnostic:
|
|
668
|
+
// the trigger itself selects the campaign, so don't layer the
|
|
669
|
+
// NPS-first default on top (it would drop FEEDBACK/CSAT/etc.).
|
|
670
|
+
// Manual fires keep the provider default unless overridden.
|
|
671
|
+
types: options?.types ?? (options?.trigger ? undefined : types),
|
|
672
|
+
screen: options?.screen,
|
|
673
|
+
trigger: options?.trigger,
|
|
674
|
+
seconds: options?.seconds,
|
|
675
|
+
event: options?.event,
|
|
676
|
+
action: options?.action,
|
|
677
|
+
});
|
|
678
|
+
if (!campaign) {
|
|
679
|
+
logger.debug('[Engage] no eligible campaign to render');
|
|
680
|
+
return false;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// Record the impression up front so throttle counts it even if the
|
|
684
|
+
// user backgrounds the app before submitting.
|
|
685
|
+
store.recordImpression(campaign.id);
|
|
686
|
+
// Emit the §2.5 impression event (P3-e #2) so the dashboard's
|
|
687
|
+
// response-rate / completion KPIs have a real denominator — the
|
|
688
|
+
// prompt path previously only counted impressions locally.
|
|
689
|
+
trackCampaign(campaign, 'impression');
|
|
690
|
+
// Rating funnel (CONTRACT §1.1): selection passed the throttle/anti-
|
|
691
|
+
// annoyance gate (→ eligible) and we are about to render (→ shown).
|
|
692
|
+
if (isRatingType(campaign.type)) {
|
|
693
|
+
emitRatingFunnel(campaign, 'rating_prompt_eligible');
|
|
694
|
+
emitRatingFunnel(campaign, 'rating_prompt_shown');
|
|
695
|
+
}
|
|
696
|
+
// Stamp the show-time screen alongside the active campaign so
|
|
697
|
+
// handleSubmit can attribute the response to its originating screen.
|
|
698
|
+
activeScreenRef.current = options?.screen;
|
|
699
|
+
surveyStartedRef.current = null;
|
|
700
|
+
trackSurveyStage(campaign, 'shown');
|
|
701
|
+
resetSubmit();
|
|
702
|
+
setActive(campaign);
|
|
703
|
+
return true;
|
|
704
|
+
} catch (err) {
|
|
705
|
+
logger.warn('[Engage] showEngagePrompt failed:', (err as Error)?.message);
|
|
706
|
+
return false;
|
|
707
|
+
}
|
|
708
|
+
},
|
|
709
|
+
[engage, types, trackCampaign, trackSurveyStage, emitRatingFunnel],
|
|
710
|
+
);
|
|
711
|
+
|
|
712
|
+
// ─── In-app message lifecycle (the second Engage family, §2.4/§2.5) ──────
|
|
713
|
+
// Reuses the SAME transport (`trackEvent`), the SAME throttle store, and the
|
|
714
|
+
// SAME provider — NOT a parallel provider. Events: impression on show, click
|
|
715
|
+
// on CTA tap, completion on a finished tour, dismiss on close/skip.
|
|
716
|
+
|
|
717
|
+
const trackInApp = useCallback(
|
|
718
|
+
(
|
|
719
|
+
message: InAppMessageConfig,
|
|
720
|
+
eventType:
|
|
721
|
+
| 'impression'
|
|
722
|
+
| 'completion'
|
|
723
|
+
| 'click'
|
|
724
|
+
| 'dismiss'
|
|
725
|
+
| 'interaction'
|
|
726
|
+
| 'render_degraded'
|
|
727
|
+
| 'render_failed'
|
|
728
|
+
| 'cta_open_failed',
|
|
729
|
+
extraMeta?: Record<string, unknown>,
|
|
730
|
+
): void => {
|
|
731
|
+
try {
|
|
732
|
+
// A/B attribution (D8/J6): when the active message resolved to an
|
|
733
|
+
// experiment arm, tag every lifecycle event with the chosen variant
|
|
734
|
+
// via the existing optional `meta` field — NO event-schema change
|
|
735
|
+
// (EngageEventUpload already carries `meta`; the backend EngageEvent
|
|
736
|
+
// accepts it). Plain (non-experiment) messages send no variant key.
|
|
737
|
+
const variant = activeInAppVariantRef.current?.variant;
|
|
738
|
+
// [T1] Test-preview tagging: a preview-flagged message stamps
|
|
739
|
+
// `previewId` + `isTest` + `source` so (a) the backend CONSUMES the
|
|
740
|
+
// matching preview row on the impression and (b) production KPIs
|
|
741
|
+
// exclude the traffic. Normal campaign messages omit all of it.
|
|
742
|
+
const isPreview = message.preview === true || message.isTest === true;
|
|
743
|
+
const meta = {
|
|
744
|
+
...(variant ? { variant } : {}),
|
|
745
|
+
// testRunId correlates a specific "Send Test" run to its render/click/
|
|
746
|
+
// dismiss in the dashboard; rides the existing meta field (no schema churn).
|
|
747
|
+
...(message.testRunId ? { testRunId: message.testRunId } : {}),
|
|
748
|
+
...(extraMeta ?? {}),
|
|
749
|
+
};
|
|
750
|
+
engage.trackEvent({
|
|
751
|
+
campaignId: message.id,
|
|
752
|
+
channel: 'inapp',
|
|
753
|
+
type: eventType,
|
|
754
|
+
deviceId: getDeviceId(),
|
|
755
|
+
...(message.previewId ? { previewId: message.previewId } : {}),
|
|
756
|
+
...(isPreview ? { isTest: true, source: 'test_preview' } : {}),
|
|
757
|
+
...(variant ? { variantId: variant } : {}),
|
|
758
|
+
...(Object.keys(meta).length > 0 ? { meta } : {}),
|
|
759
|
+
});
|
|
760
|
+
} catch (err) {
|
|
761
|
+
logger.debug('[Engage] in-app trackEvent failed:', (err as Error)?.message);
|
|
762
|
+
}
|
|
763
|
+
},
|
|
764
|
+
[engage],
|
|
765
|
+
);
|
|
766
|
+
|
|
767
|
+
// [T1] In-app message actually mounted on screen. The impression event IS the test
|
|
768
|
+
// ACK to the backend (which consumes the preview row → 'rendered'). We ALSO persist the
|
|
769
|
+
// testRunId locally so a cold restart can't re-show it before the ACK is processed
|
|
770
|
+
// server-side — the one-shot guarantee survives a flaky/slow network.
|
|
771
|
+
const handleInAppShow = useCallback(
|
|
772
|
+
(message: InAppMessageConfig): void => {
|
|
773
|
+
// A slot can be replaced or degrade to an overlay while the same message
|
|
774
|
+
// remains active. Treat that as one mount lifecycle, not two impressions.
|
|
775
|
+
if (shownInAppMessageIdRef.current === message.id) return;
|
|
776
|
+
shownInAppMessageIdRef.current = message.id;
|
|
777
|
+
trackInApp(message, 'impression');
|
|
778
|
+
if (message.preview === true || message.isTest === true) {
|
|
779
|
+
const runId = message.testRunId ?? message.previewId ?? message.id;
|
|
780
|
+
seenTestsRef.current?.markSeen(runId);
|
|
781
|
+
// Eager-flush so the backend consumes the one-shot preview row NOW — a fast
|
|
782
|
+
// close→kill→reopen must not re-serve a still-`delivered` test.
|
|
783
|
+
engage.flushEvents?.();
|
|
784
|
+
logger.debug(`[Engage] test ${runId} render displayed — ACK sent (impression), flushed`);
|
|
785
|
+
}
|
|
786
|
+
},
|
|
787
|
+
[trackInApp, engage],
|
|
788
|
+
);
|
|
789
|
+
|
|
790
|
+
const finalizeInAppMessage = useCallback((eventType: 'dismiss' | 'completion'): void => {
|
|
791
|
+
setActiveInApp((current) => {
|
|
792
|
+
if (current) {
|
|
793
|
+
const isTest = current.preview === true || current.isTest === true;
|
|
794
|
+
const runId = current.testRunId ?? current.previewId ?? current.id;
|
|
795
|
+
logger.debug(`[Engage] in-app ${eventType}${isTest ? ` (test ${runId})` : ''}`);
|
|
796
|
+
trackInApp(current, eventType);
|
|
797
|
+
if (isTest) {
|
|
798
|
+
consumedPreviewIds.current.add(current.previewId ?? current.id);
|
|
799
|
+
seenTestsRef.current?.markSeen(runId);
|
|
800
|
+
engage.flushEvents?.();
|
|
801
|
+
logger.debug(`[Engage] test ${runId} ${eventType} persisted + ACK flushed`);
|
|
802
|
+
} else {
|
|
803
|
+
// Stamp the SERVED revision: without it the completion can never be invalidated,
|
|
804
|
+
// and an edited campaign would never return to a device that closed the old one.
|
|
805
|
+
storeRef.current?.markCompleted(current.id, Date.now(), current.revision);
|
|
806
|
+
engage.flushEvents?.();
|
|
807
|
+
logger.debug(`[Engage] in-app ${current.id} ${eventType} — marked done on device`);
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
return null;
|
|
811
|
+
});
|
|
812
|
+
// Clear the resolved A/B arm after the lifecycle event has read it.
|
|
813
|
+
shownInAppMessageIdRef.current = null;
|
|
814
|
+
activeInAppVariantRef.current = null;
|
|
815
|
+
}, [trackInApp, engage]);
|
|
816
|
+
|
|
817
|
+
const dismissInAppMessage = useCallback((): void => {
|
|
818
|
+
finalizeInAppMessage('dismiss');
|
|
819
|
+
}, [finalizeInAppMessage]);
|
|
820
|
+
|
|
821
|
+
const completeInAppMessage = useCallback((): void => {
|
|
822
|
+
finalizeInAppMessage('completion');
|
|
823
|
+
}, [finalizeInAppMessage]);
|
|
824
|
+
|
|
825
|
+
const handleInAppCta = useCallback(
|
|
826
|
+
(message: InAppMessageConfig, cta: NonNullable<InAppRenderSpec['cta']>): void => {
|
|
827
|
+
if (shouldTrackInAppCta(cta)) trackInApp(message, 'click');
|
|
828
|
+
// Deep-link opening is the host's job — surface it, never open it here.
|
|
829
|
+
if (cta.action === 'link') {
|
|
830
|
+
if (!cta.deepLink) {
|
|
831
|
+
// Misconfigured link CTA (no deepLink) — observable, not silent (T1 G17).
|
|
832
|
+
logger.warn('[Engage] link CTA has no deepLink');
|
|
833
|
+
trackInApp(message, 'cta_open_failed', { reason: 'missing_deeplink' });
|
|
834
|
+
} else if (!onInAppDeepLink) {
|
|
835
|
+
// Host wired no deep-link sink — the link can't open. Diagnose it.
|
|
836
|
+
logger.warn('[Engage] link CTA but no onInAppDeepLink handler supplied');
|
|
837
|
+
trackInApp(message, 'cta_open_failed', { reason: 'no_handler' });
|
|
838
|
+
} else {
|
|
839
|
+
try {
|
|
840
|
+
onInAppDeepLink({ message, cta, deepLink: cta.deepLink });
|
|
841
|
+
} catch (err) {
|
|
842
|
+
logger.warn('[Engage] onInAppDeepLink threw:', (err as Error)?.message);
|
|
843
|
+
trackInApp(message, 'cta_open_failed', {
|
|
844
|
+
reason: (err as Error)?.message ?? 'handler_threw',
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
// A test preview the user acted on is done — don't re-show it next poll AND
|
|
850
|
+
// persist it durably (a CTA tap is as final as a close), then flush the ACK.
|
|
851
|
+
if (message.preview === true || message.isTest === true) {
|
|
852
|
+
const runId = message.testRunId ?? message.previewId ?? message.id;
|
|
853
|
+
consumedPreviewIds.current.add(message.previewId ?? message.id);
|
|
854
|
+
seenTestsRef.current?.markSeen(runId);
|
|
855
|
+
engage.flushEvents?.();
|
|
856
|
+
logger.debug(`[Engage] test ${runId} CTA — persisted locally + ACK flushed`);
|
|
857
|
+
} else {
|
|
858
|
+
// Production message: a CTA tap is as final as a close — don't re-show it.
|
|
859
|
+
storeRef.current?.markCompleted(message.id, Date.now(), message.revision);
|
|
860
|
+
engage.flushEvents?.();
|
|
861
|
+
logger.debug(`[Engage] in-app ${message.id} CTA tapped — marked done on device`);
|
|
862
|
+
}
|
|
863
|
+
setActiveInApp(null);
|
|
864
|
+
// Any enabled click event above already read the arm; clear it now.
|
|
865
|
+
shownInAppMessageIdRef.current = null;
|
|
866
|
+
activeInAppVariantRef.current = null;
|
|
867
|
+
},
|
|
868
|
+
[trackInApp, onInAppDeepLink, engage],
|
|
869
|
+
);
|
|
870
|
+
|
|
871
|
+
// [T1] Pick the ONE test preview to render from a fetched config: drop any already
|
|
872
|
+
// displayed (persistent seen store) or closed-this-session, then take the LATEST by
|
|
873
|
+
// createdAt. One-shot + latest-only is what stops the "tests stack up 1,2,3…" bug.
|
|
874
|
+
const pickLatestPreview = useCallback(
|
|
875
|
+
(messages: InAppMessageConfig[]): InAppMessageConfig | null => {
|
|
876
|
+
const latest = selectLatestUnseenTest(messages, {
|
|
877
|
+
seen: (runId) => seenTestsRef.current?.has(runId) ?? false,
|
|
878
|
+
consumed: (key) => consumedPreviewIds.current.has(key),
|
|
879
|
+
});
|
|
880
|
+
if (latest) logger.debug(`[Engage] selected latest test ${testRunIdOf(latest)}`);
|
|
881
|
+
return latest;
|
|
882
|
+
},
|
|
883
|
+
[],
|
|
884
|
+
);
|
|
885
|
+
|
|
886
|
+
// [T1] Render a test preview IMMEDIATELY — bypassing trigger/throttle/schedule/
|
|
887
|
+
// sample/variant. No throttle write (a preview must stay re-showable until it is
|
|
888
|
+
// actually rendered + its impression consumes it server-side). Idempotent: if this
|
|
889
|
+
// exact preview is already on screen, don't re-mount (avoids a duplicate impression).
|
|
890
|
+
const showPreview = useCallback(
|
|
891
|
+
(preview: InAppMessageConfig): boolean => {
|
|
892
|
+
// PRECEDENCE: a campaign prompt owns the screen — defer (the backend re-serves
|
|
893
|
+
// the preview on every poll until TTL, so the next foreground retries).
|
|
894
|
+
if (active !== null) {
|
|
895
|
+
logger.debug('[Engage] campaign prompt active — preview deferred');
|
|
896
|
+
return false;
|
|
897
|
+
}
|
|
898
|
+
if (activeInApp?.id === preview.id) return true;
|
|
899
|
+
const runId = preview.testRunId ?? preview.previewId ?? preview.id;
|
|
900
|
+
// Already closed this preview this session — don't re-show on the next poll.
|
|
901
|
+
if (consumedPreviewIds.current.has(preview.previewId ?? preview.id)) {
|
|
902
|
+
return false;
|
|
903
|
+
}
|
|
904
|
+
// [T1] One-shot: already DISPLAYED on this device (persisted across restarts) —
|
|
905
|
+
// never re-show, even if the backend briefly re-serves a not-yet-ACKed row.
|
|
906
|
+
if (seenTestsRef.current?.has(runId)) {
|
|
907
|
+
logger.debug(`[Engage] test ${runId} already displayed on device — skip`);
|
|
908
|
+
return false;
|
|
909
|
+
}
|
|
910
|
+
activeInAppVariantRef.current = null;
|
|
911
|
+
setActiveInApp(preview);
|
|
912
|
+
logger.debug(`[Engage] test ${runId} render started`);
|
|
913
|
+
return true;
|
|
914
|
+
},
|
|
915
|
+
[active, activeInApp],
|
|
916
|
+
);
|
|
917
|
+
|
|
918
|
+
const showInAppMessage = useCallback(
|
|
919
|
+
async (options?: ShowInAppMessageOptions): Promise<boolean> => {
|
|
920
|
+
const store = storeRef.current;
|
|
921
|
+
if (!store) return false;
|
|
922
|
+
// PRECEDENCE: a campaign prompt on screen wins — never stack an in-app
|
|
923
|
+
// message over an open survey/NPS/rating prompt.
|
|
924
|
+
if (active !== null) {
|
|
925
|
+
logger.debug('[Engage] campaign prompt active — in-app message deferred');
|
|
926
|
+
return false;
|
|
927
|
+
}
|
|
928
|
+
try {
|
|
929
|
+
const config = await engage.fetchConfig(buildConfigContext(engage, options?.context));
|
|
930
|
+
if (!config || !Array.isArray(config.inAppMessages)) return false;
|
|
931
|
+
|
|
932
|
+
// [T1] A queued test preview wins immediately, bypassing throttle/variant.
|
|
933
|
+
// Pick the LATEST unseen one (one-shot dedupe) — never stack old tests.
|
|
934
|
+
const preview = pickLatestPreview(config.inAppMessages);
|
|
935
|
+
if (preview) return showPreview(preview);
|
|
936
|
+
|
|
937
|
+
// Normal selection runs over NON-preview messages only — a preview must
|
|
938
|
+
// never enter the throttle store (it would falsely cap a real campaign id).
|
|
939
|
+
const normal = config.inAppMessages.filter(
|
|
940
|
+
(m) => !(m.preview === true || m.isTest === true),
|
|
941
|
+
);
|
|
942
|
+
const message = selectInAppToRender(normal, store, {
|
|
943
|
+
screen: options?.screen,
|
|
944
|
+
trigger: options?.trigger,
|
|
945
|
+
seconds: options?.seconds,
|
|
946
|
+
event: options?.event,
|
|
947
|
+
action: options?.action,
|
|
948
|
+
});
|
|
949
|
+
if (!message) {
|
|
950
|
+
logger.debug('[Engage] no eligible in-app message to render');
|
|
951
|
+
return false;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
// A/B variant selection (D8/J6): deterministically bucket this
|
|
955
|
+
// device into arm A (base spec) or B (experiment.variantB) BEFORE
|
|
956
|
+
// showing, so the impression event (and click/dismiss) attribute to
|
|
957
|
+
// the arm the user actually saw. Only retained for attribution when
|
|
958
|
+
// the message actually carries an enabled experiment; otherwise the
|
|
959
|
+
// resolved spec is just the base spec and no variant key is emitted.
|
|
960
|
+
const resolved = selectInAppVariant(message, getDeviceId());
|
|
961
|
+
activeInAppVariantRef.current = message.experiment?.enabled
|
|
962
|
+
? resolved
|
|
963
|
+
: null;
|
|
964
|
+
// Record up front so the throttle counts it (impression also emitted
|
|
965
|
+
// by the view's onShow → trackEvent for the analytics lane). Pass the
|
|
966
|
+
// content revision so an edited campaign starts a fresh cap generation.
|
|
967
|
+
store.recordImpression(message.id, Date.now(), message.revision);
|
|
968
|
+
setActiveInApp(message);
|
|
969
|
+
return true;
|
|
970
|
+
} catch (err) {
|
|
971
|
+
logger.warn('[Engage] showInAppMessage failed:', (err as Error)?.message);
|
|
972
|
+
return false;
|
|
973
|
+
}
|
|
974
|
+
},
|
|
975
|
+
[engage, active, showPreview, pickLatestPreview],
|
|
976
|
+
);
|
|
977
|
+
|
|
978
|
+
// ─── Cold-start + foreground preview check (T1) ──────────────────────────
|
|
979
|
+
// "Send Test → reopen the app → see it immediately, EVERY time": the SDK fetches
|
|
980
|
+
// config (deviceId in context, HTTP cache-bypassed) on mount AND on every
|
|
981
|
+
// AppState→active, and renders any queued preview at once — no trigger, no throttle,
|
|
982
|
+
// no schedule. The backend keeps serving the preview on every poll until its TTL, so
|
|
983
|
+
// a tester sees it on each reopen (rendering records lifecycle but does not consume).
|
|
984
|
+
const checkForPreview = useCallback(async (): Promise<void> => {
|
|
985
|
+
if (active !== null) return;
|
|
986
|
+
try {
|
|
987
|
+
const config = await engage.fetchConfig(buildConfigContext(engage));
|
|
988
|
+
// One-shot + latest-only: render the newest test not already displayed.
|
|
989
|
+
const preview = pickLatestPreview(config?.inAppMessages ?? []);
|
|
990
|
+
if (preview) showPreview(preview);
|
|
991
|
+
} catch (err) {
|
|
992
|
+
logger.warn('[Engage] preview check failed:', (err as Error)?.message);
|
|
993
|
+
}
|
|
994
|
+
}, [engage, active, showPreview, pickLatestPreview]);
|
|
995
|
+
|
|
996
|
+
useEffect(() => {
|
|
997
|
+
// Drop stale seen-test entries (past TTL) so the persistent set stays bounded.
|
|
998
|
+
seenTestsRef.current?.prune();
|
|
999
|
+
void checkForPreview();
|
|
1000
|
+
const onLifecycle = (state: string): void => {
|
|
1001
|
+
if (state === 'active') void checkForPreview();
|
|
1002
|
+
};
|
|
1003
|
+
appLifecycle.addListener(onLifecycle);
|
|
1004
|
+
return () => appLifecycle.removeListener(onLifecycle);
|
|
1005
|
+
}, [checkForPreview]);
|
|
1006
|
+
|
|
1007
|
+
// DEV/TEST warm-foreground poll (T1): covers "Send Test while the app is already
|
|
1008
|
+
// open" — no background→foreground edge fires, so without this you'd have to switch
|
|
1009
|
+
// apps to see it. Only runs when the host opts in via `previewPollMs` (unset in prod).
|
|
1010
|
+
useEffect(() => {
|
|
1011
|
+
if (!previewPollMs || previewPollMs <= 0) return;
|
|
1012
|
+
logger.debug(`[Engage] test-preview warm poll every ${previewPollMs}ms (dev)`);
|
|
1013
|
+
const interval = setInterval(() => {
|
|
1014
|
+
void checkForPreview();
|
|
1015
|
+
}, previewPollMs);
|
|
1016
|
+
return () => clearInterval(interval);
|
|
1017
|
+
}, [previewPollMs, checkForPreview]);
|
|
1018
|
+
|
|
1019
|
+
// ─── Always-on behavioral triggers (P3-e #3 / Slice E) ───────────────────
|
|
1020
|
+
// The trigger engine wires every behavioral trigger (session_start, app_open,
|
|
1021
|
+
// screen_view/exit, time_in_app, n_sessions, after_purchase, before_logout,
|
|
1022
|
+
// custom_event, failed_action, after_crash/js_error, network_error, slow_screen,
|
|
1023
|
+
// and the native gesture triggers) to the SDK signals the app already produces.
|
|
1024
|
+
// A fire first tries the survey/rating campaign path (showEngagePrompt); if no
|
|
1025
|
+
// campaign matches, the SAME trigger drives an in-app message (showInAppMessage).
|
|
1026
|
+
// Both families share the throttle store, so a behavioral fire never double-shows.
|
|
1027
|
+
// The engine buffers events fired before the first config arrives and replays
|
|
1028
|
+
// them once it does (late binding), honoring each trigger's remaining delay.
|
|
1029
|
+
useEffect(() => {
|
|
1030
|
+
return installEngageTriggerEngine({
|
|
1031
|
+
fire: (options) => {
|
|
1032
|
+
void (async () => {
|
|
1033
|
+
const shown = await showEngagePrompt(options);
|
|
1034
|
+
if (!shown && options.trigger) {
|
|
1035
|
+
await showInAppMessage({
|
|
1036
|
+
trigger: options.trigger,
|
|
1037
|
+
screen: options.screen,
|
|
1038
|
+
event: options.event,
|
|
1039
|
+
action: options.action,
|
|
1040
|
+
seconds: options.seconds,
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
})();
|
|
1044
|
+
},
|
|
1045
|
+
fetchConfig: () => engage.fetchConfig(buildConfigContext(engage)),
|
|
1046
|
+
});
|
|
1047
|
+
}, [showEngagePrompt, showInAppMessage, engage]);
|
|
1048
|
+
|
|
1049
|
+
const controller = useMemo<EngagePromptController>(
|
|
1050
|
+
() => ({
|
|
1051
|
+
showEngagePrompt,
|
|
1052
|
+
dismissEngagePrompt,
|
|
1053
|
+
showInAppMessage,
|
|
1054
|
+
dismissInAppMessage,
|
|
1055
|
+
}),
|
|
1056
|
+
[showEngagePrompt, dismissEngagePrompt, showInAppMessage, dismissInAppMessage],
|
|
1057
|
+
);
|
|
1058
|
+
|
|
1059
|
+
const activeInAppSpec = activeInAppVariantRef.current?.spec ?? activeInApp?.spec;
|
|
1060
|
+
const activeInAppPresentation = activeInApp && activeInAppSpec
|
|
1061
|
+
? resolveInAppPresentation({
|
|
1062
|
+
layout: activeInApp.layout,
|
|
1063
|
+
variantKey: activeInApp.variantKey,
|
|
1064
|
+
spec: activeInAppSpec,
|
|
1065
|
+
})
|
|
1066
|
+
: null;
|
|
1067
|
+
// Route by the canonical mount, not a variant allow-list. This covers every
|
|
1068
|
+
// current/future inline variant, including smart_inbox_message.
|
|
1069
|
+
const routesToInlineSlot = activeInAppPresentation?.mountModel === 'inline';
|
|
1070
|
+
const inlinePlacement = resolveEngageInlinePlacement(activeInAppSpec);
|
|
1071
|
+
|
|
1072
|
+
const handleActiveInAppShow = useCallback((): void => {
|
|
1073
|
+
if (!activeInApp) return;
|
|
1074
|
+
handleInAppShow(activeInApp);
|
|
1075
|
+
const tourId = activeInApp.spec.ext?.coachTourId;
|
|
1076
|
+
const first = Array.isArray(activeInApp.spec.ext?.steps) ? activeInApp.spec.ext?.steps[0] as Record<string, unknown> | undefined : undefined;
|
|
1077
|
+
if (typeof tourId === 'string') {
|
|
1078
|
+
engage.trackCoachmarkEvent?.('$coachmark_tour_started', { tourId });
|
|
1079
|
+
engage.trackCoachmarkEvent?.('$coachmark_step_entered', {
|
|
1080
|
+
tourId,
|
|
1081
|
+
stepId: String(first?.id ?? first?.anchorKey ?? '1'),
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
}, [activeInApp, handleInAppShow, engage]);
|
|
1085
|
+
const handleActiveInAppCta = useCallback((cta: NonNullable<InAppRenderSpec['cta']>): void => {
|
|
1086
|
+
if (activeInApp) handleInAppCta(activeInApp, cta);
|
|
1087
|
+
}, [activeInApp, handleInAppCta]);
|
|
1088
|
+
const handleActiveInAppInteraction = useCallback((interaction: InAppMechanicInteraction): void => {
|
|
1089
|
+
if (!activeInApp) return;
|
|
1090
|
+
trackInApp(activeInApp, 'interaction', { interaction });
|
|
1091
|
+
const tourId = activeInApp.spec.ext?.coachTourId;
|
|
1092
|
+
if (typeof tourId !== 'string' || interaction.mechanic !== 'coachmark_spotlight') return;
|
|
1093
|
+
const meta = interaction.meta ?? {};
|
|
1094
|
+
const stepId = String(meta.anchorKey ?? meta.step ?? meta.toStep ?? 'unknown');
|
|
1095
|
+
if (interaction.result === 'step_viewed' && interaction.phase !== 'started') {
|
|
1096
|
+
engage.trackCoachmarkEvent?.('$coachmark_step_entered', { tourId, stepId });
|
|
1097
|
+
} else if (interaction.phase === 'completed') {
|
|
1098
|
+
engage.trackCoachmarkEvent?.('$coachmark_tour_completed', { tourId, stepId });
|
|
1099
|
+
} else if (interaction.result === 'skipped') {
|
|
1100
|
+
engage.trackCoachmarkEvent?.('$coachmark_tour_abandoned', { tourId, stepId });
|
|
1101
|
+
}
|
|
1102
|
+
}, [activeInApp, trackInApp, engage]);
|
|
1103
|
+
const handleActiveInAppRenderError = useCallback((reason: string): void => {
|
|
1104
|
+
if (activeInApp) {
|
|
1105
|
+
trackInApp(activeInApp, 'render_failed', { reason });
|
|
1106
|
+
const tourId = activeInApp.spec.ext?.coachTourId;
|
|
1107
|
+
if (typeof tourId === 'string') {
|
|
1108
|
+
const anchorKey = reason.startsWith('anchor_not_found:') ? reason.slice('anchor_not_found:'.length) : 'unknown';
|
|
1109
|
+
engage.trackCoachmarkEvent?.('$coachmark_anchor_failed', {
|
|
1110
|
+
tourId,
|
|
1111
|
+
stepId: anchorKey,
|
|
1112
|
+
reason: reason.startsWith('anchor_not_found:') ? 'anchor_not_found' : reason,
|
|
1113
|
+
});
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
shownInAppMessageIdRef.current = null;
|
|
1117
|
+
activeInAppVariantRef.current = null;
|
|
1118
|
+
setActiveInApp(null);
|
|
1119
|
+
}, [activeInApp, trackInApp, engage]);
|
|
1120
|
+
|
|
1121
|
+
useEffect(() => {
|
|
1122
|
+
if (!routesToInlineSlot || !inlinePlacement.placementKey) return;
|
|
1123
|
+
return inlinePlacementRegistry.subscribe(inlinePlacement.placementKey, () => {
|
|
1124
|
+
setInlinePlacementRevision((revision) => revision + 1);
|
|
1125
|
+
});
|
|
1126
|
+
}, [inlinePlacement.placementKey, inlinePlacementRegistry, routesToInlineSlot]);
|
|
1127
|
+
|
|
1128
|
+
useEffect(() => {
|
|
1129
|
+
if (!activeInApp || active !== null || !routesToInlineSlot) {
|
|
1130
|
+
setInlineFallbackMessageId(null);
|
|
1131
|
+
return;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
const messageId = activeInApp.id;
|
|
1135
|
+
// Once this message has visibly degraded, keep it on that mount. Moving it
|
|
1136
|
+
// into a late slot would create a second renderer and a misleading lifecycle.
|
|
1137
|
+
if (inlineFallbackMessageId === messageId) return;
|
|
1138
|
+
const reason = inlinePlacement.placementKey
|
|
1139
|
+
? `inline_placement_not_found:${inlinePlacement.placementKey}`
|
|
1140
|
+
: 'missing_inline_placement_key';
|
|
1141
|
+
const delivery: EngageInlineDelivery = {
|
|
1142
|
+
message: activeInApp,
|
|
1143
|
+
spec: activeInAppSpec,
|
|
1144
|
+
onShow: handleActiveInAppShow,
|
|
1145
|
+
onCta: handleActiveInAppCta,
|
|
1146
|
+
onDismiss: dismissInAppMessage,
|
|
1147
|
+
onComplete: completeInAppMessage,
|
|
1148
|
+
onInteraction: handleActiveInAppInteraction,
|
|
1149
|
+
onInAppGameRequest,
|
|
1150
|
+
onRenderError: handleActiveInAppRenderError,
|
|
1151
|
+
};
|
|
1152
|
+
const delivered = inlinePlacementRegistry.deliver(
|
|
1153
|
+
inlinePlacement.placementKey,
|
|
1154
|
+
delivery,
|
|
1155
|
+
);
|
|
1156
|
+
|
|
1157
|
+
if (delivered) {
|
|
1158
|
+
setInlineFallbackMessageId(null);
|
|
1159
|
+
} else {
|
|
1160
|
+
inlinePlacementRegistry.clear(inlinePlacement.placementKey, messageId);
|
|
1161
|
+
if (inlinePlacement.fallback === 'skip') {
|
|
1162
|
+
setInlineFallbackMessageId(null);
|
|
1163
|
+
handleActiveInAppRenderError(reason);
|
|
1164
|
+
} else {
|
|
1165
|
+
// Preserve the legacy visible behavior, but make the degradation observable.
|
|
1166
|
+
trackInApp(activeInApp, 'render_degraded', {
|
|
1167
|
+
reason,
|
|
1168
|
+
placementKey: inlinePlacement.placementKey,
|
|
1169
|
+
fallback: 'overlay',
|
|
1170
|
+
});
|
|
1171
|
+
setInlineFallbackMessageId(messageId);
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
return () => inlinePlacementRegistry.clear(inlinePlacement.placementKey, messageId);
|
|
1176
|
+
}, [
|
|
1177
|
+
active,
|
|
1178
|
+
activeInApp,
|
|
1179
|
+
activeInAppSpec,
|
|
1180
|
+
dismissInAppMessage,
|
|
1181
|
+
completeInAppMessage,
|
|
1182
|
+
handleActiveInAppCta,
|
|
1183
|
+
handleActiveInAppInteraction,
|
|
1184
|
+
handleActiveInAppRenderError,
|
|
1185
|
+
handleActiveInAppShow,
|
|
1186
|
+
inlinePlacement.fallback,
|
|
1187
|
+
inlinePlacement.placementKey,
|
|
1188
|
+
inlinePlacementRegistry,
|
|
1189
|
+
inlineFallbackMessageId,
|
|
1190
|
+
inlinePlacementRevision,
|
|
1191
|
+
onInAppGameRequest,
|
|
1192
|
+
routesToInlineSlot,
|
|
1193
|
+
trackInApp,
|
|
1194
|
+
]);
|
|
1195
|
+
|
|
1196
|
+
const rootInAppVisible = activeInApp !== null &&
|
|
1197
|
+
active === null &&
|
|
1198
|
+
(!routesToInlineSlot || inlineFallbackMessageId === activeInApp.id);
|
|
1199
|
+
|
|
1200
|
+
return (
|
|
1201
|
+
<EngageAnchorProvider>
|
|
1202
|
+
<EngageInlinePlacementProvider registry={inlinePlacementRegistry}>
|
|
1203
|
+
<EngagePromptContext.Provider value={controller}>
|
|
1204
|
+
{children}
|
|
1205
|
+
<EngagePromptView
|
|
1206
|
+
campaign={active}
|
|
1207
|
+
visible={active !== null}
|
|
1208
|
+
rating={ratingRouting}
|
|
1209
|
+
submitStatus={submitStatus}
|
|
1210
|
+
onRetrySubmit={() => void runSubmit()}
|
|
1211
|
+
onCloseSubmit={closeAfterSubmit}
|
|
1212
|
+
onSubmit={(result) => {
|
|
1213
|
+
if (active) handleSubmit(active, result);
|
|
1214
|
+
}}
|
|
1215
|
+
onStart={() => {
|
|
1216
|
+
if (active && surveyStartedRef.current !== active.id) {
|
|
1217
|
+
surveyStartedRef.current = active.id;
|
|
1218
|
+
trackSurveyStage(active, 'started');
|
|
1219
|
+
}
|
|
1220
|
+
}}
|
|
1221
|
+
onDismiss={dismissEngagePrompt}
|
|
1222
|
+
/>
|
|
1223
|
+
{/* In-app message overlay. PRECEDENCE: only visible when no campaign
|
|
1224
|
+
prompt is on screen, so the two families never fight for the view. */}
|
|
1225
|
+
<EngageInAppView
|
|
1226
|
+
message={activeInApp}
|
|
1227
|
+
visible={rootInAppVisible}
|
|
1228
|
+
mountModelOverride={routesToInlineSlot && inlineFallbackMessageId === activeInApp?.id
|
|
1229
|
+
? 'overlay'
|
|
1230
|
+
: undefined}
|
|
1231
|
+
// Render the resolved A/B arm's content (D8/J6) when an experiment is
|
|
1232
|
+
// active; undefined ⇒ the view falls back to the message's base spec.
|
|
1233
|
+
spec={activeInAppVariantRef.current?.spec}
|
|
1234
|
+
onShow={handleActiveInAppShow}
|
|
1235
|
+
onCta={handleActiveInAppCta}
|
|
1236
|
+
onDismiss={dismissInAppMessage}
|
|
1237
|
+
onComplete={completeInAppMessage}
|
|
1238
|
+
onInteraction={handleActiveInAppInteraction}
|
|
1239
|
+
onInAppGameRequest={onInAppGameRequest}
|
|
1240
|
+
onRenderError={handleActiveInAppRenderError}
|
|
1241
|
+
/>
|
|
1242
|
+
</EngagePromptContext.Provider>
|
|
1243
|
+
</EngageInlinePlacementProvider>
|
|
1244
|
+
</EngageAnchorProvider>
|
|
1245
|
+
);
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
/**
|
|
1249
|
+
* Hook a host app uses to trigger/dismiss the prompt:
|
|
1250
|
+
* const { showEngagePrompt } = useEngagePrompt();
|
|
1251
|
+
* showEngagePrompt({ types: ['NPS'] });
|
|
1252
|
+
*/
|
|
1253
|
+
export function useEngagePrompt(): EngagePromptController {
|
|
1254
|
+
const ctx = useContext(EngagePromptContext);
|
|
1255
|
+
if (!ctx) {
|
|
1256
|
+
// Fail-soft: a host that calls the hook outside the provider gets no-ops
|
|
1257
|
+
// instead of a crash (matches the SDK's no-throw public-API style).
|
|
1258
|
+
return {
|
|
1259
|
+
showEngagePrompt: async () => {
|
|
1260
|
+
logger.warn('[Engage] useEngagePrompt() called outside <EngagePromptProvider>');
|
|
1261
|
+
return false;
|
|
1262
|
+
},
|
|
1263
|
+
dismissEngagePrompt: () => {},
|
|
1264
|
+
showInAppMessage: async () => {
|
|
1265
|
+
logger.warn('[Engage] useEngagePrompt() called outside <EngagePromptProvider>');
|
|
1266
|
+
return false;
|
|
1267
|
+
},
|
|
1268
|
+
dismissInAppMessage: () => {},
|
|
1269
|
+
};
|
|
1270
|
+
}
|
|
1271
|
+
return ctx;
|
|
1272
|
+
}
|