@scalebun-release/react-native 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1203) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +154 -0
  3. package/android/build.gradle +94 -0
  4. package/android/consumer-rules.pro +28 -0
  5. package/android/src/androidTest/java/com/scalebun/rn/ota/ScaleBunOtaVerifierInstrumentedTest.kt +112 -0
  6. package/android/src/main/AndroidManifest.xml +14 -0
  7. package/android/src/main/java/com/scalebun/core/crash/CrashStorage.kt +155 -0
  8. package/android/src/main/java/com/scalebun/core/crash/NativeCrashHandler.kt +93 -0
  9. package/android/src/main/java/com/scalebun/core/performance/ANRWatchdog.kt +100 -0
  10. package/android/src/main/java/com/scalebun/core/performance/AppStartCollector.kt +180 -0
  11. package/android/src/main/java/com/scalebun/core/performance/FrameMetricsCollector.kt +230 -0
  12. package/android/src/main/java/com/scalebun/core/performance/PerformanceCore.kt +165 -0
  13. package/android/src/main/java/com/scalebun/profiler/ProfilerModule.kt +398 -0
  14. package/android/src/main/java/com/scalebun/profiler/ProfilerPackage.kt +24 -0
  15. package/android/src/main/java/com/scalebun/profiler/collectors/CpuCollector.kt +161 -0
  16. package/android/src/main/java/com/scalebun/profiler/collectors/IncidentDetector.kt +223 -0
  17. package/android/src/main/java/com/scalebun/profiler/collectors/MemoryCollector.kt +157 -0
  18. package/android/src/main/java/com/scalebun/profiler/collectors/RenderCollector.kt +194 -0
  19. package/android/src/main/java/com/scalebun/profiler/collectors/SamplerScheduler.kt +218 -0
  20. package/android/src/main/java/com/scalebun/profiler/collectors/ThreadCollector.kt +142 -0
  21. package/android/src/main/java/com/scalebun/replaysdk/ReplaySdkModule.kt +1117 -0
  22. package/android/src/main/java/com/scalebun/replaysdk/ReplaySdkPackage.kt +24 -0
  23. package/android/src/main/java/com/scalebun/replaysdk/capture/CaptureReason.kt +47 -0
  24. package/android/src/main/java/com/scalebun/replaysdk/capture/FrameCaptureManager.kt +574 -0
  25. package/android/src/main/java/com/scalebun/replaysdk/capture/FrameCaptureScheduler.kt +187 -0
  26. package/android/src/main/java/com/scalebun/replaysdk/capture/UiStabilityDetector.kt +214 -0
  27. package/android/src/main/java/com/scalebun/replaysdk/core/ReplayConfig.kt +144 -0
  28. package/android/src/main/java/com/scalebun/replaysdk/core/ReplayLogger.kt +31 -0
  29. package/android/src/main/java/com/scalebun/replaysdk/core/SessionIdGenerator.kt +15 -0
  30. package/android/src/main/java/com/scalebun/replaysdk/models/ReplayModels.kt +94 -0
  31. package/android/src/main/java/com/scalebun/replaysdk/outbox/NativeOutbox.kt +574 -0
  32. package/android/src/main/java/com/scalebun/replaysdk/outbox/OutboxUploader.kt +559 -0
  33. package/android/src/main/java/com/scalebun/replaysdk/privacy/PrivacyMaskProcessor.kt +126 -0
  34. package/android/src/main/java/com/scalebun/replaysdk/session/SessionManager.kt +322 -0
  35. package/android/src/main/java/com/scalebun/replaysdk/storage/ReplayStorage.kt +136 -0
  36. package/android/src/main/java/com/scalebun/replaysdk/timeline/TimelineCollector.kt +28 -0
  37. package/android/src/main/java/com/scalebun/replaysdk/tracking/InteractionTracker.kt +470 -0
  38. package/android/src/main/java/com/scalebun/replaysdk/tracking/ScreenTracker.kt +20 -0
  39. package/android/src/main/java/com/scalebun/replaysdk/tracking/ScrollContextProbe.kt +188 -0
  40. package/android/src/main/java/com/scalebun/replaysdk/transport/ReplayTransport.kt +99 -0
  41. package/android/src/main/java/com/scalebun/replaysdk/voice/VoiceRecorder.kt +121 -0
  42. package/android/src/main/java/com/scalebun/replaysdk/voice/VoiceTranscriber.kt +170 -0
  43. package/android/src/main/java/com/scalebun/rn/ScaleBunPackage.kt +113 -0
  44. package/android/src/main/java/com/scalebun/rn/crash/ScaleBunCrashModule.kt +188 -0
  45. package/android/src/main/java/com/scalebun/rn/crash/ScaleBunCrashPackage.kt +22 -0
  46. package/android/src/main/java/com/scalebun/rn/engage/ScaleBunEngageModule.kt +579 -0
  47. package/android/src/main/java/com/scalebun/rn/engage/ScaleBunEngagePackage.kt +22 -0
  48. package/android/src/main/java/com/scalebun/rn/engage/ScaleBunNotificationPresenter.kt +110 -0
  49. package/android/src/main/java/com/scalebun/rn/ota/BsPatch.kt +240 -0
  50. package/android/src/main/java/com/scalebun/rn/ota/BundleDownloader.kt +195 -0
  51. package/android/src/main/java/com/scalebun/rn/ota/DeviceIntegrity.kt +81 -0
  52. package/android/src/main/java/com/scalebun/rn/ota/DownloadFailure.kt +55 -0
  53. package/android/src/main/java/com/scalebun/rn/ota/OtaProtocol.kt +244 -0
  54. package/android/src/main/java/com/scalebun/rn/ota/ScaleBunOtaKeyRegistry.kt +100 -0
  55. package/android/src/main/java/com/scalebun/rn/ota/ScaleBunOtaModule.kt +683 -0
  56. package/android/src/main/java/com/scalebun/rn/ota/ScaleBunOtaReleaseVerifier.kt +136 -0
  57. package/android/src/main/java/com/scalebun/rn/ota/SlotManager.kt +578 -0
  58. package/android/src/main/java/com/scalebun/rn/ota/TlsPinning.kt +118 -0
  59. package/android/src/main/java/com/scalebun/rn/performance/PerformanceModule.kt +217 -0
  60. package/android/src/main/java/com/scalebun/rn/referrer/ScaleBunInstallReferrerModule.kt +77 -0
  61. package/android/src/main/java/com/scalebun/rn/storage/ScaleBunStorageModule.kt +68 -0
  62. package/android/src/main/java/com/scalebun/storage/KvFileStore.kt +174 -0
  63. package/android/src/newarch/java/com/scalebun/profiler/ProfilerSpec.kt +12 -0
  64. package/android/src/newarch/java/com/scalebun/replaysdk/ReplaySdkSpec.kt +12 -0
  65. package/android/src/newarch/java/com/scalebun/rn/crash/ScaleBunCrashSpec.kt +15 -0
  66. package/android/src/newarch/java/com/scalebun/rn/ota/ScaleBunOtaSpec.kt +16 -0
  67. package/android/src/newarch/java/com/scalebun/rn/performance/PerformanceSpec.kt +12 -0
  68. package/android/src/newarch/java/com/scalebun/rn/referrer/ScaleBunInstallReferrerSpec.kt +14 -0
  69. package/android/src/newarch/java/com/scalebun/rn/storage/ScaleBunStorageSpec.kt +16 -0
  70. package/android/src/oldarch/java/com/scalebun/profiler/ProfilerSpec.kt +34 -0
  71. package/android/src/oldarch/java/com/scalebun/replaysdk/ReplaySdkSpec.kt +77 -0
  72. package/android/src/oldarch/java/com/scalebun/rn/crash/ScaleBunCrashSpec.kt +40 -0
  73. package/android/src/oldarch/java/com/scalebun/rn/ota/ScaleBunOtaSpec.kt +42 -0
  74. package/android/src/oldarch/java/com/scalebun/rn/performance/PerformanceSpec.kt +27 -0
  75. package/android/src/oldarch/java/com/scalebun/rn/referrer/ScaleBunInstallReferrerSpec.kt +18 -0
  76. package/android/src/oldarch/java/com/scalebun/rn/storage/ScaleBunStorageSpec.kt +26 -0
  77. package/bin/lib/androidCodemod.js +370 -0
  78. package/bin/lib/iosCodemod.js +343 -0
  79. package/bin/scalebun.js +1004 -0
  80. package/dist/scalebun.full.js +37348 -0
  81. package/dist/scalebun.slim.js +34137 -0
  82. package/ios/Capture/InteractionTracker.swift +237 -0
  83. package/ios/Capture/PrivacyMaskProcessor.swift +158 -0
  84. package/ios/Capture/ScreenshotCaptureManager.swift +398 -0
  85. package/ios/Capture/WindowResolver.swift +63 -0
  86. package/ios/Core/DeviceIdentity.swift +50 -0
  87. package/ios/Core/ReplayConfig.swift +100 -0
  88. package/ios/Core/ReplayLogger.swift +22 -0
  89. package/ios/Core/SessionIdGenerator.swift +18 -0
  90. package/ios/Crash/ScaleBunCrashBridge.mm +74 -0
  91. package/ios/Crash/ScaleBunCrashHandler.swift +84 -0
  92. package/ios/Crash/ScaleBunCrashModule.swift +98 -0
  93. package/ios/Crash/ScaleBunCrashSignalBridge.h +49 -0
  94. package/ios/Crash/ScaleBunCrashSignalBridge.m +296 -0
  95. package/ios/Crash/ScaleBunCrashSignalStress.c +137 -0
  96. package/ios/Crash/ScaleBunCrashStorage.swift +121 -0
  97. package/ios/Crash/ScaleBunExceptionChain.swift +71 -0
  98. package/ios/CrashTests/ScaleBunExceptionChainTests.swift +144 -0
  99. package/ios/Engage/ScaleBunEngageBridge.m +32 -0
  100. package/ios/Engage/ScaleBunEngageModule.swift +250 -0
  101. package/ios/Engage/ScaleBunPushNotificationCenter.swift +185 -0
  102. package/ios/Ota/BsPatch.swift +203 -0
  103. package/ios/Ota/BundleDownloader.swift +249 -0
  104. package/ios/Ota/DeviceIntegrity.swift +112 -0
  105. package/ios/Ota/DownloadFailure.swift +56 -0
  106. package/ios/Ota/OtaProtocol.swift +246 -0
  107. package/ios/Ota/OtaSlotManager.swift +613 -0
  108. package/ios/Ota/ScaleBunOtaBridge.mm +92 -0
  109. package/ios/Ota/ScaleBunOtaEventsModule.swift +61 -0
  110. package/ios/Ota/ScaleBunOtaKeyRegistry.swift +147 -0
  111. package/ios/Ota/ScaleBunOtaModule.swift +587 -0
  112. package/ios/Ota/ScaleBunOtaReleaseVerifier.swift +119 -0
  113. package/ios/Ota/TlsPinning.swift +222 -0
  114. package/ios/OtaTests/DownloadFailureTests.swift +78 -0
  115. package/ios/OtaTests/ScaleBunOtaVerifierTests.swift +548 -0
  116. package/ios/Outbox/NativeOutbox.swift +632 -0
  117. package/ios/Outbox/OutboxUploader.swift +578 -0
  118. package/ios/Performance/ScaleBunPerformanceBridge.m +32 -0
  119. package/ios/Performance/ScaleBunPerformanceModule.swift +290 -0
  120. package/ios/PrivacyInfo.xcprivacy +97 -0
  121. package/ios/Profiler/ScaleBunProfilerBridge.m +55 -0
  122. package/ios/Profiler/ScaleBunProfilerModule.swift +966 -0
  123. package/ios/ReplaySdk-Bridging-Header.h +2 -0
  124. package/ios/ReplaySdk.swift +793 -0
  125. package/ios/ReplaySdkBridge.m +97 -0
  126. package/ios/Session/SessionManager.swift +273 -0
  127. package/ios/Skan/ScaleBunSkanBridge.m +14 -0
  128. package/ios/Skan/ScaleBunSkanModule.swift +61 -0
  129. package/ios/Storage/ReplayStorage.swift +61 -0
  130. package/ios/Storage/ScaleBunKvFileStore.swift +125 -0
  131. package/ios/Storage/ScaleBunStorageBridge.mm +72 -0
  132. package/ios/Storage/ScaleBunStorageModule.swift +57 -0
  133. package/ios/Transport/ReplayTransport.swift +70 -0
  134. package/ios/VoiceRecorder.swift +145 -0
  135. package/lib/commonjs/analytics/EventTracker.js +598 -0
  136. package/lib/commonjs/analytics/automaticEvents.js +71 -0
  137. package/lib/commonjs/analytics/batching.js +64 -0
  138. package/lib/commonjs/analytics/eventLane.js +55 -0
  139. package/lib/commonjs/analytics/revenue.js +125 -0
  140. package/lib/commonjs/analytics/subscription.js +94 -0
  141. package/lib/commonjs/bootstrap/FeatureRegistry.js +86 -0
  142. package/lib/commonjs/bootstrap/SDKBootstrapper.js +748 -0
  143. package/lib/commonjs/bucketing/fnv1a32.js +45 -0
  144. package/lib/commonjs/compat/codepush.js +153 -0
  145. package/lib/commonjs/config/ConfigManager.js +238 -0
  146. package/lib/commonjs/config/configTypes.js +16 -0
  147. package/lib/commonjs/config/otaPolicyState.js +85 -0
  148. package/lib/commonjs/config/quotaState.js +435 -0
  149. package/lib/commonjs/core/architecture.js +45 -0
  150. package/lib/commonjs/core/clock/now.js +13 -0
  151. package/lib/commonjs/core/config/defaults.js +2 -0
  152. package/lib/commonjs/core/config/schema.js +512 -0
  153. package/lib/commonjs/core/constants/endpoints.js +19 -0
  154. package/lib/commonjs/core/constants/protocol.js +31 -0
  155. package/lib/commonjs/core/constants/timings.js +39 -0
  156. package/lib/commonjs/core/constants/version.js +18 -0
  157. package/lib/commonjs/core/context/app.js +2 -0
  158. package/lib/commonjs/core/context/device.js +155 -0
  159. package/lib/commonjs/core/context/session.js +2 -0
  160. package/lib/commonjs/core/context/user.js +2 -0
  161. package/lib/commonjs/core/contracts/IFeature.js +2 -0
  162. package/lib/commonjs/core/di/container.js +29 -0
  163. package/lib/commonjs/core/encoding/base64.js +50 -0
  164. package/lib/commonjs/core/id/deviceId.js +52 -0
  165. package/lib/commonjs/core/id/installationId.js +55 -0
  166. package/lib/commonjs/core/id/sessionId.js +2 -0
  167. package/lib/commonjs/core/lifecycle/appLifecycle.js +31 -0
  168. package/lib/commonjs/core/lifecycle/crashSafe.js +33 -0
  169. package/lib/commonjs/core/logger/errorClassification.js +107 -0
  170. package/lib/commonjs/core/logger/internalLogger.js +63 -0
  171. package/lib/commonjs/core/logger/levels.js +2 -0
  172. package/lib/commonjs/crypto/hmacSha256.js +132 -0
  173. package/lib/commonjs/debug/bootstrap.js +429 -0
  174. package/lib/commonjs/debug/commands.js +732 -0
  175. package/lib/commonjs/debug/configBuilder.js +70 -0
  176. package/lib/commonjs/debug/exportBridge.js +155 -0
  177. package/lib/commonjs/debug/hostResolver.js +42 -0
  178. package/lib/commonjs/debug/index.js +141 -0
  179. package/lib/commonjs/debug/metrics.js +39 -0
  180. package/lib/commonjs/debug/perf.js +186 -0
  181. package/lib/commonjs/debug/perfWiring.js +109 -0
  182. package/lib/commonjs/debug/protocol.js +121 -0
  183. package/lib/commonjs/debug/redaction.js +422 -0
  184. package/lib/commonjs/debug/replayWiring.js +149 -0
  185. package/lib/commonjs/debug/screenTracking.js +60 -0
  186. package/lib/commonjs/debug/sessionWiring.js +48 -0
  187. package/lib/commonjs/debug/stream.js +542 -0
  188. package/lib/commonjs/debug/transport.js +368 -0
  189. package/lib/commonjs/features/bugreport/BugReportFeature.js +112 -0
  190. package/lib/commonjs/features/bugreport/buildPayload.js +97 -0
  191. package/lib/commonjs/features/bugreport/index.js +2 -0
  192. package/lib/commonjs/features/crash/CrashFeature.js +86 -0
  193. package/lib/commonjs/features/crash/CrashReporter.js +160 -0
  194. package/lib/commonjs/features/crash/NativeCrashFeature.js +42 -0
  195. package/lib/commonjs/features/crash/capture.js +48 -0
  196. package/lib/commonjs/features/crash/globalHandler.js +41 -0
  197. package/lib/commonjs/features/crash/index.js +14 -0
  198. package/lib/commonjs/features/crash/nativeCrashBridge.js +361 -0
  199. package/lib/commonjs/features/crash/rejectionHandler.js +180 -0
  200. package/lib/commonjs/features/crash/scrubCrash.js +158 -0
  201. package/lib/commonjs/features/engage/EngageAnchor.js +132 -0
  202. package/lib/commonjs/features/engage/EngageArchetypeRenderers.js +4292 -0
  203. package/lib/commonjs/features/engage/EngageInAppView.js +2670 -0
  204. package/lib/commonjs/features/engage/EngageInlinePlacement.js +133 -0
  205. package/lib/commonjs/features/engage/EngagePromptProvider.js +1063 -0
  206. package/lib/commonjs/features/engage/EngagePromptView.js +1252 -0
  207. package/lib/commonjs/features/engage/EngageTransport.js +608 -0
  208. package/lib/commonjs/features/engage/EngageVariantContent.js +1778 -0
  209. package/lib/commonjs/features/engage/__test-support__/reactNativeStub.js +54 -0
  210. package/lib/commonjs/features/engage/attachmentCapture.js +48 -0
  211. package/lib/commonjs/features/engage/captureVoiceAttachment.js +88 -0
  212. package/lib/commonjs/features/engage/engageCoachmarkTour.js +106 -0
  213. package/lib/commonjs/features/engage/engageGameLogic.js +308 -0
  214. package/lib/commonjs/features/engage/engageMediaSizing.js +60 -0
  215. package/lib/commonjs/features/engage/engageMultiStepSheet.js +43 -0
  216. package/lib/commonjs/features/engage/engageOutcome.js +118 -0
  217. package/lib/commonjs/features/engage/engagePushTokenBridge.js +72 -0
  218. package/lib/commonjs/features/engage/engageShakeBridge.js +62 -0
  219. package/lib/commonjs/features/engage/engageSignals.js +39 -0
  220. package/lib/commonjs/features/engage/engageStoreReviewBridge.js +49 -0
  221. package/lib/commonjs/features/engage/engageTestSeenStore.js +99 -0
  222. package/lib/commonjs/features/engage/engageThrottle.js +404 -0
  223. package/lib/commonjs/features/engage/engageTriggerEngine.js +365 -0
  224. package/lib/commonjs/features/engage/engageTypes.js +116 -0
  225. package/lib/commonjs/features/engage/engageVariantResolver.js +143 -0
  226. package/lib/commonjs/features/engage/engageWindowInsets.js +98 -0
  227. package/lib/commonjs/features/engage/gestureTriggerDetector.js +85 -0
  228. package/lib/commonjs/features/engage/transcription/TranscriptionProvider.js +55 -0
  229. package/lib/commonjs/features/install-referrer/installReferrer.js +113 -0
  230. package/lib/commonjs/features/journey/ScaleBunDebugRoot.js +1038 -0
  231. package/lib/commonjs/features/journey/ScaleBunFlatList.js +39 -0
  232. package/lib/commonjs/features/journey/ScaleBunImpression.js +113 -0
  233. package/lib/commonjs/features/journey/ScaleBunScrollView.js +102 -0
  234. package/lib/commonjs/features/journey/ScaleBunSectionList.js +39 -0
  235. package/lib/commonjs/features/journey/autoInstrumentScroll.js +161 -0
  236. package/lib/commonjs/features/journey/calibrationContext.js +42 -0
  237. package/lib/commonjs/features/journey/gestureBuffer.js +63 -0
  238. package/lib/commonjs/features/journey/gestureDetector.js +176 -0
  239. package/lib/commonjs/features/journey/impression.js +93 -0
  240. package/lib/commonjs/features/journey/interactionProtocol.js +168 -0
  241. package/lib/commonjs/features/journey/journeyManager.js +466 -0
  242. package/lib/commonjs/features/journey/journeyTypes.js +55 -0
  243. package/lib/commonjs/features/journey/nativeScroll.js +85 -0
  244. package/lib/commonjs/features/journey/navDetector.js +161 -0
  245. package/lib/commonjs/features/journey/screenshotHelper.js +136 -0
  246. package/lib/commonjs/features/journey/scrollContext.js +154 -0
  247. package/lib/commonjs/features/journey/targetGeometry.js +185 -0
  248. package/lib/commonjs/features/journey/targetRegistry.js +53 -0
  249. package/lib/commonjs/features/journey/touchTarget.js +249 -0
  250. package/lib/commonjs/features/journey/uiState.js +188 -0
  251. package/lib/commonjs/features/navigation/AutoScreenDetector.js +607 -0
  252. package/lib/commonjs/features/network/NetworkFeature.js +216 -0
  253. package/lib/commonjs/features/network/index.js +23 -0
  254. package/lib/commonjs/features/network/thirdParty.js +151 -0
  255. package/lib/commonjs/features/ota/OtaEventEmitter.js +129 -0
  256. package/lib/commonjs/features/ota/OtaOrchestrator.js +1309 -0
  257. package/lib/commonjs/features/ota/OtaTypes.js +6 -0
  258. package/lib/commonjs/features/ota/deviceAttributes.js +48 -0
  259. package/lib/commonjs/features/ota/environment.js +172 -0
  260. package/lib/commonjs/features/ota/geoCountry.js +93 -0
  261. package/lib/commonjs/features/ota/retry.js +96 -0
  262. package/lib/commonjs/features/ota/signedDownload.js +187 -0
  263. package/lib/commonjs/features/ota/useOtaUpdate.js +106 -0
  264. package/lib/commonjs/features/performance/PerformanceFeature.js +649 -0
  265. package/lib/commonjs/features/performance/collectors/AppLaunchCollector.js +122 -0
  266. package/lib/commonjs/features/performance/collectors/AutoScreenLoadCollector.js +232 -0
  267. package/lib/commonjs/features/performance/collectors/CustomTraceCollector.js +99 -0
  268. package/lib/commonjs/features/performance/collectors/FrameMetricsCollector.js +184 -0
  269. package/lib/commonjs/features/performance/collectors/JsStallCollector.js +165 -0
  270. package/lib/commonjs/features/performance/collectors/NetworkPerfCollector.js +59 -0
  271. package/lib/commonjs/features/performance/collectors/ScreenLoadCollector.js +78 -0
  272. package/lib/commonjs/features/performance/collectors/UiHangCollector.js +78 -0
  273. package/lib/commonjs/features/performance/config.js +58 -0
  274. package/lib/commonjs/features/performance/getNativePerformanceModule.js +44 -0
  275. package/lib/commonjs/features/performance/index.js +58 -0
  276. package/lib/commonjs/features/performance/metrics/MetricsEngine.js +148 -0
  277. package/lib/commonjs/features/performance/models.js +48 -0
  278. package/lib/commonjs/features/performance/transport/PerformanceTransport.js +168 -0
  279. package/lib/commonjs/features/profiler/ProfilerFeature.js +600 -0
  280. package/lib/commonjs/features/profiler/config.js +151 -0
  281. package/lib/commonjs/features/profiler/contracts.js +62 -0
  282. package/lib/commonjs/features/profiler/index.js +40 -0
  283. package/lib/commonjs/features/profiler/models.js +112 -0
  284. package/lib/commonjs/features/profiler/transport/ProfilerTransport.js +94 -0
  285. package/lib/commonjs/features/replay/bridge/adapters/bridgeAdapter.js +203 -0
  286. package/lib/commonjs/features/replay/bridge/eventEmitter.js +128 -0
  287. package/lib/commonjs/features/replay/bridge/nativeModule.js +95 -0
  288. package/lib/commonjs/features/replay/bridge/nativeQuota.js +121 -0
  289. package/lib/commonjs/features/replay/core/clock/clock.js +47 -0
  290. package/lib/commonjs/features/replay/core/config/defaults.js +88 -0
  291. package/lib/commonjs/features/replay/core/config/validator.js +109 -0
  292. package/lib/commonjs/features/replay/core/env/environmentDetector.js +28 -0
  293. package/lib/commonjs/features/replay/core/errors/safeCall.js +42 -0
  294. package/lib/commonjs/features/replay/core/ids/sessionId.js +53 -0
  295. package/lib/commonjs/features/replay/core/logger/logger.js +36 -0
  296. package/lib/commonjs/features/replay/core/privacy/privacyTypes.js +34 -0
  297. package/lib/commonjs/features/replay/core/queue/boundedQueue.js +71 -0
  298. package/lib/commonjs/features/replay/integrations/alert/alertInstrumentation.js +259 -0
  299. package/lib/commonjs/features/replay/integrations/logs/consoleIntegration.js +139 -0
  300. package/lib/commonjs/features/replay/integrations/network/networkAdapter.js +77 -0
  301. package/lib/commonjs/features/replay/integrations/react-navigation/navigationIntegration.js +88 -0
  302. package/lib/commonjs/features/replay/integrations/touch/ReplayRoot.js +103 -0
  303. package/lib/commonjs/features/replay/pipeline/batching/batchManager.js +119 -0
  304. package/lib/commonjs/features/replay/pipeline/envelope/envelopeBuilder.js +52 -0
  305. package/lib/commonjs/features/replay/pipeline/retry/retryPolicy.js +53 -0
  306. package/lib/commonjs/features/replay/pipeline/transport/transportTypes.js +67 -0
  307. package/lib/commonjs/features/replay/public/api.js +336 -0
  308. package/lib/commonjs/features/replay/public/enums.js +85 -0
  309. package/lib/commonjs/features/replay/public/types.js +6 -0
  310. package/lib/commonjs/features/replay/replay/breadcrumbs/breadcrumbCollector.js +119 -0
  311. package/lib/commonjs/features/replay/replay/frames/frameModels.js +40 -0
  312. package/lib/commonjs/features/replay/replay/session/sessionOrchestrator.js +279 -0
  313. package/lib/commonjs/features/replay/replay/timeline/timelineModels.js +120 -0
  314. package/lib/commonjs/features/replay/transport/BackendReplayTransport.js +175 -0
  315. package/lib/commonjs/features/replay/transport/CompositeReplayTransport.js +75 -0
  316. package/lib/commonjs/features/replay/transport/DesktopReplayTransport.js +124 -0
  317. package/lib/commonjs/features/replay/transport/ReplayTransport.js +2 -0
  318. package/lib/commonjs/features/session/BackendSessionAdapter.js +1915 -0
  319. package/lib/commonjs/features/session/DesktopSessionTransport.js +124 -0
  320. package/lib/commonjs/features/session/JourneyEventPipeline.js +244 -0
  321. package/lib/commonjs/features/session/ReplayCaptureManager.js +1253 -0
  322. package/lib/commonjs/features/session/ScrollTracker.js +147 -0
  323. package/lib/commonjs/features/session/SessionManager.js +1448 -0
  324. package/lib/commonjs/features/session/SyncDecisionEngine.js +95 -0
  325. package/lib/commonjs/features/session/frameLink.js +36 -0
  326. package/lib/commonjs/features/session/frameScrollState.js +41 -0
  327. package/lib/commonjs/features/session/index.js +84 -0
  328. package/lib/commonjs/features/session/nativeCapture.js +53 -0
  329. package/lib/commonjs/features/session/outboxFrameCapture.js +83 -0
  330. package/lib/commonjs/features/session/sessionTypes.js +230 -0
  331. package/lib/commonjs/features/session/viewportPlausibility.js +143 -0
  332. package/lib/commonjs/features/skan/skanBridge.js +54 -0
  333. package/lib/commonjs/features/skan/skanConversionManager.js +134 -0
  334. package/lib/commonjs/index.js +267 -0
  335. package/lib/commonjs/integrations/fetch/fetchInterceptor.js +174 -0
  336. package/lib/commonjs/integrations/navigation/screenTracker.js +2 -0
  337. package/lib/commonjs/integrations/network/bodyCapture.js +336 -0
  338. package/lib/commonjs/integrations/xhr/xhrInterceptor.js +224 -0
  339. package/lib/commonjs/metro/composeSourceMap.js +105 -0
  340. package/lib/commonjs/metro/featureModules.js +131 -0
  341. package/lib/commonjs/metro/index.js +230 -0
  342. package/lib/commonjs/metro/optionalDependencyStub.js +6 -0
  343. package/lib/commonjs/metro/optionalModules.js +31 -0
  344. package/lib/commonjs/metro/serializerCompose.js +161 -0
  345. package/lib/commonjs/pipeline/dispatcher/dispatcher.js +28 -0
  346. package/lib/commonjs/pipeline/envelope/envelope.js +17 -0
  347. package/lib/commonjs/pipeline/envelope/serializer.js +14 -0
  348. package/lib/commonjs/pipeline/processors/dedupe.js +2 -0
  349. package/lib/commonjs/pipeline/processors/enrich.js +16 -0
  350. package/lib/commonjs/pipeline/processors/sampling.js +2 -0
  351. package/lib/commonjs/pipeline/processors/sanitize.js +28 -0
  352. package/lib/commonjs/pipeline/queue/flushQueue.js +107 -0
  353. package/lib/commonjs/pipeline/queue/memoryQueue.js +31 -0
  354. package/lib/commonjs/pipeline/queue/persistentQueue.js +342 -0
  355. package/lib/commonjs/pipeline/queue/queuePolicy.js +2 -0
  356. package/lib/commonjs/pipeline/scheduler/flushScheduler.js +45 -0
  357. package/lib/commonjs/pipeline/scheduler/retryPolicy.js +15 -0
  358. package/lib/commonjs/public/ScaleBunErrorBoundary.js +91 -0
  359. package/lib/commonjs/public/ScaleBunFacade.js +2044 -0
  360. package/lib/commonjs/public/ScaleBunProvider.js +62 -0
  361. package/lib/commonjs/public/typedTracker.js +79 -0
  362. package/lib/commonjs/public/types.js +6 -0
  363. package/lib/commonjs/push/PushManager.js +270 -0
  364. package/lib/commonjs/push/adapters/ManualAdapter.js +86 -0
  365. package/lib/commonjs/push/adapters/NativeBridgeAdapter.js +131 -0
  366. package/lib/commonjs/push/adapters/NoopAdapter.js +45 -0
  367. package/lib/commonjs/push/adapters/RNFirebaseMessagingAdapter.js +248 -0
  368. package/lib/commonjs/push/adapters/loadMessaging.js +29 -0
  369. package/lib/commonjs/push/adapters/loadNotifee.js +36 -0
  370. package/lib/commonjs/push/adapters/selectAdapter.js +153 -0
  371. package/lib/commonjs/push/detect/capabilities.js +136 -0
  372. package/lib/commonjs/push/index.js +33 -0
  373. package/lib/commonjs/push/native/nativeNotifications.js +168 -0
  374. package/lib/commonjs/push/types.js +2 -0
  375. package/lib/commonjs/specs/NativeReplaySdk.js +28 -0
  376. package/lib/commonjs/specs/NativeScaleBunCrash.js +30 -0
  377. package/lib/commonjs/specs/NativeScaleBunInstallReferrer.js +24 -0
  378. package/lib/commonjs/specs/NativeScaleBunOta.js +32 -0
  379. package/lib/commonjs/specs/NativeScaleBunPerformance.js +25 -0
  380. package/lib/commonjs/specs/NativeScaleBunProfiler.js +26 -0
  381. package/lib/commonjs/specs/NativeScaleBunStorage.js +40 -0
  382. package/lib/commonjs/storage/StorageBackend.js +240 -0
  383. package/lib/commonjs/storage/db/sqlite.js +2 -0
  384. package/lib/commonjs/storage/files/fileStore.js +2 -0
  385. package/lib/commonjs/transport/auth/sdkSession.js +28 -0
  386. package/lib/commonjs/transport/backoff/exponentialJitter.js +16 -0
  387. package/lib/commonjs/transport/http/endpoints.js +46 -0
  388. package/lib/commonjs/transport/http/httpClient.js +72 -0
  389. package/lib/commonjs/transport/rateLimit/retryAfter.js +2 -0
  390. package/lib/commonjs/transport/signing/requestSigner.js +2 -0
  391. package/lib/commonjs/vendor/protocol/index.js +327 -0
  392. package/lib/commonjs/vendor/protocol/internal/validation.js +429 -0
  393. package/lib/commonjs/vendor/sdk-contracts/bridge.js +2 -0
  394. package/lib/commonjs/vendor/sdk-contracts/config.js +2 -0
  395. package/lib/commonjs/vendor/sdk-contracts/events.js +2 -0
  396. package/lib/commonjs/vendor/sdk-contracts/features.js +2 -0
  397. package/lib/commonjs/vendor/sdk-contracts/index.js +2 -0
  398. package/lib/commonjs/vendor/sdk-contracts/platform.js +2 -0
  399. package/lib/commonjs/vendor/sdk-contracts/session-boundary.js +6 -0
  400. package/lib/commonjs/vendor/sdk-contracts/session.js +2 -0
  401. package/lib/commonjs/vendor/vendor.manifest +10 -0
  402. package/lib/module/analytics/EventTracker.js +592 -0
  403. package/lib/module/analytics/automaticEvents.js +63 -0
  404. package/lib/module/analytics/batching.js +55 -0
  405. package/lib/module/analytics/eventLane.js +47 -0
  406. package/lib/module/analytics/revenue.js +117 -0
  407. package/lib/module/analytics/subscription.js +86 -0
  408. package/lib/module/bootstrap/FeatureRegistry.js +79 -0
  409. package/lib/module/bootstrap/SDKBootstrapper.js +742 -0
  410. package/lib/module/bucketing/fnv1a32.js +37 -0
  411. package/lib/module/compat/codepush.js +147 -0
  412. package/lib/module/config/ConfigManager.js +230 -0
  413. package/lib/module/config/configTypes.js +10 -0
  414. package/lib/module/config/otaPolicyState.js +76 -0
  415. package/lib/module/config/quotaState.js +423 -0
  416. package/lib/module/core/architecture.js +38 -0
  417. package/lib/module/core/clock/now.js +7 -0
  418. package/lib/module/core/config/defaults.js +2 -0
  419. package/lib/module/core/config/schema.js +506 -0
  420. package/lib/module/core/constants/endpoints.js +13 -0
  421. package/lib/module/core/constants/protocol.js +25 -0
  422. package/lib/module/core/constants/timings.js +26 -0
  423. package/lib/module/core/constants/version.js +12 -0
  424. package/lib/module/core/context/app.js +2 -0
  425. package/lib/module/core/context/device.js +143 -0
  426. package/lib/module/core/context/session.js +2 -0
  427. package/lib/module/core/context/user.js +2 -0
  428. package/lib/module/core/contracts/IFeature.js +2 -0
  429. package/lib/module/core/di/container.js +22 -0
  430. package/lib/module/core/encoding/base64.js +44 -0
  431. package/lib/module/core/id/deviceId.js +45 -0
  432. package/lib/module/core/id/installationId.js +50 -0
  433. package/lib/module/core/id/sessionId.js +2 -0
  434. package/lib/module/core/lifecycle/appLifecycle.js +25 -0
  435. package/lib/module/core/lifecycle/crashSafe.js +26 -0
  436. package/lib/module/core/logger/errorClassification.js +96 -0
  437. package/lib/module/core/logger/internalLogger.js +59 -0
  438. package/lib/module/core/logger/levels.js +2 -0
  439. package/lib/module/crypto/hmacSha256.js +126 -0
  440. package/lib/module/debug/bootstrap.js +393 -0
  441. package/lib/module/debug/commands.js +726 -0
  442. package/lib/module/debug/configBuilder.js +63 -0
  443. package/lib/module/debug/exportBridge.js +148 -0
  444. package/lib/module/debug/hostResolver.js +37 -0
  445. package/lib/module/debug/index.js +13 -0
  446. package/lib/module/debug/metrics.js +33 -0
  447. package/lib/module/debug/perf.js +180 -0
  448. package/lib/module/debug/perfWiring.js +102 -0
  449. package/lib/module/debug/protocol.js +19 -0
  450. package/lib/module/debug/redaction.js +411 -0
  451. package/lib/module/debug/replayWiring.js +139 -0
  452. package/lib/module/debug/screenTracking.js +53 -0
  453. package/lib/module/debug/sessionWiring.js +43 -0
  454. package/lib/module/debug/stream.js +536 -0
  455. package/lib/module/debug/transport.js +362 -0
  456. package/lib/module/features/bugreport/BugReportFeature.js +105 -0
  457. package/lib/module/features/bugreport/buildPayload.js +91 -0
  458. package/lib/module/features/bugreport/index.js +2 -0
  459. package/lib/module/features/crash/CrashFeature.js +79 -0
  460. package/lib/module/features/crash/CrashReporter.js +151 -0
  461. package/lib/module/features/crash/NativeCrashFeature.js +36 -0
  462. package/lib/module/features/crash/capture.js +42 -0
  463. package/lib/module/features/crash/globalHandler.js +36 -0
  464. package/lib/module/features/crash/index.js +8 -0
  465. package/lib/module/features/crash/nativeCrashBridge.js +350 -0
  466. package/lib/module/features/crash/rejectionHandler.js +171 -0
  467. package/lib/module/features/crash/scrubCrash.js +149 -0
  468. package/lib/module/features/engage/EngageAnchor.js +121 -0
  469. package/lib/module/features/engage/EngageArchetypeRenderers.js +4264 -0
  470. package/lib/module/features/engage/EngageInAppView.js +2656 -0
  471. package/lib/module/features/engage/EngageInlinePlacement.js +123 -0
  472. package/lib/module/features/engage/EngagePromptProvider.js +1054 -0
  473. package/lib/module/features/engage/EngagePromptView.js +1243 -0
  474. package/lib/module/features/engage/EngageTransport.js +602 -0
  475. package/lib/module/features/engage/EngageVariantContent.js +1771 -0
  476. package/lib/module/features/engage/__test-support__/reactNativeStub.js +52 -0
  477. package/lib/module/features/engage/attachmentCapture.js +42 -0
  478. package/lib/module/features/engage/captureVoiceAttachment.js +80 -0
  479. package/lib/module/features/engage/engageCoachmarkTour.js +94 -0
  480. package/lib/module/features/engage/engageGameLogic.js +287 -0
  481. package/lib/module/features/engage/engageMediaSizing.js +51 -0
  482. package/lib/module/features/engage/engageMultiStepSheet.js +35 -0
  483. package/lib/module/features/engage/engageOutcome.js +108 -0
  484. package/lib/module/features/engage/engagePushTokenBridge.js +65 -0
  485. package/lib/module/features/engage/engageShakeBridge.js +56 -0
  486. package/lib/module/features/engage/engageSignals.js +34 -0
  487. package/lib/module/features/engage/engageStoreReviewBridge.js +43 -0
  488. package/lib/module/features/engage/engageTestSeenStore.js +92 -0
  489. package/lib/module/features/engage/engageThrottle.js +390 -0
  490. package/lib/module/features/engage/engageTriggerEngine.js +360 -0
  491. package/lib/module/features/engage/engageTypes.js +110 -0
  492. package/lib/module/features/engage/engageVariantResolver.js +135 -0
  493. package/lib/module/features/engage/engageWindowInsets.js +89 -0
  494. package/lib/module/features/engage/gestureTriggerDetector.js +80 -0
  495. package/lib/module/features/engage/transcription/TranscriptionProvider.js +46 -0
  496. package/lib/module/features/install-referrer/installReferrer.js +104 -0
  497. package/lib/module/features/journey/ScaleBunDebugRoot.js +1030 -0
  498. package/lib/module/features/journey/ScaleBunFlatList.js +32 -0
  499. package/lib/module/features/journey/ScaleBunImpression.js +105 -0
  500. package/lib/module/features/journey/ScaleBunScrollView.js +95 -0
  501. package/lib/module/features/journey/ScaleBunSectionList.js +32 -0
  502. package/lib/module/features/journey/autoInstrumentScroll.js +155 -0
  503. package/lib/module/features/journey/calibrationContext.js +35 -0
  504. package/lib/module/features/journey/gestureBuffer.js +56 -0
  505. package/lib/module/features/journey/gestureDetector.js +169 -0
  506. package/lib/module/features/journey/impression.js +84 -0
  507. package/lib/module/features/journey/interactionProtocol.js +158 -0
  508. package/lib/module/features/journey/journeyManager.js +459 -0
  509. package/lib/module/features/journey/journeyTypes.js +49 -0
  510. package/lib/module/features/journey/nativeScroll.js +77 -0
  511. package/lib/module/features/journey/navDetector.js +154 -0
  512. package/lib/module/features/journey/screenshotHelper.js +129 -0
  513. package/lib/module/features/journey/scrollContext.js +142 -0
  514. package/lib/module/features/journey/targetGeometry.js +175 -0
  515. package/lib/module/features/journey/targetRegistry.js +44 -0
  516. package/lib/module/features/journey/touchTarget.js +241 -0
  517. package/lib/module/features/journey/uiState.js +176 -0
  518. package/lib/module/features/navigation/AutoScreenDetector.js +601 -0
  519. package/lib/module/features/network/NetworkFeature.js +209 -0
  520. package/lib/module/features/network/index.js +17 -0
  521. package/lib/module/features/network/thirdParty.js +142 -0
  522. package/lib/module/features/ota/OtaEventEmitter.js +123 -0
  523. package/lib/module/features/ota/OtaOrchestrator.js +1302 -0
  524. package/lib/module/features/ota/OtaTypes.js +2 -0
  525. package/lib/module/features/ota/deviceAttributes.js +43 -0
  526. package/lib/module/features/ota/environment.js +165 -0
  527. package/lib/module/features/ota/geoCountry.js +86 -0
  528. package/lib/module/features/ota/retry.js +87 -0
  529. package/lib/module/features/ota/signedDownload.js +174 -0
  530. package/lib/module/features/ota/useOtaUpdate.js +100 -0
  531. package/lib/module/features/performance/PerformanceFeature.js +643 -0
  532. package/lib/module/features/performance/collectors/AppLaunchCollector.js +115 -0
  533. package/lib/module/features/performance/collectors/AutoScreenLoadCollector.js +225 -0
  534. package/lib/module/features/performance/collectors/CustomTraceCollector.js +92 -0
  535. package/lib/module/features/performance/collectors/FrameMetricsCollector.js +177 -0
  536. package/lib/module/features/performance/collectors/JsStallCollector.js +158 -0
  537. package/lib/module/features/performance/collectors/NetworkPerfCollector.js +52 -0
  538. package/lib/module/features/performance/collectors/ScreenLoadCollector.js +71 -0
  539. package/lib/module/features/performance/collectors/UiHangCollector.js +71 -0
  540. package/lib/module/features/performance/config.js +51 -0
  541. package/lib/module/features/performance/getNativePerformanceModule.js +39 -0
  542. package/lib/module/features/performance/index.js +9 -0
  543. package/lib/module/features/performance/metrics/MetricsEngine.js +139 -0
  544. package/lib/module/features/performance/models.js +42 -0
  545. package/lib/module/features/performance/transport/PerformanceTransport.js +162 -0
  546. package/lib/module/features/profiler/ProfilerFeature.js +594 -0
  547. package/lib/module/features/profiler/config.js +143 -0
  548. package/lib/module/features/profiler/contracts.js +56 -0
  549. package/lib/module/features/profiler/index.js +11 -0
  550. package/lib/module/features/profiler/models.js +106 -0
  551. package/lib/module/features/profiler/transport/ProfilerTransport.js +87 -0
  552. package/lib/module/features/replay/bridge/adapters/bridgeAdapter.js +198 -0
  553. package/lib/module/features/replay/bridge/eventEmitter.js +122 -0
  554. package/lib/module/features/replay/bridge/nativeModule.js +89 -0
  555. package/lib/module/features/replay/bridge/nativeQuota.js +109 -0
  556. package/lib/module/features/replay/core/clock/clock.js +37 -0
  557. package/lib/module/features/replay/core/config/defaults.js +82 -0
  558. package/lib/module/features/replay/core/config/validator.js +103 -0
  559. package/lib/module/features/replay/core/env/environmentDetector.js +22 -0
  560. package/lib/module/features/replay/core/errors/safeCall.js +35 -0
  561. package/lib/module/features/replay/core/ids/sessionId.js +44 -0
  562. package/lib/module/features/replay/core/logger/logger.js +29 -0
  563. package/lib/module/features/replay/core/privacy/privacyTypes.js +27 -0
  564. package/lib/module/features/replay/core/queue/boundedQueue.js +64 -0
  565. package/lib/module/features/replay/integrations/alert/alertInstrumentation.js +252 -0
  566. package/lib/module/features/replay/integrations/logs/consoleIntegration.js +131 -0
  567. package/lib/module/features/replay/integrations/network/networkAdapter.js +70 -0
  568. package/lib/module/features/replay/integrations/react-navigation/navigationIntegration.js +82 -0
  569. package/lib/module/features/replay/integrations/touch/ReplayRoot.js +96 -0
  570. package/lib/module/features/replay/pipeline/batching/batchManager.js +113 -0
  571. package/lib/module/features/replay/pipeline/envelope/envelopeBuilder.js +43 -0
  572. package/lib/module/features/replay/pipeline/retry/retryPolicy.js +45 -0
  573. package/lib/module/features/replay/pipeline/transport/transportTypes.js +60 -0
  574. package/lib/module/features/replay/public/api.js +332 -0
  575. package/lib/module/features/replay/public/enums.js +85 -0
  576. package/lib/module/features/replay/public/types.js +2 -0
  577. package/lib/module/features/replay/replay/breadcrumbs/breadcrumbCollector.js +113 -0
  578. package/lib/module/features/replay/replay/frames/frameModels.js +33 -0
  579. package/lib/module/features/replay/replay/session/sessionOrchestrator.js +272 -0
  580. package/lib/module/features/replay/replay/timeline/timelineModels.js +108 -0
  581. package/lib/module/features/replay/transport/BackendReplayTransport.js +169 -0
  582. package/lib/module/features/replay/transport/CompositeReplayTransport.js +68 -0
  583. package/lib/module/features/replay/transport/DesktopReplayTransport.js +119 -0
  584. package/lib/module/features/replay/transport/ReplayTransport.js +2 -0
  585. package/lib/module/features/session/BackendSessionAdapter.js +1908 -0
  586. package/lib/module/features/session/DesktopSessionTransport.js +118 -0
  587. package/lib/module/features/session/JourneyEventPipeline.js +239 -0
  588. package/lib/module/features/session/ReplayCaptureManager.js +1248 -0
  589. package/lib/module/features/session/ScrollTracker.js +141 -0
  590. package/lib/module/features/session/SessionManager.js +1443 -0
  591. package/lib/module/features/session/SyncDecisionEngine.js +88 -0
  592. package/lib/module/features/session/frameLink.js +29 -0
  593. package/lib/module/features/session/frameScrollState.js +34 -0
  594. package/lib/module/features/session/index.js +35 -0
  595. package/lib/module/features/session/nativeCapture.js +45 -0
  596. package/lib/module/features/session/outboxFrameCapture.js +77 -0
  597. package/lib/module/features/session/sessionTypes.js +226 -0
  598. package/lib/module/features/session/viewportPlausibility.js +137 -0
  599. package/lib/module/features/skan/skanBridge.js +48 -0
  600. package/lib/module/features/skan/skanConversionManager.js +128 -0
  601. package/lib/module/index.js +80 -0
  602. package/lib/module/integrations/fetch/fetchInterceptor.js +169 -0
  603. package/lib/module/integrations/navigation/screenTracker.js +2 -0
  604. package/lib/module/integrations/network/bodyCapture.js +320 -0
  605. package/lib/module/integrations/xhr/xhrInterceptor.js +219 -0
  606. package/lib/module/metro/composeSourceMap.js +97 -0
  607. package/lib/module/metro/featureModules.js +123 -0
  608. package/lib/module/metro/index.js +218 -0
  609. package/lib/module/metro/optionalDependencyStub.js +14 -0
  610. package/lib/module/metro/optionalModules.js +25 -0
  611. package/lib/module/metro/serializerCompose.js +152 -0
  612. package/lib/module/pipeline/dispatcher/dispatcher.js +21 -0
  613. package/lib/module/pipeline/envelope/envelope.js +11 -0
  614. package/lib/module/pipeline/envelope/serializer.js +8 -0
  615. package/lib/module/pipeline/processors/dedupe.js +2 -0
  616. package/lib/module/pipeline/processors/enrich.js +10 -0
  617. package/lib/module/pipeline/processors/sampling.js +2 -0
  618. package/lib/module/pipeline/processors/sanitize.js +22 -0
  619. package/lib/module/pipeline/queue/flushQueue.js +102 -0
  620. package/lib/module/pipeline/queue/memoryQueue.js +24 -0
  621. package/lib/module/pipeline/queue/persistentQueue.js +336 -0
  622. package/lib/module/pipeline/queue/queuePolicy.js +2 -0
  623. package/lib/module/pipeline/scheduler/flushScheduler.js +38 -0
  624. package/lib/module/pipeline/scheduler/retryPolicy.js +9 -0
  625. package/lib/module/public/ScaleBunErrorBoundary.js +82 -0
  626. package/lib/module/public/ScaleBunFacade.js +2038 -0
  627. package/lib/module/public/ScaleBunProvider.js +54 -0
  628. package/lib/module/public/typedTracker.js +72 -0
  629. package/lib/module/public/types.js +2 -0
  630. package/lib/module/push/PushManager.js +263 -0
  631. package/lib/module/push/adapters/ManualAdapter.js +79 -0
  632. package/lib/module/push/adapters/NativeBridgeAdapter.js +124 -0
  633. package/lib/module/push/adapters/NoopAdapter.js +38 -0
  634. package/lib/module/push/adapters/RNFirebaseMessagingAdapter.js +241 -0
  635. package/lib/module/push/adapters/loadMessaging.js +23 -0
  636. package/lib/module/push/adapters/loadNotifee.js +30 -0
  637. package/lib/module/push/adapters/selectAdapter.js +147 -0
  638. package/lib/module/push/detect/capabilities.js +130 -0
  639. package/lib/module/push/index.js +9 -0
  640. package/lib/module/push/native/nativeNotifications.js +155 -0
  641. package/lib/module/push/types.js +2 -0
  642. package/lib/module/specs/NativeReplaySdk.js +24 -0
  643. package/lib/module/specs/NativeScaleBunCrash.js +26 -0
  644. package/lib/module/specs/NativeScaleBunInstallReferrer.js +20 -0
  645. package/lib/module/specs/NativeScaleBunOta.js +28 -0
  646. package/lib/module/specs/NativeScaleBunPerformance.js +21 -0
  647. package/lib/module/specs/NativeScaleBunProfiler.js +22 -0
  648. package/lib/module/specs/NativeScaleBunStorage.js +36 -0
  649. package/lib/module/storage/StorageBackend.js +231 -0
  650. package/lib/module/storage/db/sqlite.js +2 -0
  651. package/lib/module/storage/files/fileStore.js +2 -0
  652. package/lib/module/transport/auth/sdkSession.js +21 -0
  653. package/lib/module/transport/backoff/exponentialJitter.js +10 -0
  654. package/lib/module/transport/http/endpoints.js +40 -0
  655. package/lib/module/transport/http/httpClient.js +64 -0
  656. package/lib/module/transport/rateLimit/retryAfter.js +2 -0
  657. package/lib/module/transport/signing/requestSigner.js +2 -0
  658. package/lib/module/vendor/protocol/index.js +312 -0
  659. package/lib/module/vendor/protocol/internal/validation.js +423 -0
  660. package/lib/module/vendor/sdk-contracts/bridge.js +2 -0
  661. package/lib/module/vendor/sdk-contracts/config.js +2 -0
  662. package/lib/module/vendor/sdk-contracts/events.js +2 -0
  663. package/lib/module/vendor/sdk-contracts/features.js +2 -0
  664. package/lib/module/vendor/sdk-contracts/index.js +2 -0
  665. package/lib/module/vendor/sdk-contracts/platform.js +2 -0
  666. package/lib/module/vendor/sdk-contracts/session-boundary.js +2 -0
  667. package/lib/module/vendor/sdk-contracts/session.js +2 -0
  668. package/lib/module/vendor/vendor.manifest +10 -0
  669. package/lib/typescript/analytics/EventTracker.d.ts +197 -0
  670. package/lib/typescript/analytics/automaticEvents.d.ts +30 -0
  671. package/lib/typescript/analytics/batching.d.ts +33 -0
  672. package/lib/typescript/analytics/eventLane.d.ts +22 -0
  673. package/lib/typescript/analytics/revenue.d.ts +94 -0
  674. package/lib/typescript/analytics/subscription.d.ts +35 -0
  675. package/lib/typescript/bootstrap/FeatureRegistry.d.ts +36 -0
  676. package/lib/typescript/bootstrap/SDKBootstrapper.d.ts +82 -0
  677. package/lib/typescript/bucketing/fnv1a32.d.ts +20 -0
  678. package/lib/typescript/compat/codepush.d.ts +76 -0
  679. package/lib/typescript/config/ConfigManager.d.ts +82 -0
  680. package/lib/typescript/config/configTypes.d.ts +73 -0
  681. package/lib/typescript/config/otaPolicyState.d.ts +55 -0
  682. package/lib/typescript/config/quotaState.d.ts +155 -0
  683. package/lib/typescript/core/architecture.d.ts +29 -0
  684. package/lib/typescript/core/clock/now.d.ts +5 -0
  685. package/lib/typescript/core/config/defaults.d.ts +1 -0
  686. package/lib/typescript/core/config/schema.d.ts +107 -0
  687. package/lib/typescript/core/constants/endpoints.d.ts +13 -0
  688. package/lib/typescript/core/constants/protocol.d.ts +23 -0
  689. package/lib/typescript/core/constants/timings.d.ts +22 -0
  690. package/lib/typescript/core/constants/version.d.ts +12 -0
  691. package/lib/typescript/core/context/app.d.ts +1 -0
  692. package/lib/typescript/core/context/device.d.ts +61 -0
  693. package/lib/typescript/core/context/session.d.ts +1 -0
  694. package/lib/typescript/core/context/user.d.ts +24 -0
  695. package/lib/typescript/core/contracts/IFeature.d.ts +44 -0
  696. package/lib/typescript/core/di/container.d.ts +9 -0
  697. package/lib/typescript/core/encoding/base64.d.ts +13 -0
  698. package/lib/typescript/core/id/deviceId.d.ts +9 -0
  699. package/lib/typescript/core/id/installationId.d.ts +20 -0
  700. package/lib/typescript/core/id/sessionId.d.ts +1 -0
  701. package/lib/typescript/core/lifecycle/appLifecycle.d.ts +14 -0
  702. package/lib/typescript/core/lifecycle/crashSafe.d.ts +7 -0
  703. package/lib/typescript/core/logger/errorClassification.d.ts +46 -0
  704. package/lib/typescript/core/logger/internalLogger.d.ts +24 -0
  705. package/lib/typescript/core/logger/levels.d.ts +1 -0
  706. package/lib/typescript/crypto/hmacSha256.d.ts +10 -0
  707. package/lib/typescript/debug/bootstrap.d.ts +148 -0
  708. package/lib/typescript/debug/commands.d.ts +77 -0
  709. package/lib/typescript/debug/configBuilder.d.ts +13 -0
  710. package/lib/typescript/debug/exportBridge.d.ts +27 -0
  711. package/lib/typescript/debug/hostResolver.d.ts +14 -0
  712. package/lib/typescript/debug/index.d.ts +12 -0
  713. package/lib/typescript/debug/metrics.d.ts +2 -0
  714. package/lib/typescript/debug/perf.d.ts +43 -0
  715. package/lib/typescript/debug/perfWiring.d.ts +33 -0
  716. package/lib/typescript/debug/protocol.d.ts +15 -0
  717. package/lib/typescript/debug/redaction.d.ts +69 -0
  718. package/lib/typescript/debug/replayWiring.d.ts +25 -0
  719. package/lib/typescript/debug/screenTracking.d.ts +16 -0
  720. package/lib/typescript/debug/sessionWiring.d.ts +16 -0
  721. package/lib/typescript/debug/stream.d.ts +77 -0
  722. package/lib/typescript/debug/transport.d.ts +110 -0
  723. package/lib/typescript/features/bugreport/BugReportFeature.d.ts +59 -0
  724. package/lib/typescript/features/bugreport/buildPayload.d.ts +51 -0
  725. package/lib/typescript/features/bugreport/index.d.ts +1 -0
  726. package/lib/typescript/features/crash/CrashFeature.d.ts +21 -0
  727. package/lib/typescript/features/crash/CrashReporter.d.ts +107 -0
  728. package/lib/typescript/features/crash/NativeCrashFeature.d.ts +17 -0
  729. package/lib/typescript/features/crash/capture.d.ts +22 -0
  730. package/lib/typescript/features/crash/globalHandler.d.ts +14 -0
  731. package/lib/typescript/features/crash/index.d.ts +2 -0
  732. package/lib/typescript/features/crash/nativeCrashBridge.d.ts +43 -0
  733. package/lib/typescript/features/crash/rejectionHandler.d.ts +65 -0
  734. package/lib/typescript/features/crash/scrubCrash.d.ts +35 -0
  735. package/lib/typescript/features/engage/EngageAnchor.d.ts +36 -0
  736. package/lib/typescript/features/engage/EngageArchetypeRenderers.d.ts +66 -0
  737. package/lib/typescript/features/engage/EngageInAppView.d.ts +164 -0
  738. package/lib/typescript/features/engage/EngageInlinePlacement.d.ts +42 -0
  739. package/lib/typescript/features/engage/EngagePromptProvider.d.ts +233 -0
  740. package/lib/typescript/features/engage/EngagePromptView.d.ts +97 -0
  741. package/lib/typescript/features/engage/EngageTransport.d.ts +158 -0
  742. package/lib/typescript/features/engage/EngageVariantContent.d.ts +12 -0
  743. package/lib/typescript/features/engage/attachmentCapture.d.ts +17 -0
  744. package/lib/typescript/features/engage/captureVoiceAttachment.d.ts +31 -0
  745. package/lib/typescript/features/engage/engageCoachmarkTour.d.ts +18 -0
  746. package/lib/typescript/features/engage/engageGameLogic.d.ts +34 -0
  747. package/lib/typescript/features/engage/engageMediaSizing.d.ts +23 -0
  748. package/lib/typescript/features/engage/engageMultiStepSheet.d.ts +25 -0
  749. package/lib/typescript/features/engage/engageOutcome.d.ts +38 -0
  750. package/lib/typescript/features/engage/engagePushTokenBridge.d.ts +30 -0
  751. package/lib/typescript/features/engage/engageShakeBridge.d.ts +20 -0
  752. package/lib/typescript/features/engage/engageSignals.d.ts +13 -0
  753. package/lib/typescript/features/engage/engageStoreReviewBridge.d.ts +23 -0
  754. package/lib/typescript/features/engage/engageTestSeenStore.d.ts +46 -0
  755. package/lib/typescript/features/engage/engageThrottle.d.ts +180 -0
  756. package/lib/typescript/features/engage/engageTriggerEngine.d.ts +16 -0
  757. package/lib/typescript/features/engage/engageTypes.d.ts +576 -0
  758. package/lib/typescript/features/engage/engageVariantResolver.d.ts +46 -0
  759. package/lib/typescript/features/engage/engageWindowInsets.d.ts +25 -0
  760. package/lib/typescript/features/engage/gestureTriggerDetector.d.ts +20 -0
  761. package/lib/typescript/features/engage/transcription/TranscriptionProvider.d.ts +51 -0
  762. package/lib/typescript/features/install-referrer/installReferrer.d.ts +39 -0
  763. package/lib/typescript/features/journey/ScaleBunDebugRoot.d.ts +49 -0
  764. package/lib/typescript/features/journey/ScaleBunFlatList.d.ts +20 -0
  765. package/lib/typescript/features/journey/ScaleBunImpression.d.ts +30 -0
  766. package/lib/typescript/features/journey/ScaleBunScrollView.d.ts +25 -0
  767. package/lib/typescript/features/journey/ScaleBunSectionList.d.ts +20 -0
  768. package/lib/typescript/features/journey/autoInstrumentScroll.d.ts +46 -0
  769. package/lib/typescript/features/journey/calibrationContext.d.ts +26 -0
  770. package/lib/typescript/features/journey/gestureBuffer.d.ts +27 -0
  771. package/lib/typescript/features/journey/gestureDetector.d.ts +40 -0
  772. package/lib/typescript/features/journey/impression.d.ts +48 -0
  773. package/lib/typescript/features/journey/interactionProtocol.d.ts +159 -0
  774. package/lib/typescript/features/journey/journeyManager.d.ts +62 -0
  775. package/lib/typescript/features/journey/journeyTypes.d.ts +161 -0
  776. package/lib/typescript/features/journey/nativeScroll.d.ts +47 -0
  777. package/lib/typescript/features/journey/navDetector.d.ts +42 -0
  778. package/lib/typescript/features/journey/screenshotHelper.d.ts +33 -0
  779. package/lib/typescript/features/journey/scrollContext.d.ts +49 -0
  780. package/lib/typescript/features/journey/targetGeometry.d.ts +126 -0
  781. package/lib/typescript/features/journey/targetRegistry.d.ts +28 -0
  782. package/lib/typescript/features/journey/touchTarget.d.ts +174 -0
  783. package/lib/typescript/features/journey/uiState.d.ts +93 -0
  784. package/lib/typescript/features/navigation/AutoScreenDetector.d.ts +196 -0
  785. package/lib/typescript/features/network/NetworkFeature.d.ts +43 -0
  786. package/lib/typescript/features/network/index.d.ts +46 -0
  787. package/lib/typescript/features/network/thirdParty.d.ts +95 -0
  788. package/lib/typescript/features/ota/OtaEventEmitter.d.ts +93 -0
  789. package/lib/typescript/features/ota/OtaOrchestrator.d.ts +287 -0
  790. package/lib/typescript/features/ota/OtaTypes.d.ts +193 -0
  791. package/lib/typescript/features/ota/deviceAttributes.d.ts +18 -0
  792. package/lib/typescript/features/ota/environment.d.ts +99 -0
  793. package/lib/typescript/features/ota/geoCountry.d.ts +14 -0
  794. package/lib/typescript/features/ota/retry.d.ts +53 -0
  795. package/lib/typescript/features/ota/signedDownload.d.ts +81 -0
  796. package/lib/typescript/features/ota/useOtaUpdate.d.ts +72 -0
  797. package/lib/typescript/features/performance/PerformanceFeature.d.ts +132 -0
  798. package/lib/typescript/features/performance/collectors/AppLaunchCollector.d.ts +27 -0
  799. package/lib/typescript/features/performance/collectors/AutoScreenLoadCollector.d.ts +70 -0
  800. package/lib/typescript/features/performance/collectors/CustomTraceCollector.d.ts +35 -0
  801. package/lib/typescript/features/performance/collectors/FrameMetricsCollector.d.ts +74 -0
  802. package/lib/typescript/features/performance/collectors/JsStallCollector.d.ts +45 -0
  803. package/lib/typescript/features/performance/collectors/NetworkPerfCollector.d.ts +23 -0
  804. package/lib/typescript/features/performance/collectors/ScreenLoadCollector.d.ts +30 -0
  805. package/lib/typescript/features/performance/collectors/UiHangCollector.d.ts +21 -0
  806. package/lib/typescript/features/performance/config.d.ts +73 -0
  807. package/lib/typescript/features/performance/getNativePerformanceModule.d.ts +2 -0
  808. package/lib/typescript/features/performance/index.d.ts +10 -0
  809. package/lib/typescript/features/performance/metrics/MetricsEngine.d.ts +69 -0
  810. package/lib/typescript/features/performance/models.d.ts +169 -0
  811. package/lib/typescript/features/performance/transport/PerformanceTransport.d.ts +40 -0
  812. package/lib/typescript/features/profiler/ProfilerFeature.d.ts +92 -0
  813. package/lib/typescript/features/profiler/config.d.ts +85 -0
  814. package/lib/typescript/features/profiler/contracts.d.ts +142 -0
  815. package/lib/typescript/features/profiler/index.d.ts +13 -0
  816. package/lib/typescript/features/profiler/models.d.ts +332 -0
  817. package/lib/typescript/features/profiler/transport/ProfilerTransport.d.ts +30 -0
  818. package/lib/typescript/features/replay/bridge/adapters/bridgeAdapter.d.ts +52 -0
  819. package/lib/typescript/features/replay/bridge/eventEmitter.d.ts +100 -0
  820. package/lib/typescript/features/replay/bridge/nativeModule.d.ts +166 -0
  821. package/lib/typescript/features/replay/bridge/nativeQuota.d.ts +26 -0
  822. package/lib/typescript/features/replay/core/clock/clock.d.ts +16 -0
  823. package/lib/typescript/features/replay/core/config/defaults.d.ts +28 -0
  824. package/lib/typescript/features/replay/core/config/validator.d.ts +13 -0
  825. package/lib/typescript/features/replay/core/env/environmentDetector.d.ts +14 -0
  826. package/lib/typescript/features/replay/core/errors/safeCall.d.ts +12 -0
  827. package/lib/typescript/features/replay/core/ids/sessionId.d.ts +15 -0
  828. package/lib/typescript/features/replay/core/logger/logger.d.ts +15 -0
  829. package/lib/typescript/features/replay/core/privacy/privacyTypes.d.ts +24 -0
  830. package/lib/typescript/features/replay/core/queue/boundedQueue.d.ts +29 -0
  831. package/lib/typescript/features/replay/integrations/alert/alertInstrumentation.d.ts +48 -0
  832. package/lib/typescript/features/replay/integrations/logs/consoleIntegration.d.ts +18 -0
  833. package/lib/typescript/features/replay/integrations/network/networkAdapter.d.ts +31 -0
  834. package/lib/typescript/features/replay/integrations/react-navigation/navigationIntegration.d.ts +25 -0
  835. package/lib/typescript/features/replay/integrations/touch/ReplayRoot.d.ts +26 -0
  836. package/lib/typescript/features/replay/pipeline/batching/batchManager.d.ts +47 -0
  837. package/lib/typescript/features/replay/pipeline/envelope/envelopeBuilder.d.ts +12 -0
  838. package/lib/typescript/features/replay/pipeline/retry/retryPolicy.d.ts +17 -0
  839. package/lib/typescript/features/replay/pipeline/transport/transportTypes.d.ts +40 -0
  840. package/lib/typescript/features/replay/public/api.d.ts +83 -0
  841. package/lib/typescript/features/replay/public/enums.d.ts +73 -0
  842. package/lib/typescript/features/replay/public/types.d.ts +249 -0
  843. package/lib/typescript/features/replay/replay/breadcrumbs/breadcrumbCollector.d.ts +26 -0
  844. package/lib/typescript/features/replay/replay/frames/frameModels.d.ts +23 -0
  845. package/lib/typescript/features/replay/replay/session/sessionOrchestrator.d.ts +53 -0
  846. package/lib/typescript/features/replay/replay/timeline/timelineModels.d.ts +29 -0
  847. package/lib/typescript/features/replay/transport/BackendReplayTransport.d.ts +45 -0
  848. package/lib/typescript/features/replay/transport/CompositeReplayTransport.d.ts +22 -0
  849. package/lib/typescript/features/replay/transport/DesktopReplayTransport.d.ts +35 -0
  850. package/lib/typescript/features/replay/transport/ReplayTransport.d.ts +72 -0
  851. package/lib/typescript/features/session/BackendSessionAdapter.d.ts +528 -0
  852. package/lib/typescript/features/session/DesktopSessionTransport.d.ts +28 -0
  853. package/lib/typescript/features/session/JourneyEventPipeline.d.ts +74 -0
  854. package/lib/typescript/features/session/ReplayCaptureManager.d.ts +391 -0
  855. package/lib/typescript/features/session/ScrollTracker.d.ts +48 -0
  856. package/lib/typescript/features/session/SessionManager.d.ts +414 -0
  857. package/lib/typescript/features/session/SyncDecisionEngine.d.ts +33 -0
  858. package/lib/typescript/features/session/frameLink.d.ts +27 -0
  859. package/lib/typescript/features/session/frameScrollState.d.ts +27 -0
  860. package/lib/typescript/features/session/index.d.ts +23 -0
  861. package/lib/typescript/features/session/nativeCapture.d.ts +18 -0
  862. package/lib/typescript/features/session/outboxFrameCapture.d.ts +20 -0
  863. package/lib/typescript/features/session/sessionTypes.d.ts +362 -0
  864. package/lib/typescript/features/session/viewportPlausibility.d.ts +72 -0
  865. package/lib/typescript/features/skan/skanBridge.d.ts +18 -0
  866. package/lib/typescript/features/skan/skanConversionManager.d.ts +69 -0
  867. package/lib/typescript/index.d.ts +59 -0
  868. package/lib/typescript/integrations/fetch/fetchInterceptor.d.ts +41 -0
  869. package/lib/typescript/integrations/navigation/screenTracker.d.ts +1 -0
  870. package/lib/typescript/integrations/network/bodyCapture.d.ts +101 -0
  871. package/lib/typescript/integrations/xhr/xhrInterceptor.d.ts +46 -0
  872. package/lib/typescript/metro/composeSourceMap.d.ts +26 -0
  873. package/lib/typescript/metro/featureModules.d.ts +49 -0
  874. package/lib/typescript/metro/index.d.ts +99 -0
  875. package/lib/typescript/metro/optionalDependencyStub.d.ts +14 -0
  876. package/lib/typescript/metro/optionalModules.d.ts +20 -0
  877. package/lib/typescript/metro/serializerCompose.d.ts +46 -0
  878. package/lib/typescript/pipeline/dispatcher/dispatcher.d.ts +7 -0
  879. package/lib/typescript/pipeline/envelope/envelope.d.ts +16 -0
  880. package/lib/typescript/pipeline/envelope/serializer.d.ts +7 -0
  881. package/lib/typescript/pipeline/processors/dedupe.d.ts +1 -0
  882. package/lib/typescript/pipeline/processors/enrich.d.ts +3 -0
  883. package/lib/typescript/pipeline/processors/sampling.d.ts +1 -0
  884. package/lib/typescript/pipeline/processors/sanitize.d.ts +3 -0
  885. package/lib/typescript/pipeline/queue/flushQueue.d.ts +12 -0
  886. package/lib/typescript/pipeline/queue/memoryQueue.d.ts +12 -0
  887. package/lib/typescript/pipeline/queue/persistentQueue.d.ts +120 -0
  888. package/lib/typescript/pipeline/queue/queuePolicy.d.ts +1 -0
  889. package/lib/typescript/pipeline/scheduler/flushScheduler.d.ts +9 -0
  890. package/lib/typescript/pipeline/scheduler/retryPolicy.d.ts +5 -0
  891. package/lib/typescript/public/ScaleBunErrorBoundary.d.ts +44 -0
  892. package/lib/typescript/public/ScaleBunFacade.d.ts +800 -0
  893. package/lib/typescript/public/ScaleBunProvider.d.ts +23 -0
  894. package/lib/typescript/public/typedTracker.d.ts +88 -0
  895. package/lib/typescript/public/types.d.ts +316 -0
  896. package/lib/typescript/push/PushManager.d.ts +69 -0
  897. package/lib/typescript/push/adapters/ManualAdapter.d.ts +40 -0
  898. package/lib/typescript/push/adapters/NativeBridgeAdapter.d.ts +37 -0
  899. package/lib/typescript/push/adapters/NoopAdapter.d.ts +21 -0
  900. package/lib/typescript/push/adapters/RNFirebaseMessagingAdapter.d.ts +39 -0
  901. package/lib/typescript/push/adapters/loadMessaging.d.ts +17 -0
  902. package/lib/typescript/push/adapters/loadNotifee.d.ts +15 -0
  903. package/lib/typescript/push/adapters/selectAdapter.d.ts +20 -0
  904. package/lib/typescript/push/detect/capabilities.d.ts +15 -0
  905. package/lib/typescript/push/index.d.ts +10 -0
  906. package/lib/typescript/push/native/nativeNotifications.d.ts +65 -0
  907. package/lib/typescript/push/types.d.ts +143 -0
  908. package/lib/typescript/specs/NativeReplaySdk.d.ts +69 -0
  909. package/lib/typescript/specs/NativeScaleBunCrash.d.ts +58 -0
  910. package/lib/typescript/specs/NativeScaleBunInstallReferrer.d.ts +28 -0
  911. package/lib/typescript/specs/NativeScaleBunOta.d.ts +141 -0
  912. package/lib/typescript/specs/NativeScaleBunPerformance.d.ts +31 -0
  913. package/lib/typescript/specs/NativeScaleBunProfiler.d.ts +38 -0
  914. package/lib/typescript/specs/NativeScaleBunStorage.d.ts +55 -0
  915. package/lib/typescript/storage/StorageBackend.d.ts +131 -0
  916. package/lib/typescript/storage/db/sqlite.d.ts +1 -0
  917. package/lib/typescript/storage/files/fileStore.d.ts +1 -0
  918. package/lib/typescript/transport/auth/sdkSession.d.ts +10 -0
  919. package/lib/typescript/transport/backoff/exponentialJitter.d.ts +5 -0
  920. package/lib/typescript/transport/http/endpoints.d.ts +26 -0
  921. package/lib/typescript/transport/http/httpClient.d.ts +23 -0
  922. package/lib/typescript/transport/rateLimit/retryAfter.d.ts +1 -0
  923. package/lib/typescript/transport/signing/requestSigner.d.ts +1 -0
  924. package/lib/typescript/vendor/protocol/index.d.ts +345 -0
  925. package/lib/typescript/vendor/protocol/internal/validation.d.ts +114 -0
  926. package/lib/typescript/vendor/sdk-contracts/bridge.d.ts +104 -0
  927. package/lib/typescript/vendor/sdk-contracts/config.d.ts +156 -0
  928. package/lib/typescript/vendor/sdk-contracts/events.d.ts +42 -0
  929. package/lib/typescript/vendor/sdk-contracts/features.d.ts +38 -0
  930. package/lib/typescript/vendor/sdk-contracts/index.d.ts +15 -0
  931. package/lib/typescript/vendor/sdk-contracts/platform.d.ts +35 -0
  932. package/lib/typescript/vendor/sdk-contracts/session-boundary.d.ts +42 -0
  933. package/lib/typescript/vendor/sdk-contracts/session.d.ts +157 -0
  934. package/package.json +153 -0
  935. package/react-native.config.js +24 -0
  936. package/scalebun-react-native.podspec +44 -0
  937. package/src/analytics/EventTracker.ts +654 -0
  938. package/src/analytics/automaticEvents.ts +109 -0
  939. package/src/analytics/batching.ts +54 -0
  940. package/src/analytics/eventLane.ts +48 -0
  941. package/src/analytics/revenue.ts +143 -0
  942. package/src/analytics/subscription.ts +145 -0
  943. package/src/bootstrap/FeatureRegistry.ts +81 -0
  944. package/src/bootstrap/SDKBootstrapper.ts +769 -0
  945. package/src/bucketing/fnv1a32.ts +40 -0
  946. package/src/compat/codepush.ts +189 -0
  947. package/src/config/ConfigManager.ts +233 -0
  948. package/src/config/configTypes.ts +62 -0
  949. package/src/config/otaPolicyState.ts +79 -0
  950. package/src/config/quotaState.ts +484 -0
  951. package/src/core/architecture.ts +39 -0
  952. package/src/core/clock/now.ts +6 -0
  953. package/src/core/config/defaults.ts +0 -0
  954. package/src/core/config/schema.ts +455 -0
  955. package/src/core/constants/endpoints.ts +12 -0
  956. package/src/core/constants/protocol.ts +24 -0
  957. package/src/core/constants/timings.ts +25 -0
  958. package/src/core/constants/version.ts +11 -0
  959. package/src/core/context/app.ts +0 -0
  960. package/src/core/context/device.ts +169 -0
  961. package/src/core/context/session.ts +0 -0
  962. package/src/core/context/user.ts +26 -0
  963. package/src/core/contracts/IFeature.ts +53 -0
  964. package/src/core/di/container.ts +26 -0
  965. package/src/core/encoding/base64.ts +46 -0
  966. package/src/core/id/deviceId.ts +51 -0
  967. package/src/core/id/installationId.ts +52 -0
  968. package/src/core/id/sessionId.ts +0 -0
  969. package/src/core/lifecycle/appLifecycle.ts +33 -0
  970. package/src/core/lifecycle/crashSafe.ts +29 -0
  971. package/src/core/logger/errorClassification.ts +108 -0
  972. package/src/core/logger/internalLogger.ts +65 -0
  973. package/src/core/logger/levels.ts +0 -0
  974. package/src/crypto/hmacSha256.ts +106 -0
  975. package/src/debug/bootstrap.ts +436 -0
  976. package/src/debug/commands.ts +597 -0
  977. package/src/debug/configBuilder.ts +56 -0
  978. package/src/debug/exportBridge.ts +155 -0
  979. package/src/debug/hostResolver.ts +34 -0
  980. package/src/debug/index.ts +25 -0
  981. package/src/debug/metrics.ts +29 -0
  982. package/src/debug/perf.ts +212 -0
  983. package/src/debug/perfWiring.ts +119 -0
  984. package/src/debug/protocol.ts +58 -0
  985. package/src/debug/redaction.ts +483 -0
  986. package/src/debug/replayWiring.ts +148 -0
  987. package/src/debug/screenTracking.ts +55 -0
  988. package/src/debug/sessionWiring.ts +59 -0
  989. package/src/debug/stream.ts +561 -0
  990. package/src/debug/transport.ts +440 -0
  991. package/src/features/bugreport/BugReportFeature.ts +128 -0
  992. package/src/features/bugreport/buildPayload.ts +116 -0
  993. package/src/features/bugreport/index.ts +0 -0
  994. package/src/features/crash/CrashFeature.ts +87 -0
  995. package/src/features/crash/CrashReporter.ts +189 -0
  996. package/src/features/crash/NativeCrashFeature.ts +42 -0
  997. package/src/features/crash/capture.ts +48 -0
  998. package/src/features/crash/globalHandler.ts +39 -0
  999. package/src/features/crash/index.ts +8 -0
  1000. package/src/features/crash/nativeCrashBridge.ts +352 -0
  1001. package/src/features/crash/rejectionHandler.ts +196 -0
  1002. package/src/features/crash/scrubCrash.ts +175 -0
  1003. package/src/features/engage/EngageAnchor.tsx +159 -0
  1004. package/src/features/engage/EngageArchetypeRenderers.tsx +3705 -0
  1005. package/src/features/engage/EngageInAppView.tsx +2678 -0
  1006. package/src/features/engage/EngageInlinePlacement.tsx +169 -0
  1007. package/src/features/engage/EngagePromptProvider.tsx +1318 -0
  1008. package/src/features/engage/EngagePromptView.tsx +1400 -0
  1009. package/src/features/engage/EngageTransport.ts +668 -0
  1010. package/src/features/engage/EngageVariantContent.tsx +1483 -0
  1011. package/src/features/engage/__test-support__/reactNativeStub.js +40 -0
  1012. package/src/features/engage/attachmentCapture.ts +45 -0
  1013. package/src/features/engage/captureVoiceAttachment.ts +81 -0
  1014. package/src/features/engage/engageCoachmarkTour.ts +120 -0
  1015. package/src/features/engage/engageGameLogic.ts +347 -0
  1016. package/src/features/engage/engageMediaSizing.ts +76 -0
  1017. package/src/features/engage/engageMultiStepSheet.ts +53 -0
  1018. package/src/features/engage/engageOutcome.ts +157 -0
  1019. package/src/features/engage/engagePushTokenBridge.ts +84 -0
  1020. package/src/features/engage/engageShakeBridge.ts +67 -0
  1021. package/src/features/engage/engageSignals.ts +40 -0
  1022. package/src/features/engage/engageStoreReviewBridge.ts +48 -0
  1023. package/src/features/engage/engageTestSeenStore.ts +95 -0
  1024. package/src/features/engage/engageThrottle.ts +478 -0
  1025. package/src/features/engage/engageTriggerEngine.ts +350 -0
  1026. package/src/features/engage/engageTypes.ts +712 -0
  1027. package/src/features/engage/engageVariantResolver.ts +364 -0
  1028. package/src/features/engage/engageWindowInsets.ts +108 -0
  1029. package/src/features/engage/gestureTriggerDetector.ts +83 -0
  1030. package/src/features/engage/transcription/TranscriptionProvider.ts +68 -0
  1031. package/src/features/install-referrer/installReferrer.ts +112 -0
  1032. package/src/features/journey/ScaleBunDebugRoot.tsx +1045 -0
  1033. package/src/features/journey/ScaleBunFlatList.tsx +39 -0
  1034. package/src/features/journey/ScaleBunImpression.tsx +109 -0
  1035. package/src/features/journey/ScaleBunScrollView.tsx +101 -0
  1036. package/src/features/journey/ScaleBunSectionList.tsx +39 -0
  1037. package/src/features/journey/autoInstrumentScroll.ts +155 -0
  1038. package/src/features/journey/calibrationContext.ts +44 -0
  1039. package/src/features/journey/gestureBuffer.ts +59 -0
  1040. package/src/features/journey/gestureDetector.ts +162 -0
  1041. package/src/features/journey/impression.ts +92 -0
  1042. package/src/features/journey/interactionProtocol.ts +243 -0
  1043. package/src/features/journey/journeyManager.ts +469 -0
  1044. package/src/features/journey/journeyTypes.ts +215 -0
  1045. package/src/features/journey/nativeScroll.ts +94 -0
  1046. package/src/features/journey/navDetector.ts +149 -0
  1047. package/src/features/journey/screenshotHelper.ts +137 -0
  1048. package/src/features/journey/scrollContext.ts +146 -0
  1049. package/src/features/journey/targetGeometry.ts +197 -0
  1050. package/src/features/journey/targetRegistry.ts +43 -0
  1051. package/src/features/journey/touchTarget.ts +339 -0
  1052. package/src/features/journey/uiState.ts +182 -0
  1053. package/src/features/navigation/AutoScreenDetector.ts +617 -0
  1054. package/src/features/network/NetworkFeature.ts +232 -0
  1055. package/src/features/network/index.ts +59 -0
  1056. package/src/features/network/thirdParty.ts +160 -0
  1057. package/src/features/ota/OtaEventEmitter.ts +187 -0
  1058. package/src/features/ota/OtaOrchestrator.ts +1513 -0
  1059. package/src/features/ota/OtaTypes.ts +230 -0
  1060. package/src/features/ota/deviceAttributes.ts +46 -0
  1061. package/src/features/ota/environment.ts +199 -0
  1062. package/src/features/ota/geoCountry.ts +85 -0
  1063. package/src/features/ota/retry.ts +123 -0
  1064. package/src/features/ota/signedDownload.ts +202 -0
  1065. package/src/features/ota/useOtaUpdate.ts +161 -0
  1066. package/src/features/performance/PerformanceFeature.ts +729 -0
  1067. package/src/features/performance/collectors/AppLaunchCollector.ts +131 -0
  1068. package/src/features/performance/collectors/AutoScreenLoadCollector.ts +258 -0
  1069. package/src/features/performance/collectors/CustomTraceCollector.ts +116 -0
  1070. package/src/features/performance/collectors/FrameMetricsCollector.ts +210 -0
  1071. package/src/features/performance/collectors/JsStallCollector.ts +184 -0
  1072. package/src/features/performance/collectors/NetworkPerfCollector.ts +69 -0
  1073. package/src/features/performance/collectors/ScreenLoadCollector.ts +95 -0
  1074. package/src/features/performance/collectors/UiHangCollector.ts +98 -0
  1075. package/src/features/performance/config.ts +136 -0
  1076. package/src/features/performance/getNativePerformanceModule.ts +38 -0
  1077. package/src/features/performance/index.ts +28 -0
  1078. package/src/features/performance/metrics/MetricsEngine.ts +152 -0
  1079. package/src/features/performance/models.ts +235 -0
  1080. package/src/features/performance/transport/PerformanceTransport.ts +161 -0
  1081. package/src/features/profiler/ProfilerFeature.ts +661 -0
  1082. package/src/features/profiler/config.ts +230 -0
  1083. package/src/features/profiler/contracts.ts +176 -0
  1084. package/src/features/profiler/index.ts +45 -0
  1085. package/src/features/profiler/models.ts +430 -0
  1086. package/src/features/profiler/transport/ProfilerTransport.ts +93 -0
  1087. package/src/features/replay/bridge/adapters/bridgeAdapter.ts +235 -0
  1088. package/src/features/replay/bridge/eventEmitter.ts +176 -0
  1089. package/src/features/replay/bridge/nativeModule.ts +252 -0
  1090. package/src/features/replay/bridge/nativeQuota.ts +111 -0
  1091. package/src/features/replay/core/clock/clock.ts +38 -0
  1092. package/src/features/replay/core/config/defaults.ts +66 -0
  1093. package/src/features/replay/core/config/validator.ts +113 -0
  1094. package/src/features/replay/core/env/environmentDetector.ts +21 -0
  1095. package/src/features/replay/core/errors/safeCall.ts +34 -0
  1096. package/src/features/replay/core/ids/sessionId.ts +44 -0
  1097. package/src/features/replay/core/logger/logger.ts +36 -0
  1098. package/src/features/replay/core/privacy/privacyTypes.ts +41 -0
  1099. package/src/features/replay/core/queue/boundedQueue.ts +71 -0
  1100. package/src/features/replay/integrations/alert/alertInstrumentation.ts +277 -0
  1101. package/src/features/replay/integrations/logs/consoleIntegration.ts +136 -0
  1102. package/src/features/replay/integrations/network/networkAdapter.ts +73 -0
  1103. package/src/features/replay/integrations/react-navigation/navigationIntegration.ts +89 -0
  1104. package/src/features/replay/integrations/touch/ReplayRoot.tsx +114 -0
  1105. package/src/features/replay/pipeline/batching/batchManager.ts +133 -0
  1106. package/src/features/replay/pipeline/envelope/envelopeBuilder.ts +66 -0
  1107. package/src/features/replay/pipeline/retry/retryPolicy.ts +62 -0
  1108. package/src/features/replay/pipeline/transport/transportTypes.ts +85 -0
  1109. package/src/features/replay/public/api.ts +364 -0
  1110. package/src/features/replay/public/enums.ts +78 -0
  1111. package/src/features/replay/public/types.ts +297 -0
  1112. package/src/features/replay/replay/breadcrumbs/breadcrumbCollector.ts +115 -0
  1113. package/src/features/replay/replay/frames/frameModels.ts +45 -0
  1114. package/src/features/replay/replay/session/sessionOrchestrator.ts +286 -0
  1115. package/src/features/replay/replay/timeline/timelineModels.ts +129 -0
  1116. package/src/features/replay/transport/BackendReplayTransport.ts +215 -0
  1117. package/src/features/replay/transport/CompositeReplayTransport.ts +82 -0
  1118. package/src/features/replay/transport/DesktopReplayTransport.ts +140 -0
  1119. package/src/features/replay/transport/ReplayTransport.ts +84 -0
  1120. package/src/features/session/BackendSessionAdapter.ts +1977 -0
  1121. package/src/features/session/DesktopSessionTransport.ts +130 -0
  1122. package/src/features/session/JourneyEventPipeline.ts +278 -0
  1123. package/src/features/session/ReplayCaptureManager.ts +1401 -0
  1124. package/src/features/session/ScrollTracker.ts +166 -0
  1125. package/src/features/session/SessionManager.ts +1687 -0
  1126. package/src/features/session/SyncDecisionEngine.ts +117 -0
  1127. package/src/features/session/frameLink.ts +41 -0
  1128. package/src/features/session/frameScrollState.ts +36 -0
  1129. package/src/features/session/index.ts +88 -0
  1130. package/src/features/session/nativeCapture.ts +43 -0
  1131. package/src/features/session/outboxFrameCapture.ts +79 -0
  1132. package/src/features/session/sessionTypes.ts +528 -0
  1133. package/src/features/session/viewportPlausibility.ts +134 -0
  1134. package/src/features/skan/skanBridge.ts +53 -0
  1135. package/src/features/skan/skanConversionManager.ts +173 -0
  1136. package/src/index.ts +206 -0
  1137. package/src/integrations/fetch/fetchInterceptor.ts +201 -0
  1138. package/src/integrations/navigation/screenTracker.ts +0 -0
  1139. package/src/integrations/network/bodyCapture.ts +328 -0
  1140. package/src/integrations/xhr/xhrInterceptor.ts +259 -0
  1141. package/src/metro/composeSourceMap.ts +104 -0
  1142. package/src/metro/featureModules.ts +143 -0
  1143. package/src/metro/index.ts +336 -0
  1144. package/src/metro/optionalDependencyStub.ts +13 -0
  1145. package/src/metro/optionalModules.ts +27 -0
  1146. package/src/metro/serializerCompose.ts +193 -0
  1147. package/src/pipeline/dispatcher/dispatcher.ts +22 -0
  1148. package/src/pipeline/envelope/envelope.ts +31 -0
  1149. package/src/pipeline/envelope/serializer.ts +14 -0
  1150. package/src/pipeline/processors/dedupe.ts +0 -0
  1151. package/src/pipeline/processors/enrich.ts +11 -0
  1152. package/src/pipeline/processors/sampling.ts +0 -0
  1153. package/src/pipeline/processors/sanitize.ts +23 -0
  1154. package/src/pipeline/queue/flushQueue.ts +144 -0
  1155. package/src/pipeline/queue/memoryQueue.ts +31 -0
  1156. package/src/pipeline/queue/persistentQueue.ts +385 -0
  1157. package/src/pipeline/queue/queuePolicy.ts +0 -0
  1158. package/src/pipeline/scheduler/flushScheduler.ts +47 -0
  1159. package/src/pipeline/scheduler/retryPolicy.ts +8 -0
  1160. package/src/public/ScaleBunErrorBoundary.tsx +91 -0
  1161. package/src/public/ScaleBunFacade.ts +2129 -0
  1162. package/src/public/ScaleBunProvider.tsx +91 -0
  1163. package/src/public/typedTracker.ts +123 -0
  1164. package/src/public/types.ts +362 -0
  1165. package/src/push/PushManager.ts +318 -0
  1166. package/src/push/adapters/ManualAdapter.ts +100 -0
  1167. package/src/push/adapters/NativeBridgeAdapter.ts +142 -0
  1168. package/src/push/adapters/NoopAdapter.ts +46 -0
  1169. package/src/push/adapters/RNFirebaseMessagingAdapter.ts +271 -0
  1170. package/src/push/adapters/loadMessaging.ts +24 -0
  1171. package/src/push/adapters/loadNotifee.ts +29 -0
  1172. package/src/push/adapters/selectAdapter.ts +176 -0
  1173. package/src/push/detect/capabilities.ts +124 -0
  1174. package/src/push/index.ts +22 -0
  1175. package/src/push/native/nativeNotifications.ts +207 -0
  1176. package/src/push/types.ts +159 -0
  1177. package/src/specs/NativeReplaySdk.ts +101 -0
  1178. package/src/specs/NativeScaleBunCrash.ts +64 -0
  1179. package/src/specs/NativeScaleBunInstallReferrer.ts +29 -0
  1180. package/src/specs/NativeScaleBunOta.ts +154 -0
  1181. package/src/specs/NativeScaleBunPerformance.ts +34 -0
  1182. package/src/specs/NativeScaleBunProfiler.ts +41 -0
  1183. package/src/specs/NativeScaleBunStorage.ts +59 -0
  1184. package/src/storage/StorageBackend.ts +272 -0
  1185. package/src/storage/db/sqlite.ts +0 -0
  1186. package/src/storage/files/fileStore.ts +0 -0
  1187. package/src/transport/auth/sdkSession.ts +27 -0
  1188. package/src/transport/backoff/exponentialJitter.ts +9 -0
  1189. package/src/transport/http/endpoints.ts +33 -0
  1190. package/src/transport/http/httpClient.ts +73 -0
  1191. package/src/transport/rateLimit/retryAfter.ts +0 -0
  1192. package/src/transport/signing/requestSigner.ts +0 -0
  1193. package/src/vendor/protocol/index.ts +391 -0
  1194. package/src/vendor/protocol/internal/validation.ts +497 -0
  1195. package/src/vendor/sdk-contracts/bridge.ts +162 -0
  1196. package/src/vendor/sdk-contracts/config.ts +192 -0
  1197. package/src/vendor/sdk-contracts/events.ts +50 -0
  1198. package/src/vendor/sdk-contracts/features.ts +42 -0
  1199. package/src/vendor/sdk-contracts/index.ts +98 -0
  1200. package/src/vendor/sdk-contracts/platform.ts +42 -0
  1201. package/src/vendor/sdk-contracts/session-boundary.ts +55 -0
  1202. package/src/vendor/sdk-contracts/session.ts +225 -0
  1203. package/src/vendor/vendor.manifest +10 -0
