@hot-updater/react-native 1.0.0-rc.4 → 1.0.0-rc.41

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 (317) hide show
  1. package/android/build.gradle +13 -2
  2. package/android/proguard-rules.pro +8 -2
  3. package/android/src/bridge/BridgeReactInstance.kt +38 -0
  4. package/android/src/bridgeless/BridgeReactInstance.kt +24 -0
  5. package/android/src/main/java/com/hotupdater/ActivityStartGate.kt +94 -0
  6. package/android/src/main/java/com/hotupdater/BuiltInAssetResolver.kt +286 -0
  7. package/android/src/main/java/com/hotupdater/BundleFileStorageService.kt +1064 -844
  8. package/android/src/main/java/com/hotupdater/BundleMetadata.kt +50 -11
  9. package/android/src/main/java/com/hotupdater/FileManagerService.kt +45 -0
  10. package/android/src/main/java/com/hotupdater/HotUpdaterException.kt +287 -22
  11. package/android/src/main/java/com/hotupdater/HotUpdaterImpl.kt +46 -30
  12. package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryManager.kt +75 -192
  13. package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryState.kt +64 -0
  14. package/android/src/main/java/com/hotupdater/InstallIdentityService.kt +37 -0
  15. package/android/src/main/java/com/hotupdater/KeyValueStorageService.kt +86 -0
  16. package/android/src/main/java/com/hotupdater/NetworkState.kt +31 -0
  17. package/android/src/main/java/com/hotupdater/NoBackupStorage.kt +17 -0
  18. package/android/src/main/java/com/hotupdater/OkHttpDownloadService.kt +127 -50
  19. package/android/src/main/java/com/hotupdater/ReactNativeValueConverters.kt +34 -0
  20. package/android/src/main/java/com/hotupdater/TarArchiveInputStream.kt +214 -375
  21. package/android/src/main/java/com/hotupdater/TarBrArchiveExtractor.kt +119 -0
  22. package/android/src/newarch/HotUpdater.kt +7 -9
  23. package/android/src/newarch/HotUpdaterModule.kt +109 -84
  24. package/android/src/newarch/JavaScriptExceptionHooks.kt +48 -0
  25. package/android/src/newarch/ReactIntegrationManager.kt +6 -32
  26. package/android/src/oldarch/HotUpdater.kt +7 -9
  27. package/android/src/oldarch/HotUpdaterModule.kt +98 -74
  28. package/android/src/oldarch/HotUpdaterSpec.kt +4 -6
  29. package/android/src/oldarch/JavaScriptExceptionHooks.kt +71 -0
  30. package/ios/HotUpdater/Internal/BrotliFileDecompressor.swift +167 -0
  31. package/ios/HotUpdater/Internal/BuiltInAssetResolver.swift +196 -0
  32. package/ios/HotUpdater/Internal/BundleFileStorageService.swift +1032 -1116
  33. package/ios/HotUpdater/Internal/BundleMetadata.swift +61 -54
  34. package/ios/HotUpdater/Internal/FileManagerService.swift +48 -0
  35. package/ios/HotUpdater/Internal/FileUtilities.swift +64 -0
  36. package/ios/HotUpdater/Internal/HotUpdater-Bridging-Header.h +0 -1
  37. package/ios/HotUpdater/Internal/HotUpdater.mm +32 -67
  38. package/ios/HotUpdater/Internal/HotUpdaterImpl.swift +229 -73
  39. package/ios/HotUpdater/Internal/KeyValueStorageService.swift +71 -0
  40. package/ios/HotUpdater/Internal/NotificationExtension.swift +0 -2
  41. package/ios/HotUpdater/Internal/TarArchiveExtractor.swift +182 -311
  42. package/ios/HotUpdater/Internal/URLSessionDownloadService.swift +119 -71
  43. package/ios/HotUpdater/Internal/UpdateFailure.swift +390 -0
  44. package/ios/HotUpdater/Recovery/HotUpdaterRecovery.h +16 -0
  45. package/ios/HotUpdater/Recovery/HotUpdaterRecovery.mm +83 -0
  46. package/ios/HotUpdater/Recovery/HotUpdaterRecoveryHooks.mm +49 -0
  47. package/lib/commonjs/appReady.js +96 -0
  48. package/lib/commonjs/appReady.js.map +1 -0
  49. package/lib/commonjs/checkForUpdate.js +121 -69
  50. package/lib/commonjs/checkForUpdate.js.map +1 -1
  51. package/lib/commonjs/clientPlugin.js +13 -0
  52. package/lib/commonjs/clientPlugin.js.map +1 -0
  53. package/lib/commonjs/error.js +5 -14
  54. package/lib/commonjs/error.js.map +1 -1
  55. package/lib/commonjs/fetchJSON.js +16 -27
  56. package/lib/commonjs/fetchJSON.js.map +1 -1
  57. package/lib/commonjs/fetchUpdateResponse.js +60 -0
  58. package/lib/commonjs/fetchUpdateResponse.js.map +1 -0
  59. package/lib/commonjs/httpClient.js +64 -95
  60. package/lib/commonjs/httpClient.js.map +1 -1
  61. package/lib/commonjs/index.js +355 -324
  62. package/lib/commonjs/index.js.map +1 -1
  63. package/lib/commonjs/init.types.js +6 -0
  64. package/lib/commonjs/init.types.js.map +1 -0
  65. package/lib/commonjs/native.js +77 -63
  66. package/lib/commonjs/native.js.map +1 -1
  67. package/lib/commonjs/pluginHost.js +41 -0
  68. package/lib/commonjs/pluginHost.js.map +1 -0
  69. package/lib/commonjs/releaseCatalogCache.js +36 -87
  70. package/lib/commonjs/releaseCatalogCache.js.map +1 -1
  71. package/lib/commonjs/sdkVersion.js +1 -1
  72. package/lib/commonjs/sdkVersion.js.map +1 -1
  73. package/lib/commonjs/specs/NativeHotUpdater.js.map +1 -1
  74. package/lib/commonjs/store.js +3 -10
  75. package/lib/commonjs/store.js.map +1 -1
  76. package/lib/commonjs/updateError.js +145 -0
  77. package/lib/commonjs/updateError.js.map +1 -0
  78. package/lib/commonjs/wrap.js +46 -38
  79. package/lib/commonjs/wrap.js.map +1 -1
  80. package/lib/module/appReady.js +90 -0
  81. package/lib/module/appReady.js.map +1 -0
  82. package/lib/module/checkForUpdate.js +114 -64
  83. package/lib/module/checkForUpdate.js.map +1 -1
  84. package/lib/module/clientPlugin.js +4 -0
  85. package/lib/module/clientPlugin.js.map +1 -0
  86. package/lib/module/error.js +5 -14
  87. package/lib/module/error.js.map +1 -1
  88. package/lib/module/fetchJSON.js +14 -26
  89. package/lib/module/fetchJSON.js.map +1 -1
  90. package/lib/module/fetchUpdateResponse.js +55 -0
  91. package/lib/module/fetchUpdateResponse.js.map +1 -0
  92. package/lib/module/httpClient.js +63 -94
  93. package/lib/module/httpClient.js.map +1 -1
  94. package/lib/module/index.js +335 -327
  95. package/lib/module/index.js.map +1 -1
  96. package/lib/module/init.types.js +4 -0
  97. package/lib/module/init.types.js.map +1 -0
  98. package/lib/module/native.js +70 -56
  99. package/lib/module/native.js.map +1 -1
  100. package/lib/module/pluginHost.js +36 -0
  101. package/lib/module/pluginHost.js.map +1 -0
  102. package/lib/module/releaseCatalogCache.js +32 -82
  103. package/lib/module/releaseCatalogCache.js.map +1 -1
  104. package/lib/module/sdkVersion.js +1 -1
  105. package/lib/module/sdkVersion.js.map +1 -1
  106. package/lib/module/specs/NativeHotUpdater.js.map +1 -1
  107. package/lib/module/store.js +3 -10
  108. package/lib/module/store.js.map +1 -1
  109. package/lib/module/updateError.js +139 -0
  110. package/lib/module/updateError.js.map +1 -0
  111. package/lib/module/wrap.js +47 -38
  112. package/lib/module/wrap.js.map +1 -1
  113. package/lib/typescript/commonjs/appReady.d.ts +30 -0
  114. package/lib/typescript/commonjs/appReady.d.ts.map +1 -0
  115. package/lib/typescript/commonjs/checkForUpdate.d.ts +20 -6
  116. package/lib/typescript/commonjs/checkForUpdate.d.ts.map +1 -1
  117. package/lib/typescript/commonjs/clientPlugin.d.ts +2 -0
  118. package/lib/typescript/commonjs/clientPlugin.d.ts.map +1 -0
  119. package/lib/typescript/commonjs/error.d.ts +5 -14
  120. package/lib/typescript/commonjs/error.d.ts.map +1 -1
  121. package/lib/typescript/commonjs/fetchJSON.d.ts +5 -5
  122. package/lib/typescript/commonjs/fetchJSON.d.ts.map +1 -1
  123. package/lib/typescript/commonjs/fetchUpdateResponse.d.ts +14 -0
  124. package/lib/typescript/commonjs/fetchUpdateResponse.d.ts.map +1 -0
  125. package/lib/typescript/commonjs/httpClient.d.ts +5 -34
  126. package/lib/typescript/commonjs/httpClient.d.ts.map +1 -1
  127. package/lib/typescript/commonjs/index.d.ts +124 -116
  128. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  129. package/lib/typescript/commonjs/init.types.d.ts +21 -0
  130. package/lib/typescript/commonjs/init.types.d.ts.map +1 -0
  131. package/lib/typescript/commonjs/native.d.ts +32 -25
  132. package/lib/typescript/commonjs/native.d.ts.map +1 -1
  133. package/lib/typescript/commonjs/pluginHost.d.ts +8 -0
  134. package/lib/typescript/commonjs/pluginHost.d.ts.map +1 -0
  135. package/lib/typescript/commonjs/releaseCatalogCache.d.ts +8 -14
  136. package/lib/typescript/commonjs/releaseCatalogCache.d.ts.map +1 -1
  137. package/lib/typescript/commonjs/sdkVersion.d.ts +1 -1
  138. package/lib/typescript/commonjs/sdkVersion.d.ts.map +1 -1
  139. package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts +35 -47
  140. package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts.map +1 -1
  141. package/lib/typescript/commonjs/store.d.ts +1 -3
  142. package/lib/typescript/commonjs/store.d.ts.map +1 -1
  143. package/lib/typescript/commonjs/types.d.ts +1 -1
  144. package/lib/typescript/commonjs/types.d.ts.map +1 -1
  145. package/lib/typescript/commonjs/updateError.d.ts +26 -0
  146. package/lib/typescript/commonjs/updateError.d.ts.map +1 -0
  147. package/lib/typescript/commonjs/wrap.d.ts +2 -3
  148. package/lib/typescript/commonjs/wrap.d.ts.map +1 -1
  149. package/lib/typescript/commonjs/wrap.types.d.ts +13 -41
  150. package/lib/typescript/commonjs/wrap.types.d.ts.map +1 -1
  151. package/lib/typescript/module/appReady.d.ts +30 -0
  152. package/lib/typescript/module/appReady.d.ts.map +1 -0
  153. package/lib/typescript/module/checkForUpdate.d.ts +20 -6
  154. package/lib/typescript/module/checkForUpdate.d.ts.map +1 -1
  155. package/lib/typescript/module/clientPlugin.d.ts +2 -0
  156. package/lib/typescript/module/clientPlugin.d.ts.map +1 -0
  157. package/lib/typescript/module/error.d.ts +5 -14
  158. package/lib/typescript/module/error.d.ts.map +1 -1
  159. package/lib/typescript/module/fetchJSON.d.ts +5 -5
  160. package/lib/typescript/module/fetchJSON.d.ts.map +1 -1
  161. package/lib/typescript/module/fetchUpdateResponse.d.ts +14 -0
  162. package/lib/typescript/module/fetchUpdateResponse.d.ts.map +1 -0
  163. package/lib/typescript/module/httpClient.d.ts +5 -34
  164. package/lib/typescript/module/httpClient.d.ts.map +1 -1
  165. package/lib/typescript/module/index.d.ts +124 -116
  166. package/lib/typescript/module/index.d.ts.map +1 -1
  167. package/lib/typescript/module/init.types.d.ts +21 -0
  168. package/lib/typescript/module/init.types.d.ts.map +1 -0
  169. package/lib/typescript/module/native.d.ts +32 -25
  170. package/lib/typescript/module/native.d.ts.map +1 -1
  171. package/lib/typescript/module/pluginHost.d.ts +8 -0
  172. package/lib/typescript/module/pluginHost.d.ts.map +1 -0
  173. package/lib/typescript/module/releaseCatalogCache.d.ts +8 -14
  174. package/lib/typescript/module/releaseCatalogCache.d.ts.map +1 -1
  175. package/lib/typescript/module/sdkVersion.d.ts +1 -1
  176. package/lib/typescript/module/sdkVersion.d.ts.map +1 -1
  177. package/lib/typescript/module/specs/NativeHotUpdater.d.ts +35 -47
  178. package/lib/typescript/module/specs/NativeHotUpdater.d.ts.map +1 -1
  179. package/lib/typescript/module/store.d.ts +1 -3
  180. package/lib/typescript/module/store.d.ts.map +1 -1
  181. package/lib/typescript/module/types.d.ts +1 -1
  182. package/lib/typescript/module/types.d.ts.map +1 -1
  183. package/lib/typescript/module/updateError.d.ts +26 -0
  184. package/lib/typescript/module/updateError.d.ts.map +1 -0
  185. package/lib/typescript/module/wrap.d.ts +2 -3
  186. package/lib/typescript/module/wrap.d.ts.map +1 -1
  187. package/lib/typescript/module/wrap.types.d.ts +13 -41
  188. package/lib/typescript/module/wrap.types.d.ts.map +1 -1
  189. package/package.json +8 -4
  190. package/src/appReady.ts +147 -0
  191. package/src/checkForUpdate.ts +156 -89
  192. package/src/clientPlugin.ts +21 -0
  193. package/src/error.ts +5 -15
  194. package/src/fetchJSON.ts +14 -30
  195. package/src/fetchUpdateResponse.ts +60 -0
  196. package/src/httpClient.ts +89 -160
  197. package/src/index.ts +413 -425
  198. package/src/init.types.ts +24 -0
  199. package/src/native.ts +101 -105
  200. package/src/pluginHost.ts +52 -0
  201. package/src/releaseCatalogCache.ts +43 -172
  202. package/src/sdkVersion.ts +1 -1
  203. package/src/specs/NativeHotUpdater.ts +34 -48
  204. package/src/store.ts +2 -23
  205. package/src/types.ts +1 -1
  206. package/src/updateError.ts +167 -0
  207. package/src/wrap.tsx +60 -43
  208. package/src/wrap.types.ts +18 -46
  209. package/android/src/main/java/com/hotupdater/DecompressService.kt +0 -89
  210. package/android/src/main/java/com/hotupdater/DecompressionStrategy.kt +0 -26
  211. package/android/src/main/java/com/hotupdater/TarBrDecompressionStrategy.kt +0 -117
  212. package/android/src/main/java/com/hotupdater/TarGzDecompressionStrategy.kt +0 -117
  213. package/android/src/main/java/com/hotupdater/ZipDecompressionStrategy.kt +0 -192
  214. package/android/src/test/java/com/hotupdater/BsdiffPatchTest.kt +0 -46
  215. package/android/src/test/java/com/hotupdater/BundleFileStorageServiceTest.kt +0 -799
  216. package/android/src/test/java/com/hotupdater/HotUpdaterImplTest.kt +0 -273
  217. package/android/src/test/java/com/hotupdater/NativeConfigUtilsTest.kt +0 -20
  218. package/android/src/test/java/com/hotupdater/OkHttpDownloadServiceTest.kt +0 -111
  219. package/android/src/test/java/com/hotupdater/RelativePathResolverTest.kt +0 -41
  220. package/android/src/test/java/com/hotupdater/ReleaseCatalogCacheServiceTest.kt +0 -118
  221. package/android/src/test/java/com/hotupdater/TarArchiveInputStreamTest.kt +0 -68
  222. package/ios/HotUpdater/Internal/ArchiveExtractionUtilities.swift +0 -178
  223. package/ios/HotUpdater/Internal/DecompressService.swift +0 -112
  224. package/ios/HotUpdater/Internal/DecompressionStrategy.swift +0 -22
  225. package/ios/HotUpdater/Internal/StreamingTarArchiveExtractor.swift +0 -370
  226. package/ios/HotUpdater/Internal/TarBrDecompressionStrategy.swift +0 -39
  227. package/ios/HotUpdater/Internal/TarGzDecompressionStrategy.swift +0 -59
  228. package/ios/HotUpdater/Internal/ZipArchiveExtractor.swift +0 -482
  229. package/ios/HotUpdater/Internal/ZipDecompressionStrategy.swift +0 -56
  230. package/lib/commonjs/catalogCacheNative.spec.js +0 -31
  231. package/lib/commonjs/catalogCacheNative.spec.js.map +0 -1
  232. package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js +0 -616
  233. package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js.map +0 -1
  234. package/lib/commonjs/httpClient.spec.js +0 -102
  235. package/lib/commonjs/httpClient.spec.js.map +0 -1
  236. package/lib/commonjs/index.spec.js +0 -302
  237. package/lib/commonjs/index.spec.js.map +0 -1
  238. package/lib/commonjs/iosInterop.spec.js +0 -18
  239. package/lib/commonjs/iosInterop.spec.js.map +0 -1
  240. package/lib/commonjs/native.spec.js +0 -883
  241. package/lib/commonjs/native.spec.js.map +0 -1
  242. package/lib/commonjs/notifyAppReadyInsights.boundary.spec.js +0 -218
  243. package/lib/commonjs/notifyAppReadyInsights.boundary.spec.js.map +0 -1
  244. package/lib/commonjs/notifyAppReadyInsights.js +0 -133
  245. package/lib/commonjs/notifyAppReadyInsights.js.map +0 -1
  246. package/lib/commonjs/notifyAppReadyInsights.spec.js +0 -246
  247. package/lib/commonjs/notifyAppReadyInsights.spec.js.map +0 -1
  248. package/lib/commonjs/notifyAppReadyInsights.test-utils.js +0 -24
  249. package/lib/commonjs/notifyAppReadyInsights.test-utils.js.map +0 -1
  250. package/lib/commonjs/notifyAppReadyInsights.transport.spec.js +0 -117
  251. package/lib/commonjs/notifyAppReadyInsights.transport.spec.js.map +0 -1
  252. package/lib/commonjs/releaseCatalogCache.spec.js +0 -195
  253. package/lib/commonjs/releaseCatalogCache.spec.js.map +0 -1
  254. package/lib/commonjs/releaseCatalogCacheNativeContract.spec.js +0 -64
  255. package/lib/commonjs/releaseCatalogCacheNativeContract.spec.js.map +0 -1
  256. package/lib/commonjs/store.notification.spec.js +0 -76
  257. package/lib/commonjs/store.notification.spec.js.map +0 -1
  258. package/lib/commonjs/store.spec.js +0 -316
  259. package/lib/commonjs/store.spec.js.map +0 -1
  260. package/lib/commonjs/wrap.spec.js +0 -329
  261. package/lib/commonjs/wrap.spec.js.map +0 -1
  262. package/lib/module/catalogCacheNative.spec.js +0 -31
  263. package/lib/module/catalogCacheNative.spec.js.map +0 -1
  264. package/lib/module/checkForUpdate.releaseCatalog.spec.js +0 -615
  265. package/lib/module/checkForUpdate.releaseCatalog.spec.js.map +0 -1
  266. package/lib/module/httpClient.spec.js +0 -102
  267. package/lib/module/httpClient.spec.js.map +0 -1
  268. package/lib/module/index.spec.js +0 -301
  269. package/lib/module/index.spec.js.map +0 -1
  270. package/lib/module/iosInterop.spec.js +0 -18
  271. package/lib/module/iosInterop.spec.js.map +0 -1
  272. package/lib/module/native.spec.js +0 -882
  273. package/lib/module/native.spec.js.map +0 -1
  274. package/lib/module/notifyAppReadyInsights.boundary.spec.js +0 -217
  275. package/lib/module/notifyAppReadyInsights.boundary.spec.js.map +0 -1
  276. package/lib/module/notifyAppReadyInsights.js +0 -128
  277. package/lib/module/notifyAppReadyInsights.js.map +0 -1
  278. package/lib/module/notifyAppReadyInsights.spec.js +0 -245
  279. package/lib/module/notifyAppReadyInsights.spec.js.map +0 -1
  280. package/lib/module/notifyAppReadyInsights.test-utils.js +0 -18
  281. package/lib/module/notifyAppReadyInsights.test-utils.js.map +0 -1
  282. package/lib/module/notifyAppReadyInsights.transport.spec.js +0 -116
  283. package/lib/module/notifyAppReadyInsights.transport.spec.js.map +0 -1
  284. package/lib/module/releaseCatalogCache.spec.js +0 -195
  285. package/lib/module/releaseCatalogCache.spec.js.map +0 -1
  286. package/lib/module/releaseCatalogCacheNativeContract.spec.js +0 -64
  287. package/lib/module/releaseCatalogCacheNativeContract.spec.js.map +0 -1
  288. package/lib/module/store.notification.spec.js +0 -77
  289. package/lib/module/store.notification.spec.js.map +0 -1
  290. package/lib/module/store.spec.js +0 -315
  291. package/lib/module/store.spec.js.map +0 -1
  292. package/lib/module/wrap.spec.js +0 -330
  293. package/lib/module/wrap.spec.js.map +0 -1
  294. package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts +0 -13
  295. package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts.map +0 -1
  296. package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts +0 -8
  297. package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts.map +0 -1
  298. package/lib/typescript/module/notifyAppReadyInsights.d.ts +0 -13
  299. package/lib/typescript/module/notifyAppReadyInsights.d.ts.map +0 -1
  300. package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts +0 -8
  301. package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts.map +0 -1
  302. package/src/catalogCacheNative.spec.ts +0 -63
  303. package/src/checkForUpdate.releaseCatalog.spec.ts +0 -612
  304. package/src/httpClient.spec.ts +0 -132
  305. package/src/index.spec.ts +0 -337
  306. package/src/iosInterop.spec.ts +0 -30
  307. package/src/native.spec.ts +0 -945
  308. package/src/notifyAppReadyInsights.boundary.spec.ts +0 -234
  309. package/src/notifyAppReadyInsights.spec.ts +0 -243
  310. package/src/notifyAppReadyInsights.test-utils.ts +0 -31
  311. package/src/notifyAppReadyInsights.transport.spec.ts +0 -130
  312. package/src/notifyAppReadyInsights.ts +0 -194
  313. package/src/releaseCatalogCache.spec.ts +0 -282
  314. package/src/releaseCatalogCacheNativeContract.spec.ts +0 -80
  315. package/src/store.notification.spec.ts +0 -92
  316. package/src/store.spec.ts +0 -372
  317. package/src/wrap.spec.ts +0 -406
