@hot-updater/react-native 1.0.0-rc.16 → 1.0.0-rc.17

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 (316) hide show
  1. package/android/src/main/java/com/hotupdater/BundleFileStorageService.kt +491 -388
  2. package/android/src/main/java/com/hotupdater/BundleMetadata.kt +5 -11
  3. package/android/src/main/java/com/hotupdater/FileManagerService.kt +45 -0
  4. package/android/src/main/java/com/hotupdater/HotUpdaterException.kt +290 -12
  5. package/android/src/main/java/com/hotupdater/HotUpdaterImpl.kt +35 -19
  6. package/android/src/main/java/com/hotupdater/InstallIdentityService.kt +37 -0
  7. package/android/src/main/java/com/hotupdater/KeyValueStorageService.kt +86 -0
  8. package/android/src/main/java/com/hotupdater/NetworkState.kt +31 -0
  9. package/android/src/main/java/com/hotupdater/NoBackupStorage.kt +17 -0
  10. package/android/src/main/java/com/hotupdater/OkHttpDownloadService.kt +110 -52
  11. package/android/src/main/java/com/hotupdater/PreviousProcessExit.kt +89 -0
  12. package/android/src/main/java/com/hotupdater/ReactNativeValueConverters.kt +34 -0
  13. package/android/src/newarch/HotUpdaterModule.kt +74 -69
  14. package/android/src/oldarch/HotUpdaterModule.kt +63 -59
  15. package/android/src/oldarch/HotUpdaterSpec.kt +4 -6
  16. package/android/src/test/java/com/hotupdater/BsdiffPatchTest.kt +1 -1
  17. package/android/src/test/java/com/hotupdater/BundleFileStorageServiceTest.kt +446 -61
  18. package/android/src/test/java/com/hotupdater/HotUpdaterExceptionTest.kt +220 -0
  19. package/android/src/test/java/com/hotupdater/HotUpdaterImplTest.kt +19 -27
  20. package/android/src/test/java/com/hotupdater/InstallIdentityServiceTest.kt +71 -0
  21. package/android/src/test/java/com/hotupdater/KeyValueStorageServiceTest.kt +106 -0
  22. package/android/src/test/java/com/hotupdater/NoBackupContext.kt +11 -0
  23. package/android/src/test/java/com/hotupdater/OkHttpDownloadServiceTest.kt +309 -23
  24. package/android/src/test/java/com/hotupdater/PreviousProcessExitTest.kt +57 -0
  25. package/ios/HotUpdater/Internal/BundleFileStorageService.swift +238 -157
  26. package/ios/HotUpdater/Internal/BundleMetadata.swift +3 -53
  27. package/ios/HotUpdater/Internal/FileManagerService.swift +48 -0
  28. package/ios/HotUpdater/Internal/HotUpdater.mm +8 -18
  29. package/ios/HotUpdater/Internal/HotUpdaterImpl.swift +48 -29
  30. package/ios/HotUpdater/Internal/KeyValueStorageService.swift +71 -0
  31. package/ios/HotUpdater/Internal/URLSessionDownloadService.swift +108 -1
  32. package/ios/HotUpdater/Internal/UpdateFailure.swift +390 -0
  33. package/lib/commonjs/appReady.js +111 -0
  34. package/lib/commonjs/appReady.js.map +1 -0
  35. package/lib/commonjs/appReady.spec.js +360 -0
  36. package/lib/commonjs/appReady.spec.js.map +1 -0
  37. package/lib/commonjs/{notifyAppReadyInsights.test-utils.js → appReady.test-utils.js} +4 -3
  38. package/lib/commonjs/appReady.test-utils.js.map +1 -0
  39. package/lib/commonjs/baseURL.js +16 -0
  40. package/lib/commonjs/baseURL.js.map +1 -0
  41. package/lib/commonjs/checkForUpdate.js +104 -56
  42. package/lib/commonjs/checkForUpdate.js.map +1 -1
  43. package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js +337 -74
  44. package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js.map +1 -1
  45. package/lib/commonjs/clientPlugin.js +49 -0
  46. package/lib/commonjs/clientPlugin.js.map +1 -0
  47. package/lib/commonjs/entryImportGraph.spec.js +50 -0
  48. package/lib/commonjs/entryImportGraph.spec.js.map +1 -0
  49. package/lib/commonjs/fetchJSON.js +2 -6
  50. package/lib/commonjs/fetchJSON.js.map +1 -1
  51. package/lib/commonjs/httpClient.js +18 -165
  52. package/lib/commonjs/httpClient.js.map +1 -1
  53. package/lib/commonjs/httpClient.spec.js +26 -199
  54. package/lib/commonjs/httpClient.spec.js.map +1 -1
  55. package/lib/commonjs/index.js +49 -36
  56. package/lib/commonjs/index.js.map +1 -1
  57. package/lib/commonjs/index.spec.js +108 -123
  58. package/lib/commonjs/index.spec.js.map +1 -1
  59. package/lib/commonjs/native.js +67 -48
  60. package/lib/commonjs/native.js.map +1 -1
  61. package/lib/commonjs/native.spec.js +80 -58
  62. package/lib/commonjs/native.spec.js.map +1 -1
  63. package/lib/commonjs/pluginHost.js +208 -0
  64. package/lib/commonjs/pluginHost.js.map +1 -0
  65. package/lib/commonjs/pluginHost.spec.js +292 -0
  66. package/lib/commonjs/pluginHost.spec.js.map +1 -0
  67. package/lib/commonjs/plugins/insights/eventId.js +129 -0
  68. package/lib/commonjs/plugins/insights/eventId.js.map +1 -0
  69. package/lib/commonjs/plugins/insights/eventId.spec.js +47 -0
  70. package/lib/commonjs/plugins/insights/eventId.spec.js.map +1 -0
  71. package/lib/commonjs/plugins/insights/index.js +272 -0
  72. package/lib/commonjs/plugins/insights/index.js.map +1 -0
  73. package/lib/commonjs/plugins/insights/insights.spec.js +640 -0
  74. package/lib/commonjs/plugins/insights/insights.spec.js.map +1 -0
  75. package/lib/commonjs/plugins/insights/sender.js +128 -0
  76. package/lib/commonjs/plugins/insights/sender.js.map +1 -0
  77. package/lib/commonjs/plugins/insights/sender.spec.js +265 -0
  78. package/lib/commonjs/plugins/insights/sender.spec.js.map +1 -0
  79. package/lib/commonjs/plugins/insights/state.js +145 -0
  80. package/lib/commonjs/plugins/insights/state.js.map +1 -0
  81. package/lib/commonjs/releaseCatalogCache.js +13 -2
  82. package/lib/commonjs/releaseCatalogCache.js.map +1 -1
  83. package/lib/commonjs/releaseCatalogCache.spec.js +18 -0
  84. package/lib/commonjs/releaseCatalogCache.spec.js.map +1 -1
  85. package/lib/commonjs/sdkVersion.js +1 -1
  86. package/lib/commonjs/specs/NativeHotUpdater.js.map +1 -1
  87. package/lib/commonjs/updateError.js +132 -0
  88. package/lib/commonjs/updateError.js.map +1 -0
  89. package/lib/commonjs/updateError.spec.js +149 -0
  90. package/lib/commonjs/updateError.spec.js.map +1 -0
  91. package/lib/commonjs/wrap.js +43 -25
  92. package/lib/commonjs/wrap.js.map +1 -1
  93. package/lib/commonjs/wrap.progress.spec.js +195 -0
  94. package/lib/commonjs/wrap.progress.spec.js.map +1 -0
  95. package/lib/commonjs/wrap.spec.js +94 -230
  96. package/lib/commonjs/wrap.spec.js.map +1 -1
  97. package/lib/module/appReady.js +103 -0
  98. package/lib/module/appReady.js.map +1 -0
  99. package/lib/module/appReady.spec.js +359 -0
  100. package/lib/module/appReady.spec.js.map +1 -0
  101. package/lib/module/{notifyAppReadyInsights.test-utils.js → appReady.test-utils.js} +4 -3
  102. package/lib/module/appReady.test-utils.js.map +1 -0
  103. package/lib/module/baseURL.js +11 -0
  104. package/lib/module/baseURL.js.map +1 -0
  105. package/lib/module/checkForUpdate.js +103 -57
  106. package/lib/module/checkForUpdate.js.map +1 -1
  107. package/lib/module/checkForUpdate.releaseCatalog.spec.js +337 -74
  108. package/lib/module/checkForUpdate.releaseCatalog.spec.js.map +1 -1
  109. package/lib/module/clientPlugin.js +44 -0
  110. package/lib/module/clientPlugin.js.map +1 -0
  111. package/lib/module/entryImportGraph.spec.js +50 -0
  112. package/lib/module/entryImportGraph.spec.js.map +1 -0
  113. package/lib/module/fetchJSON.js +2 -6
  114. package/lib/module/fetchJSON.js.map +1 -1
  115. package/lib/module/httpClient.js +18 -165
  116. package/lib/module/httpClient.js.map +1 -1
  117. package/lib/module/httpClient.spec.js +27 -200
  118. package/lib/module/httpClient.spec.js.map +1 -1
  119. package/lib/module/index.js +44 -38
  120. package/lib/module/index.js.map +1 -1
  121. package/lib/module/index.spec.js +108 -123
  122. package/lib/module/index.spec.js.map +1 -1
  123. package/lib/module/native.js +63 -44
  124. package/lib/module/native.js.map +1 -1
  125. package/lib/module/native.spec.js +80 -58
  126. package/lib/module/native.spec.js.map +1 -1
  127. package/lib/module/pluginHost.js +200 -0
  128. package/lib/module/pluginHost.js.map +1 -0
  129. package/lib/module/pluginHost.spec.js +291 -0
  130. package/lib/module/pluginHost.spec.js.map +1 -0
  131. package/lib/module/plugins/insights/eventId.js +122 -0
  132. package/lib/module/plugins/insights/eventId.js.map +1 -0
  133. package/lib/module/plugins/insights/eventId.spec.js +47 -0
  134. package/lib/module/plugins/insights/eventId.spec.js.map +1 -0
  135. package/lib/module/plugins/insights/index.js +268 -0
  136. package/lib/module/plugins/insights/index.js.map +1 -0
  137. package/lib/module/plugins/insights/insights.spec.js +639 -0
  138. package/lib/module/plugins/insights/insights.spec.js.map +1 -0
  139. package/lib/module/plugins/insights/sender.js +123 -0
  140. package/lib/module/plugins/insights/sender.js.map +1 -0
  141. package/lib/module/plugins/insights/sender.spec.js +265 -0
  142. package/lib/module/plugins/insights/sender.spec.js.map +1 -0
  143. package/lib/module/plugins/insights/state.js +139 -0
  144. package/lib/module/plugins/insights/state.js.map +1 -0
  145. package/lib/module/releaseCatalogCache.js +13 -2
  146. package/lib/module/releaseCatalogCache.js.map +1 -1
  147. package/lib/module/releaseCatalogCache.spec.js +18 -0
  148. package/lib/module/releaseCatalogCache.spec.js.map +1 -1
  149. package/lib/module/sdkVersion.js +1 -1
  150. package/lib/module/specs/NativeHotUpdater.js.map +1 -1
  151. package/lib/module/updateError.js +126 -0
  152. package/lib/module/updateError.js.map +1 -0
  153. package/lib/module/updateError.spec.js +149 -0
  154. package/lib/module/updateError.spec.js.map +1 -0
  155. package/lib/module/wrap.js +43 -25
  156. package/lib/module/wrap.js.map +1 -1
  157. package/lib/module/wrap.progress.spec.js +196 -0
  158. package/lib/module/wrap.progress.spec.js.map +1 -0
  159. package/lib/module/wrap.spec.js +93 -229
  160. package/lib/module/wrap.spec.js.map +1 -1
  161. package/lib/typescript/commonjs/appReady.d.ts +23 -0
  162. package/lib/typescript/commonjs/appReady.d.ts.map +1 -0
  163. package/lib/typescript/commonjs/appReady.test-utils.d.ts +9 -0
  164. package/lib/typescript/commonjs/appReady.test-utils.d.ts.map +1 -0
  165. package/lib/typescript/commonjs/baseURL.d.ts +4 -0
  166. package/lib/typescript/commonjs/baseURL.d.ts.map +1 -0
  167. package/lib/typescript/commonjs/checkForUpdate.d.ts +15 -2
  168. package/lib/typescript/commonjs/checkForUpdate.d.ts.map +1 -1
  169. package/lib/typescript/commonjs/clientPlugin.d.ts +185 -0
  170. package/lib/typescript/commonjs/clientPlugin.d.ts.map +1 -0
  171. package/lib/typescript/commonjs/fetchJSON.d.ts +2 -3
  172. package/lib/typescript/commonjs/fetchJSON.d.ts.map +1 -1
  173. package/lib/typescript/commonjs/httpClient.d.ts +2 -36
  174. package/lib/typescript/commonjs/httpClient.d.ts.map +1 -1
  175. package/lib/typescript/commonjs/index.d.ts +3 -6
  176. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  177. package/lib/typescript/commonjs/native.d.ts +29 -15
  178. package/lib/typescript/commonjs/native.d.ts.map +1 -1
  179. package/lib/typescript/commonjs/pluginHost.d.ts +29 -0
  180. package/lib/typescript/commonjs/pluginHost.d.ts.map +1 -0
  181. package/lib/typescript/commonjs/plugins/insights/eventId.d.ts +18 -0
  182. package/lib/typescript/commonjs/plugins/insights/eventId.d.ts.map +1 -0
  183. package/lib/typescript/commonjs/plugins/insights/index.d.ts +40 -0
  184. package/lib/typescript/commonjs/plugins/insights/index.d.ts.map +1 -0
  185. package/lib/typescript/commonjs/plugins/insights/sender.d.ts +74 -0
  186. package/lib/typescript/commonjs/plugins/insights/sender.d.ts.map +1 -0
  187. package/lib/typescript/commonjs/plugins/insights/state.d.ts +46 -0
  188. package/lib/typescript/commonjs/plugins/insights/state.d.ts.map +1 -0
  189. package/lib/typescript/commonjs/releaseCatalogCache.d.ts +5 -1
  190. package/lib/typescript/commonjs/releaseCatalogCache.d.ts.map +1 -1
  191. package/lib/typescript/commonjs/sdkVersion.d.ts +1 -1
  192. package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts +34 -12
  193. package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts.map +1 -1
  194. package/lib/typescript/commonjs/updateError.d.ts +26 -0
  195. package/lib/typescript/commonjs/updateError.d.ts.map +1 -0
  196. package/lib/typescript/commonjs/wrap.d.ts.map +1 -1
  197. package/lib/typescript/commonjs/wrap.types.d.ts +6 -10
  198. package/lib/typescript/commonjs/wrap.types.d.ts.map +1 -1
  199. package/lib/typescript/module/appReady.d.ts +23 -0
  200. package/lib/typescript/module/appReady.d.ts.map +1 -0
  201. package/lib/typescript/module/appReady.test-utils.d.ts +9 -0
  202. package/lib/typescript/module/appReady.test-utils.d.ts.map +1 -0
  203. package/lib/typescript/module/baseURL.d.ts +4 -0
  204. package/lib/typescript/module/baseURL.d.ts.map +1 -0
  205. package/lib/typescript/module/checkForUpdate.d.ts +15 -2
  206. package/lib/typescript/module/checkForUpdate.d.ts.map +1 -1
  207. package/lib/typescript/module/clientPlugin.d.ts +185 -0
  208. package/lib/typescript/module/clientPlugin.d.ts.map +1 -0
  209. package/lib/typescript/module/fetchJSON.d.ts +2 -3
  210. package/lib/typescript/module/fetchJSON.d.ts.map +1 -1
  211. package/lib/typescript/module/httpClient.d.ts +2 -36
  212. package/lib/typescript/module/httpClient.d.ts.map +1 -1
  213. package/lib/typescript/module/index.d.ts +3 -6
  214. package/lib/typescript/module/index.d.ts.map +1 -1
  215. package/lib/typescript/module/native.d.ts +29 -15
  216. package/lib/typescript/module/native.d.ts.map +1 -1
  217. package/lib/typescript/module/pluginHost.d.ts +29 -0
  218. package/lib/typescript/module/pluginHost.d.ts.map +1 -0
  219. package/lib/typescript/module/plugins/insights/eventId.d.ts +18 -0
  220. package/lib/typescript/module/plugins/insights/eventId.d.ts.map +1 -0
  221. package/lib/typescript/module/plugins/insights/index.d.ts +40 -0
  222. package/lib/typescript/module/plugins/insights/index.d.ts.map +1 -0
  223. package/lib/typescript/module/plugins/insights/sender.d.ts +74 -0
  224. package/lib/typescript/module/plugins/insights/sender.d.ts.map +1 -0
  225. package/lib/typescript/module/plugins/insights/state.d.ts +46 -0
  226. package/lib/typescript/module/plugins/insights/state.d.ts.map +1 -0
  227. package/lib/typescript/module/releaseCatalogCache.d.ts +5 -1
  228. package/lib/typescript/module/releaseCatalogCache.d.ts.map +1 -1
  229. package/lib/typescript/module/sdkVersion.d.ts +1 -1
  230. package/lib/typescript/module/specs/NativeHotUpdater.d.ts +34 -12
  231. package/lib/typescript/module/specs/NativeHotUpdater.d.ts.map +1 -1
  232. package/lib/typescript/module/updateError.d.ts +26 -0
  233. package/lib/typescript/module/updateError.d.ts.map +1 -0
  234. package/lib/typescript/module/wrap.d.ts.map +1 -1
  235. package/lib/typescript/module/wrap.types.d.ts +6 -10
  236. package/lib/typescript/module/wrap.types.d.ts.map +1 -1
  237. package/package.json +14 -2
  238. package/plugins/insights/package.json +8 -0
  239. package/src/appReady.spec.ts +393 -0
  240. package/src/{notifyAppReadyInsights.test-utils.ts → appReady.test-utils.ts} +7 -7
  241. package/src/appReady.ts +149 -0
  242. package/src/baseURL.ts +15 -0
  243. package/src/checkForUpdate.releaseCatalog.spec.ts +370 -76
  244. package/src/checkForUpdate.ts +135 -80
  245. package/src/clientPlugin.ts +231 -0
  246. package/src/entryImportGraph.spec.ts +65 -0
  247. package/src/fetchJSON.ts +3 -10
  248. package/src/httpClient.spec.ts +30 -227
  249. package/src/httpClient.ts +20 -256
  250. package/src/index.spec.ts +117 -93
  251. package/src/index.ts +67 -52
  252. package/src/native.spec.ts +98 -72
  253. package/src/native.ts +93 -77
  254. package/src/pluginHost.spec.ts +297 -0
  255. package/src/pluginHost.ts +262 -0
  256. package/src/plugins/insights/eventId.spec.ts +60 -0
  257. package/src/plugins/insights/eventId.ts +171 -0
  258. package/src/plugins/insights/index.ts +367 -0
  259. package/src/plugins/insights/insights.spec.ts +732 -0
  260. package/src/plugins/insights/sender.spec.ts +287 -0
  261. package/src/plugins/insights/sender.ts +221 -0
  262. package/src/plugins/insights/state.ts +184 -0
  263. package/src/releaseCatalogCache.spec.ts +22 -0
  264. package/src/releaseCatalogCache.ts +19 -4
  265. package/src/sdkVersion.ts +1 -1
  266. package/src/specs/NativeHotUpdater.ts +34 -13
  267. package/src/updateError.spec.ts +144 -0
  268. package/src/updateError.ts +153 -0
  269. package/src/wrap.progress.spec.ts +232 -0
  270. package/src/wrap.spec.ts +100 -283
  271. package/src/wrap.tsx +57 -26
  272. package/src/wrap.types.ts +6 -12
  273. package/lib/commonjs/notifyAppReadyInsights.boundary.spec.js +0 -225
  274. package/lib/commonjs/notifyAppReadyInsights.boundary.spec.js.map +0 -1
  275. package/lib/commonjs/notifyAppReadyInsights.js +0 -188
  276. package/lib/commonjs/notifyAppReadyInsights.js.map +0 -1
  277. package/lib/commonjs/notifyAppReadyInsights.spec.js +0 -378
  278. package/lib/commonjs/notifyAppReadyInsights.spec.js.map +0 -1
  279. package/lib/commonjs/notifyAppReadyInsights.test-utils.js.map +0 -1
  280. package/lib/commonjs/notifyAppReadyInsights.transport.spec.js +0 -171
  281. package/lib/commonjs/notifyAppReadyInsights.transport.spec.js.map +0 -1
  282. package/lib/commonjs/uuidv7.js +0 -41
  283. package/lib/commonjs/uuidv7.js.map +0 -1
  284. package/lib/commonjs/uuidv7.spec.js +0 -30
  285. package/lib/commonjs/uuidv7.spec.js.map +0 -1
  286. package/lib/module/notifyAppReadyInsights.boundary.spec.js +0 -224
  287. package/lib/module/notifyAppReadyInsights.boundary.spec.js.map +0 -1
  288. package/lib/module/notifyAppReadyInsights.js +0 -181
  289. package/lib/module/notifyAppReadyInsights.js.map +0 -1
  290. package/lib/module/notifyAppReadyInsights.spec.js +0 -377
  291. package/lib/module/notifyAppReadyInsights.spec.js.map +0 -1
  292. package/lib/module/notifyAppReadyInsights.test-utils.js.map +0 -1
  293. package/lib/module/notifyAppReadyInsights.transport.spec.js +0 -170
  294. package/lib/module/notifyAppReadyInsights.transport.spec.js.map +0 -1
  295. package/lib/module/uuidv7.js +0 -36
  296. package/lib/module/uuidv7.js.map +0 -1
  297. package/lib/module/uuidv7.spec.js +0 -30
  298. package/lib/module/uuidv7.spec.js.map +0 -1
  299. package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts +0 -25
  300. package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts.map +0 -1
  301. package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts +0 -8
  302. package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts.map +0 -1
  303. package/lib/typescript/commonjs/uuidv7.d.ts +0 -10
  304. package/lib/typescript/commonjs/uuidv7.d.ts.map +0 -1
  305. package/lib/typescript/module/notifyAppReadyInsights.d.ts +0 -25
  306. package/lib/typescript/module/notifyAppReadyInsights.d.ts.map +0 -1
  307. package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts +0 -8
  308. package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts.map +0 -1
  309. package/lib/typescript/module/uuidv7.d.ts +0 -10
  310. package/lib/typescript/module/uuidv7.d.ts.map +0 -1
  311. package/src/notifyAppReadyInsights.boundary.spec.ts +0 -242
  312. package/src/notifyAppReadyInsights.spec.ts +0 -362
  313. package/src/notifyAppReadyInsights.transport.spec.ts +0 -196
  314. package/src/notifyAppReadyInsights.ts +0 -293
  315. package/src/uuidv7.spec.ts +0 -25
  316. package/src/uuidv7.ts +0 -38
