@hot-updater/react-native 1.0.0-rc.15 → 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 (302) 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 +15 -67
  52. package/lib/commonjs/httpClient.js.map +1 -1
  53. package/lib/commonjs/httpClient.spec.js +26 -9
  54. package/lib/commonjs/httpClient.spec.js.map +1 -1
  55. package/lib/commonjs/index.js +49 -25
  56. package/lib/commonjs/index.js.map +1 -1
  57. package/lib/commonjs/index.spec.js +126 -40
  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 +14 -66
  116. package/lib/module/httpClient.js.map +1 -1
  117. package/lib/module/httpClient.spec.js +26 -9
  118. package/lib/module/httpClient.spec.js.map +1 -1
  119. package/lib/module/index.js +44 -27
  120. package/lib/module/index.js.map +1 -1
  121. package/lib/module/index.spec.js +127 -41
  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 -30
  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 -5
  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 -30
  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 -5
  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 +28 -9
  249. package/src/httpClient.ts +16 -109
  250. package/src/index.spec.ts +129 -36
  251. package/src/index.ts +67 -37
  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 -5
  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 -124
  281. package/lib/commonjs/notifyAppReadyInsights.transport.spec.js.map +0 -1
  282. package/lib/module/notifyAppReadyInsights.boundary.spec.js +0 -224
  283. package/lib/module/notifyAppReadyInsights.boundary.spec.js.map +0 -1
  284. package/lib/module/notifyAppReadyInsights.js +0 -181
  285. package/lib/module/notifyAppReadyInsights.js.map +0 -1
  286. package/lib/module/notifyAppReadyInsights.spec.js +0 -377
  287. package/lib/module/notifyAppReadyInsights.spec.js.map +0 -1
  288. package/lib/module/notifyAppReadyInsights.test-utils.js.map +0 -1
  289. package/lib/module/notifyAppReadyInsights.transport.spec.js +0 -123
  290. package/lib/module/notifyAppReadyInsights.transport.spec.js.map +0 -1
  291. package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts +0 -25
  292. package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts.map +0 -1
  293. package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts +0 -8
  294. package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts.map +0 -1
  295. package/lib/typescript/module/notifyAppReadyInsights.d.ts +0 -25
  296. package/lib/typescript/module/notifyAppReadyInsights.d.ts.map +0 -1
  297. package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts +0 -8
  298. package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts.map +0 -1
  299. package/src/notifyAppReadyInsights.boundary.spec.ts +0 -242
  300. package/src/notifyAppReadyInsights.spec.ts +0 -362
  301. package/src/notifyAppReadyInsights.transport.spec.ts +0 -138
  302. package/src/notifyAppReadyInsights.ts +0 -293
package/src/httpClient.ts CHANGED
@@ -6,10 +6,11 @@ import {
6
6
  } from "@hot-updater/core";
7
7
  import { canonicalizeAppVersion } from "@hot-updater/plugin-core";
8
8
 
9
+ import { resolveBaseURL } from "./baseURL";
9
10
  import { fetchJSON, FetchJSONResponseError } from "./fetchJSON";
10
11
  import { fetchReleaseCatalogWithCache } from "./releaseCatalogCache";
11
- import { HOT_UPDATER_SDK_VERSION } from "./sdkVersion";
12
12
  import type { HotUpdaterBaseURL } from "./types";
13
+ import { InvalidUpdateResponseError } from "./updateError";
13
14
 