@@ -0,0 +1,1401 @@
1
+ /**
2
+ * ScaleBun SDK — Replay Capture Manager
3
+ *
4
+ * Orchestration-only component for frame capture:
5
+ * - Decides WHEN to capture (navigation, interaction, scroll, loading, frequency triggers)
6
+ * - Delegates ALL frame capture to native engines via sessionReplayAdapter
7
+ * - NEVER performs screenshot logic itself
8
+ * - If native capture unavailable, returns null and logs warning
9
+ * - Manages frame retention with crash-adjacent priority
10
+ * - Uses session-bound generation guard to invalidate stale async work
11
+ * - All pending timers are cancelled on stop()
12
+ *
13
+ * Semantic Capture Coordination:
14
+ * - Tracks the last completed capture's reason + screen to prevent semantic duplicates
15
+ * - Navigation supersedes pending interaction for the SAME screen (interaction is already
16
+ * visually represented by the navigation frame)
17
+ * - Loading completion for the SAME screen coalesces with a pending navigation capture
18
+ * by cancelling the navigation capture (loading's delayed capture shows the final state)
19
+ * - Scroll captures have per-cycle identity and do not conflict with navigation/loading
20
+ * - Manual and error-context captures ALWAYS bypass coordination (explicit intent)
21
+ * - Genuinely distinct states (different screens, different reasons after settle) are never deduped
22
+ */
23
+
24
+ import { logger } from '../../core/logger/internalLogger';
25
+ import type {
26
+ ReplayFrame,
27
+ CaptureMode,
28
+ CaptureReason,
29
+ ReplayQuality,
30
+ SessionReplayConfig,
31
+ PrivacyPolicy,
32
+ NativeFrameResult,
33
+ } from './sessionTypes';
34
+ import {
35
+ FrameRetentionPriority,
36
+ getFrameRetentionPriority,
37
+ QUALITY_PRESETS,
38
+ } from './sessionTypes';
39
+ import type { PlatformOS } from '../../core/context/device';
40
+ import type { FrameScrollEntry } from './frameScrollState';
41
+
42
+ // ─── Types ──────────────────────────────────────────────────────────────────
43
+
44
+ /**
45
+ * Native capture function provided by the adapter layer.
46
+ * Calls the platform native engine (PixelCopy on Android, UIWindow on iOS).
47
+ * Returns null if native capture is unavailable.
48
+ */
49
+ export type NativeCaptureFn = (
50
+ sessionId: string,
51
+ reason: string,
52
+ quality: ReplayQuality,
53
+ ) => Promise<NativeFrameResult | null>;
54
+
55
+ export type FrameEmitCallback = (frame: ReplayFrame, imageData: string) => void;
56
+
57
+ /**
58
+ * How a wait ended. Named for what was OBSERVED, not for what it probably meant.
59
+ *
60
+ * `network_idle` is the only one that says the screen arrived, and even that is an inference from
61
+ * quiet rather than a look at the pixels. `timeout` is its opposite and must never be collapsed
62
+ * into it: the cap expired with requests still outstanding, so the screen was still loading when
63
+ * we gave up waiting and photographed it anyway. A band drawn from a `timeout` is evidence of a
64
+ * slow or stuck screen; one drawn from `network_idle` is evidence of an ordinary load.
65
+ */
66
+ export type LoadingEndReason =
67
+ | 'network_idle'
68
+ | 'timeout'
69
+ | 'superseded'
70
+ | 'session_end'
71
+ /** Capture paused mid-session by a `frames` quota block — the session did NOT end. */
72
+ | 'quota_pause';
73
+
74
+ /**
75
+ * Reports a wait the capture manager sat through, so it can be recorded as a journey event.
76
+ * Two calls per wait — one `start`, one `end` — and NO calls at all when nothing was held,
77
+ * which is the common case and the reason this costs almost nothing.
78
+ */
79
+ export type LoadingIntervalCallback = (
80
+ phase: 'start' | 'end',
81
+ screen: string | undefined,
82
+ detail: { durationMs?: number; reason?: LoadingEndReason },
83
+ ) => void;
84
+
85
+ // ─── Native File-Outbox staged capture ───────────────────────────────────────
86
+
87
+ /**
88
+ * Metadata returned by a native STAGED capture-to-file. The image bytes are
89
+ * already written to the native outbox (staged, not yet uploadable) — they NEVER
90
+ * cross the bridge. `frameHash` is a native content hash so JS change-detection
91
+ * works without base64.
92
+ */
93
+ export interface StagedFrameResult {
94
+ frameId: string;
95
+ width: number;
96
+ height: number;
97
+ byteSize: number;
98
+ format: string;
99
+ contentType: string;
100
+ frameHash: string;
101
+ masked: boolean;
102
+ timestamp: number;
103
+ // Widened: frames now carry the REAL Platform.OS instead of being relabelled 'android'.
104
+ platform: PlatformOS;
105
+ /** Sanitized visible scroll containers at capture time; undefined = not measured. */
106
+ scrollState?: FrameScrollEntry[];
107
+ }
108
+
109
+ /** JS-authoritative frame metadata written to the outbox on commit. */
110
+ export interface OutboxFrameMeta {
111
+ frameId: string;
112
+ sessionId: string;
113
+ timestamp: number;
114
+ sequenceNumber: number;
115
+ frameType: 'keyframe' | 'delta';
116
+ baseFrameId?: string;
117
+ screenName: string;
118
+ trigger: string;
119
+ format: string;
120
+ contentType: string;
121
+ width: number;
122
+ height: number;
123
+ sizeBytes: number;
124
+ masked: boolean;
125
+ /** Visible scroll containers at capture time — the native uploader forwards it verbatim. */
126
+ scrollState?: FrameScrollEntry[];
127
+ }
128
+
129
+ /**
130
+ * Native file-outbox frame capture. `capture` stages an image and returns metadata
131
+ * only (or null when the outbox is off / capture fails → caller falls back to the
132
+ * legacy native capture). `commit` writes the JS-decided meta (making the frame
133
+ * uploadable); `discard` drops a staged frame the orchestrator suppressed.
134
+ */
135
+ export interface OutboxFrameCapture {
136
+ capture(
137
+ sessionId: string,
138
+ screenName: string | undefined,
139
+ trigger: string,
140
+ ): Promise<StagedFrameResult | null>;
141
+ commit(meta: OutboxFrameMeta): Promise<boolean>;
142
+ discard(sessionId: string, frameId: string): Promise<void>;
143
+ }
144
+
145
+ // ─── Capture Intent ─────────────────────────────────────────────────────────
146
+
147
+ /**
148
+ * Represents the semantic identity of a completed capture.
149
+ * Used for dedup: two captures with the same intent fingerprint
150
+ * represent the same visual state and should not produce two frames.
151
+ */
152
+ interface CaptureIntent {
153
+ reason: CaptureReason;
154
+ screen: string | undefined;
155
+ ts: number;
156
+ }
157
+
158
+ /**
159
+ * Reasons that always bypass semantic dedup.
160
+ * These are explicit user/system requests that should ALWAYS produce a frame.
161
+ */
162
+ const BYPASS_DEDUP_REASONS: Set<CaptureReason> = new Set([
163
+ 'manual',
164
+ 'error-context',
165
+ 'frequency',
166
+ ]);
167
+
168
+ /**
169
+ * Minimum time (ms) between captures of the same semantic intent
170
+ * (same reason + same screen). Secondary heuristic only — the primary
171
+ * check is semantic (reason + screen identity).
172
+ */
173
+ const SAME_INTENT_COOLDOWN_MS = 300;
174
+
175
+ /**
176
+ * Time (ms) to defer an interaction capture before finalizing.
177
+ * If onScreenChange fires within this window (i.e. the tap caused navigation),
178
+ * the interaction capture is cancelled and absorbed into the navigation capture.
179
+ * If no navigation follows, the interaction captures normally after this delay.
180
+ * 200ms is long enough for most React navigation timings but short enough to feel instant.
181
+ */
182
+ const INTERACTION_SETTLE_MS = 200;
183
+
184
+ /**
185
+ * Grace window (ms) AFTER an interaction capture has already fired.
186
+ * If onScreenChange fires to a DIFFERENT screen within this window,
187
+ * the stale interaction frame is retroactively evicted and its tap
188
+ * metadata is carried forward to the navigation capture.
189
+ * Handles the intermittent case where navigation takes >INTERACTION_SETTLE_MS.
190
+ */
191
+ const LATE_ABSORPTION_GRACE_MS = 400;
192
+
193
+ /**
194
+ * ── WAITING FOR THE DATA, RATHER THAN PHOTOGRAPHING THE WAIT ────────────────────────────────────
195
+ *
196
+ * In `interactions` capture mode the only frames that exist are the ones a tap or a navigation
197
+ * produces, and both fire on a short render-settle timer. A screen that fetches anything therefore
198
+ * gets photographed mid-flight: the skeleton, the spinner, the empty list — and then nothing until
199
+ * the next tap, because nothing else triggers a capture. The replay is a sequence of loading
200
+ * states, which is exactly the complaint.
201
+ *
202
+ * The obvious fix — capture again when the data lands — doubles the frames for every screen that
203
+ * loads anything, which is the cost `interactions` mode was chosen to avoid. So the capture is
204
+ * DEFERRED instead of repeated: while the app has a request in flight the pending capture waits,
205
+ * and it fires once the network goes quiet and the render that follows has settled. One frame per
206
+ * interaction, as before; taken when there is something to see.
207
+ *
208
+ * `NETWORK_QUIET_MS` is the pause after the LAST response before the screen is considered
209
+ * arrived — long enough for the app to parse the body and re-render, short enough not to be felt.
210
+ * `LOADING_DEFER_CAP_MS` bounds the whole wait: past it we capture whatever is on screen, because
211
+ * a request that never returns is itself the thing worth seeing, and an unbounded defer would mean
212
+ * a tap that produced no frame at all.
213
+ */
214
+ const NETWORK_QUIET_MS = 300;
215
+ const LOADING_DEFER_CAP_MS = 4_000;
216
+
217
+ /**
218
+ * Activity sampling — the motion BETWEEN interaction frames, without a standing timer.
219
+ *
220
+ * `interactions` mode emits one frame per tap / navigation / scroll-settle / load. Everything that
221
+ * moves after that frame — a sheet sliding in, a list populating, a toast, a carousel settling — has
222
+ * no frame until the next touch, so replays play as a slideshow (median gap 1.34s, p90 5.8s on prod,
223
+ * 2026-09-23). The old `frequency` mode fixed that by sampling forever, which is the cost this mode
224
+ * exists to avoid.
225
+ *
226
+ * Instead, each semantic frame opens a short WINDOW. Inside it the screen is sampled every
227
+ * ACTIVITY_SAMPLE_INTERVAL_MS through the `frequency` lane, which already carries change detection
228
+ * (P2-1 below): a sample whose hash matches the last frame is discarded from the outbox before it is
229
+ * ever uploaded. The window closes at whichever comes first — its length, ACTIVITY_MAX_SAMPLES
230
+ * emitted, or ACTIVITY_SETTLED_STREAK unchanged samples in a row (the screen stopped moving). An idle
231
+ * screen therefore uploads ZERO extra frames, and a busy one at most ACTIVITY_MAX_SAMPLES per semantic
232
+ * frame. ACTIVITY_MAX_PER_MINUTE bounds a pathological screen (an endless animation under constant
233
+ * tapping).
234
+ *
235
+ * Samples are encoded at the SAME quality as every other frame, deliberately: the native frameHash
236
+ * is FNV-1a over the ENCODED bytes, so a lighter sample of an unchanged screen would hash differently
237
+ * from the frame before it and upload anyway — defeating the whole gate.
238
+ *
239
+ * The first sample lands AFTER LATE_ABSORPTION_GRACE_MS on purpose: a sample clears the
240
+ * late-absorption tracker, and must not do so while a tap → navigation can still claim it.
241
+ */
242
+ const ACTIVITY_SAMPLE_INTERVAL_MS = 500;
243
+ const ACTIVITY_WINDOW_MS = 2_500;
244
+ const ACTIVITY_MAX_SAMPLES = 3;
245
+ const ACTIVITY_SETTLED_STREAK = 2;
246
+ const ACTIVITY_MAX_PER_MINUTE = 30;
247
+ /** Semantic captures that open a sampling window. Samples themselves never do. */
248
+ const ACTIVITY_OPENERS: ReadonlySet<CaptureReason> = new Set<CaptureReason>([
249
+ 'interaction',
250
+ 'navigation',
251
+ 'scroll',
252
+ 'screen_loaded',
253
+ ]);
254
+
255
+ // ─── Manager ────────────────────────────────────────────────────────────────
256
+
257
+ export class ReplayCaptureManager {
258
+ private sessionId: string;
259
+ private config: SessionReplayConfig;
260
+ private nativeCapture: NativeCaptureFn;
261
+ /** Optional native file-outbox path. When ready, frames stage→commit natively. */
262
+ private outboxCapture: OutboxFrameCapture | null;
263
+ private onFrameEmit: FrameEmitCallback | null = null;
264
+ private onLoadingInterval: LoadingIntervalCallback | null = null;
265
+
266
+ private frames: ReplayFrame[] = [];
267
+ /** Set of frameIds near crashes — never evict */
268
+ private protectedFrameIds = new Set<string>();
269
+ private frequencyTimer: ReturnType<typeof setInterval> | null = null;
270
+ private capturing = false;
271
+ private currentScreen: string | null = null;
272
+ private lastInteractionCapture = 0;
273
+
274
+ /**
275
+ * App network activity, as reported by the interceptors (SDK uploads and third-party
276
+ * beacons are filtered out upstream — see NetworkFeature). This is the only evidence the
277
+ * capture manager has that a screen is still waiting for something, and it is used for
278
+ * nothing but deciding WHEN to take the frame it was already going to take.
279
+ *
280
+ * Zero when network monitoring is disabled, which makes every hold below evaluate to "fire
281
+ * now" — the deferral costs nothing and changes nothing when there is no signal to act on.
282
+ */
283
+ private _inFlightRequests = 0;
284
+ private _lastRequestStartTs = 0;
285
+ private _lastRequestEndTs = 0;
286
+
287
+ /** Epoch ms past which a capture held for loading fires regardless. 0 when nothing is held. */
288
+ private pendingInteractionDeadline = 0;
289
+ private pendingNavDeadline = 0;
290
+ // Activity sampling (see ACTIVITY_SAMPLE_INTERVAL_MS). The window is owned by the capture
291
+ // generation it was opened in: stop() bumps the generation, so a tick that outlives it no-ops.
292
+ private activityTimer: ReturnType<typeof setTimeout> | null = null;
293
+ private activityGen = -1;
294
+ private activityWindowEnd = 0;
295
+ private activitySamples = 0;
296
+ private activityUnchangedStreak = 0;
297
+ private activityMinuteStart = 0;
298
+ private activityMinuteCount = 0;
299
+
300
+ /**
301
+ * When each lane's hold began, or 0 when that lane is not holding.
302
+ *
303
+ * ── WHY THE WAIT IS RECORDED AND NOT JUST WAITED OUT ──────────────────────────────────────
304
+ *
305
+ * Deferring the capture makes the replay show the loaded screen, which is the right picture —
306
+ * but between the tap and that frame the player has nothing, and `frameAt` resolves a playhead
307
+ * to the last frame at or before it. So the gap renders as the PREVIOUS screen, and the replay
308
+ * quietly asserts the visitor was still looking at it while they were in fact watching this one
309
+ * load. That is the same defect as a recording gap rendered as idle time: the reader cannot
310
+ * tell "nothing happened" from "we did not photograph it".
311
+ *
312
+ * The alternative — keep the skeleton frame as well — costs a whole mobile screenshot (~56 KB
313
+ * measured) against ~1 KB for the pair of events below, on a screen load where 37% of this
314
+ * product's loads would qualify. So the wait is recorded as an INTERVAL and the picture is not
315
+ * duplicated: the player draws the span, the operator sees that the screen was loading and for
316
+ * how long, and no frame claims to be something it is not.
317
+ */
318
+ private navHoldStartedAt = 0;
319
+ private interactionHoldStartedAt = 0;
320
+
321
+ /**
322
+ * Session-bound generation counter.
323
+ * Incremented on stop(). All async capture work checks this before AND after
324
+ * native capture to ensure stale callbacks from a previous session lifecycle
325
+ * do not emit frames into a new session.
326
+ */
327
+ private captureGeneration = 0;
328
+
329
+ /**
330
+ * Tracked navigation capture timeout.
331
+ * Cancelled on stop() and on each new onScreenChange() call (debounce).
332
+ */
333
+ private pendingNavTimeout: ReturnType<typeof setTimeout> | null = null;
334
+ /** Screen associated with the pending navigation capture */
335
+ private pendingNavScreen: string | null = null;
336
+
337
+ /**
338
+ * Tracked scroll settle capture timeout.
339
+ * Cancelled on stop().
340
+ */
341
+ private pendingScrollTimeout: ReturnType<typeof setTimeout> | null = null;
342
+
343
+ /**
344
+ * Tracked loading end capture timeout.
345
+ * Cancelled on stop().
346
+ */
347
+ private pendingLoadingTimeout: ReturnType<typeof setTimeout> | null = null;
348
+ /** Screen associated with the pending loading capture */
349
+ private pendingLoadingScreen: string | null = null;
350
+
351
+ /**
352
+ * Pending interaction capture timeout.
353
+ * When a tap/gesture occurs, the capture is DEFERRED by INTERACTION_SETTLE_MS.
354
+ * If onScreenChange fires within that window (tap caused navigation), the
355
+ * pending interaction is cancelled and its tap metadata is carried forward
356
+ * to the navigation capture — ensuring the destination screen is captured
357
+ * instead of a stale pre-navigation screenshot.
358
+ * If no navigation follows, the interaction capture fires normally.
359
+ */
360
+ private pendingInteractionTimeout: ReturnType<typeof setTimeout> | null = null;
361
+ /** Interaction point metadata held while pending (carried to nav if absorbed) */
362
+ private pendingInteractionPoint: ReplayFrame['interactionPoint'] | undefined = undefined;
363
+ /** Screen at the time the pending interaction was created */
364
+ private pendingInteractionScreen: string | undefined = undefined;
365
+
366
+ /**
367
+ * Late absorption tracking.
368
+ * After an interaction capture fires, store its metadata so that
369
+ * a delayed onScreenChange can retroactively evict the stale frame
370
+ * and carry the tap metadata forward to the navigation capture.
371
+ */
372
+ private lastCompletedInteraction: {
373
+ frameId: string;
374
+ screen: string | undefined;
375
+ interactionPoint: ReplayFrame['interactionPoint'] | undefined;
376
+ ts: number;
377
+ } | null = null;
378
+
379
+ /**
380
+ * In-flight interaction tracking.
381
+ * Set when triggerCapture('interaction') starts the async native call and cleared
382
+ * when it completes. If onScreenChange fires for a DIFFERENT screen while a capture
383
+ * is in-flight, the capture is suppressed — the navigation frame is the correct state.
384
+ * Covers the race window between pendingInteractionTimeout firing and native returning,
385
+ * which neither pending-absorption nor late-absorption can reach.
386
+ */
387
+ private _inFlightInteractionScreen: string | undefined = undefined;
388
+ private _inFlightInteractionPoint: ReplayFrame['interactionPoint'] | undefined = undefined;
389
+ private _suppressInFlightInteraction = false;
390
+
391
+ /**
392
+ * Last completed capture intent — used for semantic dedup.
393
+ * Captures with the same reason + screen within SAME_INTENT_COOLDOWN_MS are suppressed.
394
+ */
395
+ private lastCaptureIntent: CaptureIntent | null = null;
396
+
397
+ // ── P2-0/1/5 capture state ──────────────────────────────────────────
398
+ /** P2-0: monotonic per-session sequence; first emitted frame is 1. */
399
+ private _sequenceCounter = 0;
400
+ /** P2-1: hash of the last EMITTED frame, for visual change detection. */
401
+ private _lastFrameHash: string | null = null;
402
+ /** P2-1/5: wall-clock of the last emitted keyframe (heartbeat base). */
403
+ private _lastKeyframeTs = 0;
404
+ /** Scroll containers visible in the last keyframe (native), so a tap's link to it can be checked. */
405
+ private _lastKeyframeScroll: FrameScrollEntry[] | undefined = undefined;
406
+ /** P2-5: frameId of the last emitted keyframe — delta base reference. */
407
+ private _lastKeyframeId: string | null = null;
408
+ /**
409
+ * Screen the last emitted keyframe was captured on.
410
+ *
411
+ * Tracked alongside the id purely so `currentKeyframe()` can refuse to hand a frame to an
412
+ * event on a different screen. The id and timestamp alone cannot answer that, and a frame
413
+ * from the previous screen is worse than none — it attaches a tap to a photograph of
414
+ * somewhere else, which every layer downstream would then present with full confidence.
415
+ */
416
+ private _lastKeyframeScreen: string | null = null;
417
+ /** P2-5: emitted frames since the last keyframe (keyframe-interval guard). */
418
+ private _framesSinceKeyframe = 0;
419
+
420
+ constructor(
421
+ sessionId: string,
422
+ config: SessionReplayConfig,
423
+ nativeCapture: NativeCaptureFn,
424
+ outboxCapture?: OutboxFrameCapture | null,
425
+ ) {
426
+ this.sessionId = sessionId;
427
+ this.config = config;
428
+ this.nativeCapture = nativeCapture;
429
+ this.outboxCapture = outboxCapture ?? null;
430
+ }
431
+
432
+ // ─── Public API ─────────────────────────────────────────────────────
433
+
434
+ /**
435
+ * The keyframe that is still showing, or null.
436
+ *
437
+ * Answers "which picture was the user looking at" for an event that is about to be emitted,
438
+ * so a tap can carry the id of the frame it happened ON. Read-only; captures nothing.
439
+ *
440
+ * TWO CONDITIONS, both refusals rather than approximations:
441
+ *
442
+ * SAME SCREEN. A keyframe from the previous screen is not what the user was looking at.
443
+ * Navigation evicts the pending capture rather than re-pointing it, so after a screen
444
+ * change the newest keyframe genuinely belongs to somewhere else.
445
+ *
446
+ * STILL FRESH. A screen mutates constantly — a list loads, a banner rotates, a sheet is
447
+ * dismissed. Past `maxAgeMs` the stored picture stops being evidence of what is on screen,
448
+ * and stale evidence presented as current is the failure mode this whole feature exists to
449
+ * avoid. 10 s is deliberately conservative: the capture manager already photographs on
450
+ * interaction, navigation and scroll settle, so a genuinely active screen refreshes well
451
+ * inside it, and a screen quiet for longer than that is one nobody is interacting with.
452
+ *
453
+ * Returning null is a correct, common answer and downstream MUST treat it as "not captured"
454
+ * rather than as a default.
455
+ */
456
+ currentKeyframe(
457
+ screenName?: string,
458
+ maxAgeMs = 10_000,
459
+ now: number = Date.now(),
460
+ ): { frameId: string; screen: string | null; capturedAt: number; scrollState?: FrameScrollEntry[] } | null {
461
+ if (!this._lastKeyframeId || this._lastKeyframeTs <= 0) return null;
462
+ if (now - this._lastKeyframeTs > maxAgeMs) return null;
463
+ // Compared only when the caller knows its screen. An event with no screen cannot be shown
464
+ // to belong to this frame, so it does not get one.
465
+ if (!screenName || this._lastKeyframeScreen !== screenName) return null;
466
+ return {
467
+ frameId: this._lastKeyframeId,
468
+ screen: this._lastKeyframeScreen,
469
+ capturedAt: this._lastKeyframeTs,
470
+ ...(this._lastKeyframeScroll ? { scrollState: this._lastKeyframeScroll } : {}),
471
+ };
472
+ }
473
+
474
+ /** Set callback for when a frame is captured */
475
+ setFrameEmitCallback(cb: FrameEmitCallback): void {
476
+ this.onFrameEmit = cb;
477
+ }
478
+
479
+ /** Set the callback that turns a held wait into LOADING_STARTED / LOADING_COMPLETED events. */
480
+ setLoadingIntervalCallback(cb: LoadingIntervalCallback): void {
481
+ this.onLoadingInterval = cb;
482
+ }
483
+
484
+ /**
485
+ * Open a wait on one lane. Idempotent per lane: a hold is re-checked every NETWORK_QUIET_MS
486
+ * while it lasts, and each re-check must not open a new interval.
487
+ */
488
+ private _openHold(lane: 'nav' | 'interaction', screen: string | undefined): void {
489
+ const started = lane === 'nav' ? this.navHoldStartedAt : this.interactionHoldStartedAt;
490
+ if (started) return;
491
+ const now = Date.now();
492
+ if (lane === 'nav') this.navHoldStartedAt = now;
493
+ else this.interactionHoldStartedAt = now;
494
+ try {
495
+ this.onLoadingInterval?.('start', screen, {});
496
+ } catch {
497
+ // Recording the wait must never break the capture it is describing.
498
+ }
499
+ }
500
+
501
+ /**
502
+ * Close a wait, if one is open on that lane.
503
+ *
504
+ * EVERY path that abandons a pending capture calls this, because an interval with no end is
505
+ * a claim the player cannot draw and cannot disprove — it would either render as an
506
+ * open-ended band running to the end of the session, or be dropped, and neither is what
507
+ * happened. `superseded` and `session_end` exist precisely so those paths have something
508
+ * truthful to say rather than staying silent.
509
+ */
510
+ private _closeHold(lane: 'nav' | 'interaction', reason: LoadingEndReason): void {
511
+ const started = lane === 'nav' ? this.navHoldStartedAt : this.interactionHoldStartedAt;
512
+ if (!started) return;
513
+ if (lane === 'nav') this.navHoldStartedAt = 0;
514
+ else this.interactionHoldStartedAt = 0;
515
+ const screen = lane === 'nav' ? this.pendingNavScreen ?? undefined : this.pendingInteractionScreen;
516
+ try {
517
+ this.onLoadingInterval?.('end', screen ?? this.currentScreen ?? undefined, {
518
+ durationMs: Date.now() - started,
519
+ reason,
520
+ });
521
+ } catch {
522
+ // As above — advisory.
523
+ }
524
+ }
525
+
526
+ /** Start capture according to configured mode */
527
+ start(): void {
528
+ if (this.capturing) return;
529
+ this.capturing = true;
530
+
531
+ // P2-0/1/5: reset per-session capture state so sequence + keyframe tracking
532
+ // start clean for this session lifecycle.
533
+ this._sequenceCounter = 0;
534
+ this._lastFrameHash = null;
535
+ this._lastKeyframeTs = 0;
536
+ this._lastKeyframeId = null;
537
+ this._lastKeyframeScreen = null;
538
+ this._lastKeyframeScroll = undefined;
539
+ this._framesSinceKeyframe = 0;
540
+
541
+ this._startFrequencyTimer();
542
+
543
+ __DEV__ && logger.debug(`[ReplayCaptureManager] Started (mode=${this.config.captureMode})`);
544
+ }
545
+
546
+ /**
547
+ * Resume capture WITHIN the same session after a pause (a `frames` quota block that lifted).
548
+ *
549
+ * Differs from `start()` on purpose: the sequence counter is KEPT, so frames after the pause
550
+ * continue the session's ordering instead of restarting at 0 and colliding with frames already
551
+ * stored. The keyframe base is FORGOTTEN, because every frame captured before the pause that was
552
+ * still queued was discarded — a delta against it would be unplayable. The next frame is
553
+ * therefore a keyframe.
554
+ */
555
+ resume(): void {
556
+ if (this.capturing) return;
557
+ this.capturing = true;
558
+ this._lastFrameHash = null;
559
+ this._lastKeyframeTs = 0;
560
+ this._lastKeyframeId = null;
561
+ this._lastKeyframeScreen = null;
562
+ this._lastKeyframeScroll = undefined;
563
+ this._framesSinceKeyframe = 0;
564
+ this._startFrequencyTimer();
565
+ __DEV__ && logger.debug(`[ReplayCaptureManager] Resumed (mode=${this.config.captureMode})`);
566
+ }
567
+
568
+ get isCapturing(): boolean {
569
+ return this.capturing;
570
+ }
571
+
572
+ private _startFrequencyTimer(): void {
573
+ if (this.config.captureMode !== 'frequency') return;
574
+ if (this.frequencyTimer) clearInterval(this.frequencyTimer);
575
+ const intervalMs = Math.max(500, this.config.intervalMs);
576
+ this.frequencyTimer = setInterval(() => {
577
+ this.triggerCapture('frequency').catch(() => { });
578
+ }, intervalMs);
579
+ __DEV__ && logger.debug(`[ReplayCaptureManager] Frequency mode: every ${intervalMs}ms`);
580
+ }
581
+
582
+ /** Stop capture — cancels ALL pending timers and increments generation */
583
+ stop(reason: LoadingEndReason = 'session_end'): void {
584
+ this.capturing = false;
585
+
586
+ // Increment generation — invalidates ALL in-flight async captures
587
+ this.captureGeneration++;
588
+
589
+ // Cancel frequency timer
590
+ if (this.frequencyTimer) {
591
+ clearInterval(this.frequencyTimer);
592
+ this.frequencyTimer = null;
593
+ }
594
+
595
+ // Cancel pending navigation capture
596
+ if (this.pendingNavTimeout) {
597
+ clearTimeout(this.pendingNavTimeout);
598
+ // Closed BEFORE the screen is cleared — the interval is about that screen, and an
599
+ // end reported against `null` would file the wait on whatever came next.
600
+ this._closeHold('nav', reason);
601
+ this.pendingNavTimeout = null;
602
+ this.pendingNavScreen = null;
603
+ }
604
+
605
+ // Cancel pending scroll capture
606
+ if (this.pendingScrollTimeout) {
607
+ clearTimeout(this.pendingScrollTimeout);
608
+ this.pendingScrollTimeout = null;
609
+ }
610
+
611
+ // Cancel pending loading capture
612
+ if (this.pendingLoadingTimeout) {
613
+ clearTimeout(this.pendingLoadingTimeout);
614
+ this.pendingLoadingTimeout = null;
615
+ this.pendingLoadingScreen = null;
616
+ }
617
+
618
+ // Cancel pending interaction capture
619
+ if (this.pendingInteractionTimeout) {
620
+ clearTimeout(this.pendingInteractionTimeout);
621
+ this._closeHold('interaction', reason);
622
+ this.pendingInteractionTimeout = null;
623
+ this.pendingInteractionPoint = undefined;
624
+ this.pendingInteractionScreen = undefined;
625
+ }
626
+
627
+ // Clear late absorption tracking
628
+ this.lastCompletedInteraction = null;
629
+
630
+ // Clear loading-hold deadlines
631
+ this.pendingNavDeadline = 0;
632
+ this.pendingInteractionDeadline = 0;
633
+ this._inFlightRequests = 0;
634
+
635
+ // Clear in-flight interaction tracking
636
+ this._inFlightInteractionScreen = undefined;
637
+ this._inFlightInteractionPoint = undefined;
638
+ this._suppressInFlightInteraction = false;
639
+
640
+ // Clear dedup state
641
+ this.lastCaptureIntent = null;
642
+
643
+ __DEV__ && logger.debug('[ReplayCaptureManager] Stopped (all timers cancelled, generation incremented)');
644
+ }
645
+
646
+ /**
647
+ * Report app network activity. Called by NetworkFeature for requests the app itself made —
648
+ * SDK telemetry uploads and third-party beacons are excluded there, and must stay excluded:
649
+ * this SDK uploads frames, so counting its own traffic would mean a screen never goes quiet.
650
+ *
651
+ * Advisory only. It never causes a capture, it only decides when one that was already going
652
+ * to happen actually fires. A missed or duplicated call therefore costs a slightly early or
653
+ * slightly late frame, never a wrong or an extra one — which is why it is deliberately a
654
+ * counter and not a per-request registry.
655
+ */
656
+ onNetworkActivity(phase: 'start' | 'end'): void {
657
+ const now = Date.now();
658
+ if (phase === 'start') {
659
+ this._inFlightRequests++;
660
+ this._lastRequestStartTs = now;
661
+ return;
662
+ }
663
+ // Floored at zero: an 'end' with no matching 'start' (an interceptor installed mid-flight)
664
+ // must not drive the count negative and wedge every later hold.
665
+ this._inFlightRequests = Math.max(0, this._inFlightRequests - 1);
666
+ this._lastRequestEndTs = now;
667
+ }
668
+
669
+ /**
670
+ * How much longer a capture triggered at `triggeredAt` should wait for the screen's data,
671
+ * or 0 to fire now.
672
+ *
673
+ * The question is not "is the app busy" but "is the app still fetching what this tap asked
674
+ * for". So a request that was already running when the tap happened does not hold anything:
675
+ * a background poll or an in-progress upload would otherwise hold every capture to the cap
676
+ * and make the replay LATE instead of empty, which is not an improvement. Only activity that
677
+ * began at or after the trigger counts.
678
+ *
679
+ * (A poll whose next tick happens to land just after the tap is indistinguishable from a
680
+ * fetch the tap caused, and will hold. That is bounded by the cap and produces a frame of a
681
+ * settled screen either way, so it is accepted rather than guessed at.)
682
+ */
683
+ private _loadingHoldMs(triggeredAt: number, deadline: number): number {
684
+ const now = Date.now();
685
+ if (now >= deadline) return 0;
686
+ if (this._lastRequestStartTs < triggeredAt) return 0;
687
+ // Still fetching — re-check on the quiet interval rather than waiting for the deadline,
688
+ // so the frame lands promptly once the last response arrives.
689
+ //
690
+ // The count is only trusted while it is CORROBORATED by a recent start. A request whose
691
+ // terminal event never arrives (an interceptor installed mid-flight, a socket the
692
+ // platform tears down silently) would otherwise leave the counter permanently above zero
693
+ // and hold every future capture to the cap — turning a fix for empty frames into a
694
+ // guaranteed four-second delay on all of them. Treating a stale count as zero fails
695
+ // towards today's behaviour, which is the safe direction.
696
+ const countIsStale = now - this._lastRequestStartTs > LOADING_DEFER_CAP_MS;
697
+ if (this._inFlightRequests > 0 && !countIsStale) {
698
+ return Math.min(NETWORK_QUIET_MS, deadline - now);
699
+ }
700
+ const quietFor = now - this._lastRequestEndTs;
701
+ if (quietFor >= NETWORK_QUIET_MS) return 0;
702
+ return Math.min(NETWORK_QUIET_MS - quietFor, deadline - now);
703
+ }
704
+
705
+ /** Notify of a screen change — triggers cancellable delayed capture */
706
+ onScreenChange(screenName: string): void {
707
+ this.currentScreen = screenName;
708
+
709
+ if (!this.capturing) return;
710
+ if (this._isExcludedScreen(screenName)) return;
711
+
712
+ if (this.config.captureMode === 'navigation' || this.config.captureMode === 'interactions') {
713
+ // Cancel any previous pending navigation capture (debounce rapid navigations)
714
+ if (this.pendingNavTimeout) {
715
+ clearTimeout(this.pendingNavTimeout);
716
+ this._closeHold('nav', 'superseded');
717
+ this.pendingNavTimeout = null;
718
+ this.pendingNavScreen = null;
719
+ }
720
+
721
+ // Cancel any pending scroll capture — scroll on the old screen is now obsolete
722
+ if (this.pendingScrollTimeout) {
723
+ clearTimeout(this.pendingScrollTimeout);
724
+ this.pendingScrollTimeout = null;
725
+ }
726
+
727
+ // Cancel pending loading capture ONLY if it was for a DIFFERENT screen.
728
+ if (this.pendingLoadingTimeout && this.pendingLoadingScreen !== screenName) {
729
+ clearTimeout(this.pendingLoadingTimeout);
730
+ this.pendingLoadingTimeout = null;
731
+ this.pendingLoadingScreen = null;
732
+ }
733
+
734
+ // ── Absorb pending interaction if tap caused this navigation ──────
735
+ // If a tap was pending and the screen changed (tap → navigation),
736
+ // cancel the stale interaction capture and carry its tap metadata
737
+ // forward into the navigation capture.
738
+ let absorbedInteractionPoint: ReplayFrame['interactionPoint'] | undefined;
739
+ if (this.pendingInteractionTimeout) {
740
+ clearTimeout(this.pendingInteractionTimeout);
741
+ // The tap's own wait ended here, unresolved — the visitor left for another screen
742
+ // before it arrived. That is a real outcome and is recorded as one.
743
+ this._closeHold('interaction', 'superseded');
744
+ absorbedInteractionPoint = this.pendingInteractionPoint;
745
+ this.pendingInteractionTimeout = null;
746
+ this.pendingInteractionPoint = undefined;
747
+ this.pendingInteractionScreen = undefined;
748
+ __DEV__ && logger.debug(
749
+ `[ReplayCaptureManager] Pending interaction absorbed by navigation to ${screenName}`,
750
+ );
751
+ }
752
+
753
+ // ── Late absorption: retroactively evict stale interaction frame ──
754
+ // If an interaction capture ALREADY completed (settle window expired)
755
+ // but navigation arrives within the grace window to a DIFFERENT screen,
756
+ // the interaction frame is stale (captured old screen). Evict it and
757
+ // carry its tap metadata forward to the navigation capture.
758
+ if (
759
+ !absorbedInteractionPoint &&
760
+ this.lastCompletedInteraction &&
761
+ this.lastCompletedInteraction.screen !== screenName &&
762
+ (Date.now() - this.lastCompletedInteraction.ts) < LATE_ABSORPTION_GRACE_MS
763
+ ) {
764
+ const stale = this.lastCompletedInteraction;
765
+ absorbedInteractionPoint = stale.interactionPoint;
766
+ // Evict the stale frame from the frames list
767
+ this.frames = this.frames.filter(f => f.frameId !== stale.frameId);
768
+ __DEV__ && logger.debug(
769
+ `[ReplayCaptureManager] Late absorption: evicted stale interaction frame ` +
770
+ `${stale.frameId} on ${stale.screen}, navigation to ${screenName}`,
771
+ );
772
+ this.lastCompletedInteraction = null;
773
+ }
774
+
775
+ // ── In-flight interaction suppression ─────────────────────────
776
+ // If a native interaction capture started (settle timer already fired)
777
+ // but hasn't returned yet, suppress it — the navigation represents
778
+ // the correct visual state. Carry the tap point forward if available.
779
+ if (
780
+ !absorbedInteractionPoint &&
781
+ this._inFlightInteractionScreen !== undefined &&
782
+ this._inFlightInteractionScreen !== screenName
783
+ ) {
784
+ this._suppressInFlightInteraction = true;
785
+ if (this._inFlightInteractionPoint) {
786
+ absorbedInteractionPoint = this._inFlightInteractionPoint;
787
+ }
788
+ __DEV__ && logger.debug(
789
+ `[ReplayCaptureManager] In-flight interaction suppressed by navigation to ${screenName}`,
790
+ );
791
+ }
792
+
793
+ // Track which screen this nav capture is for
794
+ this.pendingNavScreen = screenName;
795
+
796
+ // Brief delay to allow the new screen to render (but stay snappy), then — if the new
797
+ // screen set off a fetch — hold until it arrives. The capture stays PENDING while it
798
+ // waits, rather than becoming a second stage, so every cancellation above (a further
799
+ // navigation, stop(), a loading marker for this screen) still reaches it.
800
+ const navTriggeredAt = Date.now();
801
+ this.pendingNavDeadline = navTriggeredAt + LOADING_DEFER_CAP_MS;
802
+ const fireNav = (): void => {
803
+ this.pendingNavTimeout = null;
804
+ const hold = this._loadingHoldMs(navTriggeredAt, this.pendingNavDeadline);
805
+ if (hold > 0) {
806
+ this._openHold('nav', screenName);
807
+ this.pendingNavTimeout = setTimeout(fireNav, hold);
808
+ return;
809
+ }
810
+ // Past the deadline with requests still outstanding means the screen had NOT
811
+ // arrived — we stopped waiting, it did not finish. The two must stay distinct.
812
+ this._closeHold(
813
+ 'nav',
814
+ Date.now() >= this.pendingNavDeadline && this._inFlightRequests > 0
815
+ ? 'timeout'
816
+ : 'network_idle',
817
+ );
818
+ this.pendingNavScreen = null;
819
+ this.pendingNavDeadline = 0;
820
+ // Pass absorbed interaction point so the nav frame carries tap metadata
821
+ this.triggerCapture('navigation', screenName, absorbedInteractionPoint).catch(() => { });
822
+ };
823
+ this.pendingNavTimeout = setTimeout(fireNav, 150);
824
+ }
825
+ }
826
+
827
+ /**
828
+ * Notify of a user interaction — deferred capture with navigation absorption.
829
+ *
830
+ * Instead of capturing immediately (which would snapshot the OLD screen
831
+ * when the tap causes navigation), the capture is deferred by
832
+ * INTERACTION_SETTLE_MS. If onScreenChange fires within that window,
833
+ * the pending interaction is absorbed into the navigation capture.
834
+ * If no navigation follows, the interaction capture fires normally.
835
+ */
836
+ onInteraction(interactionPoint?: ReplayFrame['interactionPoint']): void {
837
+ if (!this.capturing) return;
838
+ if (this.currentScreen && this._isExcludedScreen(this.currentScreen)) return;
839
+
840
+ // Throttle: prevent duplicate captures from rapid gestures (500ms)
841
+ const now = Date.now();
842
+ if (now - this.lastInteractionCapture < 500) return;
843
+ this.lastInteractionCapture = now;
844
+
845
+ const screen = this.currentScreen ?? undefined;
846
+
847
+ // Semantic dedup: if a navigation capture is pending for the SAME screen,
848
+ // the navigation frame will represent the post-interaction state.
849
+ if (this.pendingNavTimeout && this.pendingNavScreen === screen) {
850
+ __DEV__ && logger.debug('[ReplayCaptureManager] Interaction suppressed — navigation pending for same screen');
851
+ return;
852
+ }
853
+
854
+ // Cancel any previous pending interaction (rapid tap replacement)
855
+ if (this.pendingInteractionTimeout) {
856
+ clearTimeout(this.pendingInteractionTimeout);
857
+ this._closeHold('interaction', 'superseded');
858
+ }
859
+
860
+ // Defer the interaction capture to allow navigation to absorb it
861
+ this.pendingInteractionScreen = screen;
862
+ this.pendingInteractionPoint = interactionPoint;
863
+ this.pendingInteractionDeadline = now + LOADING_DEFER_CAP_MS;
864
+ const fireInteraction = (): void => {
865
+ this.pendingInteractionTimeout = null;
866
+ // The tap opened a sheet, a tab, a filter — anything that fetches. Keep waiting, and
867
+ // keep the capture PENDING while we do: a navigation arriving now must still be able
868
+ // to absorb it, which it cannot do once triggerCapture has been called.
869
+ const hold = this._loadingHoldMs(now, this.pendingInteractionDeadline);
870
+ if (hold > 0) {
871
+ this._openHold('interaction', this.pendingInteractionScreen);
872
+ this.pendingInteractionTimeout = setTimeout(fireInteraction, hold);
873
+ return;
874
+ }
875
+ this._closeHold(
876
+ 'interaction',
877
+ Date.now() >= this.pendingInteractionDeadline && this._inFlightRequests > 0
878
+ ? 'timeout'
879
+ : 'network_idle',
880
+ );
881
+ const captureScreen = this.pendingInteractionScreen;
882
+ const capturePoint = this.pendingInteractionPoint;
883
+ this.pendingInteractionScreen = undefined;
884
+ this.pendingInteractionPoint = undefined;
885
+ this.pendingInteractionDeadline = 0;
886
+ // No navigation followed → capture the interaction on the current screen
887
+ this.triggerCapture('interaction', captureScreen, capturePoint).catch(() => { });
888
+ };
889
+ this.pendingInteractionTimeout = setTimeout(fireInteraction, INTERACTION_SETTLE_MS);
890
+ }
891
+
892
+ /** Notify of scroll settle — triggers delayed capture for post-scroll state */
893
+ onScrollSettle(screenName?: string): void {
894
+ if (!this.capturing) return;
895
+
896
+ // Cancel any previous pending scroll capture
897
+ if (this.pendingScrollTimeout) {
898
+ clearTimeout(this.pendingScrollTimeout);
899
+ this.pendingScrollTimeout = null;
900
+ }
901
+
902
+ // Small delay to let post-scroll rendering settle
903
+ this.pendingScrollTimeout = setTimeout(() => {
904
+ this.pendingScrollTimeout = null;
905
+ this.triggerCapture('scroll', screenName ?? this.currentScreen ?? undefined).catch(() => { });
906
+ }, 150);
907
+ }
908
+
909
+ /** Notify of loading end — captures the settled loaded screen */
910
+ onLoadingEnd(screenName?: string): void {
911
+ if (!this.capturing) return;
912
+
913
+ const screen = screenName ?? this.currentScreen ?? undefined;
914
+
915
+ // Cancel any previous pending loading capture for ANY screen
916
+ if (this.pendingLoadingTimeout) {
917
+ clearTimeout(this.pendingLoadingTimeout);
918
+ this.pendingLoadingTimeout = null;
919
+ this.pendingLoadingScreen = null;
920
+ }
921
+
922
+ // If a navigation capture is pending for the SAME screen, cancel it.
923
+ // The loading-end capture represents the final settled state and supersedes
924
+ // the initial navigation capture (which would show loading/skeleton UI).
925
+ if (this.pendingNavTimeout && this.pendingNavScreen === screen) {
926
+ clearTimeout(this.pendingNavTimeout);
927
+ this._closeHold('nav', 'superseded');
928
+ this.pendingNavTimeout = null;
929
+ this.pendingNavScreen = null;
930
+ __DEV__ && logger.debug('[ReplayCaptureManager] Navigation capture cancelled — loading-end supersedes for same screen');
931
+ }
932
+
933
+ // Track which screen this loading capture is for
934
+ this.pendingLoadingScreen = screen ?? null;
935
+
936
+ // Slight delay to allow the loaded content to render
937
+ this.pendingLoadingTimeout = setTimeout(() => {
938
+ this.pendingLoadingTimeout = null;
939
+ this.pendingLoadingScreen = null;
940
+ this.triggerCapture('screen_loaded', screen).catch(() => { });
941
+ }, 200);
942
+ }
943
+
944
+ /** Manual capture trigger (e.g. error-context) */
945
+ async captureManual(reason: CaptureReason): Promise<ReplayFrame | null> {
946
+ return this.triggerCapture(reason, this.currentScreen ?? undefined);
947
+ }
948
+
949
+ /** Protect frames near a crash from eviction */
950
+ protectFramesNearCrash(crashTimestamp: number, windowMs: number = 10_000): string[] {
951
+ const protectedIds: string[] = [];
952
+ for (const frame of this.frames) {
953
+ if (Math.abs(frame.ts - crashTimestamp) <= windowMs) {
954
+ this.protectedFrameIds.add(frame.frameId);
955
+ protectedIds.push(frame.frameId);
956
+ }
957
+ }
958
+ return protectedIds;
959
+ }
960
+
961
+ /** Get all frames (read-only snapshot) */
962
+ getFrames(): readonly ReplayFrame[] {
963
+ return this.frames;
964
+ }
965
+
966
+ /** Get frame IDs for artifact index */
967
+ getFrameRefs(): string[] {
968
+ return this.frames.map(f => f.frameId);
969
+ }
970
+
971
+ /** Current frame count */
972
+ get count(): number {
973
+ return this.frames.length;
974
+ }
975
+
976
+ /** Clear all frames */
977
+ clear(): void {
978
+ this.frames = [];
979
+ this.protectedFrameIds.clear();
980
+ }
981
+
982
+ // ─── Core Capture ───────────────────────────────────────────────────
983
+
984
+ /**
985
+ * Trigger a frame capture via native engine.
986
+ * This method ONLY orchestrates — native does the real work.
987
+ *
988
+ * Semantic dedup: if the last completed capture has the same reason + screen
989
+ * and happened within SAME_INTENT_COOLDOWN_MS, the capture is suppressed.
990
+ * Bypass reasons (manual, error-context, frequency) skip this check entirely.
991
+ *
992
+ * Session-bound generation guard: captures the generation counter before
993
+ * starting the async native capture and verifies it hasn't changed after.
994
+ * If it has, the capture result is silently discarded — the session that
995
+ * requested it no longer exists.
996
+ */
997
+ private async triggerCapture(
998
+ reason: CaptureReason,
999
+ screenName?: string,
1000
+ interactionPoint?: ReplayFrame['interactionPoint'],
1001
+ ): Promise<ReplayFrame | null> {
1002
+ if (!this.capturing) return null;
1003
+
1004
+ // ── Semantic dedup check ────────────────────────────────────────
1005
+ if (!BYPASS_DEDUP_REASONS.has(reason) && this.lastCaptureIntent) {
1006
+ const last = this.lastCaptureIntent;
1007
+ const sameScreen = last.screen === screenName;
1008
+ const sameReason = last.reason === reason;
1009
+ const withinCooldown = (Date.now() - last.ts) < SAME_INTENT_COOLDOWN_MS;
1010
+
1011
+ // Same reason + same screen within cooldown → semantic duplicate
1012
+ if (sameReason && sameScreen && withinCooldown) {
1013
+ __DEV__ && logger.debug(
1014
+ `[ReplayCaptureManager] Semantic dedup: ${reason}@${screenName} suppressed ` +
1015
+ `(same intent within ${SAME_INTENT_COOLDOWN_MS}ms)`,
1016
+ );
1017
+ return null;
1018
+ }
1019
+ }
1020
+
1021
+ // Capture generation at call time
1022
+ const gen = this.captureGeneration;
1023
+
1024
+ // ── In-flight interaction tracking ─────────────────────────────
1025
+ // Mark this capture as in-flight so onScreenChange can suppress it
1026
+ // if navigation arrives before the native callback returns.
1027
+ if (reason === 'interaction') {
1028
+ this._inFlightInteractionScreen = screenName;
1029
+ this._inFlightInteractionPoint = interactionPoint;
1030
+ this._suppressInFlightInteraction = false;
1031
+ }
1032
+
1033
+ try {
1034
+ // ── Capture path selection ──────────────────────────────────────
1035
+ // Prefer the native file-outbox staged path when ready: it captures +
1036
+ // masks + encodes natively and STAGES the image (bytes never cross the
1037
+ // bridge). If the outbox is off / unavailable / the staged capture fails,
1038
+ // fall back to the legacy native capture (base64 → JS upload). All
1039
+ // orchestration below (dedup, change-detection, keyframe/delta, sequencing)
1040
+ // is identical for both paths.
1041
+ const screen = screenName ?? this.currentScreen ?? undefined;
1042
+ let staged: StagedFrameResult | null = null;
1043
+ if (this.outboxCapture) {
1044
+ staged = await this.outboxCapture.capture(this.sessionId, screen, reason);
1045
+ }
1046
+ const usedStaged = staged !== null;
1047
+
1048
+ let result: NativeFrameResult | null;
1049
+ if (staged) {
1050
+ result = {
1051
+ base64: '', // bytes stay native on the outbox path — never bridged
1052
+ width: staged.width,
1053
+ height: staged.height,
1054
+ byteSize: staged.byteSize,
1055
+ format: staged.format,
1056
+ frameHash: staged.frameHash,
1057
+ platform: staged.platform,
1058
+ ...(staged.scrollState ? { scrollState: staged.scrollState } : {}),
1059
+ };
1060
+ } else {
1061
+ result = await this.nativeCapture(this.sessionId, reason, this.config.quality);
1062
+ }
1063
+
1064
+ // Drop a staged frame if any guard below rejects it (keeps the outbox clean).
1065
+ const discardStaged = (): void => {
1066
+ if (usedStaged && staged) {
1067
+ this.outboxCapture?.discard(this.sessionId, staged.frameId).catch(() => { });
1068
+ }
1069
+ };
1070
+
1071
+ // ── In-flight suppression check ─────────────────────────────
1072
+ // Clear in-flight tracking first (before any early returns).
1073
+ if (reason === 'interaction') {
1074
+ this._inFlightInteractionScreen = undefined;
1075
+ this._inFlightInteractionPoint = undefined;
1076
+ if (this._suppressInFlightInteraction) {
1077
+ this._suppressInFlightInteraction = false;
1078
+ discardStaged();
1079
+ __DEV__ && logger.debug('[ReplayCaptureManager] In-flight interaction suppressed — navigation arrived during capture');
1080
+ return null;
1081
+ }
1082
+ }
1083
+
1084
+ // Generation guard: if session was stopped/restarted during async capture,
1085
+ // discard the result to prevent stale frames
1086
+ if (gen !== this.captureGeneration) {
1087
+ discardStaged();
1088
+ __DEV__ && logger.debug('[ReplayCaptureManager] Stale capture discarded (generation mismatch)');
1089
+ return null;
1090
+ }
1091
+
1092
+ if (!this.capturing) {
1093
+ discardStaged();
1094
+ return null;
1095
+ }
1096
+
1097
+ if (!result) {
1098
+ // Native capture unavailable — log warning, return null
1099
+ // NO JS fallback — this is by design
1100
+ __DEV__ && logger.debug('[ReplayCaptureManager] Native capture returned null — frame not captured');
1101
+ return null;
1102
+ }
1103
+
1104
+ // ── P2-1: change-triggered capture + heartbeat keyframe ─────────
1105
+ // Visual suppression applies ONLY to the periodic 'frequency' lane — the
1106
+ // sole source of redundant, visually-identical consecutive frames during
1107
+ // static viewing (the −40–60% lever). Semantic captures (navigation /
1108
+ // interaction / scroll / screen_loaded) are already change-driven and are
1109
+ // handled by the semantic dedup above, so they always emit — visual-hashing
1110
+ // them risks dropping a meaningful frame whose pixels happen to match.
1111
+ // manual / error-context are explicit intent and likewise always emit.
1112
+ // The heartbeat (maxKeyframeIntervalMs) forces a keyframe even when nothing
1113
+ // changed, so static periods still have a frame AND deltas keep a fresh base.
1114
+ // Suppressed frames do NOT consume a sequence number.
1115
+ const now = Date.now();
1116
+ const hash = result.frameHash ?? hashBase64(result.base64);
1117
+ const explicit = reason === 'manual' || reason === 'error-context';
1118
+ const maxKf = this.config.maxKeyframeIntervalMs ?? 5000;
1119
+ const heartbeatDue = (now - this._lastKeyframeTs) >= maxKf;
1120
+ const changed = hash !== this._lastFrameHash;
1121
+ const changeDetection = this.config.changeDetection !== false;
1122
+ if (changeDetection && reason === 'frequency' && !changed && !heartbeatDue) {
1123
+ discardStaged();
1124
+ __DEV__ && logger.debug('[ReplayCaptureManager] Change-trigger suppressed identical frequency frame');
1125
+ return null;
1126
+ }
1127
+
1128
+ // ── P2-5: keyframe vs delta decision ────────────────────────────
1129
+ // Force a keyframe when: delta encoding is off, no base exists yet, the
1130
+ // heartbeat is due, the keyframe-interval elapsed, or this is an explicit
1131
+ // capture (full frame is safest). Otherwise emit a delta against the last
1132
+ // keyframe. NOTE: real delta-byte encoding is native (pixel ops); JS owns
1133
+ // the decision/tagging — see P2_CONTRACT.md §3/§6.
1134
+ const deltaOn = this.config.deltaEncoding === true;
1135
+ const kfInterval = this.config.deltaKeyframeInterval ?? 10;
1136
+ const mustKeyframe =
1137
+ !deltaOn ||
1138
+ this._lastKeyframeId === null ||
1139
+ heartbeatDue ||
1140
+ explicit ||
1141
+ this._framesSinceKeyframe >= kfInterval;
1142
+ const frameType: 'keyframe' | 'delta' = mustKeyframe ? 'keyframe' : 'delta';
1143
+ const baseFrameId = frameType === 'delta' ? this._lastKeyframeId ?? undefined : undefined;
1144
+
1145
+ // Build frame with artifact reference and screen context.
1146
+ // On the native-outbox staged path the image is ALREADY written to disk
1147
+ // under the native-assigned frameId; reuse it so commitOutboxFrame's
1148
+ // lookup resolves (minting a fresh id here makes the staged image
1149
+ // "missing" at commit → the frame is silently dropped → zero frames).
1150
+ // Legacy (base64) path has no staged file, so mint a new id.
1151
+ const frameId = staged?.frameId ?? generateFrameId();
1152
+
1153
+ // Fill interactionPoint screen dimensions from the capture result.
1154
+ // interactionPoint may come from an absorbed pending interaction
1155
+ // (tap → navigation), so attach it regardless of capture reason.
1156
+ const resolvedInteraction = interactionPoint
1157
+ ? { ...interactionPoint, screenWidth: result.width, screenHeight: result.height }
1158
+ : undefined;
1159
+
1160
+ const frame: ReplayFrame = {
1161
+ frameId,
1162
+ sessionId: this.sessionId,
1163
+ ts: now,
1164
+ sequenceNumber: ++this._sequenceCounter,
1165
+ frameType,
1166
+ ...(baseFrameId ? { baseFrameId } : {}),
1167
+ imageRef: frameId, // Artifact ref — transport resolves to actual content
1168
+ width: result.width,
1169
+ height: result.height,
1170
+ byteSize: result.byteSize ?? 0,
1171
+ format: result.format ?? 'jpeg',
1172
+ quality: this.config.quality,
1173
+ captureReason: reason,
1174
+ sourcePlatform: result.platform,
1175
+ screen: screenName ?? this.currentScreen ?? undefined,
1176
+ // Scroll offsets read natively beside these pixels — undefined when not measured.
1177
+ ...(result.scrollState ? { scrollState: result.scrollState } : {}),
1178
+ // Attach interaction point if this was an interaction-driven capture
1179
+ ...(resolvedInteraction ? { interactionPoint: resolvedInteraction } : {}),
1180
+ };
1181
+
1182
+ // ── Record capture intent for dedup ─────────────────────────
1183
+ this.lastCaptureIntent = {
1184
+ reason,
1185
+ screen: screenName,
1186
+ ts: Date.now(),
1187
+ };
1188
+
1189
+ // Enforce frame limit with priority-based eviction
1190
+ if (this.frames.length >= this.config.maxFrames) {
1191
+ this._evictLowestPriorityFrame();
1192
+ }
1193
+
1194
+ this.frames.push(frame);
1195
+
1196
+ // ── P2-1/5: commit change-detection + keyframe tracking ─────────
1197
+ this._lastFrameHash = hash;
1198
+ if (frameType === 'keyframe') {
1199
+ this._lastKeyframeId = frameId;
1200
+ this._lastKeyframeTs = now;
1201
+ this._lastKeyframeScreen = screenName ?? null;
1202
+ this._lastKeyframeScroll = frame.scrollState;
1203
+ this._framesSinceKeyframe = 0;
1204
+ } else {
1205
+ this._framesSinceKeyframe++;
1206
+ }
1207
+
1208
+ // ── Deliver the frame ───────────────────────────────────────────
1209
+ // Staged (native outbox) path: commit JS-authoritative metadata so the
1210
+ // native uploader owns delivery. Do NOT also emit base64 to the JS
1211
+ // transport — that would double-upload the frame. If commit fails the
1212
+ // image is left staged (no meta) and swept as an orphan on next recover().
1213
+ // Legacy path: emit base64 to the JS transport as before.
1214
+ if (usedStaged && staged) {
1215
+ const meta: OutboxFrameMeta = {
1216
+ frameId: frame.frameId,
1217
+ sessionId: this.sessionId,
1218
+ timestamp: frame.ts,
1219
+ sequenceNumber: frame.sequenceNumber,
1220
+ frameType,
1221
+ ...(baseFrameId ? { baseFrameId } : {}),
1222
+ screenName: frame.screen ?? 'unknown',
1223
+ trigger: reason,
1224
+ format: staged.format,
1225
+ contentType: staged.contentType,
1226
+ width: staged.width,
1227
+ height: staged.height,
1228
+ sizeBytes: staged.byteSize,
1229
+ masked: staged.masked,
1230
+ ...(staged.scrollState ? { scrollState: staged.scrollState } : {}),
1231
+ };
1232
+ try {
1233
+ const committed = await this.outboxCapture?.commit(meta);
1234
+ if (!committed) {
1235
+ __DEV__ && logger.debug('[ReplayCaptureManager] Outbox commit failed — frame staged but not uploadable');
1236
+ }
1237
+ } catch {
1238
+ // Commit failure must not crash capture; orphan is swept later.
1239
+ }
1240
+ } else {
1241
+ // Emit to transport — pass base64 as transport-layer data (not domain)
1242
+ try {
1243
+ this.onFrameEmit?.(frame, result.base64);
1244
+ } catch {
1245
+ // Transport emission must not crash capture
1246
+ }
1247
+ }
1248
+
1249
+ // ── Track completed interaction for late absorption ──────────
1250
+ // If this was an interaction capture, record its metadata so that
1251
+ // a delayed onScreenChange can retroactively evict it if navigation
1252
+ // follows within LATE_ABSORPTION_GRACE_MS.
1253
+ if (reason === 'interaction') {
1254
+ this.lastCompletedInteraction = {
1255
+ frameId: frame.frameId,
1256
+ screen: frame.screen,
1257
+ interactionPoint: frame.interactionPoint,
1258
+ ts: Date.now(),
1259
+ };
1260
+ } else {
1261
+ // Non-interaction captures clear the tracker — no late absorption needed
1262
+ this.lastCompletedInteraction = null;
1263
+ }
1264
+
1265
+ if (ACTIVITY_OPENERS.has(reason)) this._openActivityWindow(gen);
1266
+
1267
+ return frame;
1268
+ } catch (err) {
1269
+ // Clear in-flight tracking on error too
1270
+ if (reason === 'interaction') {
1271
+ this._inFlightInteractionScreen = undefined;
1272
+ this._inFlightInteractionPoint = undefined;
1273
+ this._suppressInFlightInteraction = false;
1274
+ }
1275
+ logger.error('[ReplayCaptureManager] Capture failed:', err);
1276
+ return null;
1277
+ }
1278
+ }
1279
+
1280
+ // ─── Activity Sampling ──────────────────────────────────────────────
1281
+
1282
+ /**
1283
+ * (Re)open the sampling window after a semantic frame. Only in `interactions` mode: `frequency`
1284
+ * already samples on its own timer, and `navigation` mode is the deliberately minimal one. Needs
1285
+ * change detection — without it every sample would upload, which is the old cost.
1286
+ */
1287
+ private _openActivityWindow(gen: number): void {
1288
+ if (this.config.captureMode !== 'interactions') return;
1289
+ if (this.config.activitySampling === false || this.config.changeDetection === false) return;
1290
+ if (!this.capturing || gen !== this.captureGeneration) return;
1291
+ this.activityGen = gen;
1292
+ this.activityWindowEnd = Date.now() + ACTIVITY_WINDOW_MS;
1293
+ this.activitySamples = 0;
1294
+ this.activityUnchangedStreak = 0;
1295
+ if (this.activityTimer) clearTimeout(this.activityTimer);
1296
+ this.activityTimer = setTimeout(() => { void this._activityTick(); }, ACTIVITY_SAMPLE_INTERVAL_MS);
1297
+ }
1298
+
1299
+ private async _activityTick(): Promise<void> {
1300
+ this.activityTimer = null;
1301
+ const gen = this.activityGen;
1302
+ if (!this.capturing || gen !== this.captureGeneration) return;
1303
+ const now = Date.now();
1304
+ if (now >= this.activityWindowEnd) return;
1305
+ if (this.currentScreen && this._isExcludedScreen(this.currentScreen)) return;
1306
+
1307
+ // A semantic capture is about to produce the real frame — let it; it reopens the window.
1308
+ const semanticPending =
1309
+ this.pendingInteractionTimeout !== null ||
1310
+ this.pendingNavTimeout !== null ||
1311
+ this.pendingScrollTimeout !== null ||
1312
+ this.pendingLoadingTimeout !== null;
1313
+
1314
+ if (!semanticPending) {
1315
+ if (now - this.activityMinuteStart >= 60_000) {
1316
+ this.activityMinuteStart = now;
1317
+ this.activityMinuteCount = 0;
1318
+ }
1319
+ if (this.activityMinuteCount >= ACTIVITY_MAX_PER_MINUTE) return;
1320
+
1321
+ // null = unchanged (discarded natively, never uploaded) or failed — either way the
1322
+ // screen gave us nothing new, which is what "settled" means here.
1323
+ const frame = await this.triggerCapture('frequency', this.currentScreen ?? undefined);
1324
+ if (gen !== this.captureGeneration || gen !== this.activityGen) return;
1325
+ if (frame) {
1326
+ this.activitySamples++;
1327
+ this.activityMinuteCount++;
1328
+ this.activityUnchangedStreak = 0;
1329
+ } else {
1330
+ this.activityUnchangedStreak++;
1331
+ }
1332
+ if (this.activitySamples >= ACTIVITY_MAX_SAMPLES) return;
1333
+ if (this.activityUnchangedStreak >= ACTIVITY_SETTLED_STREAK) return;
1334
+ }
1335
+
1336
+ if (Date.now() + ACTIVITY_SAMPLE_INTERVAL_MS > this.activityWindowEnd) return;
1337
+ this.activityTimer = setTimeout(() => { void this._activityTick(); }, ACTIVITY_SAMPLE_INTERVAL_MS);
1338
+ }
1339
+
1340
+ // ─── Frame Retention ────────────────────────────────────────────────
1341
+
1342
+ /**
1343
+ * Evict the frame with the lowest retention priority.
1344
+ * Crash-adjacent and error-context frames are NEVER evicted before generic frames.
1345
+ */
1346
+ private _evictLowestPriorityFrame(): void {
1347
+ let lowestIdx = -1;
1348
+ let lowestPriority = Infinity;
1349
+ let oldestTs = Infinity;
1350
+
1351
+ for (let i = 0; i < this.frames.length; i++) {
1352
+ const frame = this.frames[i];
1353
+ // Never evict protected (crash-adjacent) frames
1354
+ if (this.protectedFrameIds.has(frame.frameId)) continue;
1355
+
1356
+ const priority = getFrameRetentionPriority(frame.captureReason);
1357
+ if (priority < lowestPriority || (priority === lowestPriority && frame.ts < oldestTs)) {
1358
+ lowestPriority = priority;
1359
+ lowestIdx = i;
1360
+ oldestTs = frame.ts;
1361
+ }
1362
+ }
1363
+
1364
+ if (lowestIdx >= 0) {
1365
+ this.frames.splice(lowestIdx, 1);
1366
+ } else {
1367
+ // All protected — drop oldest anyway
1368
+ this.frames.shift();
1369
+ }
1370
+ }
1371
+
1372
+ // ─── Helpers ────────────────────────────────────────────────────────
1373
+
1374
+ private _isExcludedScreen(screenName: string): boolean {
1375
+ return this.config.privacyPolicy.captureExclusions.includes(screenName);
1376
+ }
1377
+ }
1378
+
1379
+ // ─── Utils ──────────────────────────────────────────────────────────────────
1380
+
1381
+ function generateFrameId(): string {
1382
+ return `frm-${Date.now().toString(36)}-${Math.random().toString(36).substring(2, 8)}`;
1383
+ }
1384
+
1385
+ /**
1386
+ * P2-1 change detection: cheap, allocation-light FNV-1a over the base64 string.
1387
+ * Exact-hash only — a perceptual/near-identical match is a native concern (the
1388
+ * native layer may supply `frameHash`; this is the JS fallback). Sampling every
1389
+ * Nth char keeps it O(1)-ish on large frames while still being change-sensitive.
1390
+ */
1391
+ function hashBase64(b64: string): string {
1392
+ let h = 0x811c9dc5;
1393
+ const len = b64.length;
1394
+ const step = len > 4096 ? Math.ceil(len / 4096) : 1;
1395
+ for (let i = 0; i < len; i += step) {
1396
+ h ^= b64.charCodeAt(i);
1397
+ h = Math.imul(h, 0x01000193);
1398
+ }
1399
+ // Fold in length so same-prefix different-length frames don't collide.
1400
+ return `${(h >>> 0).toString(36)}-${len.toString(36)}`;
1401
+ }