@hot-updater/react-native 1.0.0-rc.3 → 1.0.0-rc.31

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 (300) hide show
  1. package/android/proguard-rules.pro +17 -2
  2. package/android/src/main/java/com/hotupdater/BuiltInAssetResolver.kt +286 -0
  3. package/android/src/main/java/com/hotupdater/BundleFileStorageService.kt +954 -837
  4. package/android/src/main/java/com/hotupdater/BundleMetadata.kt +15 -11
  5. package/android/src/main/java/com/hotupdater/FileManagerService.kt +45 -0
  6. package/android/src/main/java/com/hotupdater/HotUpdaterException.kt +287 -22
  7. package/android/src/main/java/com/hotupdater/HotUpdaterImpl.kt +43 -31
  8. package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryManager.kt +37 -54
  9. package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryState.kt +64 -0
  10. package/android/src/main/java/com/hotupdater/InstallIdentityService.kt +37 -0
  11. package/android/src/main/java/com/hotupdater/KeyValueStorageService.kt +86 -0
  12. package/android/src/main/java/com/hotupdater/NetworkState.kt +31 -0
  13. package/android/src/main/java/com/hotupdater/NoBackupStorage.kt +17 -0
  14. package/android/src/main/java/com/hotupdater/OkHttpDownloadService.kt +127 -50
  15. package/android/src/main/java/com/hotupdater/PreviousProcessExit.kt +89 -0
  16. package/android/src/main/java/com/hotupdater/ReactNativeValueConverters.kt +34 -0
  17. package/android/src/main/java/com/hotupdater/TarArchiveInputStream.kt +214 -375
  18. package/android/src/main/java/com/hotupdater/TarBrArchiveExtractor.kt +119 -0
  19. package/android/src/newarch/HotUpdater.kt +7 -9
  20. package/android/src/newarch/HotUpdaterModule.kt +109 -84
  21. package/android/src/oldarch/HotUpdater.kt +7 -9
  22. package/android/src/oldarch/HotUpdaterModule.kt +98 -74
  23. package/android/src/oldarch/HotUpdaterSpec.kt +4 -6
  24. package/ios/HotUpdater/Internal/BrotliFileDecompressor.swift +167 -0
  25. package/ios/HotUpdater/Internal/BuiltInAssetResolver.swift +196 -0
  26. package/ios/HotUpdater/Internal/BundleFileStorageService.swift +950 -1112
  27. package/ios/HotUpdater/Internal/BundleMetadata.swift +8 -53
  28. package/ios/HotUpdater/Internal/FileManagerService.swift +48 -0
  29. package/ios/HotUpdater/Internal/FileUtilities.swift +64 -0
  30. package/ios/HotUpdater/Internal/HotUpdater-Bridging-Header.h +0 -1
  31. package/ios/HotUpdater/Internal/HotUpdater.mm +13 -45
  32. package/ios/HotUpdater/Internal/HotUpdaterImpl.swift +190 -73
  33. package/ios/HotUpdater/Internal/KeyValueStorageService.swift +71 -0
  34. package/ios/HotUpdater/Internal/NotificationExtension.swift +0 -2
  35. package/ios/HotUpdater/Internal/TarArchiveExtractor.swift +182 -311
  36. package/ios/HotUpdater/Internal/URLSessionDownloadService.swift +119 -71
  37. package/ios/HotUpdater/Internal/UpdateFailure.swift +390 -0
  38. package/ios/HotUpdater/Recovery/HotUpdaterRecovery.h +16 -0
  39. package/ios/HotUpdater/Recovery/HotUpdaterRecovery.mm +83 -0
  40. package/ios/HotUpdater/Recovery/HotUpdaterRecoveryHooks.mm +49 -0
  41. package/lib/commonjs/appReady.js +111 -0
  42. package/lib/commonjs/appReady.js.map +1 -0
  43. package/lib/commonjs/checkForUpdate.js +124 -69
  44. package/lib/commonjs/checkForUpdate.js.map +1 -1
  45. package/lib/commonjs/clientPlugin.js +13 -0
  46. package/lib/commonjs/clientPlugin.js.map +1 -0
  47. package/lib/commonjs/error.js +4 -13
  48. package/lib/commonjs/error.js.map +1 -1
  49. package/lib/commonjs/fetchJSON.js +16 -27
  50. package/lib/commonjs/fetchJSON.js.map +1 -1
  51. package/lib/commonjs/fetchUpdateResponse.js +54 -0
  52. package/lib/commonjs/fetchUpdateResponse.js.map +1 -0
  53. package/lib/commonjs/httpClient.js +63 -94
  54. package/lib/commonjs/httpClient.js.map +1 -1
  55. package/lib/commonjs/index.js +71 -18
  56. package/lib/commonjs/index.js.map +1 -1
  57. package/lib/commonjs/native.js +78 -60
  58. package/lib/commonjs/native.js.map +1 -1
  59. package/lib/commonjs/pluginHost.js +44 -0
  60. package/lib/commonjs/pluginHost.js.map +1 -0
  61. package/lib/commonjs/releaseCatalogCache.js +36 -87
  62. package/lib/commonjs/releaseCatalogCache.js.map +1 -1
  63. package/lib/commonjs/sdkVersion.js +1 -1
  64. package/lib/commonjs/sdkVersion.js.map +1 -1
  65. package/lib/commonjs/specs/NativeHotUpdater.js.map +1 -1
  66. package/lib/commonjs/store.js +3 -10
  67. package/lib/commonjs/store.js.map +1 -1
  68. package/lib/commonjs/updateError.js +132 -0
  69. package/lib/commonjs/updateError.js.map +1 -0
  70. package/lib/commonjs/wrap.js +43 -26
  71. package/lib/commonjs/wrap.js.map +1 -1
  72. package/lib/module/appReady.js +103 -0
  73. package/lib/module/appReady.js.map +1 -0
  74. package/lib/module/checkForUpdate.js +117 -64
  75. package/lib/module/checkForUpdate.js.map +1 -1
  76. package/lib/module/clientPlugin.js +4 -0
  77. package/lib/module/clientPlugin.js.map +1 -0
  78. package/lib/module/error.js +4 -13
  79. package/lib/module/error.js.map +1 -1
  80. package/lib/module/fetchJSON.js +14 -26
  81. package/lib/module/fetchJSON.js.map +1 -1
  82. package/lib/module/fetchUpdateResponse.js +49 -0
  83. package/lib/module/fetchUpdateResponse.js.map +1 -0
  84. package/lib/module/httpClient.js +62 -93
  85. package/lib/module/httpClient.js.map +1 -1
  86. package/lib/module/index.js +58 -20
  87. package/lib/module/index.js.map +1 -1
  88. package/lib/module/native.js +71 -53
  89. package/lib/module/native.js.map +1 -1
  90. package/lib/module/pluginHost.js +35 -0
  91. package/lib/module/pluginHost.js.map +1 -0
  92. package/lib/module/releaseCatalogCache.js +32 -82
  93. package/lib/module/releaseCatalogCache.js.map +1 -1
  94. package/lib/module/sdkVersion.js +1 -1
  95. package/lib/module/sdkVersion.js.map +1 -1
  96. package/lib/module/specs/NativeHotUpdater.js.map +1 -1
  97. package/lib/module/store.js +3 -10
  98. package/lib/module/store.js.map +1 -1
  99. package/lib/module/updateError.js +126 -0
  100. package/lib/module/updateError.js.map +1 -0
  101. package/lib/module/wrap.js +43 -26
  102. package/lib/module/wrap.js.map +1 -1
  103. package/lib/typescript/commonjs/appReady.d.ts +23 -0
  104. package/lib/typescript/commonjs/appReady.d.ts.map +1 -0
  105. package/lib/typescript/commonjs/checkForUpdate.d.ts +16 -4
  106. package/lib/typescript/commonjs/checkForUpdate.d.ts.map +1 -1
  107. package/lib/typescript/commonjs/clientPlugin.d.ts +2 -0
  108. package/lib/typescript/commonjs/clientPlugin.d.ts.map +1 -0
  109. package/lib/typescript/commonjs/error.d.ts +4 -13
  110. package/lib/typescript/commonjs/error.d.ts.map +1 -1
  111. package/lib/typescript/commonjs/fetchJSON.d.ts +5 -5
  112. package/lib/typescript/commonjs/fetchJSON.d.ts.map +1 -1
  113. package/lib/typescript/commonjs/fetchUpdateResponse.d.ts +14 -0
  114. package/lib/typescript/commonjs/fetchUpdateResponse.d.ts.map +1 -0
  115. package/lib/typescript/commonjs/httpClient.d.ts +4 -33
  116. package/lib/typescript/commonjs/httpClient.d.ts.map +1 -1
  117. package/lib/typescript/commonjs/index.d.ts +4 -8
  118. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  119. package/lib/typescript/commonjs/native.d.ts +31 -22
  120. package/lib/typescript/commonjs/native.d.ts.map +1 -1
  121. package/lib/typescript/commonjs/pluginHost.d.ts +4 -0
  122. package/lib/typescript/commonjs/pluginHost.d.ts.map +1 -0
  123. package/lib/typescript/commonjs/releaseCatalogCache.d.ts +8 -14
  124. package/lib/typescript/commonjs/releaseCatalogCache.d.ts.map +1 -1
  125. package/lib/typescript/commonjs/sdkVersion.d.ts +1 -1
  126. package/lib/typescript/commonjs/sdkVersion.d.ts.map +1 -1
  127. package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts +42 -47
  128. package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts.map +1 -1
  129. package/lib/typescript/commonjs/store.d.ts +1 -3
  130. package/lib/typescript/commonjs/store.d.ts.map +1 -1
  131. package/lib/typescript/commonjs/types.d.ts +1 -1
  132. package/lib/typescript/commonjs/types.d.ts.map +1 -1
  133. package/lib/typescript/commonjs/updateError.d.ts +26 -0
  134. package/lib/typescript/commonjs/updateError.d.ts.map +1 -0
  135. package/lib/typescript/commonjs/wrap.d.ts.map +1 -1
  136. package/lib/typescript/commonjs/wrap.types.d.ts +6 -7
  137. package/lib/typescript/commonjs/wrap.types.d.ts.map +1 -1
  138. package/lib/typescript/module/appReady.d.ts +23 -0
  139. package/lib/typescript/module/appReady.d.ts.map +1 -0
  140. package/lib/typescript/module/checkForUpdate.d.ts +16 -4
  141. package/lib/typescript/module/checkForUpdate.d.ts.map +1 -1
  142. package/lib/typescript/module/clientPlugin.d.ts +2 -0
  143. package/lib/typescript/module/clientPlugin.d.ts.map +1 -0
  144. package/lib/typescript/module/error.d.ts +4 -13
  145. package/lib/typescript/module/error.d.ts.map +1 -1
  146. package/lib/typescript/module/fetchJSON.d.ts +5 -5
  147. package/lib/typescript/module/fetchJSON.d.ts.map +1 -1
  148. package/lib/typescript/module/fetchUpdateResponse.d.ts +14 -0
  149. package/lib/typescript/module/fetchUpdateResponse.d.ts.map +1 -0
  150. package/lib/typescript/module/httpClient.d.ts +4 -33
  151. package/lib/typescript/module/httpClient.d.ts.map +1 -1
  152. package/lib/typescript/module/index.d.ts +4 -8
  153. package/lib/typescript/module/index.d.ts.map +1 -1
  154. package/lib/typescript/module/native.d.ts +31 -22
  155. package/lib/typescript/module/native.d.ts.map +1 -1
  156. package/lib/typescript/module/pluginHost.d.ts +4 -0
  157. package/lib/typescript/module/pluginHost.d.ts.map +1 -0
  158. package/lib/typescript/module/releaseCatalogCache.d.ts +8 -14
  159. package/lib/typescript/module/releaseCatalogCache.d.ts.map +1 -1
  160. package/lib/typescript/module/sdkVersion.d.ts +1 -1
  161. package/lib/typescript/module/sdkVersion.d.ts.map +1 -1
  162. package/lib/typescript/module/specs/NativeHotUpdater.d.ts +42 -47
  163. package/lib/typescript/module/specs/NativeHotUpdater.d.ts.map +1 -1
  164. package/lib/typescript/module/store.d.ts +1 -3
  165. package/lib/typescript/module/store.d.ts.map +1 -1
  166. package/lib/typescript/module/types.d.ts +1 -1
  167. package/lib/typescript/module/types.d.ts.map +1 -1
  168. package/lib/typescript/module/updateError.d.ts +26 -0
  169. package/lib/typescript/module/updateError.d.ts.map +1 -0
  170. package/lib/typescript/module/wrap.d.ts.map +1 -1
  171. package/lib/typescript/module/wrap.types.d.ts +6 -7
  172. package/lib/typescript/module/wrap.types.d.ts.map +1 -1
  173. package/package.json +7 -4
  174. package/src/appReady.ts +149 -0
  175. package/src/checkForUpdate.ts +151 -88
  176. package/src/clientPlugin.ts +18 -0
  177. package/src/error.ts +4 -14
  178. package/src/fetchJSON.ts +14 -30
  179. package/src/fetchUpdateResponse.ts +54 -0
  180. package/src/httpClient.ts +88 -159
  181. package/src/index.ts +90 -24
  182. package/src/native.ts +106 -102
  183. package/src/pluginHost.ts +45 -0
  184. package/src/releaseCatalogCache.ts +43 -172
  185. package/src/sdkVersion.ts +1 -1
  186. package/src/specs/NativeHotUpdater.ts +41 -48
  187. package/src/store.ts +2 -23
  188. package/src/types.ts +1 -1
  189. package/src/updateError.ts +153 -0
  190. package/src/wrap.tsx +57 -26
  191. package/src/wrap.types.ts +6 -7
  192. package/android/src/main/java/com/hotupdater/DecompressService.kt +0 -89
  193. package/android/src/main/java/com/hotupdater/DecompressionStrategy.kt +0 -26
  194. package/android/src/main/java/com/hotupdater/TarBrDecompressionStrategy.kt +0 -117
  195. package/android/src/main/java/com/hotupdater/TarGzDecompressionStrategy.kt +0 -117
  196. package/android/src/main/java/com/hotupdater/ZipDecompressionStrategy.kt +0 -192
  197. package/android/src/test/java/com/hotupdater/BsdiffPatchTest.kt +0 -46
  198. package/android/src/test/java/com/hotupdater/BundleFileStorageServiceTest.kt +0 -799
  199. package/android/src/test/java/com/hotupdater/HotUpdaterImplTest.kt +0 -273
  200. package/android/src/test/java/com/hotupdater/NativeConfigUtilsTest.kt +0 -20
  201. package/android/src/test/java/com/hotupdater/OkHttpDownloadServiceTest.kt +0 -111
  202. package/android/src/test/java/com/hotupdater/RelativePathResolverTest.kt +0 -41
  203. package/android/src/test/java/com/hotupdater/ReleaseCatalogCacheServiceTest.kt +0 -118
  204. package/android/src/test/java/com/hotupdater/TarArchiveInputStreamTest.kt +0 -68
  205. package/ios/HotUpdater/Internal/ArchiveExtractionUtilities.swift +0 -178
  206. package/ios/HotUpdater/Internal/DecompressService.swift +0 -112
  207. package/ios/HotUpdater/Internal/DecompressionStrategy.swift +0 -22
  208. package/ios/HotUpdater/Internal/StreamingTarArchiveExtractor.swift +0 -370
  209. package/ios/HotUpdater/Internal/TarBrDecompressionStrategy.swift +0 -39
  210. package/ios/HotUpdater/Internal/TarGzDecompressionStrategy.swift +0 -59
  211. package/ios/HotUpdater/Internal/ZipArchiveExtractor.swift +0 -482
  212. package/ios/HotUpdater/Internal/ZipDecompressionStrategy.swift +0 -56
  213. package/lib/commonjs/catalogCacheNative.spec.js +0 -31
  214. package/lib/commonjs/catalogCacheNative.spec.js.map +0 -1
  215. package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js +0 -615
  216. package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js.map +0 -1
  217. package/lib/commonjs/httpClient.spec.js +0 -102
  218. package/lib/commonjs/httpClient.spec.js.map +0 -1
  219. package/lib/commonjs/index.spec.js +0 -302
  220. package/lib/commonjs/index.spec.js.map +0 -1
  221. package/lib/commonjs/iosInterop.spec.js +0 -18
  222. package/lib/commonjs/iosInterop.spec.js.map +0 -1
  223. package/lib/commonjs/native.spec.js +0 -883
  224. package/lib/commonjs/native.spec.js.map +0 -1
  225. package/lib/commonjs/notifyAppReadyInsights.boundary.spec.js +0 -218
  226. package/lib/commonjs/notifyAppReadyInsights.boundary.spec.js.map +0 -1
  227. package/lib/commonjs/notifyAppReadyInsights.js +0 -133
  228. package/lib/commonjs/notifyAppReadyInsights.js.map +0 -1
  229. package/lib/commonjs/notifyAppReadyInsights.spec.js +0 -246
  230. package/lib/commonjs/notifyAppReadyInsights.spec.js.map +0 -1
  231. package/lib/commonjs/notifyAppReadyInsights.test-utils.js +0 -24
  232. package/lib/commonjs/notifyAppReadyInsights.test-utils.js.map +0 -1
  233. package/lib/commonjs/notifyAppReadyInsights.transport.spec.js +0 -117
  234. package/lib/commonjs/notifyAppReadyInsights.transport.spec.js.map +0 -1
  235. package/lib/commonjs/releaseCatalogCache.spec.js +0 -195
  236. package/lib/commonjs/releaseCatalogCache.spec.js.map +0 -1
  237. package/lib/commonjs/releaseCatalogCacheNativeContract.spec.js +0 -64
  238. package/lib/commonjs/releaseCatalogCacheNativeContract.spec.js.map +0 -1
  239. package/lib/commonjs/store.notification.spec.js +0 -76
  240. package/lib/commonjs/store.notification.spec.js.map +0 -1
  241. package/lib/commonjs/store.spec.js +0 -316
  242. package/lib/commonjs/store.spec.js.map +0 -1
  243. package/lib/commonjs/wrap.spec.js +0 -329
  244. package/lib/commonjs/wrap.spec.js.map +0 -1
  245. package/lib/module/catalogCacheNative.spec.js +0 -31
  246. package/lib/module/catalogCacheNative.spec.js.map +0 -1
  247. package/lib/module/checkForUpdate.releaseCatalog.spec.js +0 -614
  248. package/lib/module/checkForUpdate.releaseCatalog.spec.js.map +0 -1
  249. package/lib/module/httpClient.spec.js +0 -102
  250. package/lib/module/httpClient.spec.js.map +0 -1
  251. package/lib/module/index.spec.js +0 -301
  252. package/lib/module/index.spec.js.map +0 -1
  253. package/lib/module/iosInterop.spec.js +0 -18
  254. package/lib/module/iosInterop.spec.js.map +0 -1
  255. package/lib/module/native.spec.js +0 -882
  256. package/lib/module/native.spec.js.map +0 -1
  257. package/lib/module/notifyAppReadyInsights.boundary.spec.js +0 -217
  258. package/lib/module/notifyAppReadyInsights.boundary.spec.js.map +0 -1
  259. package/lib/module/notifyAppReadyInsights.js +0 -128
  260. package/lib/module/notifyAppReadyInsights.js.map +0 -1
  261. package/lib/module/notifyAppReadyInsights.spec.js +0 -245
  262. package/lib/module/notifyAppReadyInsights.spec.js.map +0 -1
  263. package/lib/module/notifyAppReadyInsights.test-utils.js +0 -18
  264. package/lib/module/notifyAppReadyInsights.test-utils.js.map +0 -1
  265. package/lib/module/notifyAppReadyInsights.transport.spec.js +0 -116
  266. package/lib/module/notifyAppReadyInsights.transport.spec.js.map +0 -1
  267. package/lib/module/releaseCatalogCache.spec.js +0 -195
  268. package/lib/module/releaseCatalogCache.spec.js.map +0 -1
  269. package/lib/module/releaseCatalogCacheNativeContract.spec.js +0 -64
  270. package/lib/module/releaseCatalogCacheNativeContract.spec.js.map +0 -1
  271. package/lib/module/store.notification.spec.js +0 -77
  272. package/lib/module/store.notification.spec.js.map +0 -1
  273. package/lib/module/store.spec.js +0 -315
  274. package/lib/module/store.spec.js.map +0 -1
  275. package/lib/module/wrap.spec.js +0 -330
  276. package/lib/module/wrap.spec.js.map +0 -1
  277. package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts +0 -13
  278. package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts.map +0 -1
  279. package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts +0 -8
  280. package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts.map +0 -1
  281. package/lib/typescript/module/notifyAppReadyInsights.d.ts +0 -13
  282. package/lib/typescript/module/notifyAppReadyInsights.d.ts.map +0 -1
  283. package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts +0 -8
  284. package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts.map +0 -1
  285. package/src/catalogCacheNative.spec.ts +0 -63
  286. package/src/checkForUpdate.releaseCatalog.spec.ts +0 -611
  287. package/src/httpClient.spec.ts +0 -132
  288. package/src/index.spec.ts +0 -337
  289. package/src/iosInterop.spec.ts +0 -30
  290. package/src/native.spec.ts +0 -945
  291. package/src/notifyAppReadyInsights.boundary.spec.ts +0 -234
  292. package/src/notifyAppReadyInsights.spec.ts +0 -243
  293. package/src/notifyAppReadyInsights.test-utils.ts +0 -31
  294. package/src/notifyAppReadyInsights.transport.spec.ts +0 -130
  295. package/src/notifyAppReadyInsights.ts +0 -194
  296. package/src/releaseCatalogCache.spec.ts +0 -282
  297. package/src/releaseCatalogCacheNativeContract.spec.ts +0 -80
  298. package/src/store.notification.spec.ts +0 -92
  299. package/src/store.spec.ts +0 -372
  300. package/src/wrap.spec.ts +0 -406