14
15
  export interface ReleaseCatalogRequest {
15
16
  readonly platform: "ios" | "android";
@@ -28,69 +29,31 @@ export interface ArtifactRequest {
28
29
  readonly requestTimeout?: number;
29
30
  }
30
31
 
31
- interface InsightsEventCommonParams {
32
- readonly installId: string;
33
- readonly userId?: string;
34
- readonly username?: string;
35
- readonly platform: "ios" | "android";
36
- readonly appVersion: string;
37
- readonly channel: string;
38
- readonly cohort: string;
39
- readonly fingerprintHash: string | null;
40
- readonly fromReleaseId?: string | null;
41
- readonly toReleaseId?: string | null;
42
- readonly requestHeaders?: Record<string, string>;
43
- readonly requestTimeout?: number;
44
- }
45
-
46
- type InsightsTransitionEventParams = InsightsEventCommonParams & {
47
- readonly type: "UPDATE_DOWNLOADED" | "UPDATE_APPLIED" | "RECOVERED";
48
- readonly fromBundleId: string;
49
- readonly toBundleId: string;
50
- readonly updateStrategy: "fingerprint" | "appVersion";
51
- };
52
-
53
- type InsightsUnchangedEventParams = InsightsEventCommonParams & {
54
- readonly type: "UNCHANGED";
55
- readonly fromBundleId: null;
56
- readonly toBundleId: string;
57
- readonly updateStrategy: null;
58
- };
59
-
60
- export type InsightsEventParams =
61
- | InsightsTransitionEventParams
62
- | InsightsUnchangedEventParams;
63
-
64
32
  export interface HotUpdaterHttpSession {
33
+ /** Resolves to null when the server says the scope has no catalog, so no update. */
65
34
  fetchReleaseCatalog: (
66
35
  params: ReleaseCatalogRequest,
67
- ) => Promise<ReleaseCatalog>;
36
+ ) => Promise<ReleaseCatalog | null>;
68
37
  resolveArtifact: (params: ArtifactRequest) => Promise<ArtifactInfo>;
69
- sendInsightsEvent: (params: InsightsEventParams) => Promise<void>;
70
38
  }
71
39
 
72
40
  export interface HotUpdaterHttpClient {
73
41
  createSession: () => Promise<HotUpdaterHttpSession>;
74
42
  }
75
43
 