package/src/index.spec.ts CHANGED
@@ -31,7 +31,9 @@ const mocks = vi.hoisted(() => {
31
31
  getInstallId: vi.fn(() => "install-id"),
32
32
  getManifest: vi.fn(() => null),
33
33
  getMinBundleId: vi.fn(() => "min-bundle-id"),
34
- getPersistedUserIdentity: vi.fn(() => ({})),
34
+ configurePlugins: vi.fn(),
35
+ emitAfterAppReady: vi.fn(),
36
+ reportUpdateError: vi.fn(),
35
37
  init: vi.fn(),
36
38
  isChannelSwitched: vi.fn(() => false),
37
39
  notifyAppReady: vi.fn(() => ({ status: "UNCHANGED" as const })),
@@ -39,8 +41,7 @@ const mocks = vi.hoisted(() => {
39
41
  resetChannel: vi.fn(),
40
42
  setCohort: vi.fn(),
41
43
  setReloadBehavior: vi.fn(),
42
- setUser: vi.fn(),
43
- updateBundle: vi.fn(),
44
+ stageBundle: vi.fn(),
44
45
  wrap: vi.fn((Component: unknown) => Component),
45
46
  };
46
47
  });
@@ -53,6 +54,15 @@ vi.mock("./httpClient", () => ({
53
54
 
54
55
  vi.mock("./checkForUpdate", () => ({
55
56
  checkForUpdate: mocks.checkForUpdate,
57
+ reportUpdateError: mocks.reportUpdateError,
58
+ }));
59
+
60
+ vi.mock("./pluginHost", () => ({
61
+ configurePlugins: mocks.configurePlugins,
62
+ }));
63
+
64
+ vi.mock("./appReady", () => ({
65
+ emitAfterAppReady: mocks.emitAfterAppReady,
56
66
  }));
57
67
 
58
68
  vi.mock("./native", () => ({
@@ -72,15 +82,13 @@ vi.mock("./native", () => ({
72
82
  getInstallId: mocks.getInstallId,
73
83
  getManifest: mocks.getManifest,
74
84
  getMinBundleId: mocks.getMinBundleId,
75
- getPersistedUserIdentity: mocks.getPersistedUserIdentity,
76
85
  isChannelSwitched: mocks.isChannelSwitched,
77
86
  notifyAppReady: mocks.notifyAppReady,
78
87
  reload: mocks.reload,
79
88
  resetChannel: mocks.resetChannel,
80
89
  setCohort: mocks.setCohort,
81
90
  setReloadBehavior: mocks.setReloadBehavior,
82
- setUser: mocks.setUser,
83
- updateBundle: mocks.updateBundle,
91
+ stageBundle: mocks.stageBundle,
84
92
  }));
85
93
 
86
94
  vi.mock("./wrap", () => ({
@@ -120,7 +128,6 @@ describe("HotUpdater client initialization", () => {
120
128
  const HotUpdater = await importHotUpdater();
121
129
 
122
130
  HotUpdater.init({
123
- insights: true,
124
131
  baseURL: "https://updates.example.com",
125
132
  requestHeaders: { Authorization: "Bearer token" },
126
133
  requestTimeout: 1000,
@@ -130,7 +137,6 @@ describe("HotUpdater client initialization", () => {
130
137
  "https://updates.example.com",
131
138
  );
132
139
  expect(mocks.init).toHaveBeenCalledWith({
133
- insights: true,
134
140
  client,
135
141
  requestHeaders: { Authorization: "Bearer token" },
136
142
  requestTimeout: 1000,
@@ -147,105 +153,131 @@ describe("HotUpdater client initialization", () => {
147
153
  expect(resolveBaseURL).not.toHaveBeenCalled();
148
154
  });
149
155
 
150
- it("enables insights by default for init and wrap", async () => {
151
- const HotUpdater = await importHotUpdater();
152
-
153
- HotUpdater.init({ baseURL: "https://updates.example.com" });
154
- HotUpdater.wrap({
155
- baseURL: "https://updates.example.com",
156
- updateStrategy: "appVersion",
156
+ it("sets up plugins with the settings they fetch with, before init reads the launch", async () => {
157
+ const plugin = { id: "example", setup: vi.fn() };
158
+ const onError = vi.fn();
159
+ mocks.init.mockImplementationOnce(() => {
160
+ expect(mocks.configurePlugins).toHaveBeenCalledOnce();
157
161
  });
158
-
159
- expect(mocks.init).toHaveBeenCalledWith(
160
- expect.objectContaining({ insights: true }),
161
- );
162
- expect(mocks.wrap).toHaveBeenCalledWith(
163
- expect.objectContaining({ insights: true }),
164
- );
165
- });
166
-
167
- it("preserves an explicit insights opt-out", async () => {
168
162
  const HotUpdater = await importHotUpdater();
169
163
 
170
164
  HotUpdater.init({
171
165
  baseURL: "https://updates.example.com",
172
- insights: false,
166
+ onError,
167
+ plugins: [plugin],
168
+ requestHeaders: { "x-api-key": "client-key" },
169
+ requestTimeout: 1000,
173
170
  });
174
171
  HotUpdater.wrap({
175
- baseURL: "https://updates.example.com",
176
- insights: false,
172
+ baseURL: "https://other.example.com",
173
+ plugins: [plugin],
177
174
  updateStrategy: "appVersion",
178
175
  });
179
176
 
177
+ expect(mocks.configurePlugins).toHaveBeenNthCalledWith(1, [plugin], {
178
+ baseURL: "https://updates.example.com",
179
+ onError,
180
+ requestHeaders: { "x-api-key": "client-key" },
181
+ requestTimeout: 1000,
182
+ });
183
+ expect(mocks.configurePlugins).toHaveBeenNthCalledWith(2, [plugin], {
184
+ baseURL: "https://other.example.com",
185
+ onError: undefined,
186
+ requestHeaders: undefined,
187
+ requestTimeout: undefined,
188
+ });
180
189
  expect(mocks.init).toHaveBeenCalledWith(
181
- expect.objectContaining({ insights: false }),
190
+ expect.not.objectContaining({ plugins: expect.anything() }),
182
191
  );
183
192
  expect(mocks.wrap).toHaveBeenCalledWith(
184
- expect.objectContaining({ insights: false }),
193
+ expect.not.objectContaining({ plugins: expect.anything() }),
185
194
  );
186
195
  });
187
196
 
188
- it.each([
189
- { dev: true, insights: undefined, expected: false },
190
- { dev: true, insights: true, expected: false },
191
- { dev: true, insights: false, expected: false },
192
- { dev: true, insights: { debug: true }, expected: true },
193
- { dev: false, insights: { debug: true }, expected: true },
194
- { dev: false, insights: { debug: false }, expected: true },
195
- { dev: false, insights: false, expected: false },
196
- ] as const)(
197
- "resolves insights $insights to $expected when __DEV__ is $dev",
198
- async ({ dev, insights, expected }) => {
199
- vi.stubGlobal("__DEV__", dev);
200
- vi.spyOn(console, "error").mockImplementation(() => undefined);
201
- const HotUpdater = await importHotUpdater();
197
+ it("reports a staged manual download to plugins after the launch", async () => {
198
+ mocks.stageBundle.mockResolvedValueOnce({
199
+ delivery: "archive",
200
+ patchFallback: true,
201
+ });
202
+ mocks.getActiveUpdateState.mockReturnValue({
203
+ activeSelection: {
204
+ bundleId: "next-bundle-id",
205
+ channel: "production",
206
+ kind: "BUNDLE",
207
+ releaseId: "next-release-id",
208
+ scopeKey: "v1:fingerprint:project:ios:cHJvZHVjdGlvbg:hash",
209
+ },
210
+ highestSeenCatalogs: {},
211
+ stableSelection: null,
212
+ verificationPending: true,
213
+ } as never);
214
+ const HotUpdater = await importHotUpdater();
215
+ HotUpdater.init({ baseURL: "https://updates.example.com" });
202
216
 
203
- HotUpdater.init({ baseURL: "https://updates.example.com", insights });
204
- HotUpdater.wrap({
205
- baseURL: "https://updates.example.com",
206
- insights,
207
- updateStrategy: "appVersion",
208
- });
217
+ await HotUpdater.updateBundle({
218
+ assets: {},
219
+ bundleId: "next-bundle-id",
220
+ manifestFileHash: "manifest-hash",
221
+ manifestUrl: "https://updates.example.com/manifest.json",
222
+ status: "UPDATE",
223
+ });
209
224
 
210
- expect(mocks.init).toHaveBeenCalledWith(
211
- expect.objectContaining({ insights: expected }),
212
- );
213
- expect(mocks.wrap).toHaveBeenCalledWith(
214
- expect.objectContaining({ insights: expected }),
215
- );
216
- },
217
- );
225
+ expect(mocks.emitAfterAppReady).toHaveBeenCalledOnce();
226
+ const [name, createPayload] = mocks.emitAfterAppReady.mock.calls[0] as [
227
+ string,
228
+ () => unknown,
229
+ ];
230
+ expect(name).toBe("onBundleDownloaded");
231
+ expect(createPayload()).toEqual({
232
+ channel: "production",
233
+ fromBundleId: "bundle-id",
234
+ fromReleaseId: null,
235
+ toBundleId: "next-bundle-id",
236
+ toReleaseId: "next-release-id",
237
+ updateStrategy: "fingerprint",
238
+ delivery: "archive",
239
+ patchFallback: true,
240
+ });
241
+ });
218
242
 
219
- it.each([
220
- { dev: true, reports: false },
221
- { dev: false, reports: true },
222
- ])(
223
- "gates manual checks and downloads on the build type (__DEV__: $dev)",
224
- async ({ dev, reports }) => {
225
- vi.stubGlobal("__DEV__", dev);
226
- const sendInsightsEvent = vi.fn(async () => undefined);
227
- mocks.createHttpClient.mockReturnValue({
228
- createSession: vi.fn(async () => ({ sendInsightsEvent })),
229
- } as never);
230
- mocks.updateBundle.mockResolvedValueOnce(true);
231
- const HotUpdater = await importHotUpdater();
232
- HotUpdater.init({ baseURL: "https://updates.example.com" });
243
+ it("reports a failed manual download to plugins and rethrows it", async () => {
244
+ const error = Object.assign(new Error("hash mismatch"), {
245
+ code: "SIGNATURE_VERIFICATION_FAILED",
246
+ userInfo: { reason: "hash_mismatch", stage: "download" },
247
+ });
248
+ mocks.stageBundle.mockRejectedValueOnce(error);
249
+ const HotUpdater = await importHotUpdater();
250
+ HotUpdater.init({ baseURL: "https://updates.example.com" });
233
251
 
234
- await HotUpdater.checkForUpdate({ updateStrategy: "appVersion" });
235
- await HotUpdater.updateBundle({
252
+ await expect(
253
+ HotUpdater.updateBundle({
236
254
  assets: {},
237
255
  bundleId: "next-bundle-id",
256
+ channel: "beta",
238
257
  manifestFileHash: "manifest-hash",
239
258
  manifestUrl: "https://updates.example.com/manifest.json",
259
+ selection: {
260
+ releaseId: "next-release-id",
261
+ scopeKey: "v1:app-version:project:ios:YmV0YQ",
262
+ },
240
263
  status: "UPDATE",
241
- });
242
-
243
- expect(mocks.checkForUpdate).toHaveBeenCalledWith(
244
- expect.objectContaining({ insights: reports }),
245
- );
246
- expect(sendInsightsEvent).toHaveBeenCalledTimes(reports ? 1 : 0);
247
- },
248
- );
264
+ }),
265
+ ).rejects.toBe(error);
266
+
267
+ expect(mocks.reportUpdateError).toHaveBeenCalledWith(
268
+ error,
269
+ "download",
270
+ undefined,
271
+ {
272
+ bundleId: "bundle-id",
273
+ channel: "beta",
274
+ targetBundleId: "next-bundle-id",
275
+ targetReleaseId: "next-release-id",
276
+ updateStrategy: "appVersion",
277
+ },
278
+ );
279
+ expect(mocks.emitAfterAppReady).not.toHaveBeenCalled();
280
+ });
249
281
 
250
282
  it("requires baseURL and rejects the removed resolver shape", async () => {
251
283
  const HotUpdater = await importHotUpdater();
@@ -288,13 +320,12 @@ describe("HotUpdater client initialization", () => {
288
320
  expect(wrapOptions.updateStrategy).toBe("appVersion");
289
321
  });
290
322
 
291
- it("merges settings and carries the insights gate to checks", async () => {
323
+ it("merges settings into checks", async () => {
292
324
  const client = { createSession: vi.fn() };
293
325
  mocks.createHttpClient.mockReturnValue(client as never);
294
326
  const checkOnError = vi.fn();
295
327
  const HotUpdater = await importHotUpdater();
296
328
  HotUpdater.init({
297
- insights: true,
298
329
  baseURL: "https://updates.example.com",
299
330
  requestHeaders: { Authorization: "Bearer token" },
300
331
  requestTimeout: 1000,
@@ -307,7 +338,6 @@ describe("HotUpdater client initialization", () => {
307
338
  });
308
339
 
309
340
  expect(mocks.checkForUpdate).toHaveBeenCalledWith({
310
- insights: true,
311
341
  client,
312
342
  onError: checkOnError,
313
343
  requestHeaders: {
@@ -325,13 +355,11 @@ describe("HotUpdater client initialization", () => {
325
355
  const HotUpdater = await importHotUpdater();
326
356
 
327
357
  HotUpdater.wrap({
328
- insights: true,
329
358
  baseURL: "https://updates.example.com",
330
359
  updateStrategy: "appVersion",
331
360
  });
332
361
 
333
362
  expect(mocks.wrap).toHaveBeenCalledWith({
334
- insights: true,
335
363
  client,
336
364
  updateStrategy: "appVersion",
337
365
  });
@@ -396,15 +424,11 @@ describe("HotUpdater client initialization", () => {
396
424
  ).toThrow("requires HotUpdater.wrap() or HotUpdater.init() to be used");
397
425
  });
398
426
 
399
- it("preserves native identity and user APIs", async () => {
427
+ it("keeps the install id and leaves user identity to the insights plugin", async () => {
400
428
  const HotUpdater = await importHotUpdater();
401
429
 
402
430
  expect(HotUpdater.getInstallId()).toBe("install-id");
403
431
  expect(HotUpdater.getMinBundleId()).toBe("min-bundle-id");
404
- HotUpdater.setUser({ userId: "user-123", username: "alice" });
405
- expect(mocks.setUser).toHaveBeenCalledWith({
406
- userId: "user-123",
407
- username: "alice",
408
- });
432
+ expect(HotUpdater).not.toHaveProperty("setUser");
409
433
  });
410
434
  });
package/src/index.ts CHANGED
@@ -1,7 +1,9 @@
1
+ import { emitAfterAppReady } from "./appReady";
1
2
  import {
2
3
  type CheckForUpdateOptions,
3
4
  checkForUpdate,
4
5
  type InternalCheckForUpdateOptions,
6
+ reportUpdateError,
5
7
  } from "./checkForUpdate";
6
8
  import { createHttpClient, type HotUpdaterHttpClient } from "./httpClient";
7
9
  import {
@@ -27,11 +29,10 @@ import {
27
29
  resetChannel,
28
30
  setCohort,
29
31
  setReloadBehavior,
30
- setUser,
32
+ stageBundle,
31
33
  type UpdateParams,
32
- updateBundle,
33
34
  } from "./native";
34
- import { reportBundleDownloaded } from "./notifyAppReadyInsights";
35
+ import { configurePlugins } from "./pluginHost";
35
36
  import { hotUpdaterStore } from "./store";
36
37
  import {
37
38
  type AutoUpdateOptions,
@@ -43,6 +44,21 @@ import {
43
44
  wrap,
44
45
  } from "./wrap";
45
46
 
47
+ export {
48
+ defineClientPlugin,
49
+ type AppReadyResult,
50
+ type BundleDownloadedInfo,
51
+ type HotUpdaterClientContext,
52
+ type HotUpdaterClientHooks,
53
+ type HotUpdaterClientPlugin,
54
+ type HotUpdaterClientStorage,
55
+ type ReleaseTransitionKind,
56
+ type UpdateCheckResult,
57
+ type UpdateError,
58
+ type UpdateErrorReason,
59
+ type UpdateErrorStage,
60
+ type UpdateStrategy,
61
+ } from "./clientPlugin";
46
62
  export type {
47
63
  CustomReloadHandler,
48
64
  HotUpdaterEvent,
@@ -54,7 +70,6 @@ export type {
54
70
  ActiveUpdateState,
55
71
  ReloadBehavior,
56
72
  ReloadBehaviorSetting,
57
- SetUserParams,
58
73
  } from "./native";
59
74
  export * from "./store";
60
75
  export {
@@ -93,21 +108,6 @@ type HotUpdaterWrap = {
93
108
  (options: HotUpdaterOptions): ReturnType<typeof wrap>;
94
109
  };
95
110
 
96
- /**
97
- * Debug builds report only with `insights: { debug: true }`, so development
98
- * sessions do not mix into production Insights. `__DEV__` is defined only in
99
- * a React Native bundle; anywhere else, such as unit tests, counts as release.
100
- */
101
- const resolveInsights = (
102
- insights: HotUpdaterInitOptions["insights"],
103
- ): boolean => {
104
- if (insights === false) return false;
105
- const isDebugBuild = typeof __DEV__ !== "undefined" && __DEV__;
106
- return (
107
- !isDebugBuild || (typeof insights === "object" && insights?.debug === true)
108
- );
109
- };
110
-
111
111
  /**
112
112
  * Creates a HotUpdater client instance with all update management methods.
113
113
  * This function is called once on module initialization to create a singleton instance.
@@ -118,13 +118,11 @@ function createHotUpdaterClient() {
118
118
 
119
119
  // Global configuration stored from wrap
120
120
  const globalConfig: {
121
- insights: boolean;
122
121
  client: HotUpdaterHttpClient | null;
123
122
  requestHeaders?: Record<string, string>;
124
123
  requestTimeout?: number;
125
124
  onError?: (error: unknown) => void;
126
125
  } = {
127
- insights: true,
128
126
  client: null,
129
127
  };
130
128
 
@@ -173,10 +171,9 @@ function createHotUpdaterClient() {
173
171
  const autoOptions = incoming as AutoUpdateOptions;
174
172
 
175
173
  if (autoOptions.baseURL) {
176
- const { baseURL, ...rest } = autoOptions;
174
+ const { baseURL, plugins: _plugins, ...rest } = autoOptions;
177
175
  return {
178
176
  ...rest,
179
- insights: resolveInsights(rest.insights),
180
177
  client: createHttpClient(baseURL),
181
178
  };
182
179
  }
@@ -193,10 +190,9 @@ function createHotUpdaterClient() {
193
190
  };
194
191
 
195
192
  if (rest.baseURL) {
196
- const { baseURL, ...baseURLRest } = rest;
193
+ const { baseURL, plugins: _plugins, ...baseURLRest } = rest;
197
194
  return {
198
195
  ...baseURLRest,
199
- insights: resolveInsights(baseURLRest.insights),
200
196
  client: createHttpClient(baseURL),
201
197
  };
202
198
  }
@@ -208,7 +204,13 @@ function createHotUpdaterClient() {
208
204
  normalizedOptions: InternalInitOptions | InternalWrapOptions,
209
205
  options: HotUpdaterOptions | HotUpdaterInitOptions,
210
206
  ) => {
211
- globalConfig.insights = normalizedOptions.insights ?? true;
207
+ // Plugins are set up before init or wrap reads the launch they observe.
208
+ configurePlugins(options.plugins, {
209
+ baseURL: options.baseURL,
210
+ requestHeaders: options.requestHeaders,
211
+ requestTimeout: options.requestTimeout,
212
+ onError: options.onError,
213
+ });
212
214
  globalConfig.client = normalizedOptions.client;
213
215
  globalConfig.requestHeaders = options.requestHeaders;
214
216
  globalConfig.requestTimeout = options.requestTimeout;
@@ -466,7 +468,6 @@ function createHotUpdaterClient() {
466
468
 
467
469
  const mergedConfig: InternalCheckForUpdateOptions = {
468
470
  ...config,
469
- insights: globalConfig.insights,
470
471
  client,
471
472
  requestHeaders: {
472
473
  ...globalConfig.requestHeaders,
@@ -508,33 +509,52 @@ function createHotUpdaterClient() {
508
509
  * ```
509
510
  */
510
511
  updateBundle: async (params: UpdateParams) => {
511
- const client = ensureGlobalClient("updateBundle");
512
+ ensureGlobalClient("updateBundle");
512
513
  const fromBundleId = getBundleId();
513
514
  const state = getActiveUpdateState();
514
515
  const active = state.activeSelection;
515
- const downloaded = await updateBundle(params);
516
- if (downloaded) {
517
- const selection = getActiveUpdateState().activeSelection;
518
- await reportBundleDownloaded(
519
- { ...globalConfig, client },
520
- {
516
+ const fromReleaseId =
517
+ active?.bundleId === fromBundleId
518
+ ? active.releaseId
519
+ : state.stableSelection?.bundleId === fromBundleId
520
+ ? state.stableSelection.releaseId
521
+ : null;
522
+ const channel = params.channel ?? getChannel();
523
+ const strategyOf = (scopeKey: string | null | undefined) =>
524
+ scopeKey?.startsWith("v1:fingerprint:") ? "fingerprint" : "appVersion";
525
+ let delivery: Awaited<ReturnType<typeof stageBundle>>;
526
+ try {
527
+ delivery = await stageBundle(params);
528
+ } catch (error) {
529
+ reportUpdateError(error, "download", undefined, {
530
+ bundleId: fromBundleId,
531
+ channel,
532
+ targetBundleId: params.bundleId,
533
+ targetReleaseId:
534
+ (params.selection as { releaseId?: string | null } | undefined)
535
+ ?.releaseId ?? null,
536
+ updateStrategy: strategyOf(
537
+ (params.selection as { scopeKey?: string | null } | undefined)
538
+ ?.scopeKey,
539
+ ),
540
+ });
541
+ throw error;
542
+ }
543
+ if (delivery !== null && params.bundleId !== fromBundleId) {
544
+ emitAfterAppReady("onBundleDownloaded", () => {
545
+ const selection = getActiveUpdateState().activeSelection;
546
+ return {
547
+ channel,
521
548
  fromBundleId,
522
- fromReleaseId:
523
- active?.bundleId === fromBundleId
524
- ? active.releaseId
525
- : state.stableSelection?.bundleId === fromBundleId
526
- ? state.stableSelection.releaseId
527
- : null,
549
+ fromReleaseId,
528
550
  toBundleId: params.bundleId,
529
551
  toReleaseId: selection?.releaseId ?? null,
530
- channel: params.channel ?? getChannel(),
531
- updateStrategy: selection?.scopeKey?.startsWith("v1:fingerprint:")
532
- ? "fingerprint"
533
- : "appVersion",
534
- },
535
- );
552
+ updateStrategy: strategyOf(selection?.scopeKey),
553
+ ...delivery,
554
+ };
555
+ });
536
556
  }
537
- return downloaded;
557
+ return true;
538
558
  },
539
559
 
540
560
  /**
@@ -573,11 +593,6 @@ function createHotUpdaterClient() {
573
593
  */
574
594
  getInstallId,
575
595
 
576
- /**
577
- * Persists nullable user identity fields associated with this installation.
578
- */
579
- setUser,
580
-
581
596
  /**
582
597
  * Reads the native launch report for the current process.
583
598
  */