@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,2129 @@
1
+ /**
2
+ * ScaleBun SDK — Public Facade
3
+ *
4
+ * Single clean entry point for the ScaleBun SDK.
5
+ * Delegates initialization to SDKBootstrapper, which handles config validation,
6
+ * core service setup, handshake, and feature registration via FeatureRegistry.
7
+ *
8
+ * Config model preserved exactly: projectId, publishableKey, apiBaseUrl.
9
+ * Features are default-on with explicit opt-out via `features: { replay: false }`.
10
+ */
11
+
12
+ import { noThrow, safeAsync } from '../core/lifecycle/crashSafe';
13
+ import { logger } from '../core/logger/internalLogger';
14
+ import { createEnvelope } from '../pipeline/envelope/envelope';
15
+ import { generateEventId } from '../features/replay/core/ids/sessionId';
16
+ import { buildBugReportPayload } from '../features/bugreport/buildPayload';
17
+ import type { BugSubmitResult } from '../features/bugreport/BugReportFeature';
18
+ import { BugReportFeature } from '../features/bugreport/BugReportFeature';
19
+ import { PersistentQueue } from '../pipeline/queue/persistentQueue';
20
+ import { MemoryBackend, createStorageBackend } from '../storage/StorageBackend';
21
+ import { HttpClient } from '../transport/http/httpClient';
22
+ import { getDeviceId } from '../core/id/deviceId';
23
+ import { mergeDeviceContext, nativeDeviceContext, resolveEventPlatform } from '../core/context/device';
24
+ import { coreContainer } from '../core/di/container';
25
+ import { flushQueue } from '../pipeline/queue/flushQueue';
26
+ import {
27
+ enableDebug as _enableDebug,
28
+ disableDebug as _disableDebug,
29
+ isDebugEnabled,
30
+ addBreadcrumb as _addBreadcrumb,
31
+ ping as _ping,
32
+ _getStream,
33
+ _setFlushFn,
34
+ _getSessionManager,
35
+ _getAutoScreenDetector,
36
+ getPerformanceFeature as _getPerformanceFeature,
37
+ requestExport as _requestExport,
38
+ buildDebugConfigFromInitConfig,
39
+ applyFeatureGatesToDebugConfig,
40
+ sendDebugMetric,
41
+ } from '../debug';
42
+ import type { DebugConfig } from '../debug';
43
+ import { ReplaySdk } from '../features/replay/public/api';
44
+ import type {
45
+ ReplayUser,
46
+ ReplayBreadcrumb,
47
+ ReplayPrivacyOptions,
48
+ } from '../features/replay/public/types';
49
+ import { SDKBootstrapper } from '../bootstrap/SDKBootstrapper';
50
+ import { EventTracker } from '../analytics/EventTracker';
51
+ import type { SubscriptionInput } from '../analytics/subscription';
52
+ import type { RevenueInput } from '../analytics/revenue';
53
+ import { bridgeAdapter } from '../features/replay/bridge/adapters/bridgeAdapter';
54
+ import {
55
+ emitAutomaticEvent,
56
+ type AutomaticEventName,
57
+ } from '../analytics/automaticEvents';
58
+ import { resolveEventLane, isUploadedSessionEvent } from '../analytics/eventLane';
59
+ import { ConfigManager } from '../config/ConfigManager';
60
+ import { quotaState } from '../config/quotaState';
61
+ import { resolveInstallationId } from '../core/id/installationId';
62
+ import { SDK_VERSION } from '../core/constants/version';
63
+ import { EngageTransport, type SubmitStage } from '../features/engage/EngageTransport';
64
+ import {
65
+ getNativePushToken,
66
+ subscribeNativePushTokenRefresh,
67
+ } from '../features/engage/engagePushTokenBridge';
68
+ import { requestNativeStoreReview } from '../features/engage/engageStoreReviewBridge';
69
+ import { PushManager } from '../push/PushManager';
70
+ import type { EnablePushOptions, EnablePushResult, PushNotification } from '../push/types';
71
+ import { ENGAGE_SCHEMA_VERSION } from '../features/engage/engageTypes';
72
+ import { EngageThrottleStore } from '../features/engage/engageThrottle';
73
+ import { EngageTestSeenStore } from '../features/engage/engageTestSeenStore';
74
+ import { engageSignals } from '../features/engage/engageSignals';
75
+ import type {
76
+ EngageAttachmentDraft,
77
+ EngageConfigContext,
78
+ EngageConfigResponse,
79
+ EngageEventInput,
80
+ EngageResponseInput,
81
+ RatingFunnelEventInput,
82
+ SurveyImpressionInput,
83
+ } from '../features/engage/engageTypes';
84
+ import { PerformanceFeature } from '../features/performance/PerformanceFeature';
85
+ import { SessionManager } from '../features/session/SessionManager';
86
+ import type { JourneyEventType } from '../features/session/sessionTypes';
87
+ import { getCrashReporter } from '../features/crash/CrashReporter';
88
+ import { triggerNativeCrash } from '../features/crash/nativeCrashBridge';
89
+ import { updateSkanConversionValue, isSkanAvailable, type SkanCoarseValue } from '../features/skan/skanBridge';
90
+ import { SkanConversionManager } from '../features/skan/skanConversionManager';
91
+ import {
92
+ isInstallReferrerAvailable,
93
+ getInstallReferrer,
94
+ captureInstallReferrerOnce,
95
+ type InstallReferrerSink,
96
+ } from '../features/install-referrer/installReferrer';
97
+ import type {
98
+ ScaleBunInitConfig,
99
+ ScaleBunUser,
100
+ ScaleBunFeatures,
101
+ SimplifiedInitConfig,
102
+ DebugConnectionConfig,
103
+ PrivacyConfig,
104
+ BrandingConfig,
105
+ ExportPresetName,
106
+ SimplifiedExportOptions,
107
+ ExportResult,
108
+ } from './types';
109
+
110
+ class ScaleBunFacade {
111
+ private initialized = false;
112
+ /** In-flight init promise — guards against a second init() racing before the first resolves. */
113
+ private _initInFlight: Promise<void> | null = null;
114
+ private bootstrapper = new SDKBootstrapper();
115
+ private _features: ScaleBunFeatures = {};
116
+ private _performanceFeature: PerformanceFeature | null = null;
117
+ private _privacyConfig: PrivacyConfig = {};
118
+ private _brandingConfig: BrandingConfig = {};
119
+ private _clientKey: string | undefined = undefined;
120
+ private _apiBaseUrl: string | undefined = undefined;
121
+ private _engageTransport: EngageTransport | null = null;
122
+ private _engageTokenUnsubscribe: (() => void) | null = null;
123
+ private _pushManager: PushManager | null = null;
124
+ /** Phase 1 envelope event-tracking lane (POST /v1/batch). Null until init with appId. */
125
+ private _eventTracker: EventTracker | null = null;
126
+ /** External identity last supplied through identify(); used by config targeting. */
127
+ private _identifiedUserId: string | null = null;
128
+ /** Identity supplied while async initialization is still in flight. */
129
+ private _pendingIdentity: {
130
+ userId: string;
131
+ traits?: Record<string, any>;
132
+ } | null = null;
133
+ private _configManager: ConfigManager | null = null;
134
+ /**
135
+ * The ConfigManager that owns /config refreshes for quota: `_configManager` when the event
136
+ * tracker created one, else a quota-only instance (no appId → no tracker, but a clientKey still
137
+ * has a plan with limits). Never exposed through the flags/experiments API.
138
+ */
139
+ private _configRefresher: ConfigManager | null = null;
140
+ private _configForegroundListener: ((state: string) => void) | null = null;
141
+ /** The developer's locally-configured replay captureMode — the value to revert to when an
142
+ * admin-forced frequency override (from /config) is withdrawn. Default matches the SDK default. */
143
+ private _devCaptureMode: string = 'interactions';
144
+ /** True while an admin frequency override from /config is applied, so we know to revert. */
145
+ private _replayOverrideActive = false;
146
+ /** Signature of the last identity POSTed to the ingestion identify endpoint, to skip redundant re-sends. */
147
+ private _lastIngestionIdentityKey: string | null = null;
148
+ /** Phase 3: auto-applies SKAN conversion values from the server schema (iOS only). */
149
+ private _skanManager: SkanConversionManager | null = null;
150
+
151
+ /**
152
+ * Pre-init memory buffer.
153
+ * Events tracked before init() completes are buffered here,
154
+ * then drained into the real persistent queue post-init.
155
+ */
156
+ private _preInitBuffer: PersistentQueue = new PersistentQueue(new MemoryBackend(), {
157
+ enabled: false,
158
+ maxEntries: 500,
159
+ maxBytes: 1_048_576, // 1 MB
160
+ redactBeforeWrite: false, // No redaction for memory-only buffer
161
+ });
162
+
163
+ /** Resolve the active queue (DI container or pre-init buffer) */
164
+ private _getQueue(): PersistentQueue {
165
+ if (this.initialized) {
166
+ try {
167
+ return coreContainer.get<PersistentQueue>('PersistentQueue');
168
+ } catch {
169
+ // Container not ready yet — shouldn't happen post-init
170
+ }
171
+ }
172
+ return this._preInitBuffer;
173
+ }
174
+
175
+ // ─── Initialization ─────────────────────────────────────────────────
176
+
177
+ /**
178
+ * Initialize the ScaleBun SDK.
179
+ *
180
+ * **Simplified usage** (recommended):
181
+ * ```ts
182
+ * await ScaleBun.init({
183
+ * projectId: 'proj_xxx',
184
+ * publishableKey: 'pk_xxx',
185
+ * apiBaseUrl: 'https://api.scalebun.com',
186
+ * debug: true,
187
+ * });
188
+ * ```
189
+ *
190
+ * Accepts both `SimplifiedInitConfig` (new) and `ScaleBunInitConfig` (legacy).
191
+ * If `debug` key is present, auto-connects to the desktop debugger.
192
+ */
193
+ public async init(rawConfig: SimplifiedInitConfig | ScaleBunInitConfig | any) {
194
+ if (this.initialized) return;
195
+ // Coalesce concurrent init() calls: a second call before the first resolves
196
+ // must not run a second bootstrap (which would double-register lifecycle
197
+ // listeners and repeat the backend handshake).
198
+ if (this._initInFlight) return this._initInFlight;
199
+ this._initInFlight = safeAsync(async () => {
200
+ if (this.initialized) return;
201
+
202
+ // Store feature flags (all default true)
203
+ this._features = rawConfig?.features ?? {};
204
+ // Remember the developer's local replay captureMode so we can revert to it if an
205
+ // admin-forced frequency override (delivered via /config) is later withdrawn.
206
+ this._devCaptureMode = rawConfig?.replay?.captureMode ?? 'interactions';
207
+ if (rawConfig?.sessionReplay !== undefined) {
208
+ this._features.replay = rawConfig.sessionReplay;
209
+ }
210
+
211
+ // Store privacy config if provided
212
+ if (rawConfig?.privacy) {
213
+ this._privacyConfig = rawConfig.privacy;
214
+ }
215
+
216
+ // Phase 3 (entitlements) — COST suppression: don't even register a
217
+ // collector the org isn't entitled to (no traffic → no server cost).
218
+ // Read from the cached /config (sync); first run has no cache → fail-open
219
+ // (all entitled), and the server still rejects a closed feature anyway.
220
+ const ent = ConfigManager.readCachedEntitlements();
221
+ const effectiveFeatures: ScaleBunFeatures = {
222
+ ...this._features,
223
+ replay: this._features.replay !== false && ent.replay !== false,
224
+ network: this._features.network !== false && ent.networkMonitoring !== false,
225
+ crashes: this._features.crashes !== false && ent.crashReporting !== false,
226
+ performance: this._features.performance !== false && ent.performanceMonitoring !== false,
227
+ };
228
+
229
+ // Backend bootstrap (non-blocking for debug connection)
230
+ // If the backend is unreachable, the debug WebSocket should still connect.
231
+ try {
232
+ const result = await this.bootstrapper.bootstrap(
233
+ rawConfig,
234
+ (name, payload) => this.track(name, payload),
235
+ () => this.flush() as Promise<void>,
236
+ effectiveFeatures,
237
+ );
238
+
239
+ if (result) {
240
+ this.initialized = true;
241
+ this._clientKey = result.config.clientKey;
242
+ this._apiBaseUrl = result.config.apiBaseUrl;
243
+
244
+ // Phase 1 envelope tracking lane. Enabled when an appId is supplied
245
+ // (and not explicitly disabled). Runs alongside the replay lane.
246
+ this._maybeStartEventTracker(rawConfig);
247
+ // Quota (contract v1): /config must be live whenever a clientKey is configured,
248
+ // not only when the appId-gated event tracker created a ConfigManager above.
249
+ this._startConfigLifecycle();
250
+ if (this._pendingIdentity) {
251
+ const pending = this._pendingIdentity;
252
+ this._pendingIdentity = null;
253
+ this.identify(pending.userId, pending.traits);
254
+ }
255
+
256
+ // Drain pre-init buffer into the real persistent queue
257
+ const realQueue = coreContainer.get<PersistentQueue>('PersistentQueue');
258
+ const buffered = this._preInitBuffer.popBatch(this._preInitBuffer.length());
259
+ if (buffered.length > 0) {
260
+ logger.debug(`[ScaleBun] Draining ${buffered.length} pre-init events into persistent queue`);
261
+ for (const envelope of buffered) {
262
+ realQueue.add(envelope);
263
+ }
264
+ }
265
+
266
+ // Grab a reference to the PerformanceFeature for the public API
267
+ const perfFeature = result.featureRegistry.get('performance');
268
+ if (perfFeature && perfFeature instanceof PerformanceFeature) {
269
+ this._performanceFeature = perfFeature;
270
+ }
271
+ }
272
+ } catch (bootstrapErr: any) {
273
+ logger.warn('[ScaleBun] Backend bootstrap failed (non-blocking):', bootstrapErr?.message);
274
+ // Continue — debug connection is independent of backend API
275
+ }
276
+
277
+ // OTA from init config. Without this the whole `ota` config block was
278
+ // inert: `otaOrchestrator.init()` was reachable only by importing the
279
+ // orchestrator directly, so an app that followed the documented
280
+ // `ota: { enabled: true }` path silently got no updates AND no
281
+ // signature enforcement (sync() gates on the flag init() sets).
282
+ this._maybeStartOta(rawConfig);
283
+
284
+ // Auto debug connection from init config — runs regardless of backend status
285
+ const debugConfig = (rawConfig?.desktopDebug ?? rawConfig?.debug) as DebugConnectionConfig | undefined;
286
+ if (debugConfig) {
287
+ this._autoEnableDebug(debugConfig);
288
+ }
289
+ });
290
+ try {
291
+ return await this._initInFlight;
292
+ } finally {
293
+ this._initInFlight = null;
294
+ }
295
+ }
296
+
297
+ /**
298
+ * Boot the OTA orchestrator when the init config asks for it.
299
+ *
300
+ * Signature enforcement is no longer configured from JS. Signed releases are
301
+ * verified and staged in NATIVE code against RSA keys embedded in the app
302
+ * package (SB-OTA-RSA-SHA256-V1); unsigned releases keep working on SHA-256
303
+ * integrity. There are no signing-key or `verifySignature` options to pass
304
+ * through — the host embeds its trusted keys natively.
305
+ */
306
+ private _maybeStartOta(rawConfig: any): void {
307
+ const ota = rawConfig?.ota;
308
+ if (!ota?.enabled) return;
309
+ try {
310
+ // Required lazily: hosts that never enable OTA should not pay for the
311
+ // module (or touch the native spec) at import time.
312
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
313
+ const { otaOrchestrator } = require('../features/ota/OtaOrchestrator');
314
+ // `healthyAfterMs` is the field BootGuardConfig actually declares.
315
+ // This passed `healthyTimeoutMs`, which nothing reads, so a host that
316
+ // tuned the boot-guard window silently got the 10s default instead.
317
+ // Both spellings are accepted so the older one keeps working.
318
+ const healthyAfterMs =
319
+ typeof ota.healthyAfterMs === 'number'
320
+ ? ota.healthyAfterMs
321
+ : typeof ota.healthyTimeoutMs === 'number'
322
+ ? ota.healthyTimeoutMs
323
+ : undefined;
324
+
325
+ // Root/jailbreak policy. ONLY the literal string 'withhold' opts in;
326
+ // anything else (absent, a typo, a truthy object) falls through to
327
+ // 'allow', which is the behaviour every existing app already has.
328
+ // A config typo must never be able to stop a fleet's updates.
329
+ const onCompromisedDevice: 'allow' | 'withhold' =
330
+ ota.onCompromisedDevice === 'withhold' ? 'withhold' : 'allow';
331
+
332
+ otaOrchestrator.init({
333
+ ...(healthyAfterMs !== undefined ? { healthyAfterMs } : {}),
334
+ onCompromisedDevice,
335
+ });
336
+ if (onCompromisedDevice === 'withhold') {
337
+ logger.info(
338
+ "[ScaleBun] OTA will be WITHHELD on devices reporting root/jailbreak indicators (ota.onCompromisedDevice: 'withhold').",
339
+ );
340
+ }
341
+ logger.info('[ScaleBun] OTA enabled from init config.');
342
+
343
+ // Run the checks the config asked for. Until this existed, `ota.enabled`
344
+ // initialised the orchestrator and then never checked anything: the
345
+ // documented `checkOnForeground` and `channelOverride` options were read
346
+ // by no code at all, and an app following the documented config received
347
+ // updates only if it ALSO drove `useOtaUpdate` or the CodePush shim by
348
+ // hand. Nothing logged, because "no update available" and "never asked"
349
+ // look identical from the outside.
350
+ this._startOtaChecks(ota);
351
+ } catch (err: any) {
352
+ logger.warn(`[ScaleBun] OTA init failed: ${err?.message ?? err}`);
353
+ }
354
+ }
355
+
356
+ /** Guards against overlapping config-driven OTA checks. */
357
+ private _otaCheckInFlight = false;
358
+ /** Wall clock of the last config-driven check, for the foreground floor. */
359
+ private _otaLastCheckAt = 0;
360
+ private _otaForegroundListener: ((state: string) => void) | null = null;
361
+
362
+ /**
363
+ * Minimum gap between config-driven checks.
364
+ *
365
+ * A foreground transition is cheap to trigger — app switchers, permission
366
+ * dialogs and share sheets all produce one — so an unthrottled check would
367
+ * put a request on the hot path every time the user glanced away. Ten
368
+ * minutes is well below any realistic release cadence and well above that
369
+ * noise. A host that wants a check on demand calls `useOtaUpdate().sync()`,
370
+ * which is never throttled.
371
+ */
372
+ private static readonly OTA_MIN_CHECK_INTERVAL_MS = 10 * 60 * 1000;
373
+
374
+ /**
375
+ * Drive OTA checks from init config: once at startup, then on each
376
+ * foreground when `checkOnForeground` is on (the schema default).
377
+ *
378
+ * `appVersion` is resolved from the native bridge rather than asked of the
379
+ * integrator, because it gates the server's `targetAppVersion` semver check
380
+ * — sending a wrong or invented value is worse than sending none, and there
381
+ * is no honest default. If it cannot be resolved, the check is skipped with
382
+ * a warning instead of guessing.
383
+ */
384
+ private _startOtaChecks(ota: any): void {
385
+ // Never in a debug build. `ScaleBunOtaModule.getJSBundleFile()` returns null
386
+ // there on purpose so Metro keeps ownership of the bundle — so a bundle
387
+ // downloaded in dev is installed into a slot that will never be loaded, and
388
+ // the identity check on the next launch then correctly observes that the
389
+ // running code is not what was installed and reports APPLY_FAILED. Checking
390
+ // at all in dev buys nothing and manufactures that false alarm. A developer
391
+ // testing the OTA path drives `useOtaUpdate().sync()` explicitly.
392
+ if (__DEV__) {
393
+ logger.info('[ScaleBun] OTA checks are skipped in debug builds (Metro owns the bundle).');
394
+ return;
395
+ }
396
+
397
+ const runCheck = async (trigger: 'startup' | 'foreground'): Promise<void> => {
398
+ if (this._otaCheckInFlight) return;
399
+ if (
400
+ trigger === 'foreground' &&
401
+ Date.now() - this._otaLastCheckAt < ScaleBunFacade.OTA_MIN_CHECK_INTERVAL_MS
402
+ ) {
403
+ return;
404
+ }
405
+ const clientKey = this._clientKey;
406
+ const apiUrl = this._apiBaseUrl;
407
+ if (!clientKey || !apiUrl) {
408
+ return;
409
+ }
410
+
411
+ this._otaCheckInFlight = true;
412
+ try {
413
+ const info = await bridgeAdapter.getDeviceInfo();
414
+ const appVersion = (info as { appVersion?: string } | null)?.appVersion;
415
+ if (!appVersion) {
416
+ logger.warn(
417
+ '[ScaleBun] OTA check skipped — the app version could not be read from the ' +
418
+ 'native bridge. Rebuild the native app, or drive checks yourself with ' +
419
+ 'useOtaUpdate({ appVersion }).',
420
+ );
421
+ return;
422
+ }
423
+ this._otaLastCheckAt = Date.now();
424
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
425
+ const { otaOrchestrator } = require('../features/ota/OtaOrchestrator');
426
+ await otaOrchestrator.sync({
427
+ apiUrl,
428
+ clientKey,
429
+ appVersion,
430
+ // The documented option, finally connected. Omitted means the
431
+ // server's `default` channel, exactly as before.
432
+ channelName: typeof ota.channelOverride === 'string' ? ota.channelOverride : undefined,
433
+ // Never forced from config: the release's own installMode
434
+ // decides when the app restarts, and yanking the screen out
435
+ // from under a user is not a decision this switch should make.
436
+ });
437
+ } catch (err: any) {
438
+ logger.warn(`[ScaleBun] OTA check failed: ${err?.message ?? err}`);
439
+ } finally {
440
+ this._otaCheckInFlight = false;
441
+ }
442
+ };
443
+
444
+ void runCheck('startup');
445
+
446
+ if (ota.checkOnForeground === false) return;
447
+ if (this._otaForegroundListener) return; // idempotent across repeated init()
448
+ try {
449
+ // Through `appLifecycle`, not a second AppState subscription: the SDK
450
+ // already owns one and fanning out from it keeps every consumer on the
451
+ // same transition sequence.
452
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
453
+ const { appLifecycle } = require('../core/lifecycle/appLifecycle');
454
+ this._otaForegroundListener = (state: string) => {
455
+ if (state === 'active') void runCheck('foreground');
456
+ };
457
+ appLifecycle.addListener(this._otaForegroundListener);
458
+ } catch {
459
+ // Lifecycle unavailable (tests, exotic hosts) — the startup check stands.
460
+ this._otaForegroundListener = null;
461
+ }
462
+ }
463
+
464
+ private _autoEnableDebug(debugConfig: DebugConnectionConfig): void {
465
+ try {
466
+ const dbgConfig = buildDebugConfigFromInitConfig(debugConfig);
467
+ if (!dbgConfig) return;
468
+ (dbgConfig as any).__skipDeprecationWarning = true;
469
+ this.enableDebug(dbgConfig);
470
+ logger.info('[ScaleBun] Debug auto-connected via init({ debug }).');
471
+ } catch (err: any) {
472
+ logger.warn('[ScaleBun] Auto debug connection failed:', err?.message);
473
+ }
474
+ }
475
+
476
+ /**
477
+ * Keep /config (and with it the per-feature quota state) live for any clientKey-configured app.
478
+ *
479
+ * - Creates a quota-only ConfigManager when the appId-gated event tracker did not create one.
480
+ * Its exposure/stamp hooks are inert; it is not the flags API's manager.
481
+ * - Registers the FORCED refresh quotaState runs when a block's refresh time is reached (the
482
+ * only way a block is lifted — never the device clock alone).
483
+ * - Refreshes on foreground, throttled by ConfigManager's 5-minute TTL (ETag-aware), which is how
484
+ * a raised limit reaches a long-lived app.
485
+ *
486
+ * BEHAVIOUR CHANGE, deliberate (quota contract v1): apps WITHOUT an appId now fetch /config once
487
+ * per launch, and every clientKey app re-fetches it on foreground after 5 minutes. That fetch is
488
+ * how a block — and the raising of a limit — reaches the device; it is not an ingestion request.
489
+ * The quota-only manager applies NOTHING else from /config: no flags API, no experiment
490
+ * exposure, and no admin replayCapture override (that stays an appId-app behaviour, as before).
491
+ */
492
+ private _startConfigLifecycle(): void {
493
+ try {
494
+ const clientKey = this._clientKey;
495
+ const apiBaseUrl = this._apiBaseUrl;
496
+ if (!clientKey || !apiBaseUrl) return;
497
+ let mgr = this._configManager;
498
+ // Repeat init() without an appId: reuse the quota-only manager instead of stacking one
499
+ // ConfigManager (and one /config fetch) per call.
500
+ if (!mgr && this._configRefresher) mgr = this._configRefresher;
501
+ if (!mgr) {
502
+ mgr = new ConfigManager({
503
+ apiBaseUrl,
504
+ clientKey,
505
+ installationId: resolveInstallationId(),
506
+ emitExposure: () => {},
507
+ stamp: () => {},
508
+ // Quota only: no onReplayCapture — an app without appId never honored the admin
509
+ // capture override before, and fetching /config for quota must not change that.
510
+ });
511
+ mgr.refresh().catch(() => {});
512
+ }
513
+ this._configRefresher = mgr;
514
+ const refresher = mgr;
515
+ quotaState.setRefresher(() => refresher.refresh({ force: true }));
516
+
517
+ if (this._configForegroundListener) return; // idempotent across repeated init()
518
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
519
+ const { appLifecycle } = require('../core/lifecycle/appLifecycle');
520
+ this._configForegroundListener = (state: string) => {
521
+ if (state === 'active') this._configRefresher?.maybeRefresh();
522
+ };
523
+ appLifecycle.addListener(this._configForegroundListener);
524
+ } catch (err: any) {
525
+ logger.warn('[ScaleBun] Config lifecycle unavailable:', err?.message);
526
+ }
527
+ }
528
+
529
+ /**
530
+ * Release what _startConfigLifecycle registered (the forced-refresh hook and the foreground
531
+ * listener). The facade has no teardown path today; this is the one to call when it gets one.
532
+ */
533
+ private _stopConfigLifecycle(): void {
534
+ try {
535
+ quotaState.setRefresher(null);
536
+ if (this._configForegroundListener) {
537
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
538
+ const { appLifecycle } = require('../core/lifecycle/appLifecycle');
539
+ appLifecycle.removeListener(this._configForegroundListener);
540
+ }
541
+ } catch { /* no-throw */ }
542
+ this._configForegroundListener = null;
543
+ this._configRefresher = null;
544
+ }
545
+
546
+ /** Boot the Phase 1 envelope tracking lane if an appId is configured. */
547
+ private _maybeStartEventTracker(rawConfig: any): void {
548
+ try {
549
+ const appId = rawConfig?.appId;
550
+ const enabled = rawConfig?.eventTracking !== false;
551
+ const clientKey = this._clientKey ?? rawConfig?.clientKey;
552
+ // apiBaseUrl is LOCKED — use only the bootstrapped value, never fall back to raw
553
+ // integrator input, so the event-tracker/SKAdNetwork lane can't be repointed either.
554
+ const apiBaseUrl = this._apiBaseUrl;
555
+ if (!enabled || !appId || !clientKey || !apiBaseUrl) {
556
+ if (enabled && !appId) {
557
+ logger.info('[ScaleBun] Envelope event tracking disabled — no appId in init config.');
558
+ }
559
+ return;
560
+ }
561
+ // Phase 3: auto-apply SKAdNetwork conversion values from the server-side
562
+ // CV schema (iOS only; no-op elsewhere). Created BEFORE the tracker so the
563
+ // onEvent hook is live for the very first event (first_open).
564
+ if (isSkanAvailable()) {
565
+ this._skanManager = new SkanConversionManager({ apiBaseUrl, clientKey });
566
+ this._skanManager.refreshSchema().catch(() => {});
567
+ }
568
+ this._eventTracker = new EventTracker({
569
+ appId,
570
+ clientKey,
571
+ apiBaseUrl,
572
+ // Auto-detected (Platform.OS) unless the integration overrides it — see resolveEventPlatform.
573
+ platform: rawConfig?.platform ?? resolveEventPlatform(),
574
+ appVersion: rawConfig?.appVersion,
575
+ osVersion: rawConfig?.osVersion,
576
+ autoLifecycleEvents: rawConfig?.autoLifecycleEvents !== false,
577
+ // Backward-compatible opt-in: existing init-only integrations do
578
+ // not begin uploading the new automatic collector stream merely
579
+ // because they upgraded the package. ScaleBunProvider sets this
580
+ // to true unless the integrator explicitly disables it.
581
+ automaticEventTracking:
582
+ rawConfig?.automaticEventTracking === true,
583
+ flushIntervalMs: rawConfig?.flushIntervalMs,
584
+ /**
585
+ * DETECTED, not configured.
586
+ *
587
+ * This was `rawConfig?.context` — whatever the app typed. Production carries
588
+ * `device_model: "android"` and `manufacturer: "android"` from a hand-written
589
+ * literal, while the replay lane was reading the real values off the native bridge
590
+ * the whole time. The SDK knows the device; the integrator is guessing at it.
591
+ * Everything outside the detected keys is still theirs.
592
+ */
593
+ // Everything Platform.constants knows. On iOS that is neither the model nor the
594
+ // manufacturer, so the bridge completes it below once it answers.
595
+ context: mergeDeviceContext(rawConfig?.context),
596
+ // Use the same foreground id as replay/journey capture. The
597
+ // callback is resolved per event because the session subsystem
598
+ // may start after this tracker is constructed.
599
+ sessionIdProvider: () => {
600
+ const manager = SessionManager.getExistingInstance();
601
+ return manager?.currentSessionId
602
+ ?? manager?.getBackendTransport()?.analyticsSessionId
603
+ ?? null;
604
+ },
605
+ // Feed every tracked event to the SKAN CV manager (iOS; no-op otherwise).
606
+ onEvent: (eventName, revenue) => this._skanManager?.onEvent(eventName, revenue),
607
+ });
608
+ this._eventTracker.start();
609
+ logger.info('[ScaleBun] Envelope event tracking started → /v1/batch.');
610
+
611
+ // Complete the device context from the native bridge.
612
+ //
613
+ // `Platform.constants` answers Android synchronously — model and manufacturer ride the
614
+ // first event. It answers NEITHER on iOS, so without this every iOS installation
615
+ // reported no device model at all: `nativeDeviceContext` existed for exactly this and
616
+ // had no caller, and the bridge's own answer was `UIDevice.current.model` — the string
617
+ // "iPhone", identical on every iPhone ever made.
618
+ //
619
+ // Fire-and-forget on purpose. The bridge is async and absent entirely on Expo Go or an
620
+ // older native binary; waiting on it would delay the first event, and failing on it
621
+ // would take analytics down over a nice-to-have field.
622
+ this._applyNativeDeviceContext(this._eventTracker);
623
+
624
+ // Android: capture the Play Install Referrer once per install → feeds the
625
+ // deterministic click_id path + a one-off install_referrer event (UTM/gclid).
626
+ // Fire-and-forget; no-op off Android.
627
+ this._captureInstallReferrer(this._eventTracker);
628
+
629
+ // Phase 4: runtime config (flags / remote config / experiments / rollouts).
630
+ // Resolves locally; exposure + stamps flow through the event lane above.
631
+ const tracker = this._eventTracker;
632
+ this._configManager = new ConfigManager({
633
+ apiBaseUrl,
634
+ clientKey,
635
+ installationId: tracker.ids.installationId,
636
+ emitExposure: (experiment, variant) => tracker.track('experiment_exposure', { experiment, variant }),
637
+ stamp: (key, value) => tracker.stamp(key, value),
638
+ // Admin-controlled replay capture override: apply/revert timer capture as the
639
+ // server dictates, overriding the developer's local captureMode.
640
+ onReplayCapture: (override) => this._applyReplayCaptureOverride(override),
641
+ });
642
+ // Apply any cached override immediately (offline / pre-first-fetch); refresh() then
643
+ // re-applies with the latest value once /config responds.
644
+ this._applyReplayCaptureOverride(this._configManager.getReplayCapture());
645
+ this._configManager.refresh().catch(() => {});
646
+ } catch (err: any) {
647
+ logger.warn('[ScaleBun] Failed to start envelope event tracking:', err?.message);
648
+ }
649
+ }
650
+
651
+
652
+ /**
653
+ * Fold the native bridge's device facts into the analytics context once it answers.
654
+ *
655
+ * Detected values never overwrite a populated one with an empty one — `nativeDeviceContext`
656
+ * drops absent keys and `applyDetectedContext` ignores an empty patch — so a bridge that
657
+ * cannot answer leaves whatever `Platform.constants` already found.
658
+ */
659
+ private _applyNativeDeviceContext(tracker: EventTracker): void {
660
+ Promise.resolve()
661
+ .then(() => bridgeAdapter.getDeviceInfo())
662
+ .then(info => {
663
+ if (!info) return;
664
+ tracker.applyDetectedContext(
665
+ nativeDeviceContext({
666
+ osVersion: info.osVersion,
667
+ deviceModel: info.deviceModel,
668
+ // iOS ships no manufacturer over the bridge; it is a constant there and the
669
+ // static path already set it. Android's arrives via Platform.constants.
670
+ }),
671
+ );
672
+ })
673
+ .catch(() => { /* bridge unavailable — the static context stands */ });
674
+ }
675
+
676
+ /**
677
+ * Apply (or revert) the admin-controlled replay capture override delivered via GET /config.
678
+ *
679
+ * When the super-admin has forced timer capture, `override` is `{ mode: 'frequency', intervalMs }`
680
+ * and we switch replay to frequency at that interval — overriding the developer's local
681
+ * captureMode (which Part 1 restricts to navigation/interactions). When the override is withdrawn
682
+ * (`null`) AND we had previously applied one, we revert to the developer's configured mode.
683
+ *
684
+ * Non-throwing and a no-op when replay is disabled. Idempotent — re-applying the same override
685
+ * just re-asserts the native state, which is harmless.
686
+ */
687
+ private _applyReplayCaptureOverride(
688
+ override: { mode: 'frequency'; intervalMs: number } | null,
689
+ ): void {
690
+ try {
691
+ if (this._features.replay === false) return; // replay off — nothing to drive
692
+ if (override && override.mode === 'frequency') {
693
+ this._replayOverrideActive = true;
694
+ this.replay.setCaptureMode('frequency').catch(() => {});
695
+ ReplaySdk.setScreenshotCaptureInterval(override.intervalMs).catch(() => {});
696
+ } else if (this._replayOverrideActive) {
697
+ // Override withdrawn — restore the developer's configured captureMode.
698
+ this._replayOverrideActive = false;
699
+ this.replay.setCaptureMode(this._devCaptureMode).catch(() => {});
700
+ }
701
+ } catch { /* no-throw */ }
702
+ }
703
+ /**
704
+ * Android-only: read the Play Install Referrer once per install and route it into
705
+ * attribution. `scalebun_click_id` → the deterministic click path; the full
706
+ * referrer (utm_source/gclid/…) rides on a one-off `install_referrer` event. A
707
+ * `null` fetch (Play unavailable/transient) is not marked captured, so a later
708
+ * launch retries while Play still has the referrer. Never throws.
709
+ */
710
+ private _captureInstallReferrer(tracker: EventTracker): void {
711
+ try {
712
+ if (!isInstallReferrerAvailable()) return;
713
+ const storage = createStorageBackend();
714
+ const KEY = 'scalebun_install_referrer_done';
715
+ const sink: InstallReferrerSink = {
716
+ alreadyCaptured: () => { try { return storage.get(KEY) === '1'; } catch { return false; } },
717
+ markCaptured: () => { try { storage.set(KEY, '1'); } catch { /* no-throw */ } },
718
+ setClickId: (id) => tracker.setAttributionClickId(id),
719
+ emit: (name, props) => tracker.track(name, props as Record<string, any>),
720
+ fetch: () => getInstallReferrer(),
721
+ };
722
+ void captureInstallReferrerOnce(sink);
723
+ } catch (err: any) {
724
+ logger.warn('[ScaleBun] Install Referrer capture failed:', err?.message);
725
+ }
726
+ }
727
+
728
+ /**
729
+ * Phase 1 envelope event tracking API (POST /v1/batch).
730
+ * Methods are no-ops (never throw) until init() is called with an `appId`.
731
+ */
732
+ public get events() {
733
+ const tracker = this._eventTracker;
734
+ return {
735
+ track: (eventName: string, properties?: Record<string, any>) => tracker?.track(eventName, properties),
736
+ identify: (userId: string, traits?: Record<string, any>) => tracker?.identify(userId, traits),
737
+ trackPurchase: (input: RevenueInput) =>
738
+ tracker?.trackPurchase(input),
739
+ trackSubscription: (input: SubscriptionInput) =>
740
+ tracker?.trackSubscription(input),
741
+ setIdentifiers: (ids: { idfa?: string; gaid?: string; idfv?: string }) => tracker?.setIdentifiers(ids),
742
+ // Phase 2: record a deferred deep-link click token for deterministic install attribution.
743
+ setAttributionClickId: (clickId: string) => tracker?.setAttributionClickId(clickId),
744
+ flush: () => tracker?.flush() ?? Promise.resolve(),
745
+ newSession: () => tracker?.newSession(),
746
+ ids: () => tracker?.ids ?? null,
747
+ /** Pending and dropped event counts for host diagnostics. */
748
+ stats: () => tracker?.stats ?? null,
749
+ // Phase 3: update the SKAdNetwork conversion value (iOS only; no-op elsewhere).
750
+ updateSkanConversionValue: (value: number, coarseValue?: SkanCoarseValue, lockWindow?: boolean) =>
751
+ updateSkanConversionValue(value, coarseValue, lockWindow),
752
+ };
753
+ }
754
+
755
+ /**
756
+ * Phase 4: runtime config delivered via GET /v1/config. All resolution is local
757
+ * and non-throwing; values default sensibly until init() runs / config is fetched.
758
+ *
759
+ * ScaleBun.config.get('max_items', 10)
760
+ * ScaleBun.flags.isEnabled('new_checkout')
761
+ * ScaleBun.rollouts.isOn('beta_paywall')
762
+ * ScaleBun.experiments.variant('checkout_cta') // → 'control' | 'treatment' | null
763
+ */
764
+ public get config() {
765
+ const cm = this._configManager;
766
+ return {
767
+ get: <T = any>(key: string, fallback: T): T => (cm ? cm.get(key, fallback) : fallback),
768
+ refresh: () => cm?.refresh() ?? Promise.resolve(),
769
+ };
770
+ }
771
+
772
+ public get flags() {
773
+ const cm = this._configManager;
774
+ return { isEnabled: (key: string) => cm?.isEnabled(key) ?? false };
775
+ }
776
+
777
+ public get rollouts() {
778
+ const cm = this._configManager;
779
+ return { isOn: (key: string) => cm?.rolloutIsOn(key) ?? false };
780
+ }
781
+
782
+ public get experiments() {
783
+ const cm = this._configManager;
784
+ return { variant: (key: string): string | null => cm?.variant(key) ?? null };
785
+ }
786
+
787
+ /** Convenience: emit a Phase 1 purchase event (revenue + currency + transaction_id). */
788
+ /**
789
+ * Declare which UI state the user is looking at, so taps are attributed to the surface they
790
+ * happened on rather than averaged across every variant of the screen.
791
+ *
792
+ * ScaleBun.setUiState('filter-sheet', 'open');
793
+ * ScaleBun.setUiState('checkout-step', 'payment');
794
+ *
795
+ * Call it when the state CHANGES — the value is read at tap time, so it only has to be right by
796
+ * the time the next tap lands. On React Native this is the ONLY source of UI state: unlike the web,
797
+ * there is no queryable accessibility tree that says a sheet is up, and guessing would produce a
798
+ * state key that is right on some apps and silently wrong on others.
799
+ *
800
+ * Names and values are identifiers, not content: they become query keys in the dashboard, so a
801
+ * person's name or a cart total does not belong in one. `;`, `:` and `|` are stripped and both
802
+ * halves are capped at 32 characters.
803
+ */
804
+ public setUiState(name: string, value: string): void {
805
+ try {
806
+ const { setUiState } = require('../features/journey/uiState');
807
+ setUiState(name, value);
808
+ } catch { /* no-throw: a state declaration must never break the host */ }
809
+ }
810
+
811
+ /**
812
+ * Stop reporting a UI state dimension — or, with no argument, all of them.
813
+ *
814
+ * Clear on screen unmount. A declaration left behind follows the user onto a surface where it means
815
+ * nothing, and every tap there is filed under a state that was not on screen.
816
+ */
817
+ public clearUiState(name?: string): void {
818
+ try {
819
+ const { clearUiState } = require('../features/journey/uiState');
820
+ clearUiState(name);
821
+ } catch { /* no-throw */ }
822
+ }
823
+
824
+ public trackPurchase(input: RevenueInput): void {
825
+ noThrow(() => this._eventTracker?.trackPurchase(input));
826
+ }
827
+
828
+ /** Record a trial, renewal, plan change or cancellation in the subscription ledger. */
829
+ public trackSubscription(input: SubscriptionInput): void {
830
+ noThrow(() => this._eventTracker?.trackSubscription(input));
831
+ }
832
+
833
+ /**
834
+ * Phase 3: set the SKAdNetwork fine conversion value (0–63), optionally with a
835
+ * SKAN 4.0 coarse value and window-lock. iOS only — a no-op on Android / Expo Go.
836
+ */
837
+ public updateSkanConversionValue(value: number, coarseValue?: SkanCoarseValue, lockWindow?: boolean): void {
838
+ noThrow(() => { void updateSkanConversionValue(value, coarseValue, lockWindow); });
839
+ }
840
+
841
+ // ─── Feature Flags ──────────────────────────────────────────────────
842
+
843
+ /** Get the current feature flags (consumed by enableDebug) */
844
+ public getFeatureFlags(): ScaleBunFeatures {
845
+ return this._features;
846
+ }
847
+
848
+ // ─── Identity ───────────────────────────────────────────────────────
849
+
850
+ /** Identify a user by ID and optional traits */
851
+ public identify(userId: string, traits?: Record<string, any>) {
852
+ return noThrow(() => {
853
+ this._identifiedUserId = userId;
854
+ if (!this.initialized) {
855
+ this._pendingIdentity = { userId, traits };
856
+ return;
857
+ }
858
+ this._pendingIdentity = null;
859
+ // Forward to the Phase 1 envelope lane (sets user_id for subsequent events).
860
+ this._eventTracker?.identify(userId, traits);
861
+ /**
862
+ * The session marker carries the user id ONLY — never the traits.
863
+ *
864
+ * This used to spread `...traits` into the event, and `track()` uploads it as a
865
+ * `USER_ACTION` on the session lane, unredacted. Production held 751 such rows in 7
866
+ * days with name/email/phone-verified fields in `replay_events.data`, shown in the
867
+ * replay timeline as user actions. Traits already travel on the lanes built for them:
868
+ * `_eventTracker.identify` above and the ingestion identify POST below.
869
+ */
870
+ this.track('$identify', { id: userId });
871
+ const sessionId = SessionManager.getExistingInstance()?.currentSessionId;
872
+ if (this._clientKey && sessionId) {
873
+ // Skip the network POST when the same identity was already sent for this
874
+ // session (repeat identify() with identical traits is a no-op upsert).
875
+ const identityKey = `${sessionId}|${userId}|${JSON.stringify(traits ?? {})}`;
876
+ if (identityKey !== this._lastIngestionIdentityKey) {
877
+ this._lastIngestionIdentityKey = identityKey;
878
+ const user: ScaleBunUser = {
879
+ id: userId,
880
+ name: traits?.name,
881
+ email: traits?.email,
882
+ properties: traits,
883
+ };
884
+ this._callIngestionIdentify(sessionId, user).catch(() => {
885
+ // Re-arm on failure so a later retry is not suppressed.
886
+ this._lastIngestionIdentityKey = null;
887
+ });
888
+ }
889
+ }
890
+ });
891
+ }
892
+
893
+ /**
894
+ * Stable public alias for {@link identify}. Part of the minimal public push
895
+ * API surface (ScaleBun.init / identifyUser / enablePush) that stays
896
+ * identical across RN versions and future platforms.
897
+ */
898
+ public identifyUser(userId: string, traits?: Record<string, any>) {
899
+ return this.identify(userId, traits);
900
+ }
901
+
902
+ /** POST user identity to the SaaS ingestion identify endpoint */
903
+ private async _callIngestionIdentify(sessionId: string, user: ScaleBunUser): Promise<void> {
904
+ if (!this._clientKey || !this._apiBaseUrl) return;
905
+ const url = `${this._apiBaseUrl}/ingestion/sessions/${sessionId}/identify`;
906
+ try {
907
+ await fetch(url, {
908
+ method: 'POST',
909
+ headers: {
910
+ 'Content-Type': 'application/json',
911
+ 'x-scalebun-client-key': this._clientKey,
912
+ },
913
+ body: JSON.stringify({
914
+ userId: user.id,
915
+ username: user.name,
916
+ email: user.email,
917
+ properties: user.properties,
918
+ }),
919
+ });
920
+ } catch (err: any) {
921
+ logger.warn('[ScaleBun] ingestion identify failed:', err?.message);
922
+ }
923
+ }
924
+
925
+ /** Set user identity (for session context) */
926
+ public setUser(user: ScaleBunUser) {
927
+ return noThrow(() => {
928
+ this.identify(user.id, {
929
+ name: user.name,
930
+ email: user.email,
931
+ ...user.attributes,
932
+ });
933
+ });
934
+ }
935
+
936
+ /**
937
+ * Clear user identity.
938
+ *
939
+ * SB-11: pass `{ purgeLocal: true }` on logout / consent withdrawal to also
940
+ * erase all locally-stored SDK data (see {@link eraseLocalData}). Without it,
941
+ * behaviour is unchanged (identity-only clear).
942
+ */
943
+ public clearUser(options?: { purgeLocal?: boolean }) {
944
+ return noThrow(() => {
945
+ this._identifiedUserId = null;
946
+ this._pendingIdentity = null;
947
+ if (!this.initialized) return;
948
+ this._eventTracker?.clearIdentity();
949
+ this.track('$clear_user', {});
950
+ if (options?.purgeLocal) void this.eraseLocalData();
951
+ });
952
+ }
953
+
954
+ /**
955
+ * SB-11: erase all locally-stored SDK data from the device — the durable event
956
+ * queue, the pre-init buffer, and the first-party KV store (cached install /
957
+ * anonymous / session IDs, plus any queued payloads including SB-26 disk data).
958
+ *
959
+ * Order matters: capture is stopped FIRST so nothing is written back in behind
960
+ * the delete. Best-effort and never throws.
961
+ *
962
+ * Note: native replay frames written to disk on iOS are addressed separately
963
+ * (SB-15); this covers every store reachable from JS today.
964
+ */
965
+ public async eraseLocalData(): Promise<void> {
966
+ try {
967
+ // 1) Stop capture so no new frames/events are produced mid-erase.
968
+ try {
969
+ SessionManager.getExistingInstance()?.endSession('ended');
970
+ } catch { /* best-effort */ }
971
+ // 2) Clear the durable queue and the pre-init buffer.
972
+ try {
973
+ this._getQueue().clear();
974
+ } catch { /* best-effort */ }
975
+ try {
976
+ this._preInitBuffer.clear();
977
+ } catch { /* best-effort */ }
978
+ // 3) Wipe the first-party KV store (cached IDs + any on-disk queue
979
+ // residue) by removing every key through the backend interface.
980
+ try {
981
+ const store = createStorageBackend();
982
+ for (const key of store.getAllKeys()) {
983
+ store.delete(key);
984
+ }
985
+ } catch { /* best-effort */ }
986
+ } catch {
987
+ // Never throw — erasure is a safety operation on a best-effort basis.
988
+ }
989
+ }
990
+
991
+ /**
992
+ * SB-11: record the user's data-collection consent. When `enabled` is false,
993
+ * capture is stopped immediately; pass `{ purgeLocal: true }` to also erase
994
+ * everything already stored locally. Never throws.
995
+ */
996
+ public setConsent(enabled: boolean, options?: { purgeLocal?: boolean }): void {
997
+ noThrow(() => {
998
+ if (enabled) return;
999
+ try {
1000
+ SessionManager.getExistingInstance()?.endSession('ended');
1001
+ } catch { /* best-effort */ }
1002
+ if (options?.purgeLocal) void this.eraseLocalData();
1003
+ });
1004
+ }
1005
+
1006
+ /**
1007
+ * SB-10: return the effective privacy policy actually in force, resolving the
1008
+ * public config against the SDK's safe defaults. Lets callers and tests assert
1009
+ * what is active rather than guessing from the (previously dead) config object.
1010
+ */
1011
+ public getEffectivePrivacyPolicy(): Required<
1012
+ Pick<PrivacyConfig, 'maskTextInputs' | 'maskImages' | 'redactAuth' | 'redactCookies' | 'redactBodies'>
1013
+ > {
1014
+ const p = this._privacyConfig ?? {};
1015
+ return {
1016
+ // Real default is true (matches the replay capture default) — the old
1017
+ // doc comment claiming "false" was both wrong and less safe.
1018
+ maskTextInputs: p.maskTextInputs ?? true,
1019
+ maskImages: p.maskImages ?? false,
1020
+ redactAuth: p.redactAuth ?? true,
1021
+ redactCookies: p.redactCookies ?? true,
1022
+ redactBodies: p.redactBodies ?? false,
1023
+ };
1024
+ }
1025
+
1026
+ /**
1027
+ * Submit in-app rating (1-5 stars).
1028
+ * Attaches to current session when available; otherwise sends standalone.
1029
+ * Never throws.
1030
+ */
1031
+ public submitRating(input: {
1032
+ rating: number;
1033
+ comment?: string;
1034
+ source?: 'in_app' | 'prompt' | 'manual';
1035
+ /** [ADDITIVE] client-generated UUID for app-rating idempotency (contract §1.4, D8). */
1036
+ clientRatingId?: string;
1037
+ }) {
1038
+ return safeAsync(async () => {
1039
+ if (!this._clientKey || !this._apiBaseUrl) return { ok: false, reason: 'sdk_not_configured' as const };
1040
+ const rating = Math.round(Number(input?.rating));
1041
+ if (!Number.isFinite(rating) || rating < 1 || rating > 5) {
1042
+ return { ok: false, reason: 'invalid_rating' as const };
1043
+ }
1044
+
1045
+ const sessionId = this.getActiveSessionId();
1046
+ const meta = SessionManager.getExistingInstance()?.currentSessionMetadata;
1047
+ const path = sessionId
1048
+ ? `/ingestion/sessions/${sessionId}/rating`
1049
+ : `/ingestion/ratings`;
1050
+ const url = `${this._apiBaseUrl}${path}`;
1051
+
1052
+ try {
1053
+ const res = await fetch(url, {
1054
+ method: 'POST',
1055
+ headers: {
1056
+ 'Content-Type': 'application/json',
1057
+ 'x-scalebun-client-key': this._clientKey,
1058
+ },
1059
+ body: JSON.stringify({
1060
+ rating,
1061
+ comment: input.comment,
1062
+ source: input.source ?? 'in_app',
1063
+ appVersion: meta?.appVersion,
1064
+ platform: meta?.platform,
1065
+ // [ADDITIVE] idempotency + versioning (contract §1.4); omitted when unset.
1066
+ ...(input.clientRatingId ? { clientRatingId: input.clientRatingId } : {}),
1067
+ schemaVersion: ENGAGE_SCHEMA_VERSION,
1068
+ }),
1069
+ });
1070
+ if (!res.ok) {
1071
+ logger.warn('[ScaleBun] submitRating non-ok', res.status);
1072
+ return { ok: false, reason: 'http_error' as const, status: res.status };
1073
+ }
1074
+ return { ok: true as const };
1075
+ } catch (err: any) {
1076
+ logger.warn('[ScaleBun] submitRating failed:', err?.message);
1077
+ return { ok: false, reason: 'network_error' as const };
1078
+ }
1079
+ });
1080
+ }
1081
+
1082
+ private getActiveSessionId(): string | null {
1083
+ try {
1084
+ return SessionManager.getExistingInstance()?.currentSessionId ?? null;
1085
+ } catch {}
1086
+ return null;
1087
+ }
1088
+
1089
+ // ─── Bug reports (F-BUG) ────────────────────────────────────────────
1090
+
1091
+ /**
1092
+ * Thin feature object; the facade owns the HTTP, mirroring the web SDK split.
1093
+ * Its only job here is raising the 'report' capture signal so replay flushes.
1094
+ */
1095
+ private readonly _bugReport = new BugReportFeature();
1096
+
1097
+ /**
1098
+ * Submit a bug report against the CURRENT session.
1099
+ *
1100
+ * Mirrors the web SDK's `reportBugDetailed` ordering, which is load-bearing rather than
1101
+ * incidental:
1102
+ *
1103
+ * 1. resolve the session — a report with no session cannot be joined to its evidence
1104
+ * 2. signal 'report' — replay flushes its buffer so the report has visual context
1105
+ * 3. snapshot the anchor — BEFORE the POST. A flush asks the recorder to deliver pending
1106
+ * bytes; it cannot retroactively manufacture a frame, so an absent
1107
+ * coordinate must stay absent rather than becoming a misleading
1108
+ * "start of session" link in the dashboard
1109
+ * 4. build + POST — bounds enforced by buildBugReportPayload against the server DTO
1110
+ *
1111
+ * Returns the report id, or `{ e }` naming which branch failed — 'init' (SDK not configured)
1112
+ * reads differently from 'send' (network), and that difference is what tells an integrator
1113
+ * whether to check their setup or their connection. It never throws: this is called from a UI
1114
+ * the host app renders, usually from a user gesture, and an exception escaping into a React
1115
+ * Native render tree is a redbox shown to the customer's user over a report they were sending us.
1116
+ */
1117
+ public async reportBugDetailed(input: {
1118
+ message: string;
1119
+ title?: string;
1120
+ email?: string;
1121
+ clientReportId?: string;
1122
+ }): Promise<BugSubmitResult> {
1123
+ if (!input || !input.message || input.message.trim().length === 0) {
1124
+ logger.warn('[ScaleBun] reportBug: a message is required');
1125
+ return { e: 'empty' };
1126
+ }
1127
+ if (!this._clientKey || !this._apiBaseUrl) {
1128
+ logger.warn('[ScaleBun] reportBug: SDK is not configured (clientKey/apiBaseUrl)');
1129
+ return { e: 'init' };
1130
+ }
1131
+
1132
+ const sessionId = this.getActiveSessionId();
1133
+ if (!sessionId) {
1134
+ // No session means no row to attach to, and the ingestion route is session-scoped.
1135
+ logger.warn('[ScaleBun] reportBug: no active session');
1136
+ return { e: 'init' };
1137
+ }
1138
+
1139
+ try {
1140
+ // Flush replay into the session BEFORE reading the anchor below.
1141
+ this._bugReport.signalReport();
1142
+
1143
+ const coord = this._replayCoord();
1144
+ const payload = buildBugReportPayload(input, this._recentBreadcrumbs(), {
1145
+ replayCoord: coord,
1146
+ timestamp: Date.now(),
1147
+ });
1148
+
1149
+ const res = await fetch(
1150
+ `${this._apiBaseUrl}/ingestion/sessions/${sessionId}/bug-reports`,
1151
+ {
1152
+ method: 'POST',
1153
+ headers: {
1154
+ 'Content-Type': 'application/json',
1155
+ 'x-scalebun-client-key': this._clientKey,
1156
+ },
1157
+ body: JSON.stringify(payload),
1158
+ },
1159
+ );
1160
+ if (!res.ok) {
1161
+ logger.warn('[ScaleBun] reportBug: server rejected the report', res.status);
1162
+ return { e: 'send' };
1163
+ }
1164
+ const body = await res.json().catch(() => null);
1165
+ return body?.id ?? { e: 'send' };
1166
+ } catch (err: any) {
1167
+ logger.warn('[ScaleBun] reportBug failed:', err?.message);
1168
+ return { e: 'send' };
1169
+ }
1170
+ }
1171
+
1172
+ /**
1173
+ * The replay coordinate at submit time, or null.
1174
+ *
1175
+ * Deliberately returns null rather than a zeroed coordinate when replay is disabled, paused, or
1176
+ * has not produced a frame yet — see the anchor note on reportBug.
1177
+ */
1178
+ /**
1179
+ * The replay coordinate at submit time.
1180
+ *
1181
+ * ALWAYS null today, deliberately and visibly.
1182
+ *
1183
+ * The web SDK reads this from its recorder, but the RN replay subsystem exposes no sequence or
1184
+ * segment accessor on its public API (features/replay/public/api.ts) -- there is currently no
1185
+ * supported way to ask it where playback is. Probing for it through an `any` cast would compile,
1186
+ * miss, and leave every report anchor-less while looking wired: the same defect as the existing
1187
+ * reportBug(), which emits an analytics event and looks like it files a report.
1188
+ *
1189
+ * Returning null keeps the payload HONEST -- buildBugReportPayload omits replaySeq entirely, so
1190
+ * the dashboard shows no anchor rather than a false one pointing at the start of the session.
1191
+ * To finish this: expose the current seq + segment id from the replay recorder, then read them
1192
+ * here. The payload builder and its contract tests already handle a real coordinate, including
1193
+ * a genuine seq of 0.
1194
+ */
1195
+ private _replayCoord(): { seq?: number | null; segmentId?: string | null } | null {
1196
+ return null;
1197
+ }
1198
+ /** Recent console breadcrumbs for quick triage. The full set already travels with the session. */
1199
+ private _recentBreadcrumbs(): readonly unknown[] {
1200
+ try {
1201
+ const f = (this as any)._loggerFeature ?? (this as any)._consoleFeature;
1202
+ return f?.getRecent?.() ?? [];
1203
+ } catch {
1204
+ return [];
1205
+ }
1206
+ }
1207
+
1208
+ // ─── Engage ─────────────────────────────────────────────────────────
1209
+
1210
+ /**
1211
+ * Lazily resolve the Engage transport. Requires a configured SaaS clientKey +
1212
+ * apiBaseUrl (same gate as the rating/ingestion lanes); returns null otherwise.
1213
+ * The transport mirrors the existing BackendSessionAdapter outbox: upload lanes
1214
+ * batch-flush and re-queue on failure, the config GET is a direct fetch.
1215
+ */
1216
+ private _getEngageTransport(): EngageTransport | null {
1217
+ if (!this._clientKey || !this._apiBaseUrl) return null;
1218
+ if (!this._engageTransport) {
1219
+ this._engageTransport = new EngageTransport({
1220
+ endpoint: this._apiBaseUrl,
1221
+ clientKey: this._clientKey,
1222
+ });
1223
+ }
1224
+ return this._engageTransport;
1225
+ }
1226
+
1227
+ /**
1228
+ * Engage surface namespace (foundation: transport + native push-token plumbing).
1229
+ *
1230
+ * Rendering of campaigns/in-app messages is a SHARED cross-platform JS overlay
1231
+ * (D4) built in a later stage. This namespace exposes only the foundation:
1232
+ * versioned config fetch, idempotent response/event upload (via the existing
1233
+ * outbox), and native push-token registration on both platforms.
1234
+ */
1235
+ public engage = {
1236
+ /** Current external identity, forwarded by the provider for segment targeting. */
1237
+ getIdentifiedUserId: (): string | undefined =>
1238
+ this._identifiedUserId ?? undefined,
1239
+
1240
+ /**
1241
+ * Fetch the versioned Engage config (campaigns + in-app messages).
1242
+ *
1243
+ * slice-agent: the shared cross-platform JS overlay renderer consumes this
1244
+ * payload (EngageConfigResponse.campaigns / .inAppMessages) in a later stage.
1245
+ */
1246
+ fetchConfig: async (
1247
+ context?: EngageConfigContext,
1248
+ ): Promise<EngageConfigResponse | null> => {
1249
+ const transport = this._getEngageTransport();
1250
+ if (!transport) return null;
1251
+ const [engageConfig, coachConfig] = await Promise.all([
1252
+ transport.fetchEngageConfig(context),
1253
+ transport.fetchCoachConfig(),
1254
+ ]);
1255
+ if (!engageConfig && !coachConfig) return null;
1256
+ const coachMessages = (coachConfig?.tours ?? [])
1257
+ .filter((tour) => Array.isArray(tour.steps) && tour.steps.length > 0)
1258
+ .map((tour) => ({
1259
+ id: tour.id,
1260
+ layout: 'tooltip' as const,
1261
+ trigger: 'app_open',
1262
+ variantKey: 'coachmark_spotlight',
1263
+ revision: String(tour.version),
1264
+ preview: tour.preview === true,
1265
+ spec: {
1266
+ title: tour.name,
1267
+ body: tour.steps[0]?.body ?? tour.name,
1268
+ anchorKey: tour.steps[0]?.anchorKey,
1269
+ ext: {
1270
+ coachTourId: tour.id,
1271
+ coachTourVersion: tour.version,
1272
+ steps: tour.steps,
1273
+ },
1274
+ },
1275
+ }));
1276
+ return {
1277
+ configVersion: engageConfig?.configVersion ?? 1,
1278
+ serverTime: engageConfig?.serverTime ?? new Date().toISOString(),
1279
+ campaigns: engageConfig?.campaigns ?? [],
1280
+ inAppMessages: [...(engageConfig?.inAppMessages ?? []), ...coachMessages],
1281
+ };
1282
+ },
1283
+
1284
+ /** Internal bridge used by the shared renderer to feed standalone tour analytics. */
1285
+ trackCoachmarkEvent: (name: string, properties: Record<string, unknown>): void => {
1286
+ this.track(name, properties as Record<string, any>);
1287
+ },
1288
+
1289
+ /**
1290
+ * DEBUG/DEV ONLY — clear the persisted in-app/campaign frequency-cap state
1291
+ * (every `scalebun_engage_throttle:*` key: impressions, showOnce/completed, cooldown).
1292
+ * Lets a tester see throttled/dismissed messages again WITHOUT uninstalling the
1293
+ * app. Does NOT change the device id (identity is preserved). Returns the number
1294
+ * of cleared entries. NOT a substitute for the real fix (revision-scoped state +
1295
+ * test-preview bypass already make normal Send Test work without this).
1296
+ */
1297
+ clearInAppMessageCache: (): number => {
1298
+ return noThrow(() => new EngageThrottleStore().clearAll() + new EngageTestSeenStore().clear()) ?? 0;
1299
+ },
1300
+
1301
+ /**
1302
+ * DEBUG/DEV ONLY — alias of {@link clearInAppMessageCache} with the broader name
1303
+ * used in docs. Resets all on-device in-app frequency/dismiss/impression state so
1304
+ * the next config poll can show messages again. Identity (device id) is untouched.
1305
+ */
1306
+ resetInAppState: (): number => {
1307
+ // Clears BOTH lanes: production frequency/dismiss/impression state (throttle
1308
+ // store) AND the one-shot test-seen store — so a dismissed test reappears after
1309
+ // a debug reset (the "block forever UNLESS debug reset" contract). Identity
1310
+ // (device id) is a separate key and stays untouched.
1311
+ return noThrow(() => new EngageThrottleStore().clearAll() + new EngageTestSeenStore().clear()) ?? 0;
1312
+ },
1313
+
1314
+ /**
1315
+ * Force an immediate flush of queued in-app events. The provider calls this right
1316
+ * after a TEST preview's impression/dismiss ACK so the backend consumes the
1317
+ * one-shot preview row promptly — a fast close→kill→reopen can't re-serve a
1318
+ * still-`delivered` test. Best-effort, never throws.
1319
+ */
1320
+ flushEvents: (): void => {
1321
+ noThrow(() => this._getEngageTransport()?.flushEventsNow());
1322
+ },
1323
+
1324
+ /**
1325
+ * DEBUG/DEV ONLY — force a fresh config fetch (deviceId in context) and return the
1326
+ * in-app messages the backend is serving THIS device right now, including any
1327
+ * queued test previews (`preview:true`). Use it to verify Send Test targeting/
1328
+ * delivery without rendering. Logs a one-line summary for the dev console.
1329
+ */
1330
+ debugFetchInAppMessages: async (
1331
+ context?: EngageConfigContext,
1332
+ ): Promise<EngageConfigResponse['inAppMessages']> => {
1333
+ const cfg = await (this._getEngageTransport()?.fetchEngageConfig(context) ?? Promise.resolve(null));
1334
+ const messages = cfg?.inAppMessages ?? [];
1335
+ const previews = messages.filter((m) => m.preview === true || m.isTest === true);
1336
+ logger.info(
1337
+ `[Engage] debugFetchInAppMessages → ${messages.length} message(s), ${previews.length} test preview(s)`,
1338
+ );
1339
+ return messages;
1340
+ },
1341
+
1342
+ /** Upload a survey/NPS/feedback response (idempotent, rides the outbox). */
1343
+ submitResponse: (input: EngageResponseInput): void => {
1344
+ noThrow(() => this._getEngageTransport()?.uploadEngageResponse(input));
1345
+ },
1346
+
1347
+ /**
1348
+ * [P3-e] Submit a response carrying native attachments (screenshot/voice).
1349
+ * Presigns + PUTs bytes direct to storage, then enqueues the response with
1350
+ * key-only metadata linked by responseId. Falls back to a plain response
1351
+ * (no media) when storage is disabled. Best-effort, never throws.
1352
+ */
1353
+ submitResponseWithAttachments: (
1354
+ input: EngageResponseInput,
1355
+ attachments: EngageAttachmentDraft[],
1356
+ ): void => {
1357
+ noThrow(() => {
1358
+ void this._getEngageTransport()?.submitResponseWithAttachments(input, attachments);
1359
+ });
1360
+ },
1361
+
1362
+ /**
1363
+ * [Slice D5] CONFIRMED response submit for the in-prompt submitting→success→error
1364
+ * UI. UNLIKE submitResponse*, this AWAITS real server persistence (presign+PUT any
1365
+ * audio/screenshot bytes, then a direct response POST) and REJECTS on failure so the
1366
+ * caller can show a retryable error. Idempotent: pass the SAME `responseId` on retry
1367
+ * — both response and attachments de-dupe server-side. Used by EVERY question type.
1368
+ */
1369
+ submitResponseConfirmed: (
1370
+ input: EngageResponseInput,
1371
+ attachments: EngageAttachmentDraft[],
1372
+ opts: { responseId: string; onStage?: (stage: SubmitStage) => void },
1373
+ ): Promise<void> => {
1374
+ const transport = this._getEngageTransport();
1375
+ if (!transport) return Promise.reject(new Error('sdk_not_configured'));
1376
+ return transport.submitResponseConfirmed(input, attachments, opts);
1377
+ },
1378
+
1379
+ /** Upload an in-app impression/click/dismiss event (idempotent, rides the outbox). */
1380
+ trackEvent: (input: EngageEventInput): void => {
1381
+ noThrow(() => {
1382
+ const automaticName: Partial<Record<EngageEventInput['type'], AutomaticEventName>> = {
1383
+ impression: 'in_app_displayed',
1384
+ rendered: 'in_app_displayed',
1385
+ completion: 'in_app_completed',
1386
+ click: 'in_app_clicked',
1387
+ dismiss: 'in_app_dismissed',
1388
+ interaction: 'in_app_interaction',
1389
+ render_failed: 'in_app_render_failed',
1390
+ cta_open_failed: 'in_app_cta_open_failed',
1391
+ };
1392
+ const eventName = automaticName[input.type];
1393
+ if (eventName) {
1394
+ emitAutomaticEvent(eventName, {
1395
+ campaign_id: input.campaignId,
1396
+ variant_id: input.variantId,
1397
+ preview_id: input.previewId,
1398
+ is_test: input.isTest,
1399
+ source: input.source,
1400
+ interaction_type:
1401
+ typeof input.meta?.type === 'string'
1402
+ ? input.meta.type
1403
+ : undefined,
1404
+ });
1405
+ }
1406
+ this._getEngageTransport()?.uploadEngageEvent(input);
1407
+ });
1408
+ },
1409
+
1410
+ /** Upload an idempotent survey shown/started funnel beacon. */
1411
+ trackSurveyImpression: (input: SurveyImpressionInput): void => {
1412
+ noThrow(() => this._getEngageTransport()?.uploadSurveyImpression(input));
1413
+ },
1414
+
1415
+ /**
1416
+ * Emit a rating-funnel tracking event (ratings-rebuild CONTRACT §1.2). These
1417
+ * are dimensioned FACTS feeding the Overview funnel — NOT campaign responses
1418
+ * (D1) — so they ride their own `/ingestion/rating-events` lane. Idempotent
1419
+ * (client `eventId`, D8). Best-effort, never throws.
1420
+ */
1421
+ emitRatingEvent: (input: RatingFunnelEventInput): void => {
1422
+ noThrow(() => {
1423
+ emitAutomaticEvent(input.type, {
1424
+ prompt_id: input.promptId,
1425
+ trigger_id: input.triggerId,
1426
+ variant_id: input.variantId,
1427
+ stars: input.stars,
1428
+ });
1429
+ this._getEngageTransport()?.uploadRatingEvent(input);
1430
+ });
1431
+ },
1432
+
1433
+ /**
1434
+ * Trigger the native in-app review sheet (Play In-App Review on Android,
1435
+ * SKStoreReviewController on iOS) — the genuinely-native leg of the rating
1436
+ * funnel (D5). Resolves `true` ONLY when the OS flow ran/resolved after a
1437
+ * positive route, so the caller emits `store_redirect_clicked` solely on a
1438
+ * `true` result. Fail-soft: resolves `false` when native review is unavailable.
1439
+ */
1440
+ requestStoreReview: async (): Promise<boolean> => {
1441
+ return (await safeAsync(async () => requestNativeStoreReview())) ?? false;
1442
+ },
1443
+
1444
+ /**
1445
+ * Submit a 1–5 app-store rating via the EXISTING app-rating lane (D1 keeps
1446
+ * ratings a distinct funnel — NOT submitResponse). Delegates to the
1447
+ * facade's `submitRating`, threading the renderer's `clientRatingId` for
1448
+ * idempotency (D8). Used by the RATING_PROMPT render branch.
1449
+ */
1450
+ submitRating: (input: {
1451
+ rating: number;
1452
+ comment?: string;
1453
+ source?: 'in_app' | 'prompt' | 'manual';
1454
+ clientRatingId?: string;
1455
+ }): void => {
1456
+ noThrow(() => {
1457
+ void this.submitRating(input);
1458
+ });
1459
+ },
1460
+
1461
+ /**
1462
+ * Acquire the native push token (FCM/APNs) and register it for delivery.
1463
+ * Subscribes to native token-refresh (rotation) so the backend always holds
1464
+ * the live token. Fail-soft: no-op when native push is unavailable.
1465
+ */
1466
+ registerForPush: async (): Promise<void> => {
1467
+ return safeAsync(async () => {
1468
+ const transport = this._getEngageTransport();
1469
+ if (!transport) return;
1470
+
1471
+ const initial = await getNativePushToken();
1472
+ if (initial) {
1473
+ transport.registerDeviceToken({
1474
+ pushToken: initial.token,
1475
+ platform: initial.platform,
1476
+ pushProvider: initial.platform === 'ios' ? 'apns' : 'fcm',
1477
+ });
1478
+ }
1479
+
1480
+ // Avoid stacking listeners on repeated calls.
1481
+ this._engageTokenUnsubscribe?.();
1482
+ this._engageTokenUnsubscribe = subscribeNativePushTokenRefresh((refreshed) => {
1483
+ this._getEngageTransport()?.registerDeviceToken({
1484
+ pushToken: refreshed.token,
1485
+ platform: refreshed.platform,
1486
+ pushProvider: refreshed.platform === 'ios' ? 'apns' : 'fcm',
1487
+ });
1488
+ });
1489
+ }) as Promise<void>;
1490
+ },
1491
+ };
1492
+
1493
+ // ─── Push Notifications ─────────────────────────────────────────────
1494
+
1495
+ /**
1496
+ * Lazily build the PushManager. Backend token registration is injected and
1497
+ * routes through the existing Engage outbox (EngageTransport.registerDeviceToken),
1498
+ * so push reuses the SDK's single device-token lane rather than a parallel
1499
+ * fetch. Returns {ok:false} when the SDK isn't configured (clientKey absent).
1500
+ */
1501
+ private _getPushManager(): PushManager {
1502
+ if (!this._pushManager) {
1503
+ this._pushManager = new PushManager({
1504
+ registerToken: async (input) => {
1505
+ const transport = this._getEngageTransport();
1506
+ if (!transport) return { ok: false, reason: 'sdk_not_configured' as const };
1507
+ transport.registerDeviceToken({
1508
+ pushToken: input.pushToken,
1509
+ platform: input.platform,
1510
+ pushProvider: input.pushProvider,
1511
+ sdkVersion: SDK_VERSION,
1512
+ ...(this._eventTracker
1513
+ ? { installationId: this._eventTracker.getInstallationId() }
1514
+ : {}),
1515
+ });
1516
+ return { ok: true as const };
1517
+ },
1518
+ });
1519
+ }
1520
+ return this._pushManager;
1521
+ }
1522
+
1523
+ /**
1524
+ * Enable push notifications with smart, version-aware adapter selection.
1525
+ *
1526
+ * Detects the RN version, architecture (legacy bridge vs New
1527
+ * Architecture/bridgeless), whether @react-native-firebase/messaging is
1528
+ * installed & compatible, and whether the ScaleBunEngage native token bridge is
1529
+ * linked, then picks the safest supported path automatically: RNFirebase
1530
+ * (full callbacks) → native ScaleBunEngage bridge (token-only fallback that works
1531
+ * under bridgeless regardless of RNFirebase version) → manual → noop.
1532
+ *
1533
+ * Requests OS permission, creates the Android channel, acquires the push
1534
+ * token, keeps it in sync on refresh, registers it with the ScaleBun backend
1535
+ * (via the Engage outbox), and wires foreground/opened callbacks.
1536
+ *
1537
+ * Fails clearly (ok:false + actionable reason) when no usable provider
1538
+ * exists — never silently breaks. Never throws.
1539
+ *
1540
+ * ```ts
1541
+ * await ScaleBun.enablePush({
1542
+ * onForegroundNotification: (n) => {},
1543
+ * onNotificationOpened: (n) => {},
1544
+ * });
1545
+ * ```
1546
+ */
1547
+ public enablePush(options?: EnablePushOptions): Promise<EnablePushResult> {
1548
+ return this._getPushManager().enable(options ?? {});
1549
+ }
1550
+
1551
+ /**
1552
+ * Subscribe to notifications received while the app is foregrounded. Thin,
1553
+ * platform-agnostic alias for `enablePush({ onForegroundNotification })`; use it
1554
+ * to attach a handler after enablePush. Returns an unsubscribe function. Inert
1555
+ * until push is enabled. (iOS direct APNs delivers these via the native
1556
+ * UNUserNotificationCenter surface.)
1557
+ */
1558
+ public onForegroundNotification(cb: (notification: PushNotification) => void): () => void {
1559
+ return noThrow(() => this._getPushManager().onForegroundNotification(cb)) ?? (() => {});
1560
+ }
1561
+
1562
+ /**
1563
+ * Subscribe to the user tapping a notification (open / deep-link), including the
1564
+ * cold-start notification that launched the app. Thin alias for
1565
+ * `enablePush({ onNotificationOpened })`. Returns an unsubscribe function. The
1566
+ * event shape ({ data, title?, body? }) matches across Android and iOS.
1567
+ */
1568
+ public onNotificationOpened(cb: (notification: PushNotification) => void): () => void {
1569
+ return noThrow(() => this._getPushManager().onNotificationOpened(cb)) ?? (() => {});
1570
+ }
1571
+
1572
+ /**
1573
+ * Push control namespace. Most apps only need {@link enablePush}; these are
1574
+ * for the manual/custom provider path and diagnostics.
1575
+ */
1576
+ public push = {
1577
+ /** Inject/rotate a token (manual provider) — syncs to the backend. */
1578
+ setToken: (token: string): void => {
1579
+ noThrow(() => this._getPushManager().setToken(token));
1580
+ },
1581
+ /** Current push token, if acquired. */
1582
+ getToken: (): string | null => {
1583
+ return noThrow(() => this._getPushManager().getToken()) ?? null;
1584
+ },
1585
+ /** Deliver a foreground notification to registered callbacks (manual provider). */
1586
+ emitForeground: (message: PushNotification): void => {
1587
+ noThrow(() => this._getPushManager().emitForeground(message));
1588
+ },
1589
+ /** Deliver a notification-open event to registered callbacks (manual provider). */
1590
+ emitNotificationOpened: (message: PushNotification): void => {
1591
+ noThrow(() => this._getPushManager().emitNotificationOpened(message));
1592
+ },
1593
+ /** Current push status: selected adapter, usability, reason, token. */
1594
+ status: () => this._getPushManager().status(),
1595
+ /** Tear down all push listeners. */
1596
+ teardown: (): void => {
1597
+ noThrow(() => this._pushManager?.teardown());
1598
+ },
1599
+ };
1600
+
1601
+ // ─── Event Tracking ─────────────────────────────────────────────────
1602
+
1603
+ /**
1604
+ * Report the outcome of an OS permission prompt.
1605
+ *
1606
+ * Permission results were state the SDK held privately and never an event, so the core mobile
1607
+ * growth loop — "reached the paywall → was prompted → granted" — could not be expressed as a funnel.
1608
+ *
1609
+ * Notification permission is captured AUTOMATICALLY (the SDK runs that prompt itself, see
1610
+ * PushManager). Every other permission belongs to the host app: the SDK never sees a camera or
1611
+ * location request, so guessing at one would be inventing data. Call this right after the prompt
1612
+ * resolves:
1613
+ *
1614
+ * ```ts
1615
+ * const { status } = await Location.requestForegroundPermissionsAsync();
1616
+ * ScaleBun.trackPermission('location', status === 'granted' ? 'granted' : 'denied');
1617
+ * ```
1618
+ *
1619
+ * `permission` is free-form on purpose — platforms disagree on names and a fixed enum would go
1620
+ * stale — but stick to one spelling per permission or the funnel splits in two.
1621
+ */
1622
+ public trackPermission(
1623
+ permission: string,
1624
+ status: 'granted' | 'denied' | 'blocked' | 'undetermined' | 'limited',
1625
+ details?: Record<string, any>,
1626
+ ) {
1627
+ return noThrow(() => {
1628
+ const name = String(permission || '').trim();
1629
+ if (!name) return; // Nothing to attribute the result to — drop rather than emit a blank.
1630
+ emitAutomaticEvent('permission_result', {
1631
+ ...details,
1632
+ permission: name,
1633
+ status,
1634
+ // Distinguishes a host-reported result from the SDK's own push prompt.
1635
+ source: 'host',
1636
+ });
1637
+ });
1638
+ }
1639
+
1640
+ /** Track a named event with optional payload */
1641
+ public track(name: string, payload?: Record<string, any>) {
1642
+ return noThrow(() => {
1643
+ if (!this.initialized && !name.startsWith('$')) {
1644
+ logger.warn('SDK not initialized. Event dropped:', name);
1645
+ return;
1646
+ }
1647
+ logger.debug('Tracking event:', name);
1648
+
1649
+ // Fan this event out to the Engage trigger engine. Same single funnel,
1650
+ // extra observer — lets behavioral triggers (custom_event, failed_action,
1651
+ // after_crash, network_error, before_logout, …) fire off events the SDK
1652
+ // already produces, without a parallel capture pipeline.
1653
+ engageSignals.emit(name, payload);
1654
+
1655
+ const adapter = SessionManager.getExistingInstance()?.getBackendTransport();
1656
+ // Internal-only signals ($network_request, …) fan out to engage/perf/debug below but
1657
+ // are never uploaded as session events — their data already travels on a dedicated
1658
+ // lane (see INTERNAL_ONLY_SIGNALS in analytics/eventLane). The uploaded copy was pure
1659
+ // duplication: ~15% of measured mobile event volume, filtered out as noise by every
1660
+ // dashboard reader.
1661
+ if (!isUploadedSessionEvent(name)) {
1662
+ // fall through to the in-process consumers
1663
+ } else if (this._clientKey && adapter) {
1664
+ // SaaS mode → always-on analytics ingestion lane (NOT /sdk/events).
1665
+ // sessionId is stamped by the lane at flush time, so the call-time
1666
+ // value is a placeholder; endpoint id == body sessionId by construction.
1667
+ adapter.trackEvent({
1668
+ eventId: generateEventId(),
1669
+ sessionId: adapter.analyticsSessionId ?? '',
1670
+ ts: Date.now(),
1671
+ type: name === '$log' ? 'LOG_EMITTED' : 'USER_ACTION',
1672
+ subtype: name,
1673
+ payload,
1674
+ });
1675
+ } else {
1676
+ // Legacy mode (projectId/publishableKey): persistent queue → /sdk/events.
1677
+ const envelope = createEnvelope('event', { name, ...payload });
1678
+ this._getQueue().add(envelope);
1679
+ }
1680
+
1681
+ // Phase 1 analytics envelope lane (/batch → raw_events → events).
1682
+ // Runs alongside the session/replay lane above; only active when an
1683
+ // appId was configured at init. SDK-internal ($-prefixed) signals stay
1684
+ // on the session/debug lane and must not pollute the events table — the
1685
+ // split is owned by resolveEventLane (see analytics/eventLane).
1686
+ if (this._eventTracker && resolveEventLane(name) === 'analytics') {
1687
+ this._eventTracker.track(name, payload);
1688
+ }
1689
+
1690
+ // Tap into debug stream if enabled (non-blocking)
1691
+ const stream = _getStream();
1692
+ if (stream) {
1693
+ stream.tapEnvelope(createEnvelope('event', { name, ...payload }));
1694
+ }
1695
+
1696
+ // Tap network events into performance feature
1697
+ if (name === '$network_request' && this._performanceFeature?.isActive && payload) {
1698
+ this._performanceFeature.processNetworkEvent(payload);
1699
+ }
1700
+ });
1701
+ }
1702
+
1703
+ /**
1704
+ * Log a message. Delivered to BOTH lanes:
1705
+ * - the Diagnose → Logs lane (tagged `source: 'sdk'`), so an explicit `log()` call shows
1706
+ * up where a developer looks for logs. The method name promised this, but it previously
1707
+ * only emitted a `$log` analytics EVENT and never reached the Logs page.
1708
+ * - the analytics `$log` event (unchanged), so anything already built on it keeps working.
1709
+ * `queueLog` self-gates on `clientKey`, so the Logs-lane write is a no-op outside SaaS mode.
1710
+ */
1711
+ public log(level: 'debug' | 'info' | 'warn' | 'error', message: string, data?: Record<string, unknown>) {
1712
+ try {
1713
+ const transport = SessionManager.getExistingInstance()?.getBackendTransport();
1714
+ transport?.queueLog({
1715
+ level,
1716
+ message,
1717
+ source: 'sdk',
1718
+ platform: 'js',
1719
+ timestamp: new Date().toISOString(),
1720
+ ...(data ? { metadata: data } : {}),
1721
+ });
1722
+ } catch { /* no-throw: a logging call must never break the host app */ }
1723
+ return this.track('$log', { level, message, ...data });
1724
+ }
1725
+
1726
+ /**
1727
+ * Capture a handled error/exception and deliver it to the backend
1728
+ * errors endpoint (shows up in the dashboard Crashes view).
1729
+ *
1730
+ * No-throw. Routes to: desktop debug stream ($crash event) + SaaS
1731
+ * backend errors ingestion (when a clientKey session is active).
1732
+ */
1733
+ public captureError(
1734
+ error: Error | string,
1735
+ context?: { screenName?: string; fatal?: boolean; type?: string; metadata?: Record<string, unknown> },
1736
+ ) {
1737
+ return noThrow(() => {
1738
+ const err = typeof error === 'string' ? new Error(error) : error;
1739
+ const isFatal = context?.fatal ?? false;
1740
+
1741
+ getCrashReporter().report({
1742
+ source: 'handled',
1743
+ type: context?.type ?? (isFatal ? 'crash' : 'handled'),
1744
+ isFatal,
1745
+ message: err.message,
1746
+ stack: err.stack,
1747
+ screenName: context?.screenName,
1748
+ metadata: context?.metadata,
1749
+ });
1750
+
1751
+ // Flush the event queue (desktop $crash) too
1752
+ this.flush().catch(() => {});
1753
+ });
1754
+ }
1755
+
1756
+ /**
1757
+ * DEV/TEST ONLY — trigger a real native crash to validate the native
1758
+ * capture → next-launch drain → backend pipeline. No-op when the native
1759
+ * module is unavailable. Do not ship calls to this in production code.
1760
+ */
1761
+ public nativeCrash() {
1762
+ return noThrow(() => triggerNativeCrash());
1763
+ }
1764
+
1765
+ /** Report a bug (convenience wrapper over track) */
1766
+ public reportBug(description: string, metadata?: Record<string, unknown>) {
1767
+ // D11: this used to be ONLY `track('$bug_report')` — an analytics event
1768
+ // with zero consumers (no mapper, no handler, no BugReport row), so
1769
+ // /diagnose/bug-reports stayed empty forever for RN apps while the web
1770
+ // SDK used the real ingest. Route to the same endpoint the web SDK
1771
+ // uses; the analytics event is kept as a breadcrumb, not the delivery.
1772
+ try {
1773
+ const transport = SessionManager.getExistingInstance()?.getBackendTransport();
1774
+ transport?.submitBugReport({
1775
+ message: description,
1776
+ title:
1777
+ typeof metadata?.title === 'string' ? (metadata.title as string) : undefined,
1778
+ email:
1779
+ typeof metadata?.email === 'string' ? (metadata.email as string) : undefined,
1780
+ });
1781
+ } catch {
1782
+ /* delivery is best-effort; the track below still records intent */
1783
+ }
1784
+ return this.track('$bug_report', { description, ...metadata });
1785
+ }
1786
+
1787
+ /** Set a custom attribute on the current session */
1788
+ public setAttribute(key: string, value: string | number | boolean) {
1789
+ return this.track('$set_attribute', { key, value });
1790
+ }
1791
+
1792
+ // ─── Flush ──────────────────────────────────────────────────────────
1793
+
1794
+ /** Force-flush all pending events */
1795
+ public async flush() {
1796
+ return safeAsync(async () => {
1797
+ if (!this.initialized) return;
1798
+ // SaaS mode has two analytics lanes: EventTracker writes normalized
1799
+ // product events to /batch, while BackendSessionAdapter writes the
1800
+ // matching timeline events to /ingestion/sessions/:id/events. Drain
1801
+ // both before an app background/navigation can suspend their timers.
1802
+ // The legacy persistent queue posts to /sdk/events, which the SaaS
1803
+ // backend does not serve, so it remains exclusive to legacy mode.
1804
+ if (this._clientKey) {
1805
+ const adapter = SessionManager.getExistingInstance()?.getBackendTransport();
1806
+ await Promise.all([
1807
+ this._eventTracker?.flush() ?? Promise.resolve(),
1808
+ adapter?.flushAnalytics() ?? Promise.resolve(),
1809
+ ]);
1810
+ return;
1811
+ }
1812
+ logger.debug('Flushing events from persistent queue...');
1813
+ const httpClient = coreContainer.get<HttpClient>('HttpClient');
1814
+ await flushQueue(this._getQueue(), httpClient, getDeviceId());
1815
+ });
1816
+ }
1817
+
1818
+ /**
1819
+ * Enable the debug subsystem.
1820
+ *
1821
+ * @deprecated Use `ScaleBun.init({ debug: true })` instead.
1822
+ * This method still works for backward compatibility.
1823
+ */
1824
+ public enableDebug(config: DebugConfig) {
1825
+ return noThrow(() => {
1826
+ if (!(config as any).__skipDeprecationWarning) {
1827
+ logger.warn(
1828
+ '[ScaleBun] enableDebug() is deprecated. ' +
1829
+ 'Use ScaleBun.init({ ..., debug: true }) instead.',
1830
+ );
1831
+ }
1832
+
1833
+ const gatedConfig = applyFeatureGatesToDebugConfig(config, this._features);
1834
+ _enableDebug(gatedConfig);
1835
+ _setFlushFn(() => this.flush() as Promise<void>);
1836
+
1837
+ const bootstrapPerfFeature = _getPerformanceFeature();
1838
+ if (bootstrapPerfFeature) {
1839
+ this._performanceFeature = bootstrapPerfFeature;
1840
+ logger.debug('Performance feature linked from bootstrap');
1841
+ }
1842
+
1843
+ logger.info('Debug enabled');
1844
+ });
1845
+ }
1846
+
1847
+ /** Disable the debug subsystem and clean up */
1848
+ public disableDebug() {
1849
+ return noThrow(() => {
1850
+ _disableDebug();
1851
+ });
1852
+ }
1853
+
1854
+ /**
1855
+ * Diagnostic-only: stamp the *expected* target for the very next gesture
1856
+ * event. Calibration screens call this immediately before their onPress
1857
+ * fires so SessionManager merges expectedTargetId / expectedNX / expectedNY
1858
+ * into the stored gesture payload. Pure observability — never affects
1859
+ * capture, normalization, or marker placement. TTL ≈ 500 ms.
1860
+ */
1861
+ public setCalibrationTarget(target: { targetId: string; expectedNX: number; expectedNY: number }): void {
1862
+ noThrow(() => {
1863
+ const mod = require('../features/journey/calibrationContext') as
1864
+ typeof import('../features/journey/calibrationContext');
1865
+ mod.setCalibrationTarget(target);
1866
+ });
1867
+ }
1868
+
1869
+ /**
1870
+ * Debug utilities namespace.
1871
+ * All methods are no-op if debug is not enabled.
1872
+ */
1873
+ public debug = {
1874
+ addBreadcrumb: (message: string, data?: Record<string, unknown>) => {
1875
+ noThrow(() => _addBreadcrumb(message, data));
1876
+ },
1877
+ ping: () => {
1878
+ noThrow(() => _ping());
1879
+ },
1880
+ isEnabled: () => isDebugEnabled(),
1881
+ sendMetric: (name: string, value: number, unit?: string, tags?: Record<string, string>) => {
1882
+ sendDebugMetric(name, value, unit, tags);
1883
+ },
1884
+ };
1885
+
1886
+ // ─── Replay ─────────────────────────────────────────────────────────
1887
+
1888
+ /**
1889
+ * Session Replay namespace.
1890
+ * Provides control over session replay: recording, capture,
1891
+ * user identity, privacy, breadcrumbs, and transport.
1892
+ * All methods are no-op if replay feature is disabled.
1893
+ */
1894
+ public replay = {
1895
+ start: (): Promise<void> => ReplaySdk.start(),
1896
+ stop: (): Promise<void> => ReplaySdk.stop(),
1897
+ pause: (): Promise<void> => ReplaySdk.pause(),
1898
+ resume: (): Promise<void> => ReplaySdk.resume(),
1899
+ captureFrame: (): Promise<void> => ReplaySdk.captureManualFrame(),
1900
+ setUser: (user: ReplayUser): Promise<void> => ReplaySdk.setUser(user),
1901
+ clearUser: (): Promise<void> => ReplaySdk.clearUser(),
1902
+ addBreadcrumb: (breadcrumb: ReplayBreadcrumb): Promise<void> =>
1903
+ ReplaySdk.addBreadcrumb(breadcrumb),
1904
+ setPrivacy: (opts: Partial<ReplayPrivacyOptions>): Promise<void> =>
1905
+ ReplaySdk.setPrivacyOptions(opts),
1906
+ setEnabled: (enabled: boolean): Promise<void> => ReplaySdk.setEnabled(enabled),
1907
+ setQuality: (quality: any): Promise<void> => ReplaySdk.setScreenshotQuality(quality),
1908
+ setCaptureMode: (mode: any): Promise<void> => ReplaySdk.setCapturingMode(mode),
1909
+ setScreen: (name: string): Promise<void> => ReplaySdk.setCurrentScreen(name),
1910
+ flush: (): Promise<void> => ReplaySdk.flush(),
1911
+ get isRecording(): boolean {
1912
+ return ReplaySdk.isRecording;
1913
+ },
1914
+ get sessionId(): string | null {
1915
+ return ReplaySdk.sessionId;
1916
+ },
1917
+ };
1918
+
1919
+ // ─── Performance ────────────────────────────────────────────────────
1920
+
1921
+ /**
1922
+ * Performance monitoring namespace.
1923
+ * Provides control over custom traces, screen load markers,
1924
+ * and access to captured metrics.
1925
+ * All methods are no-op if performance feature is disabled.
1926
+ */
1927
+ public performance = {
1928
+ /** Start a custom trace. Returns traceId or null. */
1929
+ startTrace: (name: string): string | null => {
1930
+ return this._performanceFeature?.startTrace(name) ?? null;
1931
+ },
1932
+ /** Stop a custom trace by ID. */
1933
+ stopTrace: (traceId: string): void => {
1934
+ this._performanceFeature?.stopTrace(traceId);
1935
+ },
1936
+ /** Add a span to an active custom trace. */
1937
+ addTraceSpan: (traceId: string, name: string, durationMs: number, data?: Record<string, unknown>): void => {
1938
+ this._performanceFeature?.addTraceSpan(traceId, name, durationMs, data);
1939
+ },
1940
+ /** Attach a measurement to an active custom trace. */
1941
+ addTraceMeasurement: (traceId: string, name: string, value: number, unit: string): void => {
1942
+ this._performanceFeature?.addTraceMeasurement(traceId, name, value, unit);
1943
+ },
1944
+ /** Mark the start of a screen load. */
1945
+ markScreenLoadStart: (screenName: string): void => {
1946
+ this._performanceFeature?.markScreenLoadStart(screenName);
1947
+ },
1948
+ /** Mark the end of a screen load. */
1949
+ markScreenLoadEnd: (screenName: string): void => {
1950
+ this._performanceFeature?.markScreenLoadEnd(screenName);
1951
+ },
1952
+ /** Set the current screen for context correlation. */
1953
+ setCurrentScreen: (screenName: string): void => {
1954
+ this._performanceFeature?.setCurrentScreen(screenName);
1955
+ },
1956
+ /** Forward navigation state changes for auto screen load detection. */
1957
+ onNavigationStateChange: (state: unknown): void => {
1958
+ this._performanceFeature?.onNavigationStateChange(state);
1959
+ },
1960
+ /** Check if performance monitoring is active */
1961
+ isActive: (): boolean => {
1962
+ return this._performanceFeature?.isActive ?? false;
1963
+ },
1964
+ /**
1965
+ * Send a raw performance metric through the transport.
1966
+ * Used for manual/simulated performance metrics.
1967
+ */
1968
+ sendMetric: (name: string, value: number, unit?: string, tags?: Record<string, string>): void => {
1969
+ if (!this._performanceFeature) {
1970
+ logger.warn('performance.sendMetric: PerformanceFeature not available — is debug enabled?');
1971
+ return;
1972
+ }
1973
+ this._performanceFeature.sendMetric(name, value, unit, tags);
1974
+ },
1975
+ };
1976
+
1977
+ // ─── Unified Session ────────────────────────────────────────────────
1978
+
1979
+ /**
1980
+ * Unified Session namespace.
1981
+ * Provides access to the unified SessionManager.
1982
+ * Sessions auto-start on desktop connect.
1983
+ */
1984
+ public session = {
1985
+ get isActive(): boolean {
1986
+ return SessionManager.getExistingInstance()?.isActive ?? false;
1987
+ },
1988
+ get currentSessionId(): string | null {
1989
+ return SessionManager.getExistingInstance()?.currentSessionId ?? null;
1990
+ },
1991
+ start: (metadata?: Record<string, unknown>): boolean => {
1992
+ const sm = SessionManager.getExistingInstance();
1993
+ if (!sm) {
1994
+ logger.warn('session.start() — SessionManager not available.');
1995
+ return false;
1996
+ }
1997
+ sm.startSession(metadata as Parameters<SessionManager['startSession']>[0]);
1998
+ logger.info('session.start() ✅ sessionId:', sm.currentSessionId);
1999
+ return true;
2000
+ },
2001
+ end: (reason?: 'ended' | 'timeout'): boolean => {
2002
+ const sm = SessionManager.getExistingInstance();
2003
+ if (!sm || !sm.isActive) return false;
2004
+ sm.endSession(reason);
2005
+ logger.info('session.end() ✅');
2006
+ return true;
2007
+ },
2008
+ emitEvent: (type: string, data?: Record<string, unknown>) => {
2009
+ const sm = SessionManager.getExistingInstance();
2010
+ if (!sm || !sm.isActive) return;
2011
+ sm.emitEvent(type as JourneyEventType, data as Parameters<SessionManager['emitEvent']>[1]);
2012
+ },
2013
+ };
2014
+
2015
+ // ─── Session Convenience Methods ────────────────────────────────────
2016
+
2017
+ /** Start a session (delegates to session namespace) */
2018
+ public startSession(metadata?: Record<string, unknown>): boolean {
2019
+ return this.session.start(metadata);
2020
+ }
2021
+
2022
+ /** Stop the current session (delegates to session namespace) */
2023
+ public stopSession(reason?: 'ended' | 'timeout'): boolean {
2024
+ return this.session.end(reason);
2025
+ }
2026
+
2027
+ // ─── Report / Export ───────────────────────────────────────────
2028
+
2029
+ /**
2030
+ * Report generation and export namespace.
2031
+ *
2032
+ * Usage:
2033
+ * ```ts
2034
+ * // Export with default preset
2035
+ * const result = await ScaleBun.report.export();
2036
+ *
2037
+ * // Export with a named preset
2038
+ * const result = await ScaleBun.report.export('engineering');
2039
+ *
2040
+ * // Export with custom options
2041
+ * const result = await ScaleBun.report.export({ format: 'pdf', detail: 'detailed' });
2042
+ * ```
2043
+ *
2044
+ * Requires an active desktop debug connection (`debug: true` in init).
2045
+ */
2046
+ public report = {
2047
+ /**
2048
+ * Trigger a report export on the desktop application.
2049
+ *
2050
+ * @param presetOrOptions - Optional. A preset name ('executive', 'engineering', 'qa',
2051
+ * 'forensic', 'journey', 'compact') or a SimplifiedExportOptions object.
2052
+ * @returns Promise<ExportResult> with success status, file path, or error.
2053
+ */
2054
+ export: (presetOrOptions?: ExportPresetName | SimplifiedExportOptions): Promise<ExportResult> => {
2055
+ return _requestExport(presetOrOptions);
2056
+ },
2057
+
2058
+ /** Set SDK-wide privacy settings for report generation. */
2059
+ setPrivacy: (config: PrivacyConfig): void => {
2060
+ this._privacyConfig = { ...this._privacyConfig, ...config };
2061
+ logger.debug('[report] Privacy config updated');
2062
+ },
2063
+
2064
+ /** Set branding for exported reports. */
2065
+ setBranding: (config: BrandingConfig): void => {
2066
+ this._brandingConfig = { ...this._brandingConfig, ...config };
2067
+ logger.debug('[report] Branding config updated');
2068
+ },
2069
+
2070
+ /** Get current privacy config. */
2071
+ getPrivacy: (): PrivacyConfig => ({ ...this._privacyConfig }),
2072
+
2073
+ /** Get current branding config. */
2074
+ getBranding: (): BrandingConfig => ({ ...this._brandingConfig }),
2075
+ };
2076
+
2077
+ // ─── Navigation ───────────────────────────────────────────────
2078
+
2079
+ /**
2080
+ * Set the React Navigation container ref for automatic screen detection.
2081
+ *
2082
+ * This is the **recommended** way to enable auto screen detection.
2083
+ * Once set, the SDK automatically detects screen changes and feeds them
2084
+ * to all subsystems (SessionManager, PerformanceFeature, ProfilerFeature).
2085
+ * No per-screen `<ScaleBunScreen>` or `useScaleBunScreen()` needed.
2086
+ *
2087
+ * ```ts
2088
+ * import { NavigationContainer } from '@react-navigation/native';
2089
+ * import ScaleBun from '@scalebun/react-native';
2090
+ *
2091
+ * const navigationRef = React.createRef();
2092
+ *
2093
+ * function App() {
2094
+ * useEffect(() => {
2095
+ * ScaleBun.setNavigationRef(navigationRef);
2096
+ * }, []);
2097
+ *
2098
+ * return (
2099
+ * <NavigationContainer ref={navigationRef}>
2100
+ * ...screens...
2101
+ * </NavigationContainer>
2102
+ * );
2103
+ * }
2104
+ * ```
2105
+ */
2106
+ public setNavigationRef(ref: any): void {
2107
+ noThrow(() => {
2108
+ // Always stash on the global so heuristic polling / late consumers resolve it.
2109
+ (globalThis as any).__scalebun_navigationRef = ref;
2110
+
2111
+ // Wire the LIVE AutoScreenDetector singleton (started by SDKBootstrapper in
2112
+ // production). _getAutoScreenDetector() is the debug-only handle and is null
2113
+ // when desktopDebug is off, so relying on it alone never wires the explicit
2114
+ // React-Navigation 'state' listener and degrades to slow heuristic polling.
2115
+ try {
2116
+ const { AutoScreenDetector } = require('../features/navigation/AutoScreenDetector');
2117
+ AutoScreenDetector.getInstance().setNavigationRef(ref);
2118
+ logger.info('[ScaleBun] Navigation ref set → auto screen detection active');
2119
+ } catch (err: any) {
2120
+ logger.debug('[ScaleBun] Navigation ref stashed (detector not ready):', err?.message);
2121
+ }
2122
+ });
2123
+ }
2124
+ }
2125
+
2126
+ /** Singleton Facade instance */
2127
+ const instance = new ScaleBunFacade();
2128
+ export default instance;
2129
+ export { ScaleBunFacade };