@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,1513 @@
1
+ import {
2
+ AppState,
3
+ DeviceEventEmitter,
4
+ DevSettings,
5
+ NativeEventEmitter,
6
+ NativeModules,
7
+ Platform,
8
+ } from 'react-native';
9
+ import { logger } from '../../core/logger/internalLogger';
10
+ import { noThrow } from '../../core/lifecycle/crashSafe';
11
+ import NativeScaleBunOta from '../../specs/NativeScaleBunOta';
12
+ import type { OtaCheckRequest, OtaCheckResponse, OtaBundlePayload } from './OtaTypes';
13
+ import { otaEventEmitter } from './OtaEventEmitter';
14
+ import { getDeviceCountry, prefetchDeviceCountry } from './geoCountry';
15
+ import { deviceTargetingAttributes } from './deviceAttributes';
16
+ import { resolveInstallationId } from '../../core/id/installationId';
17
+ import { detectOtaEnvironment, type OtaEnvironment } from './environment';
18
+ import { retryWithBackoff, isRetryableNetworkError, HttpStatusError } from './retry';
19
+ import {
20
+ stageSignedWithRetry,
21
+ verdictErrorCode,
22
+ signedPatchSupported,
23
+ trySignedPatch,
24
+ type StageVerdict,
25
+ } from './signedDownload';
26
+ import { createStorageBackend, type StorageBackend } from '../../storage/StorageBackend';
27
+ import { resolveMobileOS } from '../../core/context/device';
28
+
29
+ /**
30
+ * Identity marker injected into the bundle by `scalebun ota publish` before
31
+ * Hermes compilation. Lets the SDK prove that the bundle it *installed* is the
32
+ * bundle actually *running* — see `verifyRunningBundleIdentity`.
33
+ */
34
+ function readRunningBundleMarker(): string | null {
35
+ try {
36
+ const id = (globalThis as unknown as { __SCALEBUN_OTA_ID__?: string }).__SCALEBUN_OTA_ID__;
37
+ return typeof id === 'string' && id.length > 0 ? id : null;
38
+ } catch {
39
+ return null;
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Download progress: native → JS → (hook + backend live tracker).
45
+ *
46
+ * Both native downloaders emit throttled `ScaleBunOtaProgress` ticks — Android
47
+ * over `RCTDeviceEventEmitter`, iOS via the `ScaleBunOtaEvents` RCTEventEmitter.
48
+ * This subscribes for the duration of one download. Until this existed, the
49
+ * hook's `downloadProgress` and the backend's `/sdk/ota/progress` +
50
+ * live-downloads dashboard were declared on both ends and connected by
51
+ * NOTHING — the tracker had never received a single real row.
52
+ */
53
+ interface NativeProgressTick {
54
+ bytesRead: number;
55
+ /** -1 when the server sent no usable length (chunked / gzip). */
56
+ totalBytes: number;
57
+ }
58
+
59
+ function subscribeNativeProgress(
60
+ onTick: (tick: NativeProgressTick) => void,
61
+ ): () => void {
62
+ try {
63
+ if (Platform.OS === 'ios') {
64
+ const eventsModule = NativeModules.ScaleBunOtaEvents;
65
+ if (!eventsModule) return () => {};
66
+ const emitter = new NativeEventEmitter(eventsModule);
67
+ const sub = emitter.addListener('ScaleBunOtaProgress', onTick);
68
+ return () => sub.remove();
69
+ }
70
+ const sub = DeviceEventEmitter.addListener('ScaleBunOtaProgress', onTick);
71
+ return () => sub.remove();
72
+ } catch {
73
+ return () => {};
74
+ }
75
+ }
76
+
77
+ /** POST at most once per this interval; first and terminal ticks always go. */
78
+ const PROGRESS_POST_INTERVAL_MS = 1_000;
79
+
80
+
81
+ /**
82
+ * Deliver queued OTA lifecycle events to the backend's batch endpoint.
83
+ *
84
+ * ── Why the orchestrator owns this ──────────────────────────────────────────
85
+ *
86
+ * `otaEventEmitter.setFlushCallback` documents itself as "called by the SDK
87
+ * core to wire into the existing batch transport" — and nothing, anywhere,
88
+ * ever called it. `flush()` drained the queue into a null callback, so every
89
+ * OTA event the real SDK ever emitted was silently discarded in-process.
90
+ * All 129 ota_events rows in the dev database came from the test app's
91
+ * SIMULATOR; the funnel, adoption charts, and guard thresholds had never seen
92
+ * one byte of real-device telemetry.
93
+ *
94
+ * Owning delivery here (with the params sync() already has) instead of relying
95
+ * on bootstrap wiring means OTA telemetry works in every integration shape —
96
+ * full SDK, standalone orchestrator, CodePush shim — because the component
97
+ * that EMITS the events is the component that delivers them.
98
+ */
99
+ async function deliverOtaEvents(params: {
100
+ apiUrl: string;
101
+ clientKey: string;
102
+ appVersion: string;
103
+ installationId: string;
104
+ }): Promise<void> {
105
+ const events = otaEventEmitter.flush();
106
+ if (!events.length) return;
107
+ // A platform OTA cannot serve is not reported as Android — it is not reported at all.
108
+ const mobileOS = resolveMobileOS();
109
+ if (!mobileOS) return;
110
+
111
+ const items = events.map((e) => ({
112
+ kind: 'ota_event' as const,
113
+ type: e.type,
114
+ bundleId: e.bundleId,
115
+ // Without this the backend stored a null releaseId on every row it ingested,
116
+ // while serving the release id on every check — so the delivery funnel could
117
+ // only ever be grouped by bundle, and a bundle re-promoted under a second
118
+ // release merged the two into one indistinguishable series.
119
+ releaseId: e.releaseId,
120
+ installationId: params.installationId,
121
+ // OTA bundles are compiled per platform, so this genuinely is ios|android. Narrowed via
122
+ // resolveMobileOS so a non-mobile RN target is skipped rather than served an Android bundle.
123
+ platform: mobileOS,
124
+ appVersion: params.appVersion,
125
+ durationMs: e.durationMs,
126
+ errorCode: e.error ?? e.reason,
127
+ patchUsed: e.patchUsed,
128
+ timestamp: e.timestamp,
129
+ }));
130
+
131
+ try {
132
+ const base = params.apiUrl.replace(/\/+$/, '');
133
+ // The batch lane is session-scoped for replay items; OTA rows carry their
134
+ // own installationId and ignore the session, so a synthetic id is correct.
135
+ const res = await fetch(
136
+ `${base}/ingestion/sessions/ota-${params.installationId}/batch`,
137
+ {
138
+ method: 'POST',
139
+ headers: {
140
+ 'Content-Type': 'application/json',
141
+ 'x-scalebun-client-key': params.clientKey,
142
+ },
143
+ body: JSON.stringify({ items }),
144
+ },
145
+ );
146
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
147
+ logger.debug(`[OTA] Delivered ${items.length} telemetry event(s)`);
148
+ } catch (err: any) {
149
+ // Failed delivery must not fail the update — but the events must not be
150
+ // lost either: requeue so the next sync retries them.
151
+ for (const e of events) otaEventEmitter.emit(e);
152
+ logger.debug(`[OTA] Telemetry delivery failed (will retry next sync): ${err?.message}`);
153
+ }
154
+ }
155
+
156
+ export interface SyncResult {
157
+ /**
158
+ * `WITHHELD` means the device reported root/jailbreak indicators and the host
159
+ * configured `onCompromisedDevice: 'withhold'`. It is NOT `UP_TO_DATE`: the
160
+ * device may well be behind, we simply declined to find out. Collapsing the
161
+ * two would make a withheld fleet indistinguishable from a current one.
162
+ */
163
+ status:
164
+ | 'UP_TO_DATE'
165
+ | 'UPDATE_INSTALLED'
166
+ | 'ROLLED_BACK'
167
+ | 'ERROR'
168
+ | 'WITHHELD';
169
+ bundle?: OtaBundlePayload;
170
+ error?: string;
171
+ /** True when the server-side release has isMandatory set */
172
+ isMandatory?: boolean;
173
+ }
174
+
175
+ /** Boot-guard configuration */
176
+ export interface BootGuardConfig {
177
+ /**
178
+ * Milliseconds the app must run without crashing after an OTA update
179
+ * before the boot-guard marker is cleared. Default: 10_000 (10s).
180
+ */
181
+ healthyAfterMs?: number;
182
+ /**
183
+ * @deprecated Not honoured, and never was — nothing in JS reads this field.
184
+ *
185
+ * The boot-attempt limit lives in native code, where the counter it bounds is
186
+ * incremented (`MAX_BOOT_ATTEMPTS` in `SlotManager.kt` / `OtaSlotManager.swift`,
187
+ * both 2). Setting it here has no effect; the field is kept only so existing
188
+ * call sites keep compiling. Change the limit natively, or file a request for
189
+ * it to be plumbed through `initOutbox`-style native config.
190
+ */
191
+ maxRevertAttempts?: number;
192
+ /**
193
+ * What to do when the device reports root/jailbreak indicators.
194
+ *
195
+ * 'allow' — DEFAULT. Check, download and install as normal. The
196
+ * indicators are still detected, still logged, and still sent
197
+ * with the check request as telemetry.
198
+ * 'withhold' — Do not check for or install updates on this device. The
199
+ * device stays on whatever bundle it is already running.
200
+ *
201
+ * The default is `'allow'` and must stay `'allow'`. Flipping it would
202
+ * silently stop updates for every existing host app — including the ones
203
+ * whose "indicators" are a developer's test-keys build or a false positive —
204
+ * which is a far worse outcome than the risk it mitigates. Withholding is an
205
+ * opt-in a security-sensitive host makes with knowledge of its own users.
206
+ *
207
+ * What this is and is not: root defeats any check made from inside the app,
208
+ * so this is a POLICY, not a security boundary. A rooted device can patch the
209
+ * check out. What it does buy is that the SDK stops handing fresh, signed
210
+ * bundles to a device whose OTA slot other privileged processes can rewrite,
211
+ * and that the decision is auditable — an `UPDATE_WITHHELD` OTA event is
212
+ * emitted every time it fires, so the host never has to infer it from
213
+ * silence.
214
+ *
215
+ * Mobile only by nature. The web SDK ships no OTA lane at all — there is no
216
+ * bundle slot on a device to protect and no web counterpart to this flag.
217
+ */
218
+ onCompromisedDevice?: 'allow' | 'withhold';
219
+ }
220
+
221
+ import { resolveCompromisedDevicePolicy } from '../../config/otaPolicyState';
222
+
223
+ const DEFAULT_HEALTHY_AFTER_MS = 10_000;
224
+
225
+ export class OtaOrchestrator {
226
+ private enabled = false;
227
+ private currentBundle: OtaBundlePayload | null = null;
228
+
229
+ /**
230
+ * The bundle this process is running, once hydrated from the native slots.
231
+ * Read-only view for integrations (e.g. the CodePush shim's
232
+ * getUpdateMetadata) that need to report the running version.
233
+ */
234
+ public getCurrentBundle(): OtaBundlePayload | null {
235
+ return this.currentBundle;
236
+ }
237
+ private isRestartRequiredState = false;
238
+
239
+ /**
240
+ * The sync currently running, if any. sync() had NO concurrency control:
241
+ * every caller started a full check/download/stage/apply cycle against the
242
+ * SAME slot directories. Two of them overlapping is not a wasted request,
243
+ * it is a corrupted install — native stage() ends with "remove next/,
244
+ * rename tmp -> next/" while apply() is doing "move next/ -> current/", so
245
+ * one racing the other throws and apply() can leave NO current/ slot at
246
+ * all. A host with a screen that syncs on mount and another that syncs on
247
+ * foreground reproduces this in seconds; on 2026-09-21 it cost two devices
248
+ * that could only be recovered by reinstalling.
249
+ */
250
+ private syncInFlight: Promise<SyncResult> | null = null;
251
+
252
+ /** When the last network check actually went out (see MIN_CHECK_INTERVAL_MS). */
253
+ private lastCheckAt = 0;
254
+
255
+ /**
256
+ * A bundle that is staged and waiting for its restart.
257
+ *
258
+ * Kept SEPARATE from `currentBundle`, which must keep naming the bundle
259
+ * this process is actually executing. Overwriting `currentBundle` at apply
260
+ * time told the server the device was already running code it had never
261
+ * run, so the next check was answered with the NEXT release instead of
262
+ * "up to date" — which is how a single launch chained three installs. It
263
+ * also mis-attributed every CHECK and BOOT_SUCCESS event to a bundle the
264
+ * device had not booted.
265
+ */
266
+ private pendingBundle: OtaBundlePayload | null = null;
267
+ /** Root/jailbreak indicators observed at init; empty when none found. */
268
+ private integrityIndicators: string[] = [];
269
+ /**
270
+ * The native detector was actually asked and answered on this launch.
271
+ *
272
+ * Kept separate from an empty `integrityIndicators` because the two are not
273
+ * the same fact: `false` means never measured (no native module, or the read
274
+ * threw), `true` with an empty list means measured and clean. Reporting the
275
+ * first as the second would show an unmeasured fleet as a clean one.
276
+ */
277
+ private integrityMeasured = false;
278
+ private healthyTimer: ReturnType<typeof setTimeout> | null = null;
279
+ private bootGuardConfig: BootGuardConfig = {};
280
+ private environment: OtaEnvironment | null = null;
281
+ /** One-time boot checks have run in this process (init is idempotent). */
282
+ private initialized = false;
283
+ private storageBackend: StorageBackend | null = null;
284
+
285
+ /**
286
+ * Initialize the orchestrator. Checks for boot-guard recovery state.
287
+ *
288
+ * Signature enforcement is no longer a JS concern: signed releases are
289
+ * verified and staged in NATIVE code against RSA keys embedded in the app
290
+ * package (SB-OTA-RSA-SHA256-V1), and unsigned releases keep working on
291
+ * SHA-256 integrity alone. There is nothing for the host to configure here.
292
+ */
293
+ init(config?: BootGuardConfig): void {
294
+ noThrow(() => {
295
+ // Idempotent: init() runs its one-time checks ONCE per process. Found
296
+ // live — a host that calls init() again after installing an update (any
297
+ // retry/re-entry path does this) re-runs the identity verification in a
298
+ // process whose running JS legitimately predates the install, producing
299
+ // a false "INSTALL DID NOT TAKE EFFECT" alarm. The boot-time checks are
300
+ // only meaningful in a fresh process; a second init() must not repeat
301
+ // them. Config is still refreshed so late signature setup works.
302
+ if (this.initialized) {
303
+ this.bootGuardConfig = config ?? this.bootGuardConfig;
304
+ return;
305
+ }
306
+
307
+ if (!NativeScaleBunOta) {
308
+ logger.warn('[OTA] NativeScaleBunOta module unavailable — OTA disabled');
309
+ return;
310
+ }
311
+
312
+ // ── RUNTIME GATE ─────────────────────────────────────────────────────
313
+ // Refuse to run on a runtime where the install would silently no-op.
314
+ // See environment.ts: bridgeless below RN 0.76.1 ignores
315
+ // getJSBundleFile() entirely, so a bundle installs, reports INSTALLED,
316
+ // and the app keeps running the APK asset. Staying loudly disabled is
317
+ // strictly better than reporting success that never happened — those
318
+ // false INSTALLED rows feed adoption metrics and guard thresholds.
319
+ this.environment = detectOtaEnvironment();
320
+ if (!this.environment.supported) {
321
+ logger.error(`[OTA] DISABLED — ${this.environment.blockReason}`);
322
+ this.enabled = false;
323
+ return;
324
+ }
325
+ if (this.environment.bridgeless && !this.environment.rnVersion) {
326
+ logger.warn(
327
+ '[OTA] Running bridgeless but the React Native version could not be determined. ' +
328
+ 'If this app is below RN 0.76.1, OTA updates will install and never load.',
329
+ );
330
+ }
331
+ if (this.environment.requiresReactHostIntegration) {
332
+ // RN 0.82 removed ReactNativeHost, so the legacy
333
+ // `override fun getJSBundleFile()` integration does not exist there.
334
+ // We cannot see which form the host used — the identity check after
335
+ // restart is what proves it — but naming the right fix up front turns
336
+ // a confusing silent failure into a one-line correction.
337
+ logger.debug(
338
+ '[OTA] React Native >= 0.82 detected. The only valid Android integration is ' +
339
+ 'getDefaultReactHost(..., jsBundleFilePath = ScaleBunOtaModule.getJSBundleFile(ctx)) — ' +
340
+ 'ReactNativeHost and its getJSBundleFile() override no longer exist.',
341
+ );
342
+ }
343
+
344
+ this.initialized = true;
345
+ this.enabled = true;
346
+
347
+ // Config lands BEFORE the integrity read, so the log below can state the
348
+ // policy that will actually be applied rather than assume the default.
349
+ // (It used to be assigned after; the boot-guard heartbeat hit the same
350
+ // ordering bug once and silently fell back to the default window.)
351
+ this.bootGuardConfig = config ?? {};
352
+
353
+ // Device integrity signal.
354
+ //
355
+ // Reported, not enforced. Root defeats any check made from inside the app,
356
+ // so this is not a boundary — it is context. It tells an operator that a
357
+ // device's OTA slot is writable by other processes, which is what makes the
358
+ // launch-time hash re-check in SlotManager meaningful rather than paranoid.
359
+ //
360
+ // A host app that wants to act on it sets `onCompromisedDevice:
361
+ // 'withhold'` (default `'allow'` — see BootGuardConfig), or reads
362
+ // `deviceIntegrityIndicators()` and decides for itself. The DETECTION here
363
+ // is unconditional either way; only the decision downstream changes.
364
+ try {
365
+ const raw = NativeScaleBunOta?.getDeviceIntegrity?.();
366
+ this.integrityIndicators = raw ? (JSON.parse(raw) as string[]) : [];
367
+ // Only a string the detector actually returned counts as a measurement;
368
+ // an absent method (older native, unsupported platform) leaves this
369
+ // false so the check request omits the field instead of claiming clean.
370
+ this.integrityMeasured = typeof raw === 'string';
371
+ if (this.integrityIndicators.length > 0) {
372
+ logger.warn(
373
+ `[OTA] Device integrity indicators present: ${this.integrityIndicators.join(', ')}. ` +
374
+ (this.shouldWithhold()
375
+ ? "onCompromisedDevice is 'withhold' — this device will NOT be offered or " +
376
+ 'installed any update while the indicators persist.'
377
+ : 'Updates still install and are still signature-verified, but an installed ' +
378
+ 'bundle on this device can be modified by other privileged processes. ' +
379
+ "Set ota.onCompromisedDevice: 'withhold' to stop updating such devices."),
380
+ );
381
+ }
382
+ } catch {
383
+ this.integrityIndicators = [];
384
+ this.integrityMeasured = false;
385
+ }
386
+ logger.debug(
387
+ `[OTA] Orchestrator initialized (RN ${this.environment.rnVersionString ?? 'unknown'}` +
388
+ `${this.environment.bridgeless ? ', bridgeless' : ''}` +
389
+ `${this.environment.hermes ? `, Hermes HBC v${this.environment.hermesBytecodeVersion ?? '?'}` : ''})`,
390
+ );
391
+
392
+ // ONE read of the slot state, shared by both boot-time consumers.
393
+ //
394
+ // `getSlotState()` is CONSUME-ON-READ for the revert record: both native
395
+ // implementations delete it as they serialise, so that a rollback is
396
+ // reported exactly once instead of on every launch forever. Calling it
397
+ // twice therefore means the second caller never sees the revert — which is
398
+ // precisely what happened, since hydration ran first and swallowed it. It
399
+ // is also a blocking synchronous bridge call, so one read is cheaper.
400
+ const slotState = this.readSlotState();
401
+
402
+ // Rehydrate which bundle we are running from the native slot state.
403
+ // Without this `currentBundle` stays null for the whole process after a
404
+ // restart, so every check reported no current bundle and the backend had
405
+ // no way to know what the device was actually on.
406
+ this.hydrateCurrentBundleFromSlots(slotState);
407
+
408
+ // Warm the device-country cache (edge Worker lookup) so checks can carry
409
+ // a country when the API itself sits behind no geo-stamping CDN.
410
+ // Fire-and-forget and failure-soft — a check without a country is valid.
411
+ void prefetchDeviceCountry();
412
+
413
+ // Check if the boot guard fired on this launch (native reverted before JS
414
+ // loaded). BEFORE the identity check, because both read the install record
415
+ // and the identity check retires it — a revert must get its chance to name
416
+ // the bundle that failed while the record still describes it.
417
+ this.checkBootGuardRecovery(slotState);
418
+
419
+ // Prove the bundle we installed is the bundle that loaded.
420
+ this.verifyRunningBundleIdentity();
421
+
422
+ // Boot-guard health is a LOCAL fact: this process booted from the staged
423
+ // bundle and did not crash. The heartbeat used to start only on the
424
+ // `action === 'NONE'` branch of sync(), so confirming a good bundle needed
425
+ // a successful network round-trip that returned exactly that answer — a
426
+ // device offline, rate-limited, or still being offered an update could
427
+ // never clear its marker, and the guard reverted a bundle that was working.
428
+ //
429
+ // It runs HERE, last, and is handed the slot state that was already read.
430
+ // Starting it earlier made it call getSlotState() itself, and that read is
431
+ // consume-on-read for the revert record — it swallowed the revert before
432
+ // checkBootGuardRecovery() could name the bundle that failed, so a
433
+ // crash-rollback went unreported. It also read bootGuardConfig before
434
+ // init() had assigned it, so healthyAfterMs silently fell back to the
435
+ // default.
436
+ this.startBootGuardHeartbeat(slotState);
437
+ });
438
+ }
439
+
440
+ /**
441
+ * Read the active slot back into `currentBundle` so the next check reports
442
+ * what this device is genuinely running.
443
+ */
444
+ /**
445
+ * Parse the native slot state once. Returns null when the module is absent or
446
+ * the payload is unreadable — every caller treats that as "factory bundle".
447
+ */
448
+ private readSlotState(): Record<string, any> | null {
449
+ if (!NativeScaleBunOta) return null;
450
+ try {
451
+ return JSON.parse(NativeScaleBunOta.getSlotState());
452
+ } catch {
453
+ return null;
454
+ }
455
+ }
456
+
457
+ private hydrateCurrentBundleFromSlots(state: Record<string, any> | null): void {
458
+ try {
459
+ const current = state?.current;
460
+ if (!current?.sha256) return;
461
+
462
+ // Keyed on sha256, NOT bundleId. The native `stageBundle` is never told
463
+ // the bundleId — it writes a meta.json containing only `sha256` and
464
+ // `installedAt` — so `current.bundleId` is always absent. Hydrating from
465
+ // it left `currentBundle` null on every launch, which meant the device
466
+ // never told the server what it was running and the server re-offered
467
+ // the same bundle forever. sha256 is the field that is actually there.
468
+ const record = this.readInstallRecord();
469
+ if (record && record.sha256 === current.sha256) {
470
+ this.currentBundle = {
471
+ id: record.bundleId,
472
+ version: record.version,
473
+ releaseId: record.releaseId ?? undefined,
474
+ sha256: record.sha256,
475
+ } as OtaBundlePayload;
476
+ logger.debug(`[OTA] Running bundle v${record.version} (${record.bundleId})`);
477
+ return;
478
+ }
479
+
480
+ // An OTA bundle is installed but we have no record of installing it —
481
+ // a reinstall of the app, cleared storage, or a bundle staged by an
482
+ // older SDK. Report the hash so the server can still recognise it.
483
+ this.currentBundle = { sha256: current.sha256 } as OtaBundlePayload;
484
+ logger.debug(
485
+ `[OTA] Running an OTA bundle (sha ${String(current.sha256).slice(0, 12)}…) with no local install record.`,
486
+ );
487
+ } catch {
488
+ // Slot state unreadable — treat as factory bundle.
489
+ }
490
+ }
491
+
492
+ /**
493
+ * Compare the bundle the slot manager believes is active against the identity
494
+ * marker compiled into the bundle that actually loaded.
495
+ *
496
+ * A mismatch means the install path reported success while the runtime kept
497
+ * executing different code — the silent no-op this whole guard exists for.
498
+ * It is reported as APPLY_FAILED, because that is what happened, regardless
499
+ * of what the previous session's telemetry claimed.
500
+ *
501
+ * The expectation recorded at install time is what makes this conclusive.
502
+ * Without it, a missing marker is ambiguous — it could be a bundle published
503
+ * before markers existed, or an install that never took effect. Having
504
+ * written down "this bundle definitely carries marker X" before restarting,
505
+ * a missing marker afterwards can only mean the second.
506
+ */
507
+ private verifyRunningBundleIdentity(): void {
508
+ if (!this.currentBundle) return;
509
+
510
+ const running = readRunningBundleMarker();
511
+ const record = this.readInstallRecord();
512
+
513
+ // No record at all — installed by an SDK that predates install records, or
514
+ // local storage was cleared. NOTHING can be concluded here and nothing is
515
+ // reported: the marker is a random per-publish token, never the bundle id,
516
+ // so comparing the two would flag a false mismatch on every healthy launch.
517
+ if (!record) return;
518
+
519
+ // The record describes a bundle that is no longer the active one (a revert,
520
+ // or a bundle staged by another path). It cannot verify this launch, and
521
+ // keeping it would make the next launch mis-report what is running.
522
+ if (record.sha256 !== this.currentBundle.sha256) {
523
+ this.clearInstallExpectation();
524
+ return;
525
+ }
526
+
527
+ // Already proven on an earlier launch. The token is retired once verified
528
+ // while the REST of the record stays — it is also the sha256 -> bundleId map
529
+ // that `hydrateCurrentBundleFromSlots` reads to report what this device is
530
+ // running. Wiping the whole record here is what made every launch after the
531
+ // first send `currentBundleId: undefined`, which the server reads as "not on
532
+ // this bundle" and answers by serving the same bundle again, forever.
533
+ if (!record.identityToken) return;
534
+
535
+ if (running === record.identityToken) {
536
+ logger.debug('[OTA] Install verified — running bundle matches what was installed.');
537
+ this.retireIdentityToken(record);
538
+ return;
539
+ }
540
+
541
+ logger.error(
542
+ `[OTA] INSTALL DID NOT TAKE EFFECT — bundle ${this.currentBundle.id} was installed and ` +
543
+ `carries a known identity marker, but the running bundle reports ` +
544
+ `${running ?? 'no marker at all'}. The app is executing different code than the slot ` +
545
+ 'manager believes. Check that the host app resolves the OTA bundle path at launch ' +
546
+ '(see the ScaleBunOta integration for your React Native version).',
547
+ );
548
+ otaEventEmitter.emitSimple('APPLY_FAILED', this.currentBundle.id, {
549
+ releaseId: this.currentBundle.releaseId,
550
+ error: `install_not_effective — expected ${record.identityToken}, running ${running ?? 'none'}`,
551
+ });
552
+ // Deliberately NOT retired: the condition is still true on the next boot and
553
+ // should keep reporting until the integration is fixed. Retiring the token
554
+ // here would make a permanently broken install look like a one-off.
555
+ }
556
+
557
+ // ── Install expectation ────────────────────────────────────────────────────
558
+ // Written just before the restart that activates a bundle, read on the next
559
+ // boot. Synchronous, disk-backed, and the same store used for the device id —
560
+ // it has to survive a process death that happens moments after the write.
561
+
562
+ private static readonly INSTALL_EXPECTATION_KEY = 'scalebun.ota.pendingInstall';
563
+
564
+ private recordInstallExpectation(bundle: OtaBundlePayload): void {
565
+ try {
566
+ this.storage().set(
567
+ OtaOrchestrator.INSTALL_EXPECTATION_KEY,
568
+ JSON.stringify({
569
+ bundleId: bundle.id,
570
+ version: bundle.version,
571
+ // Carried so telemetry emitted on a LATER launch (a boot-guard
572
+ // rollback, an ineffective install) can still be attributed to the
573
+ // release, not merely the bundle. The check response is long gone by
574
+ // then; this record is the only thing that remembers.
575
+ releaseId: bundle.releaseId ?? null,
576
+ // The join key back to the native slot, which records sha256 and
577
+ // nothing else identifying.
578
+ sha256: bundle.sha256,
579
+ identityToken: bundle.identityToken ?? null,
580
+ }),
581
+ );
582
+ } catch {
583
+ // Verification is a safety net, never a precondition for installing.
584
+ }
585
+ }
586
+
587
+ private readInstallRecord(): {
588
+ bundleId: string;
589
+ version: number;
590
+ releaseId?: string | null;
591
+ sha256: string;
592
+ identityToken: string | null;
593
+ } | null {
594
+ try {
595
+ const raw = this.storage().get(OtaOrchestrator.INSTALL_EXPECTATION_KEY);
596
+ if (!raw) return null;
597
+ const parsed = JSON.parse(raw);
598
+ return typeof parsed?.bundleId === 'string' && typeof parsed?.sha256 === 'string'
599
+ ? parsed
600
+ : null;
601
+ } catch {
602
+ return null;
603
+ }
604
+ }
605
+
606
+ /**
607
+ * Drop the identity token once the install has been proven, keeping the rest
608
+ * of the record.
609
+ *
610
+ * The record does two jobs: it proves an install took effect (once), and it
611
+ * maps the native slot's sha256 back to a bundle id (for the life of that
612
+ * bundle). Only the first job is finished after a successful verification, so
613
+ * only the token is retired.
614
+ */
615
+ private retireIdentityToken(record: {
616
+ bundleId: string;
617
+ version: number;
618
+ releaseId?: string | null;
619
+ sha256: string;
620
+ }): void {
621
+ try {
622
+ this.storage().set(
623
+ OtaOrchestrator.INSTALL_EXPECTATION_KEY,
624
+ JSON.stringify({
625
+ bundleId: record.bundleId,
626
+ version: record.version,
627
+ releaseId: record.releaseId ?? null,
628
+ sha256: record.sha256,
629
+ identityToken: null,
630
+ }),
631
+ );
632
+ } catch {
633
+ /* non-fatal */
634
+ }
635
+ }
636
+
637
+ private clearInstallExpectation(): void {
638
+ try {
639
+ this.storage().set(OtaOrchestrator.INSTALL_EXPECTATION_KEY, '');
640
+ } catch {
641
+ /* non-fatal */
642
+ }
643
+ }
644
+
645
+ private storage(): StorageBackend {
646
+ if (!this.storageBackend) this.storageBackend = createStorageBackend();
647
+ return this.storageBackend;
648
+ }
649
+
650
+ /**
651
+ * Sprint 5 (S5-NAT-1): Check if the native boot guard reverted us on this cold start.
652
+ * If getSlotState() shows bootMarkerPresent=false but we have a 'previous' slot
653
+ * and no 'current' OTA bundle, the native layer already reverted.
654
+ */
655
+ private checkBootGuardRecovery(state: Record<string, any> | null): void {
656
+ try {
657
+ if (!state?.bootGuardReverted) return;
658
+
659
+ // WHICH bundle was rolled back, and it has to come from the install
660
+ // record. The obvious source — `state.previous` — is wrong twice over:
661
+ // slot meta.json carries only `{sha256, installedAt}` so it has no bundle
662
+ // id to read, and `revert()` deletes the previous slot as its last step,
663
+ // so by the time this runs there is no previous meta at all. The event
664
+ // therefore reported `bundleId: 'unknown'` on every rollback, and the
665
+ // backend drops any ota_event whose bundleId does not resolve to a bundle
666
+ // the app owns — so the crash-guard's own rollback signal never arrived.
667
+ //
668
+ // Native now stamps the sha256 of the bundle it reverted AWAY FROM into
669
+ // the revert record; the install record maps that back to a bundle id.
670
+ const record = this.readInstallRecord();
671
+ const revertedSha: string | undefined = state.bootGuardRevertedSha256;
672
+ const matchesRecord = !!record && (!revertedSha || record.sha256 === revertedSha);
673
+
674
+ // Report the reason native actually determined — a hash mismatch and a
675
+ // crash loop are different incidents and were being collapsed into one.
676
+ const reason: string = state.bootGuardRevertReason || 'boot_crash_guard';
677
+
678
+ if (matchesRecord && record) {
679
+ logger.warn(
680
+ `[OTA] Boot guard fired — reverted away from bundle ${record.bundleId} ` +
681
+ `(v${record.version}); reason: ${reason}`,
682
+ );
683
+ otaEventEmitter.emitSimple('AUTO_ROLLBACK', record.bundleId, {
684
+ releaseId: record.releaseId ?? undefined,
685
+ version: record.version,
686
+ reason,
687
+ });
688
+ // The record describes a bundle this device is no longer running.
689
+ this.clearInstallExpectation();
690
+ return;
691
+ }
692
+
693
+ // No usable record (older SDK, cleared storage). Say so rather than
694
+ // emitting an event the server is obliged to discard.
695
+ logger.warn(
696
+ `[OTA] Boot guard fired (reason: ${reason}) but the rolled-back bundle could not be ` +
697
+ 'identified locally — no install record. The rollback is not reported to the server.',
698
+ );
699
+ } catch {
700
+ // Slot state parsing failed — non-fatal
701
+ }
702
+ }
703
+
704
+ isEnabled(): boolean {
705
+ return this.enabled;
706
+ }
707
+
708
+ /**
709
+ * Root/jailbreak indicators detected on this device, as stable reason strings.
710
+ * Empty means nothing was detected — not proof the device is clean.
711
+ */
712
+ deviceIntegrityIndicators(): string[] {
713
+ return [...this.integrityIndicators];
714
+ }
715
+
716
+ /**
717
+ * Should this device be refused an update?
718
+ *
719
+ * TRUE only when BOTH are so: the host opted into `'withhold'`, and the native
720
+ * detector actually found something. An empty indicator list is never a reason
721
+ * to withhold — "nothing detected" is the normal state of every healthy
722
+ * device, and treating it as a reason would brick updates for the whole fleet
723
+ * the moment a host set the flag.
724
+ */
725
+ private shouldWithhold(): boolean {
726
+ // Resolved at DECISION time, not at init: /config is fetched asynchronously,
727
+ // so a policy that arrives mid-session takes effect on the next check rather
728
+ // than only on the next launch.
729
+ //
730
+ // STRICTEST WINS and the server can only TIGHTEN — see
731
+ // resolveCompromisedDevicePolicy. A host that asked for 'withhold' keeps it
732
+ // whatever the server says; a customer who has shipped nothing can still be
733
+ // switched on without an app release, which is the point of the feature.
734
+ return (
735
+ resolveCompromisedDevicePolicy(this.bootGuardConfig.onCompromisedDevice) ===
736
+ 'withhold' && this.integrityIndicators.length > 0
737
+ );
738
+ }
739
+
740
+ /**
741
+ * Announce the refusal, once per decision point.
742
+ *
743
+ * A withheld update must be visible as a decision, not as an absence. The
744
+ * event carries the indicators that drove it so the host can log WHY, and it
745
+ * names the bundle the device stays on (`'unknown'` for a device still on the
746
+ * factory bundle, which owns no OTA bundle id).
747
+ */
748
+ private emitWithheld(): void {
749
+ logger.warn(
750
+ `[OTA] Update WITHHELD — device integrity indicators present (${this.integrityIndicators.join(', ')}) ` +
751
+ "and ota.onCompromisedDevice is 'withhold'. This device stays on its current bundle.",
752
+ );
753
+ otaEventEmitter.emitSimple('UPDATE_WITHHELD', this.currentBundle?.id ?? 'unknown', {
754
+ releaseId: this.currentBundle?.releaseId,
755
+ version: this.currentBundle?.version,
756
+ indicators: [...this.integrityIndicators],
757
+ });
758
+ }
759
+
760
+ isRestartRequired(): boolean {
761
+ return this.isRestartRequiredState;
762
+ }
763
+
764
+ /**
765
+ * Perform an OTA check against the backend endpoint.
766
+ */
767
+ async checkForUpdate(requestParams: {
768
+ apiUrl: string;
769
+ clientKey: string;
770
+ appVersion: string;
771
+ installationId: string;
772
+ channelName?: string;
773
+ country?: string;
774
+ attributes?: Record<string, string | number>;
775
+ segmentIds?: string[];
776
+ lifecycleStage?: string;
777
+ }): Promise<OtaCheckResponse> {
778
+ try {
779
+ // ── COMPROMISED-DEVICE POLICY ────────────────────────────────────────
780
+ // Opt-in, default 'allow' (see BootGuardConfig.onCompromisedDevice). The
781
+ // short-circuit is HERE as well as in sync() because checkForUpdate is a
782
+ // public entry point in its own right — the CodePush shim's
783
+ // `checkForUpdate` and any host that drives the check by hand reach the
784
+ // network through this method without going through sync().
785
+ if (this.shouldWithhold()) {
786
+ this.emitWithheld();
787
+ return { action: 'NONE' };
788
+ }
789
+
790
+ const env = this.environment ?? detectOtaEnvironment();
791
+
792
+ // C1: send the channel and targeting context. `channelName` was already an
793
+ // accepted parameter here and was then dropped on the floor — the payload
794
+ // never carried it — so every device resolved to `default` no matter what
795
+ // the host app asked for. Undefined fields are omitted by JSON.stringify,
796
+ // so an app that supplies nothing behaves exactly as before.
797
+ // OTA has no bundle for a non-mobile target; claiming Android there would install the wrong one.
798
+ const mobileOS = resolveMobileOS();
799
+ if (!mobileOS) throw new Error('OTA is not supported on this platform');
800
+ // SDK trust coverage (CICDPAGE §12): report which trusted key IDs are
801
+ // embedded in this binary so the dashboard can measure key-rotation
802
+ // adoption. Telemetry only — the server never trusts a key a device claims.
803
+ // Defensive: optional native method, never let it break a check.
804
+ let trustedKeyIds: string[] | undefined;
805
+ try {
806
+ const raw = NativeScaleBunOta?.getTrustedKeyIds?.();
807
+ if (raw) {
808
+ const arr = JSON.parse(raw);
809
+ if (Array.isArray(arr) && arr.length) trustedKeyIds = arr.slice(0, 16);
810
+ }
811
+ } catch {
812
+ /* trust reporting is best-effort — never break the update check */
813
+ }
814
+ const payload: OtaCheckRequest = {
815
+ appVersion: requestParams.appVersion,
816
+ platform: mobileOS,
817
+ installationId: requestParams.installationId,
818
+ currentBundleId: this.currentBundle?.id,
819
+ currentBundleHash: this.currentBundle?.sha256,
820
+ ...(signedPatchSupported(NativeScaleBunOta) ? { otaCapabilities: ['signed_patch_v1'] } : {}),
821
+ trustedKeyIds,
822
+ // Root/jailbreak indicators, so a console can report how much of a fleet
823
+ // is affected instead of every operator guessing. Telemetry only — the
824
+ // server must never trust it (a rooted device can send `[]`), and the
825
+ // withholding decision above is made entirely on-device.
826
+ //
827
+ // `[]` and absent mean DIFFERENT things and are kept apart: `[]` is
828
+ // "the detector ran and found nothing", absent is "never measured"
829
+ // (native module missing, or the read threw). Sending `[]` for both
830
+ // would report an unmeasured fleet as a clean one.
831
+ integrityIndicators: this.integrityMeasured
832
+ ? [...this.integrityIndicators]
833
+ : undefined,
834
+ channelName: requestParams.channelName,
835
+ // Host-supplied country wins; otherwise the cached edge-Worker lookup
836
+ // fills in (see geoCountry.ts). Undefined when neither knows — the
837
+ // server renders unknown as unknown rather than guessing.
838
+ country: requestParams.country ?? getDeviceCountry() ?? undefined,
839
+ // Hardware/OS context under the host's own attributes (host wins on
840
+ // collision) — this is what lets ATTRIBUTE rules target device classes
841
+ // (deviceModel / manufacturer / brand / osVersion / formFactor).
842
+ attributes: { ...deviceTargetingAttributes(), ...requestParams.attributes },
843
+ segmentIds: requestParams.segmentIds,
844
+ lifecycleStage: requestParams.lifecycleStage,
845
+ // Runtime compatibility context. Without these the backend cannot tell
846
+ // whether a bundle is safe for this binary: appVersion is a marketing
847
+ // string, while the RN version and the Hermes bytecode format are the
848
+ // actual runtime contract. A bundle compiled against a different HBC
849
+ // version either fails to load or crashes later on a missing path.
850
+ rnVersion: env.rnVersionString ?? undefined,
851
+ hermes: env.hermes,
852
+ hermesBytecodeVersion: env.hermesBytecodeVersion ?? undefined,
853
+ bridgeless: env.bridgeless,
854
+ };
855
+
856
+ const url = `${requestParams.apiUrl.replace(/\/+$/, '')}/sdk/ota/check`;
857
+
858
+ const data = await retryWithBackoff<OtaCheckResponse>(
859
+ async () => {
860
+ const res = await fetch(url, {
861
+ method: 'POST',
862
+ headers: {
863
+ 'Content-Type': 'application/json',
864
+ 'x-scalebun-client-key': requestParams.clientKey,
865
+ },
866
+ body: JSON.stringify(payload),
867
+ });
868
+
869
+ if (!res.ok) {
870
+ throw new HttpStatusError(
871
+ `OTA check failed with status ${res.status}`,
872
+ res.status,
873
+ );
874
+ }
875
+ return (await res.json()) as OtaCheckResponse;
876
+ },
877
+ { label: 'check', isRetryable: isRetryableNetworkError },
878
+ );
879
+
880
+ return data;
881
+ } catch (err: any) {
882
+ logger.error(`[OTA] checkForUpdate failed: ${err.message}`);
883
+ return { action: 'NONE' };
884
+ }
885
+ }
886
+
887
+ /**
888
+ * Downloads, stage, and apply an update in one step.
889
+ * Sprint 5: emits lifecycle events + starts boot-guard heartbeat.
890
+ */
891
+ /**
892
+ * Minimum gap between network checks. Not a policy, a stampede guard: an
893
+ * app that syncs on mount AND on every foreground transition can otherwise
894
+ * issue a burst of identical checks. Small enough not to get in the way of
895
+ * publishing and testing a release.
896
+ */
897
+ private static readonly MIN_CHECK_INTERVAL_MS = 15_000;
898
+
899
+ /**
900
+ * Check, download, stage and apply — at most ONE at a time.
901
+ *
902
+ * Concurrent callers join the sync already running rather than starting a
903
+ * second one, and a call made while an update is already staged returns
904
+ * without touching the slots: the staged bundle has to be activated by a
905
+ * restart before anything else can usefully happen, and re-checking here
906
+ * is what used to chain a second install onto the first.
907
+ */
908
+ async sync(rawParams: Parameters<OtaOrchestrator['runSync']>[0]): Promise<SyncResult> {
909
+ if (this.isRestartRequiredState) {
910
+ logger.debug(
911
+ '[OTA] An update is staged and waiting for a restart — skipping this check.',
912
+ );
913
+ return { status: 'UP_TO_DATE', bundle: this.pendingBundle ?? undefined };
914
+ }
915
+ if (this.syncInFlight) {
916
+ logger.debug('[OTA] A sync is already running — joining it.');
917
+ return this.syncInFlight;
918
+ }
919
+ const elapsed = Date.now() - this.lastCheckAt;
920
+ if (this.lastCheckAt > 0 && elapsed < OtaOrchestrator.MIN_CHECK_INTERVAL_MS) {
921
+ logger.debug(
922
+ `[OTA] Checked ${Math.round(elapsed / 1000)}s ago — within the ${
923
+ OtaOrchestrator.MIN_CHECK_INTERVAL_MS / 1000
924
+ }s minimum interval, skipping.`,
925
+ );
926
+ return { status: 'UP_TO_DATE' };
927
+ }
928
+ this.lastCheckAt = Date.now();
929
+ this.syncInFlight = this.runSync(rawParams).finally(() => {
930
+ this.syncInFlight = null;
931
+ });
932
+ return this.syncInFlight;
933
+ }
934
+
935
+ private async runSync(rawParams: {
936
+ apiUrl: string;
937
+ clientKey: string;
938
+ appVersion: string;
939
+ /** Omit to use the SDK's canonical per-install id (recommended — P8). */
940
+ installationId?: string;
941
+ // P1: these five existed on checkForUpdate and on the wire contract, but
942
+ // sync() — the only caller that matters — never accepted them, so they
943
+ // were structurally undefined on every real device: every install pinned
944
+ // to the `default` channel and the whole targeting engine matched nothing.
945
+ // The C1 comment in OtaTypes.ts claimed this was fixed; the plumbing had
946
+ // stopped exactly one function short of true.
947
+ channelName?: string;
948
+ country?: string;
949
+ attributes?: Record<string, string | number>;
950
+ segmentIds?: string[];
951
+ lifecycleStage?: string;
952
+ /**
953
+ * @deprecated IGNORED. Activation is driven strictly by the release's
954
+ * installMode (IMMEDIATE / ON_NEXT_RESUME / ON_NEXT_RESTART). This flag is
955
+ * pinned false internally and honoured nowhere — publish an IMMEDIATE
956
+ * release instead of forcing a client-side restart.
957
+ */
958
+ autoRestart?: boolean;
959
+ }): Promise<SyncResult> {
960
+ const params = {
961
+ ...rawParams,
962
+ installationId: rawParams.installationId ?? resolveInstallationId(),
963
+ // ENFORCED GLOBALLY: the legacy client `autoRestart` override is ignored —
964
+ // pinned false here so no app config (or future code path that reads
965
+ // params.autoRestart) can re-enable it. Activation is driven STRICTLY by
966
+ // the release's server-set installMode: IMMEDIATE restarts now,
967
+ // ON_NEXT_RESUME arms a resume-restart, ON_NEXT_RESTART (default) applies
968
+ // on the next cold start. Honouring `autoRestart:true` forced every release
969
+ // to restart immediately (defeating installMode), and on bridgeless it
970
+ // forced the in-process restart that cannot load a staged bundle.
971
+ autoRestart: false as boolean,
972
+ };
973
+ try {
974
+ if (!this.enabled || !NativeScaleBunOta) {
975
+ return { status: 'ERROR', error: 'OTA native module disabled or missing' };
976
+ }
977
+
978
+ // ── COMPROMISED-DEVICE POLICY ────────────────────────────────────────
979
+ // Before ANY network call and before the CHECK event: a withheld device
980
+ // must not appear in the funnel's denominator as a device that asked and
981
+ // was told nothing. It did not ask. Default is 'allow', so this is inert
982
+ // unless the host opted in (see BootGuardConfig.onCompromisedDevice).
983
+ if (this.shouldWithhold()) {
984
+ this.emitWithheld();
985
+ return { status: 'WITHHELD' };
986
+ }
987
+
988
+ logger.debug('[OTA] Sync started…');
989
+
990
+ // The funnel's denominator, for devices already on an OTA bundle. Emitted
991
+ // before the request, so a check that fails outright still counts as a
992
+ // check — the only CHECK rows before this came from a server-side geo
993
+ // side-effect that is skipped whenever the request carries no country.
994
+ //
995
+ // Only when a current bundle is known: every ota_event must name a bundle
996
+ // the app owns or the server drops it, and a device still on the binary's
997
+ // factory bundle has no such id to give. Those devices are counted
998
+ // server-side when they are offered something.
999
+ if (this.currentBundle?.id) {
1000
+ otaEventEmitter.emitSimple('CHECK', this.currentBundle.id, {
1001
+ releaseId: this.currentBundle.releaseId,
1002
+ version: this.currentBundle.version,
1003
+ });
1004
+ }
1005
+
1006
+ const checkRes = await this.checkForUpdate(params);
1007
+
1008
+ if (checkRes.action === 'NONE') {
1009
+ logger.debug('[OTA] App is up to date');
1010
+ // If we booted from an OTA bundle and it's healthy, clear the boot guard
1011
+ this.startBootGuardHeartbeat();
1012
+ return { status: 'UP_TO_DATE' };
1013
+ }
1014
+
1015
+ // Handle server-initiated rollback (Sprint 4)
1016
+ if (checkRes.action === 'ROLLBACK') {
1017
+ logger.warn('[OTA] Server requested ROLLBACK — reverting to previous bundle');
1018
+ otaEventEmitter.emitSimple('MANUAL_ROLLBACK', this.currentBundle?.id ?? 'unknown', {
1019
+ releaseId: this.currentBundle?.releaseId,
1020
+ });
1021
+ const reverted = await NativeScaleBunOta.revertToPrevious();
1022
+ if (reverted) {
1023
+ this.currentBundle = null;
1024
+ // isRestartRequired flips true; the reverted bundle binds on the next
1025
+ // cold start. autoRestart is intentionally not consulted (pinned false
1026
+ // in sync()) — activation policy is uniform across update and rollback.
1027
+ this.isRestartRequiredState = true;
1028
+ return { status: 'ROLLED_BACK' };
1029
+ }
1030
+ return { status: 'ERROR', error: 'Native rollback failed' };
1031
+ }
1032
+
1033
+ if (!checkRes.bundle) {
1034
+ return { status: 'UP_TO_DATE' };
1035
+ }
1036
+
1037
+ const bundle = checkRes.bundle;
1038
+ // When the presigned download URL (300 s TTL) was issued — a retry past 240 s re-checks.
1039
+ const offeredAt = Date.now();
1040
+ let patchUsed = false;
1041
+
1042
+ // The offer itself. Everything downstream (download, install, activation)
1043
+ // is a conversion against this, so without it the top of the funnel was
1044
+ // unmeasurable and a rollout that never reached devices looked identical
1045
+ // to one whose devices all declined to download.
1046
+ otaEventEmitter.emitSimple('OFFERED', bundle.id, {
1047
+ releaseId: bundle.releaseId,
1048
+ version: bundle.version,
1049
+ });
1050
+
1051
+ // ── DOWNLOAD ─────────────────────────────────────────────────────────
1052
+ // Authenticity is enforced NATIVELY now (see the envelope branch below):
1053
+ // SHA-256 proves the bytes arrived intact, and for signed releases the
1054
+ // RSA signature — checked in native code against keys embedded in the app
1055
+ // package — proves they came from you. JS neither pins keys nor verifies
1056
+ // signatures.
1057
+ otaEventEmitter.emitSimple('DOWNLOAD_STARTED', bundle.id, {
1058
+ releaseId: bundle.releaseId,
1059
+ version: bundle.version,
1060
+ });
1061
+ const downloadStart = Date.now();
1062
+ logger.debug(`[OTA] Downloading update v${bundle.version}…`);
1063
+
1064
+ // Live progress: native tick → DOWNLOAD_PROGRESS (feeds useOtaUpdate) →
1065
+ // throttled POST to the live tracker. `bundle.size` is the authoritative
1066
+ // total — the server just told us — so an unknown native total (-1 on
1067
+ // chunked/gzip bodies) still yields a truthful percentage.
1068
+ let lastPostAt = 0;
1069
+ const postProgress = (bytesRead: number, status: string) => {
1070
+ const total = bundle.size > 0 ? bundle.size : Math.max(bytesRead, 1);
1071
+ const percent = Math.min(100, Math.round((bytesRead / total) * 100));
1072
+ const elapsedS = (Date.now() - downloadStart) / 1000;
1073
+ const payload = {
1074
+ installationId: params.installationId,
1075
+ bundleId: bundle.id,
1076
+ bytesRead,
1077
+ totalBytes: total,
1078
+ progressPercent: percent,
1079
+ speedKbps: elapsedS > 0 ? Math.round(bytesRead / 1024 / elapsedS) : 0,
1080
+ status,
1081
+ };
1082
+ // Fire-and-forget: progress display must never delay or fail the
1083
+ // download it describes.
1084
+ fetch(`${params.apiUrl.replace(/\/+$/, '')}/sdk/ota/progress`, {
1085
+ method: 'POST',
1086
+ headers: {
1087
+ 'Content-Type': 'application/json',
1088
+ 'x-scalebun-client-key': params.clientKey,
1089
+ },
1090
+ body: JSON.stringify(payload),
1091
+ }).catch(() => {});
1092
+ };
1093
+
1094
+ const unsubscribeProgress = subscribeNativeProgress(({ bytesRead }) => {
1095
+ const total = bundle.size > 0 ? bundle.size : bytesRead;
1096
+ otaEventEmitter.emit({
1097
+ type: 'DOWNLOAD_PROGRESS',
1098
+ bundleId: bundle.id,
1099
+ timestamp: Date.now(),
1100
+ progress: Math.min(100, Math.round((bytesRead / Math.max(total, 1)) * 100)),
1101
+ });
1102
+ const now = Date.now();
1103
+ if (now - lastPostAt >= PROGRESS_POST_INTERVAL_MS) {
1104
+ lastPostAt = now;
1105
+ postProgress(bytesRead, 'DOWNLOADING');
1106
+ }
1107
+ });
1108
+
1109
+ let staged = false;
1110
+
1111
+ if (bundle.envelope) {
1112
+ // ── NATIVE-ENFORCED VERIFY + STAGE (SB-OTA-RSA-SHA256-V1) ───────────
1113
+ // Hand the whole envelope to native code, which verifies the RSA
1114
+ // signature against the keys EMBEDDED in the app package, then downloads
1115
+ // the artifact, enforces the SIGNED size + SHA-256, and stages it into
1116
+ // the `next` slot — all outside JS. JavaScript never stages bytes it has
1117
+ // not proven authentic. No patch path here: a signed offer is always a
1118
+ // full verified download (native patch is a documented follow-up).
1119
+ //
1120
+ // Retried when — and only when — a retry can help (see signedDownload.ts): one dropped
1121
+ // connection used to lose a 19 MB update until the next cold start. A retry after an
1122
+ // expired URL asks the server again, and stops quietly if the release was withdrawn.
1123
+ const native = NativeScaleBunOta;
1124
+
1125
+ // Patch FIRST when the server offered one and this binary can apply it signed. One
1126
+ // attempt, no retry: on any failure the full download below runs exactly as before, so a
1127
+ // patch can only ever save bytes. Security lives in native (verifyAndStagePatch): the
1128
+ // rebuilt bundle must hash to the SIGNED artifactSha256, from a signed base.
1129
+ if (bundle.patch && signedPatchSupported(native)) {
1130
+ const pv = await trySignedPatch(native as any, bundle.envelope, bundle.url, bundle.patch);
1131
+ if (pv.ok) {
1132
+ patchUsed = true;
1133
+ staged = true;
1134
+ logger.debug(`[OTA] Staged v${bundle.version} from a ${(bundle.patch.size / 1024).toFixed(0)} KB patch`);
1135
+ } else {
1136
+ logger.info(`[OTA] Patch not applied (${pv.code ?? "unknown"}) — downloading the full bundle`);
1137
+ }
1138
+ }
1139
+
1140
+ if (!staged) {
1141
+ const result = await stageSignedWithRetry<typeof bundle>(
1142
+ {
1143
+ attempt: async (b) => {
1144
+ try {
1145
+ const verdictJson = await native.verifyAndStageRelease(
1146
+ JSON.stringify({ ...b.envelope, downloadUrl: b.url }),
1147
+ );
1148
+ return JSON.parse(verdictJson) as StageVerdict;
1149
+ } catch (err: any) {
1150
+ // A rejected promise (or an unparseable verdict) is machinery failure,
1151
+ // never a valid result — treat it as a hard failure (not retried).
1152
+ return { ok: false, code: 'verify_stage_threw', message: err?.message ?? String(err) };
1153
+ }
1154
+ },
1155
+ recheck: async () => {
1156
+ const again = await this.checkForUpdate(params);
1157
+ return again.action === 'DOWNLOAD' && again.bundle?.envelope ? again.bundle : null;
1158
+ },
1159
+ now: () => Date.now(),
1160
+ sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
1161
+ },
1162
+ bundle,
1163
+ offeredAt,
1164
+ );
1165
+ const verdict = result.verdict;
1166
+
1167
+ if (result.withdrawn) {
1168
+ unsubscribeProgress();
1169
+ // No progress post: the live tracker's vocabulary has no "withdrawn", and FAILED would
1170
+ // report a release the server stopped offering as a device that failed to download it.
1171
+ logger.info(
1172
+ `[OTA] Release v${bundle.version} is no longer offered — stopping the download without reporting a failure.`,
1173
+ );
1174
+ return { status: 'UP_TO_DATE' };
1175
+ }
1176
+
1177
+ if (!verdict.ok) {
1178
+ unsubscribeProgress();
1179
+ postProgress(0, 'FAILED');
1180
+ logger.error(
1181
+ `[OTA] Native verify/stage refused the release: ${verdict.code ?? 'unknown'}` +
1182
+ `${verdict.message ? ` — ${verdict.message}` : ''}`,
1183
+ );
1184
+ otaEventEmitter.emitSimple('APPLY_FAILED', bundle.id, {
1185
+ releaseId: bundle.releaseId,
1186
+ // `error` is mapped onto the wire `errorCode` by deliverOtaEvents —
1187
+ // carry the stable native verdict code there, with the download
1188
+ // reason when native gave one from the fixed vocabulary
1189
+ // (`DOWNLOAD_FAILED:http_403`). Emitted ONCE, after the last attempt.
1190
+ error: verdictErrorCode(verdict),
1191
+ version: bundle.version,
1192
+ });
1193
+ return {
1194
+ status: 'ERROR',
1195
+ error: `Release verification failed (${verdict.code ?? 'unknown'})`,
1196
+ bundle,
1197
+ };
1198
+ }
1199
+
1200
+ staged = true;
1201
+ }
1202
+ } else {
1203
+ // ── LEGACY / UNSIGNED (SHA-256 integrity only) ─────────────────────
1204
+ // No envelope means the app embeds no trusted keys and the release is
1205
+ // unsigned: keep the pre-RSA behaviour so those apps still update.
1206
+
1207
+ // Sprint 7: Try patch first if offered, fall back to full bundle
1208
+ if (bundle.patch && NativeScaleBunOta.stagePatch) {
1209
+ logger.debug(
1210
+ `[OTA] Patch available (${(bundle.patch.size / 1024).toFixed(0)} KB vs ` +
1211
+ `${(bundle.size / 1024).toFixed(0)} KB full) — trying patch…`,
1212
+ );
1213
+ try {
1214
+ staged = await NativeScaleBunOta.stagePatch(
1215
+ bundle.patch.url,
1216
+ bundle.patch.sha256,
1217
+ bundle.sha256, // expected full-bundle hash after patching
1218
+ );
1219
+ if (staged) {
1220
+ patchUsed = true;
1221
+ logger.debug('[OTA] Patch applied successfully');
1222
+ } else {
1223
+ logger.warn('[OTA] Patch staging returned false — falling back to full bundle');
1224
+ }
1225
+ } catch (patchErr: any) {
1226
+ logger.warn(`[OTA] Patch staging failed: ${patchErr.message} — falling back to full bundle`);
1227
+ }
1228
+ }
1229
+
1230
+ // Full-bundle fallback (or primary path when no patch is available).
1231
+ // Retried with backoff: on a mobile network a transient drop mid-download
1232
+ // is the common case, and previously one failure meant waiting for the
1233
+ // next cold start — often hours away, sometimes never.
1234
+ if (!staged) {
1235
+ try {
1236
+ staged = await retryWithBackoff(
1237
+ async () => {
1238
+ const ok = await NativeScaleBunOta!.stageBundle(bundle.url, bundle.sha256);
1239
+ if (!ok) {
1240
+ // Native returns a bare boolean, so a hash mismatch and a
1241
+ // dropped connection are indistinguishable here. Retrying a
1242
+ // genuine mismatch a couple of times is cheap; not retrying a
1243
+ // dropped connection costs the whole update.
1244
+ throw new Error('stageBundle returned false');
1245
+ }
1246
+ return ok;
1247
+ },
1248
+ { label: `download v${bundle.version}`, attempts: 3 },
1249
+ );
1250
+ } catch {
1251
+ staged = false;
1252
+ }
1253
+ }
1254
+ }
1255
+
1256
+ unsubscribeProgress();
1257
+
1258
+ if (!staged) {
1259
+ postProgress(0, 'FAILED');
1260
+ logger.error('[OTA] Staging bundle failed after retries');
1261
+ otaEventEmitter.emitSimple('APPLY_FAILED', bundle.id, {
1262
+ releaseId: bundle.releaseId,
1263
+ error: 'Staging failed — SHA-256 mismatch or download error',
1264
+ version: bundle.version,
1265
+ });
1266
+ return { status: 'ERROR', error: 'Staging bundle failed', bundle };
1267
+ }
1268
+
1269
+ postProgress(bundle.size, 'COMPLETED');
1270
+
1271
+ const downloadDuration = Date.now() - downloadStart;
1272
+ otaEventEmitter.emitSimple('DOWNLOAD_COMPLETE', bundle.id, {
1273
+ releaseId: bundle.releaseId,
1274
+ version: bundle.version,
1275
+ durationMs: downloadDuration,
1276
+ patchUsed,
1277
+ });
1278
+
1279
+ // ── APPLY ────────────────────────────────────────────────────────────
1280
+ // 2. Apply update atomically (next→current, current→previous, sets boot marker)
1281
+ const applied = await NativeScaleBunOta.applyUpdate();
1282
+ if (!applied) {
1283
+ logger.error('[OTA] Applying update failed');
1284
+ otaEventEmitter.emitSimple('APPLY_FAILED', bundle.id, {
1285
+ releaseId: bundle.releaseId,
1286
+ error: 'Atomic slot swap failed',
1287
+ version: bundle.version,
1288
+ });
1289
+ return { status: 'ERROR', error: 'Applying update failed', bundle };
1290
+ }
1291
+
1292
+ // NOT `this.currentBundle` — see the field docs. This process is still
1293
+ // executing the previous bundle; the staged one becomes current when a
1294
+ // restart binds it, and hydrateCurrentBundleFromSlots reads it back from
1295
+ // the install record on the next launch.
1296
+ this.pendingBundle = bundle;
1297
+ this.isRestartRequiredState = true;
1298
+
1299
+ // Written BEFORE the restart, so the next boot can prove whether this
1300
+ // install actually took effect. Only recorded when the server told us the
1301
+ // bundle carries a marker — otherwise there is nothing to compare against
1302
+ // and a recorded expectation would produce a false alarm.
1303
+ // Recorded unconditionally, not only when a marker is present: this is
1304
+ // also the record that tells the next launch WHICH bundle the slot's
1305
+ // sha256 belongs to, without which the device cannot report what it is
1306
+ // running. Identity verification is the second job of this record, and
1307
+ // it is skipped when there is no marker to compare.
1308
+ this.recordInstallExpectation(bundle);
1309
+
1310
+ otaEventEmitter.emitSimple('INSTALLED', bundle.id, {
1311
+ releaseId: bundle.releaseId,
1312
+ version: bundle.version,
1313
+ });
1314
+ logger.debug(`[OTA] Update v${bundle.version} installed successfully!`);
1315
+
1316
+ // Deliver telemetry BEFORE a restart tears the JS runtime down —
1317
+ // an INSTALLED event queued but not sent would vanish with the process.
1318
+ await deliverOtaEvents(params);
1319
+
1320
+ // Activation is driven STRICTLY by the release's installMode. The legacy
1321
+ // client `autoRestart` override is pinned false in sync() (see above), so
1322
+ // it no longer participates — a release activates exactly as published:
1323
+ // IMMEDIATE restarts now, ON_NEXT_RESUME on next foreground, and
1324
+ // ON_NEXT_RESTART (the default) on the next cold start.
1325
+ const installMode = bundle.installMode ?? 'ON_NEXT_RESTART';
1326
+ if (installMode === 'IMMEDIATE') {
1327
+ this.restart();
1328
+ } else if (installMode === 'ON_NEXT_RESUME') {
1329
+ this.armResumeRestart();
1330
+ }
1331
+
1332
+ return {
1333
+ status: 'UPDATE_INSTALLED',
1334
+ bundle,
1335
+ isMandatory: bundle.isMandatory,
1336
+ };
1337
+ } catch (err: any) {
1338
+ logger.error(`[OTA] Sync error: ${err.message}`);
1339
+ return { status: 'ERROR', error: err.message ?? 'Unexpected sync failure' };
1340
+ } finally {
1341
+ // Every other exit (UP_TO_DATE, ROLLBACK, staging failure, throw)
1342
+ // delivers here. This also carries events queued at INIT — boot-guard
1343
+ // AUTO_ROLLBACKs and identity-check APPLY_FAILEDs fire before any
1344
+ // apiUrl/clientKey exist, so they wait in the queue for the first sync.
1345
+ // Fire-and-forget: delivery is never allowed to delay a result.
1346
+ void deliverOtaEvents(params);
1347
+ }
1348
+ }
1349
+
1350
+ /**
1351
+ * Sprint 5 (S5-NAT-1): Boot-guard heartbeat.
1352
+ *
1353
+ * After booting from an OTA bundle, start a timer. If the app survives
1354
+ * `healthyAfterMs` without crashing, call `markHealthy()` to clear the
1355
+ * native boot-guard marker. If JS crashes before the timer fires, the
1356
+ * marker stays set and native code reverts on next cold start.
1357
+ */
1358
+ private startBootGuardHeartbeat(preRead?: Record<string, any> | null): void {
1359
+ if (!NativeScaleBunOta) return;
1360
+ // A render error already condemned this launch; nothing may re-arm the heartbeat.
1361
+ if (this.bootFailedThisLaunch) return;
1362
+
1363
+ // Cancel any existing timer
1364
+ if (this.healthyTimer) {
1365
+ clearTimeout(this.healthyTimer);
1366
+ this.healthyTimer = null;
1367
+ }
1368
+
1369
+ try {
1370
+ // getSlotState() is CONSUME-ON-READ for the revert record, so a caller that
1371
+ // has already read it passes the parsed result down rather than letting
1372
+ // this read again and swallow a rollback. `null` is a real answer (module
1373
+ // absent or payload unreadable) — only `undefined` means "nobody read it".
1374
+ const state =
1375
+ preRead !== undefined
1376
+ ? preRead
1377
+ : (JSON.parse(NativeScaleBunOta.getSlotState()) as Record<string, any>);
1378
+
1379
+ // Only run the heartbeat if boot-guard marker is present
1380
+ // (meaning we're running from a freshly-applied OTA bundle)
1381
+ if (!state?.bootMarkerPresent) {
1382
+ return;
1383
+ }
1384
+
1385
+ const healthyMs = this.bootGuardConfig.healthyAfterMs ?? DEFAULT_HEALTHY_AFTER_MS;
1386
+ logger.debug(`[OTA] Boot guard active — marking healthy after ${healthyMs}ms`);
1387
+
1388
+ this.healthyTimer = setTimeout(() => {
1389
+ noThrow(() => {
1390
+ NativeScaleBunOta?.markHealthy();
1391
+ logger.info('[OTA] Boot guard cleared — bundle marked healthy ✓');
1392
+ this.healthyTimer = null;
1393
+
1394
+ // The honest activation signal. INSTALLED is emitted optimistically,
1395
+ // BEFORE the bundle has ever executed, so counting it as adoption
1396
+ // credits bundles that were installed and then crash-reverted. This
1397
+ // fires only once the bundle has actually booted and survived.
1398
+ const running = this.currentBundle;
1399
+ if (running?.id) {
1400
+ otaEventEmitter.emitSimple('BOOT_SUCCESS', running.id, {
1401
+ releaseId: running.releaseId,
1402
+ version: running.version,
1403
+ durationMs: healthyMs,
1404
+ });
1405
+ }
1406
+ });
1407
+ }, healthyMs);
1408
+ } catch {
1409
+ // State parsing failed — non-fatal, don't block
1410
+ }
1411
+ }
1412
+
1413
+ private bootFailedThisLaunch = false;
1414
+
1415
+ /**
1416
+ * A render error was caught while a freshly-applied bundle is still inside its health window.
1417
+ *
1418
+ * WHY. The boot guard's only evidence of a bad bundle is that the process died before
1419
+ * `healthyAfterMs`. An error boundary with a fallback keeps the process ALIVE: the user sees the
1420
+ * fallback, the timer fires, `markHealthy()` runs, and a bundle that cannot render its first
1421
+ * screen is recorded as healthy and never reverted. ScaleBunErrorBoundary calls this so the
1422
+ * marker stays set: the next cold start counts toward the bundle's revert exactly as a crash
1423
+ * would have.
1424
+ *
1425
+ * No-op outside the window (the bundle already proved itself, or this launch is not an OTA
1426
+ * bundle's first run), so a boundary catching an ordinary bug later in the session never
1427
+ * condemns a healthy release.
1428
+ *
1429
+ * @returns true when the window was open and `markHealthy` has been withheld.
1430
+ */
1431
+ noteBootFailure(): boolean {
1432
+ if (!this.healthyTimer) return false;
1433
+ clearTimeout(this.healthyTimer);
1434
+ this.healthyTimer = null;
1435
+ this.bootFailedThisLaunch = true;
1436
+ logger.warn(
1437
+ '[OTA] Boot guard: a render error was caught inside the health window — this bundle is NOT ' +
1438
+ 'marked healthy, and the next cold start counts toward reverting it.',
1439
+ );
1440
+ return true;
1441
+ }
1442
+
1443
+ /** One-shot guard so repeated syncs cannot stack resume listeners. */
1444
+ private resumeRestartArmed = false;
1445
+
1446
+ /**
1447
+ * ON_NEXT_RESUME: restart the JS runtime the next time the app returns to
1448
+ * the foreground after genuinely being in the background.
1449
+ *
1450
+ * The staged bundle is already applied at this point — the restart is purely
1451
+ * about WHEN the user experiences the reload. Two deliberate choices:
1452
+ *
1453
+ * - Armed only after a real background→active transition, never on the
1454
+ * initial 'active' state, so installing while the user is mid-session
1455
+ * does not instantly yank the screen out from under them.
1456
+ * - One-shot. The listener removes itself after firing (or after the
1457
+ * restart makes the whole question moot).
1458
+ */
1459
+ private armResumeRestart(): void {
1460
+ if (this.resumeRestartArmed) return;
1461
+ this.resumeRestartArmed = true;
1462
+
1463
+ let wasBackground = false;
1464
+ try {
1465
+ const sub = AppState.addEventListener('change', (state) => {
1466
+ if (state === 'background') {
1467
+ wasBackground = true;
1468
+ return;
1469
+ }
1470
+ if (state === 'active' && wasBackground) {
1471
+ try {
1472
+ sub.remove();
1473
+ } catch {
1474
+ /* the restart below makes cleanup moot */
1475
+ }
1476
+ this.resumeRestartArmed = false;
1477
+ logger.info('[OTA] App resumed — activating the staged update now');
1478
+ this.restart();
1479
+ }
1480
+ });
1481
+ logger.debug('[OTA] Update staged — will activate on next resume (ON_NEXT_RESUME)');
1482
+ } catch {
1483
+ // AppState unavailable (tests, exotic hosts): the update still activates
1484
+ // on the next cold start, which is the documented fallback behaviour.
1485
+ this.resumeRestartArmed = false;
1486
+ }
1487
+ }
1488
+
1489
+ /**
1490
+ * Reload the JS app bundle to apply the new update immediately.
1491
+ *
1492
+ * Order matters: the native `restartApp()` is the only path that works in
1493
+ * RELEASE builds. `DevSettings.reload()` looks callable there too — it
1494
+ * logged, returned, and reloaded nothing when tested live on a release APK,
1495
+ * which made every "restart" this SDK ever promised a silent no-op in
1496
+ * production. DevSettings remains as the dev-build fallback for hosts that
1497
+ * have not rebuilt native yet.
1498
+ */
1499
+ restart(): void {
1500
+ noThrow(() => {
1501
+ logger.info('[OTA] Triggering app restart…');
1502
+ if (NativeScaleBunOta && typeof NativeScaleBunOta.restartApp === 'function') {
1503
+ NativeScaleBunOta.restartApp();
1504
+ } else if (DevSettings && typeof DevSettings.reload === 'function') {
1505
+ DevSettings.reload();
1506
+ } else if (NativeModules.RNReload) {
1507
+ NativeModules.RNReload.reload();
1508
+ }
1509
+ });
1510
+ }
1511
+ }
1512
+
1513
+ export const otaOrchestrator = new OtaOrchestrator();