76
- const resolveBaseURL = async (baseURL: HotUpdaterBaseURL): Promise<string> => {
77
- const resolvedBaseURL =
78
- typeof baseURL === "function" ? await baseURL() : baseURL;
79
-
80
- if (!resolvedBaseURL) {
81
- throw new Error("baseURL function must return a non-empty string");
82
- }
83
-
84
- return resolvedBaseURL.replace(/\/+$/, "");
85
- };
86
-
87
44
  const resolveArtifactUrl = (baseURL: string, value: string): string => {
88
45
  if (/^https?:\/\//i.test(value)) {
89
- new URL(value);
46
+ try {
47
+ new URL(value);
48
+ } catch (error) {
49
+ throw new InvalidUpdateResponseError(`Invalid artifact URL: ${value}`, {
50
+ cause: error,
51
+ });
52
+ }
90
53
  return value;
91
54
  }
92
55
  if (!value.startsWith("/storage/")) {
93
- throw new Error(
56
+ throw new InvalidUpdateResponseError(
94
57
  "Artifact URLs must be absolute HTTP(S) URLs or client-relative storage paths.",
95
58
  );
96
59
  }
@@ -136,13 +99,13 @@ const requireArtifactProtocolV1 = (info: ArtifactInfo): ArtifactInfo => {
136
99
  !info.manifestFileHash ||
137
100
  (info.archiveUrl !== undefined && typeof info.archiveUrl !== "string")
138
101
  ) {
139
- throw new Error(
102
+ throw new InvalidUpdateResponseError(
140
103
  `Server does not support artifact protocol ${ARTIFACT_PROTOCOL_VERSION}.`,
141
104
  );
142
105
  }
143
106
  for (const asset of Object.values(info.assets)) {
144
107
  if (!asset.file?.url || !asset.fileHash) {
145
- throw new Error(
108
+ throw new InvalidUpdateResponseError(
146
109
  "Artifact protocol 1 requires an original file for every asset.",
147
110
  );
148
111
  }
@@ -150,63 +113,8 @@ const requireArtifactProtocolV1 = (info: ArtifactInfo): ArtifactInfo => {
150
113
  return info;
151
114
  };
152
115
 
153
- const sendInsightsEvent = async (
154
- baseURL: string,
155
- params: InsightsEventParams,
156
- ): Promise<void> => {
157
- const controller = new AbortController();
158
- const timeoutId = setTimeout(() => {
159
- controller.abort();
160
- }, params.requestTimeout ?? 5000);
161
-
162
- try {
163
- const response = await fetch(`${baseURL}/events`, {
164
- body: JSON.stringify({
165
- appVersion: params.appVersion,
166
- channel: params.channel,
167
- cohort: params.cohort,
168
- fingerprintHash: params.fingerprintHash,
169
- fromBundleId: params.fromBundleId,
170
- ...(params.fromReleaseId === undefined
171
- ? {}
172
- : { fromReleaseId: params.fromReleaseId }),
173
- installId: params.installId,
174
- platform: params.platform,
175
- sdkVersion: HOT_UPDATER_SDK_VERSION,
176
- toBundleId: params.toBundleId,
177
- ...(params.toReleaseId === undefined
178
- ? {}
179
- : { toReleaseId: params.toReleaseId }),
180
- type: params.type,
181
- updateStrategy: params.updateStrategy,
182
- ...(params.userId != null ? { userId: params.userId } : {}),
183
- ...(params.username != null ? { username: params.username } : {}),
184
- }),
185
- headers: {
186
- "Content-Type": "application/json",
187
- ...params.requestHeaders,
188
- },
189
- method: "POST",
190
- signal: controller.signal,
191
- });
192
-
193
- if (response.status !== 204) {
194
- throw new Error(
195
- `Expected HTTP 204 from /events, received ${response.status}`,
196
- );
197
- }
198
- } catch (error: unknown) {
199
- if (error instanceof Error && error.name === "AbortError") {
200
- throw new Error("Request timed out");
201
- }
202
- throw error;
203
- } finally {
204
- clearTimeout(timeoutId);
205
- }
206
- };
207
-
208
116
  const createSession = (baseURL: string): HotUpdaterHttpSession => ({
209
- fetchReleaseCatalog: async (params): Promise<ReleaseCatalog> => {
117
+ fetchReleaseCatalog: async (params): Promise<ReleaseCatalog | null> => {
210
118
  const channelKey = encodeChannelKey(params.channel);
211
119
  let strategyValue: string;
212
120
  if (params.updateStrategy === "fingerprint") {
@@ -255,7 +163,7 @@ const createSession = (baseURL: string): HotUpdaterHttpSession => ({
255
163
  });
256
164
  } catch (error) {
257
165
  if (error instanceof FetchJSONResponseError && error.status === 404) {
258
- throw new Error(
166
+ throw new InvalidUpdateResponseError(
259
167
  `Server does not support artifact protocol ${ARTIFACT_PROTOCOL_VERSION}.`,
260
168
  { cause: error },
261
169
  );
@@ -264,7 +172,6 @@ const createSession = (baseURL: string): HotUpdaterHttpSession => ({
264
172
  }
265
173
  return resolveArtifactUrls(baseURL, requireArtifactProtocolV1(info));
266
174
  },
267
- sendInsightsEvent: (params) => sendInsightsEvent(baseURL, params),
268
175
  });
269
176
 
270
177
  /** Creates the private HTTP client used by HotUpdater.init and HotUpdater.wrap. */
package/src/index.spec.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { beforeEach, describe, expect, it, vi } from "vitest";
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
2
 
3
3
  import type { HotUpdaterInitOptions, HotUpdaterOptions } from "./wrap";
4
4
 
@@ -31,6 +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
+ configurePlugins: vi.fn(),
35
+ emitAfterAppReady: vi.fn(),
36
+ reportUpdateError: vi.fn(),
34
37
  init: vi.fn(),
35
38
  isChannelSwitched: vi.fn(() => false),
36
39
  notifyAppReady: vi.fn(() => ({ status: "UNCHANGED" as const })),
@@ -38,8 +41,7 @@ const mocks = vi.hoisted(() => {
38
41
  resetChannel: vi.fn(),
39
42
  setCohort: vi.fn(),
40
43
  setReloadBehavior: vi.fn(),
41
- setUser: vi.fn(),
42
- updateBundle: vi.fn(),
44
+ stageBundle: vi.fn(),
43
45
  wrap: vi.fn((Component: unknown) => Component),
44
46
  };
45
47
  });
@@ -52,6 +54,15 @@ vi.mock("./httpClient", () => ({
52
54
 
53
55
  vi.mock("./checkForUpdate", () => ({
54
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,
55
66
  }));
56
67
 
57
68
  vi.mock("./native", () => ({
@@ -77,8 +88,7 @@ vi.mock("./native", () => ({
77
88
  resetChannel: mocks.resetChannel,
78
89
  setCohort: mocks.setCohort,
79
90
  setReloadBehavior: mocks.setReloadBehavior,
80
- setUser: mocks.setUser,
81
- updateBundle: mocks.updateBundle,
91
+ stageBundle: mocks.stageBundle,
82
92
  }));
83
93
 
84
94
  vi.mock("./wrap", () => ({
@@ -99,6 +109,11 @@ describe("HotUpdater client initialization", () => {
99
109
  mocks.wrap.mockImplementation((Component: unknown) => Component);
100
110
  });
101
111
 
112
+ afterEach(() => {
113
+ vi.unstubAllGlobals();
114
+ vi.restoreAllMocks();
115
+ });
116
+
102
117
  it("exposes the console ID through the existing getter only", async () => {
103
118
  const HotUpdater = await importHotUpdater();
104
119
 
@@ -113,7 +128,6 @@ describe("HotUpdater client initialization", () => {
113
128
  const HotUpdater = await importHotUpdater();
114
129
 
115
130
  HotUpdater.init({
116
- insights: true,
117
131
  baseURL: "https://updates.example.com",
118
132
  requestHeaders: { Authorization: "Bearer token" },
119
133
  requestTimeout: 1000,
@@ -123,7 +137,6 @@ describe("HotUpdater client initialization", () => {
123
137
  "https://updates.example.com",
124
138
  );
125
139
  expect(mocks.init).toHaveBeenCalledWith({
126
- insights: true,
127
140
  client,
128
141
  requestHeaders: { Authorization: "Bearer token" },
129
142
  requestTimeout: 1000,
@@ -140,42 +153,130 @@ describe("HotUpdater client initialization", () => {
140
153
  expect(resolveBaseURL).not.toHaveBeenCalled();
141
154
  });
142
155
 
143
- it("enables insights by default for init and wrap", async () => {
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();
161
+ });
144
162
  const HotUpdater = await importHotUpdater();
145
163
 
146
- HotUpdater.init({ baseURL: "https://updates.example.com" });
147
- HotUpdater.wrap({
164
+ HotUpdater.init({
148
165
  baseURL: "https://updates.example.com",
166
+ onError,
167
+ plugins: [plugin],
168
+ requestHeaders: { "x-api-key": "client-key" },
169
+ requestTimeout: 1000,
170
+ });
171
+ HotUpdater.wrap({
172
+ baseURL: "https://other.example.com",
173
+ plugins: [plugin],
149
174
  updateStrategy: "appVersion",
150
175
  });
151
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
+ });
152
189
  expect(mocks.init).toHaveBeenCalledWith(
153
- expect.objectContaining({ insights: true }),
190
+ expect.not.objectContaining({ plugins: expect.anything() }),
154
191
  );
155
192
  expect(mocks.wrap).toHaveBeenCalledWith(
156
- expect.objectContaining({ insights: true }),
193
+ expect.not.objectContaining({ plugins: expect.anything() }),
157
194
  );
158
195
  });
159
196
 
160
- it("preserves an explicit insights opt-out", async () => {
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);
161
214
  const HotUpdater = await importHotUpdater();
215
+ HotUpdater.init({ baseURL: "https://updates.example.com" });
162
216
 
163
- HotUpdater.init({
164
- baseURL: "https://updates.example.com",
165
- insights: false,
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",
166
223
  });
167
- HotUpdater.wrap({
168
- baseURL: "https://updates.example.com",
169
- insights: false,
170
- updateStrategy: "appVersion",
224
+
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,
171
240
  });
241
+ });
172
242
 
173
- expect(mocks.init).toHaveBeenCalledWith(
174
- expect.objectContaining({ insights: false }),
175
- );
176
- expect(mocks.wrap).toHaveBeenCalledWith(
177
- expect.objectContaining({ insights: false }),
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" });
251
+
252
+ await expect(
253
+ HotUpdater.updateBundle({
254
+ assets: {},
255
+ bundleId: "next-bundle-id",
256
+ channel: "beta",
257
+ manifestFileHash: "manifest-hash",
258
+ manifestUrl: "https://updates.example.com/manifest.json",
259
+ selection: {
260
+ releaseId: "next-release-id",
261
+ scopeKey: "v1:app-version:project:ios:YmV0YQ",
262
+ },
263
+ status: "UPDATE",
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
+ },
178
278
  );
279
+ expect(mocks.emitAfterAppReady).not.toHaveBeenCalled();
179
280
  });
180
281
 
181
282
  it("requires baseURL and rejects the removed resolver shape", async () => {
@@ -219,13 +320,12 @@ describe("HotUpdater client initialization", () => {
219
320
  expect(wrapOptions.updateStrategy).toBe("appVersion");
220
321
  });
221
322
 
222
- it("merges settings and carries the insights gate to checks", async () => {
323
+ it("merges settings into checks", async () => {
223
324
  const client = { createSession: vi.fn() };
224
325
  mocks.createHttpClient.mockReturnValue(client as never);
225
326
  const checkOnError = vi.fn();
226
327
  const HotUpdater = await importHotUpdater();
227
328
  HotUpdater.init({
228
- insights: true,
229
329
  baseURL: "https://updates.example.com",
230
330
  requestHeaders: { Authorization: "Bearer token" },
231
331
  requestTimeout: 1000,
@@ -238,7 +338,6 @@ describe("HotUpdater client initialization", () => {
238
338
  });
239
339
 
240
340
  expect(mocks.checkForUpdate).toHaveBeenCalledWith({
241
- insights: true,
242
341
  client,
243
342
  onError: checkOnError,
244
343
  requestHeaders: {
@@ -256,13 +355,11 @@ describe("HotUpdater client initialization", () => {
256
355
  const HotUpdater = await importHotUpdater();
257
356
 
258
357
  HotUpdater.wrap({
259
- insights: true,
260
358
  baseURL: "https://updates.example.com",
261
359
  updateStrategy: "appVersion",
262
360
  });
263
361
 
264
362
  expect(mocks.wrap).toHaveBeenCalledWith({
265
- insights: true,
266
363
  client,
267
364
  updateStrategy: "appVersion",
268
365
  });
@@ -327,15 +424,11 @@ describe("HotUpdater client initialization", () => {
327
424
  ).toThrow("requires HotUpdater.wrap() or HotUpdater.init() to be used");
328
425
  });
329
426
 
330
- it("preserves native identity and user APIs", async () => {
427
+ it("keeps the install id and leaves user identity to the insights plugin", async () => {
331
428
  const HotUpdater = await importHotUpdater();
332
429
 
333
430
  expect(HotUpdater.getInstallId()).toBe("install-id");
334
431
  expect(HotUpdater.getMinBundleId()).toBe("min-bundle-id");
335
- HotUpdater.setUser({ userId: "user-123", username: "alice" });
336
- expect(mocks.setUser).toHaveBeenCalledWith({
337
- userId: "user-123",
338
- username: "alice",
339
- });
432
+ expect(HotUpdater).not.toHaveProperty("setUser");
340
433
  });
341
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 {
@@ -103,13 +118,11 @@ function createHotUpdaterClient() {
103
118
 
104
119
  // Global configuration stored from wrap
105
120
  const globalConfig: {
106
- insights: boolean;
107
121
  client: HotUpdaterHttpClient | null;
108
122
  requestHeaders?: Record<string, string>;
109
123
  requestTimeout?: number;
110
124
  onError?: (error: unknown) => void;
111
125
  } = {
112
- insights: true,
113
126
  client: null,
114
127
  };
115
128
 
@@ -158,10 +171,9 @@ function createHotUpdaterClient() {
158
171
  const autoOptions = incoming as AutoUpdateOptions;
159
172
 
160
173
  if (autoOptions.baseURL) {
161
- const { baseURL, ...rest } = autoOptions;
174
+ const { baseURL, plugins: _plugins, ...rest } = autoOptions;
162
175
  return {
163
176
  ...rest,
164
- insights: rest.insights ?? true,
165
177
  client: createHttpClient(baseURL),
166
178
  };
167
179
  }
@@ -178,10 +190,9 @@ function createHotUpdaterClient() {
178
190
  };
179
191
 
180
192
  if (rest.baseURL) {
181
- const { baseURL, ...baseURLRest } = rest;
193
+ const { baseURL, plugins: _plugins, ...baseURLRest } = rest;
182
194
  return {
183
195
  ...baseURLRest,
184
- insights: baseURLRest.insights ?? true,
185
196
  client: createHttpClient(baseURL),
186
197
  };
187
198
  }
@@ -193,7 +204,13 @@ function createHotUpdaterClient() {
193
204
  normalizedOptions: InternalInitOptions | InternalWrapOptions,
194
205
  options: HotUpdaterOptions | HotUpdaterInitOptions,
195
206
  ) => {
196
- 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
+ });
197
214
  globalConfig.client = normalizedOptions.client;
198
215
  globalConfig.requestHeaders = options.requestHeaders;
199
216
  globalConfig.requestTimeout = options.requestTimeout;
@@ -451,7 +468,6 @@ function createHotUpdaterClient() {
451
468
 
452
469
  const mergedConfig: InternalCheckForUpdateOptions = {
453
470
  ...config,
454
- insights: globalConfig.insights,
455
471
  client,
456
472
  requestHeaders: {
457
473
  ...globalConfig.requestHeaders,
@@ -493,33 +509,52 @@ function createHotUpdaterClient() {
493
509
  * ```
494
510
  */
495
511
  updateBundle: async (params: UpdateParams) => {
496
- const client = ensureGlobalClient("updateBundle");
512
+ ensureGlobalClient("updateBundle");
497
513
  const fromBundleId = getBundleId();
498
514
  const state = getActiveUpdateState();
499
515
  const active = state.activeSelection;
500
- const downloaded = await updateBundle(params);
501
- if (downloaded) {
502
- const selection = getActiveUpdateState().activeSelection;
503
- await reportBundleDownloaded(
504
- { ...globalConfig, client },
505
- {
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,
506
548
  fromBundleId,
507
- fromReleaseId:
508
- active?.bundleId === fromBundleId
509
- ? active.releaseId
510
- : state.stableSelection?.bundleId === fromBundleId
511
- ? state.stableSelection.releaseId
512
- : null,
549
+ fromReleaseId,
513
550
  toBundleId: params.bundleId,
514
551
  toReleaseId: selection?.releaseId ?? null,
515
- channel: params.channel ?? getChannel(),
516
- updateStrategy: selection?.scopeKey?.startsWith("v1:fingerprint:")
517
- ? "fingerprint"
518
- : "appVersion",
519
- },
520
- );
552
+ updateStrategy: strategyOf(selection?.scopeKey),
553
+ ...delivery,
554
+ };
555
+ });
521
556
  }
522
- return downloaded;
557
+ return true;
523
558
  },
524
559
 
525
560
  /**
@@ -558,11 +593,6 @@ function createHotUpdaterClient() {
558
593
  */
559
594
  getInstallId,
560
595
 
561
- /**
562
- * Persists nullable user identity fields associated with this installation.
563
- */
564
- setUser,
565
-
566
596
  /**
567
597
  * Reads the native launch report for the current process.
568
598
  */