package/src/httpClient.ts CHANGED
@@ -1,14 +1,17 @@
1
1
  import {
2
+ ARTIFACT_PROTOCOL_VERSION,
3
+ canonicalizeAppVersion,
2
4
  encodeChannelKey,
5
+ resolveBaseURL,
3
6
  type ArtifactInfo,
7
+ type HotUpdaterBaseURL,
4
8
  type ReleaseCatalog,
5
- } from "@hot-updater/core";
6
- import { canonicalizeAppVersion } from "@hot-updater/plugin-core";
9
+ type UpdateHttpResponse,
10
+ } from "@hot-updater/protocol";
7
11
 
8
- import { fetchJSON } from "./fetchJSON";
12
+ import { fetchJSON, FetchJSONResponseError } from "./fetchJSON";
9
13
  import { fetchReleaseCatalogWithCache } from "./releaseCatalogCache";
10
- import { HOT_UPDATER_SDK_VERSION } from "./sdkVersion";
11
- import type { HotUpdaterBaseURL } from "./types";
14
+ import { InvalidUpdateResponseError } from "./updateError";
12
15
 
13
16
  export interface ReleaseCatalogRequest {
14
17
  readonly platform: "ios" | "android";
@@ -27,69 +30,31 @@ export interface ArtifactRequest {
27
30
  readonly requestTimeout?: number;
28
31
  }
29
32
 
30
- interface InsightsEventCommonParams {
31
- readonly installId: string;
32
- readonly userId?: string;
33
- readonly username?: string;
34
- readonly platform: "ios" | "android";
35
- readonly appVersion: string;
36
- readonly channel: string;
37
- readonly cohort: string;
38
- readonly fingerprintHash: string | null;
39
- readonly fromReleaseId?: string | null;
40
- readonly toReleaseId?: string | null;
41
- readonly requestHeaders?: Record<string, string>;
42
- readonly requestTimeout?: number;
43
- }
44
-
45
- type InsightsTransitionEventParams = InsightsEventCommonParams & {
46
- readonly type: "UPDATE_APPLIED" | "RECOVERED" | "RELEASE_ADOPTED";
47
- readonly fromBundleId: string;
48
- readonly toBundleId: string;
49
- readonly updateStrategy: "fingerprint" | "appVersion";
50
- };
51
-
52
- type InsightsUnchangedEventParams = InsightsEventCommonParams & {
53
- readonly type: "UNCHANGED";
54
- readonly fromBundleId: null;
55
- readonly toBundleId: string;
56
- readonly updateStrategy: null;
57
- };
58
-
59
- export type InsightsEventParams =
60
- | InsightsTransitionEventParams
61
- | InsightsUnchangedEventParams;
62
-
63
33
  export interface HotUpdaterHttpSession {
34
+ /** Resolves to null when the server says the scope has no catalog, so no update. */
64
35
  fetchReleaseCatalog: (
65
36
  params: ReleaseCatalogRequest,
66
- ) => Promise<ReleaseCatalog>;
37
+ ) => Promise<ReleaseCatalog | null>;
67
38
  resolveArtifact: (params: ArtifactRequest) => Promise<ArtifactInfo>;
68
- sendInsightsEvent: (params: InsightsEventParams) => Promise<void>;
69
39
  }