package/src/wrap.tsx CHANGED
@@ -1,30 +1,21 @@
1
1
  import React, { useEffect, useState } from "react";
2
2
 
3
- import { checkForUpdate } from "./checkForUpdate";
4
3
  import { useEventCallback } from "./hooks/useEventCallback";
5
4
  import { getUpdateId, reload } from "./native";
6
- import { handleNotifyAppReady } from "./notifyAppReadyInsights";
7
5
  import { useHotUpdaterStore } from "./store";
8
6
  import type {
9
- InternalInitOptions,
7
+ HotUpdaterFallbackComponentProps,
10
8
  InternalWrapOptions,
11
9
  UpdateStatus,
12
10
  } from "./wrap.types";
13
11
 
14
12
  export type {
15
- AutoUpdateOptions,
16
13
  HotUpdaterFallbackComponentProps,
17
- HotUpdaterInitOptions,
18
- HotUpdaterOptions,
19
- InternalInitOptions,
14
+ HotUpdaterWrapOptions,
20
15
  InternalWrapOptions,
21
16
  RunUpdateProcessResponse,
22
17
  } from "./wrap.types";
23
18
 
24
- export function init(options: InternalInitOptions): void {
25
- void handleNotifyAppReady(options);
26
- }
27
-
28
19
  export function wrap(
29
20
  options: InternalWrapOptions,
30
21
  ): <P extends object>(
@@ -32,11 +23,46 @@ export function wrap(
32
23
  ) => React.ComponentType<P> {
33
24
  const { reloadOnForceUpdate = true, ...restOptions } = options;
34
25
 
26
+ // Progress is subscribed only where it is rendered or reported, so progress
27
+ // events don't re-render the wrapped app.
28
+ const ProgressReporter = ({
29
+ onProgress,
30
+ }: {
31
+ onProgress: (progress: number) => void;
32
+ }) => {
33
+ const progress = useHotUpdaterStore((state) => state.progress);
34
+
35
+ useEffect(() => {
36
+ onProgress(progress);
37
+ }, [progress]);
38
+
39
+ return null;
40
+ };
41
+
42
+ const FallbackWithProgress = ({
43
+ Fallback,
44
+ status,
45
+ message,
46
+ }: {
47
+ Fallback: React.FC<HotUpdaterFallbackComponentProps>;
48
+ status: HotUpdaterFallbackComponentProps["status"];
49
+ message: string | null;
50
+ }) => {
51
+ const progressState = useHotUpdaterStore((state) => state);
52
+
53
+ return (
54
+ <Fallback
55
+ artifactType={progressState.artifactType}
56
+ details={progressState.details}
57
+ progress={progressState.progress}
58
+ status={status}
59
+ message={message}
60
+ />
61
+ );
62
+ };
63
+
35
64
  return <P extends object>(WrappedComponent: React.ComponentType<P>) => {
36
65
  const HotUpdaterHOC: React.FC<P> = (props: P) => {
37
- const progressState = useHotUpdaterStore((state) => state);
38
- const progress = progressState.progress;
39
-
40
66
  const [message, setMessage] = useState<string | null>(null);
41
67
  const [updateStatus, setUpdateStatus] =
42
68
  useState<UpdateStatus>("CHECK_FOR_UPDATE");
@@ -45,15 +71,12 @@ export function wrap(
45
71
  try {
46
72
  setUpdateStatus("CHECK_FOR_UPDATE");
47
73
 
48
- const updateInfo = await checkForUpdate({
49
- insights: restOptions.insights,
50
- client: restOptions.client,
74
+ const updateInfo = await restOptions.checkForUpdate({
51
75
  updateStrategy: restOptions.updateStrategy,
52
- requestHeaders: restOptions.requestHeaders,
53
- requestTimeout: restOptions.requestTimeout,
54
- onError: restOptions.onError,
55
76
  });
56
77
 
78
+ // A forced update reloads only after init has read this launch.
79
+ await restOptions.appReady();
57
80
  setMessage(updateInfo?.message ?? null);
58
81
 
59
82
  if (!updateInfo) {
@@ -69,7 +92,7 @@ export function wrap(
69
92
 
70
93
  if (updateInfo.shouldForceUpdate === false) {
71
94
  void updateInfo.updateBundle().catch((error: unknown) => {
72
- restOptions.onError?.(error);
95
+ restOptions.onError(error);
73
96
  });
74
97
 
75
98
  restOptions.onUpdateProcessCompleted?.({
@@ -106,44 +129,38 @@ export function wrap(
106
129
  } catch (error) {
107
130
  const normalizedError =
108
131
  error instanceof Error ? error : new Error(String(error));
109
- restOptions.onError?.(normalizedError);
132
+ restOptions.onError(normalizedError);
110
133
  setUpdateStatus("UPDATE_PROCESS_COMPLETED");
111
134
  }
112
135
  });
113
136
 
114
- useEffect(() => {
115
- restOptions.onProgress?.(progress);
116
- }, [progress]);
117
-
118
- // Read the native launch report after the first render commit.
119
- useEffect(() => {
120
- void handleNotifyAppReady(restOptions);
121
- }, []);
122
-
123
137
  // Start update check
124
138
  useEffect(() => {
125
139
  initHotUpdater();
126
140
  }, []);
127
141
 
128
- if (
142
+ const content =
129
143
  restOptions.fallbackComponent &&
130
- updateStatus !== "UPDATE_PROCESS_COMPLETED"
131
- ) {
132
- const Fallback = restOptions.fallbackComponent;
133
- return (
134
- <Fallback
135
- artifactType={progressState.artifactType}
136
- details={progressState.details}
137
- downloadedBytes={progressState.downloadedBytes}
138
- progress={progress}
144
+ updateStatus !== "UPDATE_PROCESS_COMPLETED" ? (
145
+ <FallbackWithProgress
146
+ Fallback={restOptions.fallbackComponent}
139
147
  status={updateStatus}
140
148
  message={message}
141
- totalBytes={progressState.totalBytes}
142
149
  />
150
+ ) : (
151
+ <WrappedComponent {...props} />
143
152
  );
153
+
154
+ if (!restOptions.onProgress) {
155
+ return content;
144
156
  }
145
157
 
146
- return <WrappedComponent {...props} />;
158
+ return (
159
+ <>
160
+ {content}
161
+ <ProgressReporter onProgress={restOptions.onProgress} />
162
+ </>
163
+ );
147
164
  };
148
165
 
149
166
  return HotUpdaterHOC as React.ComponentType<P>;
package/src/wrap.types.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import type React from "react";
2
2
 
3
- import type { HotUpdaterError } from "./error";
4
- import type { HotUpdaterHttpClient } from "./httpClient";
5
- import type { NotifyAppReadyResult } from "./native";
3
+ import type {
4
+ CheckForUpdateOptions,
5
+ CheckForUpdateResult,
6
+ } from "./checkForUpdate";
6
7
  import type { HotUpdaterState } from "./store";
7
- import type { HotUpdaterBaseURL } from "./types";
8
8
 
9
9
  export interface RunUpdateProcessResponse {
10
10
  status: "ROLLBACK" | "UPDATE" | "UP_TO_DATE";
@@ -21,57 +21,29 @@ export type UpdateStatus =
21
21
  export type HotUpdaterFallbackComponentProps = {
22
22
  status: Exclude<UpdateStatus, "UPDATE_PROCESS_COMPLETED">;
23
23
  progress: number;
24
- downloadedBytes: HotUpdaterState["downloadedBytes"];
25
- totalBytes: HotUpdaterState["totalBytes"];
26
24
  message: string | null;
27
25
  artifactType: HotUpdaterState["artifactType"];
28
26
  details: HotUpdaterState["details"];
29
27
  };
30
28
 
31
- interface CommonHotUpdaterOptions {
32
- /**
33
- * Sends app-ready transitions and same-Bundle Release adoptions to the
34
- * configured server. Defaults to `true`; set to `false` to disable client
35
- * reporting.
36
- */
37
- insights?: boolean;
38
- /** Base URL of a server exposing the Hot Updater v1 client HTTP protocol. */
39
- baseURL: HotUpdaterBaseURL;
40
- requestHeaders?: Record<string, string>;
41
- requestTimeout?: number;
42
- onNotifyAppReady?: (result: NotifyAppReadyResult) => void;
43
- onError?: (error: HotUpdaterError | Error | unknown) => void;
44
- }
45
-
46
- export type AutoUpdateOptions = CommonHotUpdaterOptions & {
29
+ /**
30
+ * The update flow `hotUpdater.wrap` runs when the wrapped root mounts. The
31
+ * server, request settings, and plugins come from `HotUpdater.init`.
32
+ */
33
+ export interface HotUpdaterWrapOptions {
47
34
  updateStrategy: "fingerprint" | "appVersion";
48
35
  fallbackComponent?: React.FC<HotUpdaterFallbackComponentProps>;
49
36
  onProgress?: (progress: number) => void;
50
37
  reloadOnForceUpdate?: boolean;
51
38
  onUpdateProcessCompleted?: (response: RunUpdateProcessResponse) => void;
52
- };
53
-
54
- export type HotUpdaterInitOptions = CommonHotUpdaterOptions;
55
-
56
- export type HotUpdaterOptions = AutoUpdateOptions;
39
+ }
57
40
 
58
- type InternalCommonOptions = {
59
- insights?: boolean;
60
- client: HotUpdaterHttpClient;
61
- requestHeaders?: Record<string, string>;
62
- requestTimeout?: number;
63
- onNotifyAppReady?: (result: NotifyAppReadyResult) => void;
64
- onError?: (error: HotUpdaterError | Error | unknown) => void;
41
+ export type InternalWrapOptions = HotUpdaterWrapOptions & {
42
+ /** The instance's check, over the configuration of `HotUpdater.init`. */
43
+ checkForUpdate: (
44
+ options: Pick<CheckForUpdateOptions, "updateStrategy">,
45
+ ) => Promise<CheckForUpdateResult | null>;
46
+ /** Settles once `HotUpdater.init` has read this launch. */
47
+ appReady: () => Promise<unknown>;
48
+ onError: (error: unknown) => void;
65
49
  };
66
-
67
- type InternalAutoUpdateOptions = InternalCommonOptions & {
68
- updateStrategy: "fingerprint" | "appVersion";
69
- fallbackComponent?: React.FC<HotUpdaterFallbackComponentProps>;
70
- onProgress?: (progress: number) => void;
71
- reloadOnForceUpdate?: boolean;
72
- onUpdateProcessCompleted?: (response: RunUpdateProcessResponse) => void;
73
- };
74
-
75
- export type InternalInitOptions = InternalCommonOptions;
76
-
77
- export type InternalWrapOptions = InternalAutoUpdateOptions;
@@ -1,89 +0,0 @@
1
- package com.hotupdater
2
-
3
- import android.util.Log
4
- import java.io.File
5
-
6
- /**
7
- * Unified decompression service that uses Strategy pattern to handle multiple compression formats.
8
- * Automatically detects format by trying each strategy's validation and delegates to appropriate decompression strategy.
9
- */
10
- class DecompressService {
11
- companion object {
12
- private const val TAG = "DecompressService"
13
- }
14
-
15
- // Strategies with reliable file signatures that can be validated cheaply.
16
- // TAR.BR is attempted only as the final fallback because Brotli has no reliable magic bytes.
17
- private val signatureStrategies =
18
- listOf(
19
- ZipDecompressionStrategy(),
20
- TarGzDecompressionStrategy(),
21
- )
22
- private val tarBrStrategy = TarBrDecompressionStrategy()
23
-
24
- /**
25
- * Extracts a compressed file to the destination directory.
26
- * Automatically detects compression format by trying each strategy's validation.
27
- * @param filePath Path to the compressed file
28
- * @param destinationPath Path to the destination directory
29
- * @param progressCallback Callback for progress updates (0.0 - 1.0)
30
- * @return true if extraction was successful, false otherwise
31
- */
32
- fun extractZipFile(
33
- filePath: String,
34
- destinationPath: String,
35
- progressCallback: (Double) -> Unit,
36
- ): Boolean {
37
- // Collect file information for better error messages
38
- val file = File(filePath)
39
- val fileName = file.name
40
- val fileSize = if (file.exists()) file.length() else 0L
41
-
42
- // Try each signature-based strategy first.
43
- for (strategy in signatureStrategies) {
44
- if (strategy.isValid(filePath)) {
45
- Log.d(TAG, "Using strategy for $fileName")
46
- return strategy.decompress(filePath, destinationPath, progressCallback)
47
- }
48
- }
49
-
50
- Log.d(TAG, "No ZIP/TAR.GZ signature matched for $fileName, trying TAR.BR fallback")
51
-
52
- if (tarBrStrategy.decompress(filePath, destinationPath, progressCallback)) {
53
- Log.d(TAG, "Using TAR.BR fallback for $fileName")
54
- return true
55
- }
56
-
57
- val errorMessage = createInvalidArchiveMessage(fileName, fileSize)
58
- Log.e(TAG, errorMessage)
59
- return false
60
- }
61
-
62
- /**
63
- * Validates if a file matches one of the signature-based archive formats.
64
- * @param filePath Path to the file to validate
65
- * @return true if the file is a valid compressed archive
66
- */
67
- fun isValidZipFile(filePath: String): Boolean {
68
- for (strategy in signatureStrategies) {
69
- if (strategy.isValid(filePath)) {
70
- return true
71
- }
72
- }
73
- Log.d(TAG, "No ZIP/TAR.GZ signature matched for file: $filePath. TAR.BR is handled during extraction fallback.")
74
- return false
75
- }
76
-
77
- private fun createInvalidArchiveMessage(
78
- fileName: String,
79
- fileSize: Long,
80
- ): String =
81
- """
82
- The downloaded bundle file is not a valid compressed archive: $fileName ($fileSize bytes)
83
-
84
- Supported formats:
85
- - ZIP archives (.zip)
86
- - GZIP compressed TAR archives (.tar.gz)
87
- - Brotli compressed TAR archives (.tar.br)
88
- """.trimIndent()
89
- }
@@ -1,26 +0,0 @@
1
- package com.hotupdater
2
-
3
- /**
4
- * Interface for decompression strategies
5
- */
6
- interface DecompressionStrategy {
7
- /**
8
- * Validates if a file can be decompressed by this strategy
9
- * @param filePath Path to the file to validate
10
- * @return true if the file is valid for this strategy
11
- */
12
- fun isValid(filePath: String): Boolean
13
-
14
- /**
15
- * Decompresses a file to the destination directory
16
- * @param filePath Path to the compressed file
17
- * @param destinationPath Path to the destination directory
18
- * @param progressCallback Callback for progress updates (0.0 - 1.0)
19
- * @return true if decompression was successful, false otherwise
20
- */
21
- fun decompress(
22
- filePath: String,
23
- destinationPath: String,
24
- progressCallback: (Double) -> Unit,
25
- ): Boolean
26
- }
@@ -1,117 +0,0 @@
1
- package com.hotupdater
2
-
3
- import android.util.Log
4
- import com.hotupdater.vendor.brotli.dec.BrotliInputStream
5
- import java.io.BufferedInputStream
6
- import java.io.File
7
- import java.io.FileInputStream
8
- import java.io.FileOutputStream
9
-
10
- /**
11
- * Strategy for handling TAR+Brotli compressed files
12
- * Uses native Brotli decoder and custom TAR parser
13
- */
14
- class TarBrDecompressionStrategy : DecompressionStrategy {
15
- companion object {
16
- private const val TAG = "TarBrStrategy"
17
- private const val MIN_FILE_SIZE = 10L
18
- }
19
-
20
- override fun isValid(filePath: String): Boolean {
21
- val file = File(filePath)
22
-
23
- if (!file.exists() || file.length() < MIN_FILE_SIZE) {
24
- Log.d(TAG, "Invalid file: doesn't exist or too small (${file.length()} bytes)")
25
- return false
26
- }
27
-
28
- return try {
29
- FileInputStream(file).use { fileInputStream ->
30
- BufferedInputStream(fileInputStream).use { bufferedInputStream ->
31
- BrotliInputStream(bufferedInputStream).use { brotliInputStream ->
32
- TarArchiveInputStream(brotliInputStream).use { tarInputStream ->
33
- val firstEntry = tarInputStream.getNextEntry()
34
- val isValid = firstEntry != null
35
-
36
- if (!isValid) {
37
- Log.d(TAG, "Invalid file: tar archive has no entries")
38
- }
39
-
40
- isValid
41
- }
42
- }
43
- }
44
- }
45
- } catch (e: Exception) {
46
- Log.d(TAG, "Invalid file: Brotli/TAR validation failed - ${e.message}")
47
- false
48
- }
49
- }
50
-
51
- override fun decompress(
52
- filePath: String,
53
- destinationPath: String,
54
- progressCallback: (Double) -> Unit,
55
- ): Boolean =
56
- try {
57
- val destinationDir = File(destinationPath)
58
- if (!destinationDir.exists()) {
59
- destinationDir.mkdirs()
60
- }
61
-
62
- val sourceFile = File(filePath)
63
- val totalSize = sourceFile.length()
64
- var processedBytes = 0L
65
-
66
- Log.d(TAG, "Extracting tar.br file: $filePath")
67
-
68
- FileInputStream(filePath).use { fileInputStream ->
69
- BufferedInputStream(fileInputStream).use { bufferedInputStream ->
70
- BrotliInputStream(bufferedInputStream).use { brotliInputStream ->
71
- TarArchiveInputStream(brotliInputStream).use { tarInputStream ->
72
- var entry = tarInputStream.getNextEntry()
73
-
74
- while (entry != null) {
75
- val file = RelativePathResolver.resolveInside(destinationDir, entry.name)
76
-
77
- if (file == null) {
78
- Log.w(TAG, "Skipping potentially malicious tar entry: ${entry.name}")
79
- entry = tarInputStream.getNextEntry()
80
- continue
81
- }
82
-
83
- if (entry.isDirectory) {
84
- file.mkdirs()
85
- } else {
86
- file.parentFile?.mkdirs()
87
-
88
- FileOutputStream(file).use { output ->
89
- val buffer = ByteArray(8 * 1024)
90
- var bytesRead: Int
91
-
92
- while (tarInputStream.read(buffer).also { bytesRead = it } != -1) {
93
- output.write(buffer, 0, bytesRead)
94
- processedBytes += bytesRead
95
- }
96
- }
97
- }
98
-
99
- val progress = processedBytes.toDouble() / (totalSize * 2.0)
100
- progressCallback.invoke(progress.coerceIn(0.0, 1.0))
101
-
102
- entry = tarInputStream.getNextEntry()
103
- }
104
- }
105
- }
106
- }
107
- }
108
-
109
- Log.d(TAG, "Successfully extracted tar.br file")
110
- progressCallback.invoke(1.0)
111
- true
112
- } catch (e: Exception) {
113
- Log.d(TAG, "Failed to extract tar.br file: ${e.message}")
114
- e.printStackTrace()
115
- false
116
- }
117
- }
@@ -1,117 +0,0 @@
1
- package com.hotupdater
2
-
3
- import android.util.Log
4
- import java.io.BufferedInputStream
5
- import java.io.File
6
- import java.io.FileInputStream
7
- import java.io.FileOutputStream
8
- import java.util.zip.GZIPInputStream
9
-
10
- /**
11
- * Strategy for handling TAR+GZIP compressed files
12
- * Uses native GZIP decoder and custom TAR parser
13
- */
14
- class TarGzDecompressionStrategy : DecompressionStrategy {
15
- companion object {
16
- private const val TAG = "TarGzStrategy"
17
- private const val MIN_FILE_SIZE = 10L
18
- }
19
-
20
- override fun isValid(filePath: String): Boolean {
21
- val file = File(filePath)
22
-
23
- if (!file.exists() || file.length() < MIN_FILE_SIZE) {
24
- Log.d(TAG, "Invalid file: doesn't exist or too small (${file.length()} bytes)")
25
- return false
26
- }
27
-
28
- try {
29
- FileInputStream(file).use { fis ->
30
- val header = ByteArray(2)
31
- if (fis.read(header) != 2) {
32
- Log.d(TAG, "Invalid file: cannot read header")
33
- return false
34
- }
35
-
36
- // Check GZIP magic bytes (0x1F 0x8B)
37
- val isGzip = header[0] == 0x1F.toByte() && header[1] == 0x8B.toByte()
38
- if (!isGzip) {
39
- Log.d(
40
- TAG,
41
- "Invalid file: wrong magic bytes (expected 0x1F 0x8B, got 0x${header[0].toString(16)} 0x${header[1].toString(16)})",
42
- )
43
- }
44
- return isGzip
45
- }
46
- } catch (e: Exception) {
47
- Log.d(TAG, "Invalid file: error reading header: ${e.message}")
48
- return false
49
- }
50
- }
51
-
52
- override fun decompress(
53
- filePath: String,
54
- destinationPath: String,
55
- progressCallback: (Double) -> Unit,
56
- ): Boolean =
57
- try {
58
- val destinationDir = File(destinationPath)
59
- if (!destinationDir.exists()) {
60
- destinationDir.mkdirs()
61
- }
62
-
63
- val sourceFile = File(filePath)
64
- val totalSize = sourceFile.length()
65
- var processedBytes = 0L
66
-
67
- Log.d(TAG, "Extracting tar.gz file: $filePath")
68
-
69
- FileInputStream(filePath).use { fileInputStream ->
70
- BufferedInputStream(fileInputStream).use { bufferedInputStream ->
71
- GZIPInputStream(bufferedInputStream).use { gzipInputStream ->
72
- TarArchiveInputStream(gzipInputStream).use { tarInputStream ->
73
- var entry = tarInputStream.getNextEntry()
74
-
75
- while (entry != null) {
76
- val file = RelativePathResolver.resolveInside(destinationDir, entry.name)
77
-
78
- if (file == null) {
79
- Log.w(TAG, "Skipping potentially malicious tar entry: ${entry.name}")
80
- entry = tarInputStream.getNextEntry()
81
- continue
82
- }
83
-
84
- if (entry.isDirectory) {
85
- file.mkdirs()
86
- } else {
87
- file.parentFile?.mkdirs()
88
-
89
- FileOutputStream(file).use { output ->
90
- val buffer = ByteArray(8 * 1024)
91
- var bytesRead: Int
92
-
93
- while (tarInputStream.read(buffer).also { bytesRead = it } != -1) {
94
- output.write(buffer, 0, bytesRead)
95
- processedBytes += bytesRead
96
- }
97
- }
98
- }
99
-
100
- val progress = processedBytes.toDouble() / (totalSize * 2.0)
101
- progressCallback.invoke(progress.coerceIn(0.0, 1.0))
102
-
103
- entry = tarInputStream.getNextEntry()
104
- }
105
- }
106
- }
107
- }
108
- }
109
-
110
- Log.d(TAG, "Successfully extracted tar.gz file")
111
- progressCallback.invoke(1.0)
112
- true
113
- } catch (e: Exception) {
114
- Log.e(TAG, "Error extracting tar.gz file: ${e.message}", e)
115
- false
116
- }
117
- }