70
40
 
71
41
  export interface HotUpdaterHttpClient {
72
42
  createSession: () => Promise<HotUpdaterHttpSession>;
73
43
  }
74
44
 
75
- const resolveBaseURL = async (baseURL: HotUpdaterBaseURL): Promise<string> => {
76
- const resolvedBaseURL =
77
- typeof baseURL === "function" ? await baseURL() : baseURL;
78
-
79
- if (!resolvedBaseURL) {
80
- throw new Error("baseURL function must return a non-empty string");
81
- }
82
-
83
- return resolvedBaseURL.replace(/\/+$/, "");
84
- };
85
-
86
45
  const resolveArtifactUrl = (baseURL: string, value: string): string => {
87
46
  if (/^https?:\/\//i.test(value)) {
88
- new URL(value);
47
+ try {
48
+ new URL(value);
49
+ } catch (error) {
50
+ throw new InvalidUpdateResponseError(`Invalid artifact URL: ${value}`, {
51
+ cause: error,
52
+ });
53
+ }
89
54
  return value;
90
55
  }
91
56
  if (!value.startsWith("/storage/")) {
92
- throw new Error(
57
+ throw new InvalidUpdateResponseError(
93
58
  "Artifact URLs must be absolute HTTP(S) URLs or client-relative storage paths.",
94
59
  );
95
60
  }
@@ -101,109 +66,59 @@ const resolveArtifactUrls = (
101
66
  info: ArtifactInfo,
102
67
  ): ArtifactInfo => ({
103
68
  ...info,
104
- fileUrl:
105
- info.fileUrl === null ? null : resolveArtifactUrl(baseURL, info.fileUrl),
106
- ...(info.manifestUrl === undefined
107
- ? {}
108
- : {
109
- manifestUrl:
110
- info.manifestUrl === null
111
- ? null
112
- : resolveArtifactUrl(baseURL, info.manifestUrl),
113
- }),
114
- ...(info.changedAssets === undefined
115
- ? {}
116
- : {
117
- changedAssets:
118
- info.changedAssets === null
119
- ? null
120
- : Object.fromEntries(
121
- Object.entries(info.changedAssets).map(([path, asset]) => [
122
- path,
123
- {
124
- ...asset,
125
- ...(asset.file
126
- ? {
127
- file: {
128
- ...asset.file,
129
- url: resolveArtifactUrl(baseURL, asset.file.url),
130
- },
131
- }
132
- : {}),
133
- ...(asset.patch
134
- ? {
135
- patch: {
136
- ...asset.patch,
137
- patchUrl: resolveArtifactUrl(
138
- baseURL,
139
- asset.patch.patchUrl,
140
- ),
141
- },
142
- }
143
- : {}),
144
- },
145
- ]),
146
- ),
147
- }),
148
- });
149
-
150
- const sendInsightsEvent = async (
151
- baseURL: string,
152
- params: InsightsEventParams,
153
- ): Promise<void> => {
154
- const controller = new AbortController();
155
- const timeoutId = setTimeout(() => {
156
- controller.abort();
157
- }, params.requestTimeout ?? 5000);
158
-
159
- try {
160
- const response = await fetch(`${baseURL}/events`, {
161
- body: JSON.stringify({
162
- appVersion: params.appVersion,
163
- channel: params.channel,
164
- cohort: params.cohort,
165
- fingerprintHash: params.fingerprintHash,
166
- fromBundleId: params.fromBundleId,
167
- ...(params.fromReleaseId === undefined
168
- ? {}
169
- : { fromReleaseId: params.fromReleaseId }),
170
- installId: params.installId,
171
- platform: params.platform,
172
- sdkVersion: HOT_UPDATER_SDK_VERSION,
173
- toBundleId: params.toBundleId,
174
- ...(params.toReleaseId === undefined
175
- ? {}
176
- : { toReleaseId: params.toReleaseId }),
177
- type: params.type,
178
- updateStrategy: params.updateStrategy,
179
- ...(params.userId != null ? { userId: params.userId } : {}),
180
- ...(params.username != null ? { username: params.username } : {}),
181
- }),
182
- headers: {
183
- "Content-Type": "application/json",
184
- ...params.requestHeaders,
69
+ manifestUrl: resolveArtifactUrl(baseURL, info.manifestUrl),
70
+ ...(info.archiveUrl
71
+ ? { archiveUrl: resolveArtifactUrl(baseURL, info.archiveUrl) }
72
+ : {}),
73
+ assets: Object.fromEntries(
74
+ Object.entries(info.assets).map(([path, asset]) => [
75
+ path,
76
+ {
77
+ ...asset,
78
+ file: {
79
+ ...asset.file,
80
+ url: resolveArtifactUrl(baseURL, asset.file.url),
81
+ },
82
+ ...(asset.patch
83
+ ? {
84
+ patch: {
85
+ ...asset.patch,
86
+ patchUrl: resolveArtifactUrl(baseURL, asset.patch.patchUrl),
87
+ },
88
+ }
89
+ : {}),
185
90
  },
186
- method: "POST",
187
- signal: controller.signal,
188
- });
91
+ ]),
92
+ ),
93
+ });
189
94
 
190
- if (response.status !== 204) {
191
- throw new Error(
192
- `Expected HTTP 204 from /events, received ${response.status}`,
95
+ const requireArtifactProtocolV1 = (info: ArtifactInfo): ArtifactInfo => {
96
+ if (
97
+ info.artifactProtocolVersion !== ARTIFACT_PROTOCOL_VERSION ||
98
+ !info.assets ||
99
+ !info.manifestUrl ||
100
+ !info.manifestFileHash ||
101
+ (info.archiveUrl !== undefined && typeof info.archiveUrl !== "string")
102
+ ) {
103
+ throw new InvalidUpdateResponseError(
104
+ `Server does not support artifact protocol ${ARTIFACT_PROTOCOL_VERSION}.`,
105
+ );
106
+ }
107
+ for (const asset of Object.values(info.assets)) {
108
+ if (!asset.file?.url || !asset.fileHash) {
109
+ throw new InvalidUpdateResponseError(
110
+ "Artifact protocol 1 requires an original file for every asset.",
193
111
  );
194
112
  }
195
- } catch (error: unknown) {
196
- if (error instanceof Error && error.name === "AbortError") {
197
- throw new Error("Request timed out");
198
- }
199
- throw error;
200
- } finally {
201
- clearTimeout(timeoutId);
202
113
  }
114
+ return info;
203
115
  };
204
116
 
205
- const createSession = (baseURL: string): HotUpdaterHttpSession => ({
206
- fetchReleaseCatalog: async (params): Promise<ReleaseCatalog> => {
117
+ const createSession = (
118
+ baseURL: string,
119
+ onResponse?: (response: UpdateHttpResponse) => void,
120
+ ): HotUpdaterHttpSession => ({
121
+ fetchReleaseCatalog: async (params): Promise<ReleaseCatalog | null> => {
207
122
  const channelKey = encodeChannelKey(params.channel);
208
123
  let strategyValue: string;
209
124
  if (params.updateStrategy === "fingerprint") {
@@ -222,6 +137,7 @@ const createSession = (baseURL: string): HotUpdaterHttpSession => ({
222
137
 
223
138
  return fetchReleaseCatalogWithCache({
224
139
  baseURL,
140
+ ...(onResponse ? { onResponse } : {}),
225
141
  expectedScope:
226
142
  params.updateStrategy === "fingerprint"
227
143
  ? {
@@ -241,21 +157,34 @@ const createSession = (baseURL: string): HotUpdaterHttpSession => ({
241
157
  });
242
158
  },
243
159
  resolveArtifact: async (params): Promise<ArtifactInfo> => {
244
- const info = await fetchJSON<ArtifactInfo>({
245
- requestHeaders: params.requestHeaders,
246
- requestTimeout: params.requestTimeout,
247
- url: `${baseURL}/artifacts/${encodeURIComponent(
248
- params.targetBundleId,
249
- )}/from/${encodeURIComponent(params.currentBundleId)}`,
250
- });
251
- return resolveArtifactUrls(baseURL, info);
160
+ let info: ArtifactInfo;
161
+ try {
162
+ info = await fetchJSON<ArtifactInfo>({
163
+ ...(onResponse ? { onResponse } : {}),
164
+ requestHeaders: params.requestHeaders,
165
+ requestTimeout: params.requestTimeout,
166
+ url: `${baseURL}/artifacts/v1/${encodeURIComponent(
167
+ params.targetBundleId,
168
+ )}/from/${encodeURIComponent(params.currentBundleId)}`,
169
+ });
170
+ } catch (error) {
171
+ if (error instanceof FetchJSONResponseError && error.status === 404) {
172
+ throw new InvalidUpdateResponseError(
173
+ `Server does not support artifact protocol ${ARTIFACT_PROTOCOL_VERSION}.`,
174
+ { cause: error },
175
+ );
176
+ }
177
+ throw error;
178
+ }
179
+ return resolveArtifactUrls(baseURL, requireArtifactProtocolV1(info));
252
180
  },
253
- sendInsightsEvent: (params) => sendInsightsEvent(baseURL, params),
254
181
  });
255
182
 
256
183
  /** Creates the private HTTP client used by HotUpdater.init and HotUpdater.wrap. */
257
184
  export const createHttpClient = (
258
185
  baseURL: HotUpdaterBaseURL,
186
+ onResponse?: (response: UpdateHttpResponse) => void,
259
187
  ): HotUpdaterHttpClient => ({
260
- createSession: async () => createSession(await resolveBaseURL(baseURL)),
188
+ createSession: async () =>
189
+ createSession(await resolveBaseURL(baseURL), onResponse),
261
190
  });
package/src/index.ts CHANGED
@@ -1,12 +1,16 @@
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 {
8
10
  addListener,
9
11
  getPublicActiveUpdateState,
12
+ getActiveUpdateState,
13
+ getBundleId,
10
14
  clearCrashHistory,
11
15
  getAppVersion,
12
16
  getBaseURL,
@@ -25,10 +29,10 @@ import {
25
29
  resetChannel,
26
30
  setCohort,
27
31
  setReloadBehavior,
28
- setUser,
32
+ stageBundle,
29
33
  type UpdateParams,
30
- updateBundle,
31
34
  } from "./native";
35
+ import { configurePlugins } from "./pluginHost";
32
36
  import { hotUpdaterStore } from "./store";
33
37
  import {
34
38
  type AutoUpdateOptions,
@@ -40,6 +44,29 @@ import {
40
44
  wrap,
41
45
  } from "./wrap";
42
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 UpdateHttpResponse,
61
+ type UpdateStrategy,
62
+ } from "./clientPlugin";
63
+ // The built-in Insights client plugin, for HotUpdater.init({ plugins }).
64
+ export {
65
+ insights,
66
+ type InsightsOptions,
67
+ type InsightsPlugin,
68
+ type InsightsUser,
69
+ } from "@hot-updater/plugin-insights/client";
43
70
  export type {
44
71
  CustomReloadHandler,
45
72
  HotUpdaterEvent,
@@ -51,7 +78,6 @@ export type {
51
78
  ActiveUpdateState,
52
79
  ReloadBehavior,
53
80
  ReloadBehaviorSetting,
54
- SetUserParams,
55
81
  } from "./native";
56
82
  export * from "./store";
57
83
  export {
@@ -100,13 +126,11 @@ function createHotUpdaterClient() {
100
126
 
101
127
  // Global configuration stored from wrap
102
128
  const globalConfig: {
103
- insights: boolean;
104
129
  client: HotUpdaterHttpClient | null;
105
130
  requestHeaders?: Record<string, string>;
106
131
  requestTimeout?: number;
107
132
  onError?: (error: unknown) => void;
108
133
  } = {
109
- insights: true,
110
134
  client: null,
111
135
  };
112
136
 
@@ -155,11 +179,12 @@ function createHotUpdaterClient() {
155
179
  const autoOptions = incoming as AutoUpdateOptions;
156
180
 
157
181
  if (autoOptions.baseURL) {
158
- const { baseURL, ...rest } = autoOptions;
182
+ const { baseURL, plugins: _plugins, ...rest } = autoOptions;
159
183
  return {
160
184
  ...rest,
161
- insights: rest.insights ?? true,
162
- client: createHttpClient(baseURL),
185
+ client: createHttpClient(baseURL, (response) => {
186
+ emitAfterAppReady("onHttpResponse", () => response);
187
+ }),
163
188
  };
164
189
  }
165
190
 
@@ -175,11 +200,12 @@ function createHotUpdaterClient() {
175
200
  };
176
201
 
177
202
  if (rest.baseURL) {
178
- const { baseURL, ...baseURLRest } = rest;
203
+ const { baseURL, plugins: _plugins, ...baseURLRest } = rest;
179
204
  return {
180
205
  ...baseURLRest,
181
- insights: baseURLRest.insights ?? true,
182
- client: createHttpClient(baseURL),
206
+ client: createHttpClient(baseURL, (response) => {
207
+ emitAfterAppReady("onHttpResponse", () => response);
208
+ }),
183
209
  };
184
210
  }
185
211
 
@@ -190,7 +216,13 @@ function createHotUpdaterClient() {
190
216
  normalizedOptions: InternalInitOptions | InternalWrapOptions,
191
217
  options: HotUpdaterOptions | HotUpdaterInitOptions,
192
218
  ) => {
193
- globalConfig.insights = normalizedOptions.insights ?? true;
219
+ // Plugins are set up before init or wrap reads the launch they observe.
220
+ configurePlugins(options.plugins, {
221
+ baseURL: options.baseURL,
222
+ requestHeaders: options.requestHeaders,
223
+ requestTimeout: options.requestTimeout,
224
+ onError: options.onError,
225
+ });
194
226
  globalConfig.client = normalizedOptions.client;
195
227
  globalConfig.requestHeaders = options.requestHeaders;
196
228
  globalConfig.requestTimeout = options.requestTimeout;
@@ -448,7 +480,6 @@ function createHotUpdaterClient() {
448
480
 
449
481
  const mergedConfig: InternalCheckForUpdateOptions = {
450
482
  ...config,
451
- insights: globalConfig.insights,
452
483
  client,
453
484
  requestHeaders: {
454
485
  ...globalConfig.requestHeaders,
@@ -466,8 +497,6 @@ function createHotUpdaterClient() {
466
497
  *
467
498
  * @param {UpdateBundleParams} params - Parameters object required for bundle update
468
499
  * @param {string} params.bundleId - The bundle ID of the app
469
- * @param {string|null} params.fileUrl - The URL of the zip file
470
- *
471
500
  * @returns {Promise<boolean>} Whether the update was successful
472
501
  *
473
502
  * @example
@@ -491,9 +520,53 @@ function createHotUpdaterClient() {
491
520
  * }
492
521
  * ```
493
522
  */
494
- updateBundle: (params: UpdateParams) => {
523
+ updateBundle: async (params: UpdateParams) => {
495
524
  ensureGlobalClient("updateBundle");
496
- return updateBundle(params);
525
+ const fromBundleId = getBundleId();
526
+ const state = getActiveUpdateState();
527
+ const active = state.activeSelection;
528
+ const fromReleaseId =
529
+ active?.bundleId === fromBundleId
530
+ ? active.releaseId
531
+ : state.stableSelection?.bundleId === fromBundleId
532
+ ? state.stableSelection.releaseId
533
+ : null;
534
+ const channel = params.channel ?? getChannel();
535
+ const strategyOf = (scopeKey: string | null | undefined) =>
536
+ scopeKey?.startsWith("v1:fingerprint:") ? "fingerprint" : "appVersion";
537
+ let delivery: Awaited<ReturnType<typeof stageBundle>>;
538
+ try {
539
+ delivery = await stageBundle(params);
540
+ } catch (error) {
541
+ reportUpdateError(error, "download", undefined, {
542
+ bundleId: fromBundleId,
543
+ channel,
544
+ targetBundleId: params.bundleId,
545
+ targetReleaseId:
546
+ (params.selection as { releaseId?: string | null } | undefined)
547
+ ?.releaseId ?? null,
548
+ updateStrategy: strategyOf(
549
+ (params.selection as { scopeKey?: string | null } | undefined)
550
+ ?.scopeKey,
551
+ ),
552
+ });
553
+ throw error;
554
+ }
555
+ if (delivery !== null && params.bundleId !== fromBundleId) {
556
+ emitAfterAppReady("onBundleDownloaded", () => {
557
+ const selection = getActiveUpdateState().activeSelection;
558
+ return {
559
+ channel,
560
+ fromBundleId,
561
+ fromReleaseId,
562
+ toBundleId: params.bundleId,
563
+ toReleaseId: selection?.releaseId ?? null,
564
+ updateStrategy: strategyOf(selection?.scopeKey),
565
+ ...delivery,
566
+ };
567
+ });
568
+ }
569
+ return true;
497
570
  },
498
571
 
499
572
  /**
@@ -507,10 +580,8 @@ function createHotUpdaterClient() {
507
580
  hotUpdaterStore.setState({
508
581
  artifactType: null,
509
582
  details: null,
510
- downloadedBytes: undefined,
511
583
  isUpdateDownloaded: false,
512
584
  progress: 0,
513
- totalBytes: undefined,
514
585
  });
515
586
  }
516
587
  return ok;
@@ -534,11 +605,6 @@ function createHotUpdaterClient() {
534
605
  */
535
606
  getInstallId,
536
607
 
537
- /**
538
- * Persists nullable user identity fields associated with this installation.
539
- */
540
- setUser,
541
-
542
608
  /**
543
609
  * Reads the native launch report for the current process.
544
610
  */