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

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 (306) 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 +102 -0
  48. package/lib/commonjs/appReady.js.map +1 -0
  49. package/lib/commonjs/checkForUpdate.js +120 -68
  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 +4 -13
  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 +63 -94
  60. package/lib/commonjs/httpClient.js.map +1 -1
  61. package/lib/commonjs/index.js +71 -18
  62. package/lib/commonjs/index.js.map +1 -1
  63. package/lib/commonjs/native.js +74 -60
  64. package/lib/commonjs/native.js.map +1 -1
  65. package/lib/commonjs/pluginHost.js +45 -0
  66. package/lib/commonjs/pluginHost.js.map +1 -0
  67. package/lib/commonjs/releaseCatalogCache.js +36 -87
  68. package/lib/commonjs/releaseCatalogCache.js.map +1 -1
  69. package/lib/commonjs/sdkVersion.js +1 -1
  70. package/lib/commonjs/sdkVersion.js.map +1 -1
  71. package/lib/commonjs/specs/NativeHotUpdater.js.map +1 -1
  72. package/lib/commonjs/store.js +3 -10
  73. package/lib/commonjs/store.js.map +1 -1
  74. package/lib/commonjs/updateError.js +145 -0
  75. package/lib/commonjs/updateError.js.map +1 -0
  76. package/lib/commonjs/wrap.js +43 -26
  77. package/lib/commonjs/wrap.js.map +1 -1
  78. package/lib/module/appReady.js +95 -0
  79. package/lib/module/appReady.js.map +1 -0
  80. package/lib/module/checkForUpdate.js +113 -63
  81. package/lib/module/checkForUpdate.js.map +1 -1
  82. package/lib/module/clientPlugin.js +4 -0
  83. package/lib/module/clientPlugin.js.map +1 -0
  84. package/lib/module/error.js +4 -13
  85. package/lib/module/error.js.map +1 -1
  86. package/lib/module/fetchJSON.js +14 -26
  87. package/lib/module/fetchJSON.js.map +1 -1
  88. package/lib/module/fetchUpdateResponse.js +55 -0
  89. package/lib/module/fetchUpdateResponse.js.map +1 -0
  90. package/lib/module/httpClient.js +62 -93
  91. package/lib/module/httpClient.js.map +1 -1
  92. package/lib/module/index.js +58 -20
  93. package/lib/module/index.js.map +1 -1
  94. package/lib/module/native.js +67 -53
  95. package/lib/module/native.js.map +1 -1
  96. package/lib/module/pluginHost.js +36 -0
  97. package/lib/module/pluginHost.js.map +1 -0
  98. package/lib/module/releaseCatalogCache.js +32 -82
  99. package/lib/module/releaseCatalogCache.js.map +1 -1
  100. package/lib/module/sdkVersion.js +1 -1
  101. package/lib/module/sdkVersion.js.map +1 -1
  102. package/lib/module/specs/NativeHotUpdater.js.map +1 -1
  103. package/lib/module/store.js +3 -10
  104. package/lib/module/store.js.map +1 -1
  105. package/lib/module/updateError.js +139 -0
  106. package/lib/module/updateError.js.map +1 -0
  107. package/lib/module/wrap.js +43 -26
  108. package/lib/module/wrap.js.map +1 -1
  109. package/lib/typescript/commonjs/appReady.d.ts +21 -0
  110. package/lib/typescript/commonjs/appReady.d.ts.map +1 -0
  111. package/lib/typescript/commonjs/checkForUpdate.d.ts +16 -4
  112. package/lib/typescript/commonjs/checkForUpdate.d.ts.map +1 -1
  113. package/lib/typescript/commonjs/clientPlugin.d.ts +2 -0
  114. package/lib/typescript/commonjs/clientPlugin.d.ts.map +1 -0
  115. package/lib/typescript/commonjs/error.d.ts +4 -13
  116. package/lib/typescript/commonjs/error.d.ts.map +1 -1
  117. package/lib/typescript/commonjs/fetchJSON.d.ts +5 -5
  118. package/lib/typescript/commonjs/fetchJSON.d.ts.map +1 -1
  119. package/lib/typescript/commonjs/fetchUpdateResponse.d.ts +14 -0
  120. package/lib/typescript/commonjs/fetchUpdateResponse.d.ts.map +1 -0
  121. package/lib/typescript/commonjs/httpClient.d.ts +4 -33
  122. package/lib/typescript/commonjs/httpClient.d.ts.map +1 -1
  123. package/lib/typescript/commonjs/index.d.ts +4 -8
  124. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  125. package/lib/typescript/commonjs/native.d.ts +29 -22
  126. package/lib/typescript/commonjs/native.d.ts.map +1 -1
  127. package/lib/typescript/commonjs/pluginHost.d.ts +4 -0
  128. package/lib/typescript/commonjs/pluginHost.d.ts.map +1 -0
  129. package/lib/typescript/commonjs/releaseCatalogCache.d.ts +8 -14
  130. package/lib/typescript/commonjs/releaseCatalogCache.d.ts.map +1 -1
  131. package/lib/typescript/commonjs/sdkVersion.d.ts +1 -1
  132. package/lib/typescript/commonjs/sdkVersion.d.ts.map +1 -1
  133. package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts +35 -47
  134. package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts.map +1 -1
  135. package/lib/typescript/commonjs/store.d.ts +1 -3
  136. package/lib/typescript/commonjs/store.d.ts.map +1 -1
  137. package/lib/typescript/commonjs/types.d.ts +1 -1
  138. package/lib/typescript/commonjs/types.d.ts.map +1 -1
  139. package/lib/typescript/commonjs/updateError.d.ts +26 -0
  140. package/lib/typescript/commonjs/updateError.d.ts.map +1 -0
  141. package/lib/typescript/commonjs/wrap.d.ts.map +1 -1
  142. package/lib/typescript/commonjs/wrap.types.d.ts +6 -7
  143. package/lib/typescript/commonjs/wrap.types.d.ts.map +1 -1
  144. package/lib/typescript/module/appReady.d.ts +21 -0
  145. package/lib/typescript/module/appReady.d.ts.map +1 -0
  146. package/lib/typescript/module/checkForUpdate.d.ts +16 -4
  147. package/lib/typescript/module/checkForUpdate.d.ts.map +1 -1
  148. package/lib/typescript/module/clientPlugin.d.ts +2 -0
  149. package/lib/typescript/module/clientPlugin.d.ts.map +1 -0
  150. package/lib/typescript/module/error.d.ts +4 -13
  151. package/lib/typescript/module/error.d.ts.map +1 -1
  152. package/lib/typescript/module/fetchJSON.d.ts +5 -5
  153. package/lib/typescript/module/fetchJSON.d.ts.map +1 -1
  154. package/lib/typescript/module/fetchUpdateResponse.d.ts +14 -0
  155. package/lib/typescript/module/fetchUpdateResponse.d.ts.map +1 -0
  156. package/lib/typescript/module/httpClient.d.ts +4 -33
  157. package/lib/typescript/module/httpClient.d.ts.map +1 -1
  158. package/lib/typescript/module/index.d.ts +4 -8
  159. package/lib/typescript/module/index.d.ts.map +1 -1
  160. package/lib/typescript/module/native.d.ts +29 -22
  161. package/lib/typescript/module/native.d.ts.map +1 -1
  162. package/lib/typescript/module/pluginHost.d.ts +4 -0
  163. package/lib/typescript/module/pluginHost.d.ts.map +1 -0
  164. package/lib/typescript/module/releaseCatalogCache.d.ts +8 -14
  165. package/lib/typescript/module/releaseCatalogCache.d.ts.map +1 -1
  166. package/lib/typescript/module/sdkVersion.d.ts +1 -1
  167. package/lib/typescript/module/sdkVersion.d.ts.map +1 -1
  168. package/lib/typescript/module/specs/NativeHotUpdater.d.ts +35 -47
  169. package/lib/typescript/module/specs/NativeHotUpdater.d.ts.map +1 -1
  170. package/lib/typescript/module/store.d.ts +1 -3
  171. package/lib/typescript/module/store.d.ts.map +1 -1
  172. package/lib/typescript/module/types.d.ts +1 -1
  173. package/lib/typescript/module/types.d.ts.map +1 -1
  174. package/lib/typescript/module/updateError.d.ts +26 -0
  175. package/lib/typescript/module/updateError.d.ts.map +1 -0
  176. package/lib/typescript/module/wrap.d.ts.map +1 -1
  177. package/lib/typescript/module/wrap.types.d.ts +6 -7
  178. package/lib/typescript/module/wrap.types.d.ts.map +1 -1
  179. package/package.json +7 -4
  180. package/src/appReady.ts +141 -0
  181. package/src/checkForUpdate.ts +145 -86
  182. package/src/clientPlugin.ts +18 -0
  183. package/src/error.ts +4 -14
  184. package/src/fetchJSON.ts +14 -30
  185. package/src/fetchUpdateResponse.ts +60 -0
  186. package/src/httpClient.ts +88 -159
  187. package/src/index.ts +90 -24
  188. package/src/native.ts +98 -102
  189. package/src/pluginHost.ts +47 -0
  190. package/src/releaseCatalogCache.ts +43 -172
  191. package/src/sdkVersion.ts +1 -1
  192. package/src/specs/NativeHotUpdater.ts +34 -48
  193. package/src/store.ts +2 -23
  194. package/src/types.ts +1 -1
  195. package/src/updateError.ts +167 -0
  196. package/src/wrap.tsx +57 -26
  197. package/src/wrap.types.ts +6 -7
  198. package/android/src/main/java/com/hotupdater/DecompressService.kt +0 -89
  199. package/android/src/main/java/com/hotupdater/DecompressionStrategy.kt +0 -26
  200. package/android/src/main/java/com/hotupdater/TarBrDecompressionStrategy.kt +0 -117
  201. package/android/src/main/java/com/hotupdater/TarGzDecompressionStrategy.kt +0 -117
  202. package/android/src/main/java/com/hotupdater/ZipDecompressionStrategy.kt +0 -192
  203. package/android/src/test/java/com/hotupdater/BsdiffPatchTest.kt +0 -46
  204. package/android/src/test/java/com/hotupdater/BundleFileStorageServiceTest.kt +0 -799
  205. package/android/src/test/java/com/hotupdater/HotUpdaterImplTest.kt +0 -273
  206. package/android/src/test/java/com/hotupdater/NativeConfigUtilsTest.kt +0 -20
  207. package/android/src/test/java/com/hotupdater/OkHttpDownloadServiceTest.kt +0 -111
  208. package/android/src/test/java/com/hotupdater/RelativePathResolverTest.kt +0 -41
  209. package/android/src/test/java/com/hotupdater/ReleaseCatalogCacheServiceTest.kt +0 -118
  210. package/android/src/test/java/com/hotupdater/TarArchiveInputStreamTest.kt +0 -68
  211. package/ios/HotUpdater/Internal/ArchiveExtractionUtilities.swift +0 -178
  212. package/ios/HotUpdater/Internal/DecompressService.swift +0 -112
  213. package/ios/HotUpdater/Internal/DecompressionStrategy.swift +0 -22
  214. package/ios/HotUpdater/Internal/StreamingTarArchiveExtractor.swift +0 -370
  215. package/ios/HotUpdater/Internal/TarBrDecompressionStrategy.swift +0 -39
  216. package/ios/HotUpdater/Internal/TarGzDecompressionStrategy.swift +0 -59
  217. package/ios/HotUpdater/Internal/ZipArchiveExtractor.swift +0 -482
  218. package/ios/HotUpdater/Internal/ZipDecompressionStrategy.swift +0 -56
  219. package/lib/commonjs/catalogCacheNative.spec.js +0 -31
  220. package/lib/commonjs/catalogCacheNative.spec.js.map +0 -1
  221. package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js +0 -616
  222. package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js.map +0 -1
  223. package/lib/commonjs/httpClient.spec.js +0 -102
  224. package/lib/commonjs/httpClient.spec.js.map +0 -1
  225. package/lib/commonjs/index.spec.js +0 -302
  226. package/lib/commonjs/index.spec.js.map +0 -1
  227. package/lib/commonjs/iosInterop.spec.js +0 -18
  228. package/lib/commonjs/iosInterop.spec.js.map +0 -1
  229. package/lib/commonjs/native.spec.js +0 -883
  230. package/lib/commonjs/native.spec.js.map +0 -1
  231. package/lib/commonjs/notifyAppReadyInsights.boundary.spec.js +0 -218
  232. package/lib/commonjs/notifyAppReadyInsights.boundary.spec.js.map +0 -1
  233. package/lib/commonjs/notifyAppReadyInsights.js +0 -133
  234. package/lib/commonjs/notifyAppReadyInsights.js.map +0 -1
  235. package/lib/commonjs/notifyAppReadyInsights.spec.js +0 -246
  236. package/lib/commonjs/notifyAppReadyInsights.spec.js.map +0 -1
  237. package/lib/commonjs/notifyAppReadyInsights.test-utils.js +0 -24
  238. package/lib/commonjs/notifyAppReadyInsights.test-utils.js.map +0 -1
  239. package/lib/commonjs/notifyAppReadyInsights.transport.spec.js +0 -117
  240. package/lib/commonjs/notifyAppReadyInsights.transport.spec.js.map +0 -1
  241. package/lib/commonjs/releaseCatalogCache.spec.js +0 -195
  242. package/lib/commonjs/releaseCatalogCache.spec.js.map +0 -1
  243. package/lib/commonjs/releaseCatalogCacheNativeContract.spec.js +0 -64
  244. package/lib/commonjs/releaseCatalogCacheNativeContract.spec.js.map +0 -1
  245. package/lib/commonjs/store.notification.spec.js +0 -76
  246. package/lib/commonjs/store.notification.spec.js.map +0 -1
  247. package/lib/commonjs/store.spec.js +0 -316
  248. package/lib/commonjs/store.spec.js.map +0 -1
  249. package/lib/commonjs/wrap.spec.js +0 -329
  250. package/lib/commonjs/wrap.spec.js.map +0 -1
  251. package/lib/module/catalogCacheNative.spec.js +0 -31
  252. package/lib/module/catalogCacheNative.spec.js.map +0 -1
  253. package/lib/module/checkForUpdate.releaseCatalog.spec.js +0 -615
  254. package/lib/module/checkForUpdate.releaseCatalog.spec.js.map +0 -1
  255. package/lib/module/httpClient.spec.js +0 -102
  256. package/lib/module/httpClient.spec.js.map +0 -1
  257. package/lib/module/index.spec.js +0 -301
  258. package/lib/module/index.spec.js.map +0 -1
  259. package/lib/module/iosInterop.spec.js +0 -18
  260. package/lib/module/iosInterop.spec.js.map +0 -1
  261. package/lib/module/native.spec.js +0 -882
  262. package/lib/module/native.spec.js.map +0 -1
  263. package/lib/module/notifyAppReadyInsights.boundary.spec.js +0 -217
  264. package/lib/module/notifyAppReadyInsights.boundary.spec.js.map +0 -1
  265. package/lib/module/notifyAppReadyInsights.js +0 -128
  266. package/lib/module/notifyAppReadyInsights.js.map +0 -1
  267. package/lib/module/notifyAppReadyInsights.spec.js +0 -245
  268. package/lib/module/notifyAppReadyInsights.spec.js.map +0 -1
  269. package/lib/module/notifyAppReadyInsights.test-utils.js +0 -18
  270. package/lib/module/notifyAppReadyInsights.test-utils.js.map +0 -1
  271. package/lib/module/notifyAppReadyInsights.transport.spec.js +0 -116
  272. package/lib/module/notifyAppReadyInsights.transport.spec.js.map +0 -1
  273. package/lib/module/releaseCatalogCache.spec.js +0 -195
  274. package/lib/module/releaseCatalogCache.spec.js.map +0 -1
  275. package/lib/module/releaseCatalogCacheNativeContract.spec.js +0 -64
  276. package/lib/module/releaseCatalogCacheNativeContract.spec.js.map +0 -1
  277. package/lib/module/store.notification.spec.js +0 -77
  278. package/lib/module/store.notification.spec.js.map +0 -1
  279. package/lib/module/store.spec.js +0 -315
  280. package/lib/module/store.spec.js.map +0 -1
  281. package/lib/module/wrap.spec.js +0 -330
  282. package/lib/module/wrap.spec.js.map +0 -1
  283. package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts +0 -13
  284. package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts.map +0 -1
  285. package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts +0 -8
  286. package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts.map +0 -1
  287. package/lib/typescript/module/notifyAppReadyInsights.d.ts +0 -13
  288. package/lib/typescript/module/notifyAppReadyInsights.d.ts.map +0 -1
  289. package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts +0 -8
  290. package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts.map +0 -1
  291. package/src/catalogCacheNative.spec.ts +0 -63
  292. package/src/checkForUpdate.releaseCatalog.spec.ts +0 -612
  293. package/src/httpClient.spec.ts +0 -132
  294. package/src/index.spec.ts +0 -337
  295. package/src/iosInterop.spec.ts +0 -30
  296. package/src/native.spec.ts +0 -945
  297. package/src/notifyAppReadyInsights.boundary.spec.ts +0 -234
  298. package/src/notifyAppReadyInsights.spec.ts +0 -243
  299. package/src/notifyAppReadyInsights.test-utils.ts +0 -31
  300. package/src/notifyAppReadyInsights.transport.spec.ts +0 -130
  301. package/src/notifyAppReadyInsights.ts +0 -194
  302. package/src/releaseCatalogCache.spec.ts +0 -282
  303. package/src/releaseCatalogCacheNativeContract.spec.ts +0 -80
  304. package/src/store.notification.spec.ts +0 -92
  305. package/src/store.spec.ts +0 -372
  306. package/src/wrap.spec.ts +0 -406
@@ -2,48 +2,21 @@ import type { TurboModule } from "react-native";
2
2
  import { TurboModuleRegistry } from "react-native";
3
3
  import type { UnsafeObject } from "react-native/Libraries/Types/CodegenTypes";
4
4
 
5
- export interface ChangedAsset {
6
- file?: {
7
- compression?: "br" | null;
8
- url: string;
9
- } | null;
10
- fileHash: string;
11
- patch?: {
12
- algorithm: "bsdiff";
13
- baseBundleId: string;
14
- baseFileHash: string;
15
- patchFileHash: string;
16
- patchUrl: string;
17
- } | null;
18
- }
19
-
20
5
  export interface UpdateBundleParams {
21
6
  bundleId: string;
22
7
  channel?: string;
23
- fileUrl: string | null;
24
8
  /**
25
- * File hash for integrity/signature verification.
26
- *
27
- * Format depends on signing configuration:
28
- * - Signed: `sig:<base64_signature>` - Native will verify signature (and implicitly hash)
29
- * - Unsigned: `<hex_hash>` - Native will verify SHA256 hash only
30
- *
31
- * Native determines verification mode by checking for "sig:" prefix.
9
+ * Signed manifest URL for installation.
32
10
  */
33
- fileHash: string | null;
34
- /**
35
- * Optional signed manifest URL for manifest-driven installation.
36
- */
37
- manifestUrl?: string | null;
11
+ manifestUrl: string;
38
12
  /**
39
13
  * File hash/signature for the manifest file itself.
40
14
  */
41
- manifestFileHash?: string | null;
42
- /**
43
- * Per-file URLs for assets that must be downloaded instead of reused from
44
- * the currently active bundle.
45
- */
46
- changedAssets?: UnsafeObject | null;
15
+ manifestFileHash: string;
16
+ /** Optional tar.br URL; integrity and sizes come from the verified manifest. */
17
+ archiveUrl?: string | null;
18
+ /** Full protocol v1 target file descriptor map. */
19
+ assets: UnsafeObject;
47
20
  /** Full Release Catalog selection receipt committed with the staged Bundle. */
48
21
  selection?: UnsafeObject | null;
49
22
  }
@@ -61,18 +34,21 @@ export interface Spec extends TurboModule {
61
34
  * Downloads and applies a bundle update.
62
35
  *
63
36
  * @param params - Update bundle parameters
64
- * @returns Promise that resolves to true if successful
37
+ * @returns Promise that resolves, once the bundle is staged, to how it
38
+ * arrived: `{ delivery, patchFallback }`. `delivery` is "patch" when a
39
+ * bsdiff patch produced a file, "manifest" when only changed files were
40
+ * downloaded, or "archive" for the full archive; `patchFallback` is true
41
+ * when a patch was tried but the file or archive was downloaded instead.
65
42
  * @throws {HotUpdaterErrorCode} Rejects with one of the following error codes:
66
43
  *
67
44
  * Parameter validation:
68
45
  * - MISSING_BUNDLE_ID: Missing or empty bundleId
69
- * - INVALID_FILE_URL: Invalid fileUrl provided
46
+ * - INVALID_FILE_URL: Invalid manifest or asset URL provided
70
47
  *
71
48
  * Bundle storage:
72
49
  * - DIRECTORY_CREATION_FAILED: Failed to create bundle directory
73
50
  * - DOWNLOAD_FAILED: Failed to download bundle
74
51
  * - INCOMPLETE_DOWNLOAD: Download incomplete (size mismatch)
75
- * - EXTRACTION_FORMAT_ERROR: Invalid or corrupted archive format
76
52
  * - INVALID_BUNDLE: Bundle missing required platform files
77
53
  * - INSUFFICIENT_DISK_SPACE: Insufficient disk space
78
54
  * - MOVE_OPERATION_FAILED: Failed to move bundle files
@@ -87,8 +63,20 @@ export interface Spec extends TurboModule {
87
63
  *
88
64
  * Note: iOS normalizes rare signature/storage errors to SIGNATURE_VERIFICATION_FAILED
89
65
  * or UNKNOWN_ERROR to keep the JS error surface small.
66
+ *
67
+ * A rejection from the download or install also carries `userInfo`
68
+ * `{ stage, reason, resource?, httpStatus?, transport?, originCode? }`:
69
+ * `stage` is "download" (transfer and verification) or "install" (patch,
70
+ * extract, move into place); `reason` is one of "network", "http",
71
+ * "invalid_response", "hash_mismatch", "signature", "patch", "extract",
72
+ * "storage", or "unknown"; `resource` is what was being fetched or
73
+ * applied: "manifest", "file", "patch", or "archive". `httpStatus` is
74
+ * present when `reason` is "http", with `originCode`, the storage
75
+ * origin's XML error `<Code>` when the body names one. `transport` is
76
+ * present when no response arrived: "timeout", "dns", "tls",
77
+ * "connection", "offline", or "cancelled".
90
78
  */
91
- updateBundle(params: UpdateBundleParams): Promise<boolean>;
79
+ updateBundle(params: UpdateBundleParams): Promise<UnsafeObject>;
92
80
 
93
81
  /** Accepts and durably advances the catalog high-water for a scope. */
94
82
  acceptReleaseCatalog(params: UnsafeObject): boolean;
@@ -192,24 +180,22 @@ export interface Spec extends TurboModule {
192
180
  getCohort: () => string;
193
181
 
194
182
  /**
195
- * Gets the persisted install id for this app installation.
183
+ * Gets the install id: a random id native creates once per app
184
+ * installation and keeps out of device backups.
196
185
  */
197
186
  getInstallId: () => string;
198
187
 
199
188
  /**
200
- * Gets the persisted nullable user id associated with this installation.
201
- */
202
- getUserId: () => string | null;
203
-
204
- /**
205
- * Gets the persisted nullable username associated with this installation.
189
+ * Reads a value from the SDK's persistent key-value store, which native
190
+ * keeps out of device backups. Returns null when the key has no value.
206
191
  */
207
- getUsername: () => string | null;
192
+ getStorageItem: (key: string) => string | null;
208
193
 
209
194
  /**
210
- * Persists nullable user identity fields associated with this installation.
195
+ * Writes a value to the SDK's persistent key-value store; null removes the
196
+ * key.
211
197
  */
212
- setUser: (userId: string | null, username: string | null) => void;
198
+ setStorageItem: (key: string, value: string | null) => void;
213
199
 
214
200
  // EventEmitter
215
201
  addListener(eventName: string): void;
package/src/store.ts CHANGED
@@ -9,10 +9,8 @@ import { addListener } from "./native";
9
9
 
10
10
  export type HotUpdaterState = {
11
11
  progress: number;
12
- downloadedBytes: number | undefined;
13
- totalBytes: number | undefined;
14
12
  isUpdateDownloaded: boolean;
15
- artifactType: "archive" | "diff" | null;
13
+ artifactType: "diff" | null;
16
14
  details: HotUpdaterDiffProgressDetails | null;
17
15
  };
18
16
 
@@ -56,8 +54,6 @@ const areDiffDetailsEqual = (
56
54
  const areStatesEqual = (left: HotUpdaterState, right: HotUpdaterState) => {
57
55
  return (
58
56
  left.progress === right.progress &&
59
- left.downloadedBytes === right.downloadedBytes &&
60
- left.totalBytes === right.totalBytes &&
61
57
  left.isUpdateDownloaded === right.isUpdateDownloaded &&
62
58
  left.artifactType === right.artifactType &&
63
59
  areDiffDetailsEqual(left.details, right.details)
@@ -78,8 +74,6 @@ const normalizeDownloadPath = (value: string | undefined) => {
78
74
  const createHotUpdaterStore = () => {
79
75
  let state: HotUpdaterState = {
80
76
  progress: 0,
81
- downloadedBytes: undefined,
82
- totalBytes: undefined,
83
77
  isUpdateDownloaded: false,
84
78
  artifactType: null,
85
79
  details: null,
@@ -165,10 +159,6 @@ const createHotUpdaterStore = () => {
165
159
  nextState.details = state.details;
166
160
  }
167
161
 
168
- if (nextState.artifactType !== "diff") {
169
- nextState.details = null;
170
- }
171
-
172
162
  if (areStatesEqual(state, nextState)) {
173
163
  return;
174
164
  }
@@ -180,19 +170,8 @@ const createHotUpdaterStore = () => {
180
170
  const applyProgressEvent = (event: HotUpdaterProgressEvent) => {
181
171
  setState({
182
172
  artifactType: event.artifactType,
183
- details:
184
- event.artifactType === "diff"
185
- ? normalizeDiffDetails(event.details)
186
- : null,
187
- downloadedBytes:
188
- event.artifactType === "archive"
189
- ? normalizeByteCount(event.downloadedBytes)
190
- : undefined,
173
+ details: normalizeDiffDetails(event.details),
191
174
  progress: event.progress,
192
- totalBytes:
193
- event.artifactType === "archive"
194
- ? normalizeByteCount(event.totalBytes)
195
- : undefined,
196
175
  });
197
176
  };
198
177
 
package/src/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type HotUpdaterBaseURL = string | (() => string | Promise<string>);
1
+ export type { HotUpdaterBaseURL } from "@hot-updater/protocol";
2
2
 
3
3
  /**
4
4
  * Information about a signature verification failure.
@@ -0,0 +1,167 @@
1
+ import type {
2
+ UpdateError,
3
+ UpdateErrorReason,
4
+ UpdateErrorResource,
5
+ UpdateErrorStage,
6
+ UpdateErrorTransport,
7
+ } from "./clientPlugin";
8
+ import { HotUpdaterError } from "./error";
9
+
10
+ /**
11
+ * A response the SDK cannot use: a malformed or stale catalog, an artifact
12
+ * in another protocol, or an invalid URL.
13
+ */
14
+ export class InvalidUpdateResponseError extends HotUpdaterError {
15
+ constructor(message: string, options?: { cause?: unknown }) {
16
+ super(message);
17
+ this.name = "InvalidUpdateResponseError";
18
+ if (options?.cause !== undefined) this.cause = options.cause;
19
+ }
20
+ }
21
+
22
+ /** A request the server answered with a status the SDK does not accept. */
23
+ export class UpdateHttpError extends HotUpdaterError {
24
+ constructor(
25
+ readonly status: number,
26
+ statusText: string,
27
+ ) {
28
+ super(
29
+ `Request failed with HTTP ${status}${statusText ? ` ${statusText}` : ""}`,
30
+ );
31
+ this.name = "UpdateHttpError";
32
+ }
33
+ }
34
+
35
+ const STAGES: readonly UpdateErrorStage[] = ["check", "download", "install"];
36
+ const REASONS: readonly UpdateErrorReason[] = [
37
+ "network",
38
+ "http",
39
+ "invalid_response",
40
+ "hash_mismatch",
41
+ "signature",
42
+ "patch",
43
+ "extract",
44
+ "storage",
45
+ "unknown",
46
+ ];
47
+ const RESOURCES: readonly UpdateErrorResource[] = [
48
+ "catalog",
49
+ "artifact",
50
+ "manifest",
51
+ "file",
52
+ "patch",
53
+ "archive",
54
+ ];
55
+ const TRANSPORTS: readonly UpdateErrorTransport[] = [
56
+ "timeout",
57
+ "dns",
58
+ "tls",
59
+ "connection",
60
+ "offline",
61
+ "cancelled",
62
+ ];
63
+ /** An S3, R2, or GCS error code: letters, digits, and punctuation only. */
64
+ const ORIGIN_CODE = /^[A-Za-z0-9._-]{1,64}$/;
65
+ /** Expo's iOS and Android names for a fetch canceled before its response. */
66
+ const EXPO_FETCH_CANCELED =
67
+ /FetchRequestCanceledException|Fetch request has been canceled|The operation was aborted/;
68
+
69
+ type Classification = Pick<
70
+ UpdateError,
71
+ "stage" | "reason" | "resource" | "httpStatus" | "originCode" | "transport"
72
+ >;
73
+
74
+ const oneOf = <T extends string>(
75
+ values: readonly T[],
76
+ value: unknown,
77
+ ): value is T => values.includes(value as T);
78
+
79
+ const readNativeClassification = (
80
+ error: object,
81
+ ): Classification | null | undefined => {
82
+ if (!("code" in error) || typeof error.code !== "string") return undefined;
83
+ const userInfo =
84
+ "userInfo" in error && typeof error.userInfo === "object"
85
+ ? (error.userInfo as Record<string, unknown> | null)
86
+ : null;
87
+ const { stage, reason, resource, transport, originCode } = userInfo ?? {};
88
+ // Native classifies every failure of its download and install; a rejection
89
+ // without it, such as a stale selection, is not an update failure.
90
+ if (!oneOf(STAGES, stage) || !oneOf(REASONS, reason)) return null;
91
+ const httpStatus = Number(userInfo?.httpStatus);
92
+ return {
93
+ stage,
94
+ reason,
95
+ ...(oneOf(RESOURCES, resource) ? { resource } : {}),
96
+ ...(reason === "http" && Number.isSafeInteger(httpStatus)
97
+ ? { httpStatus }
98
+ : {}),
99
+ ...(reason === "http" &&
100
+ typeof originCode === "string" &&
101
+ ORIGIN_CODE.test(originCode)
102
+ ? { originCode }
103
+ : {}),
104
+ ...(reason === "network" && oneOf(TRANSPORTS, transport)
105
+ ? { transport }
106
+ : {}),
107
+ };
108
+ };
109
+
110
+ /**
111
+ * Where and why an update failed, or null when the error is not an update
112
+ * failure. Native rejections carry their own classification; an error the
113
+ * SDK's JavaScript raised happened in `stage`, fetching `resource` when one
114
+ * is given.
115
+ */
116
+ export const classifyUpdateError = (
117
+ error: unknown,
118
+ stage: UpdateErrorStage,
119
+ resource?: UpdateErrorResource,
120
+ ): Classification | null => {
121
+ if (typeof error === "object" && error !== null) {
122
+ const native = readNativeClassification(error);
123
+ if (native !== undefined) return native;
124
+ }
125
+ const scope = {
126
+ stage,
127
+ ...(resource === undefined ? {} : { resource }),
128
+ };
129
+ // Names, not classes, so an error from another copy of a module still
130
+ // classifies, as it does across test module resets.
131
+ const name = error instanceof Error ? error.name : null;
132
+ // A selection that became stale is a race between checks, not a failure.
133
+ if (name === "StaleReleaseCatalogError") return null;
134
+ if (name === "UpdateHttpError") {
135
+ return {
136
+ ...scope,
137
+ reason: "http",
138
+ httpStatus: (error as UpdateHttpError).status,
139
+ };
140
+ }
141
+ if (name === "InvalidUpdateResponseError" || name === "SyntaxError") {
142
+ return { ...scope, reason: "invalid_response" };
143
+ }
144
+ if (error instanceof Error && error.message === "Request timed out") {
145
+ return { ...scope, reason: "network", transport: "timeout" };
146
+ }
147
+ if (name === "AbortError") {
148
+ return { ...scope, reason: "network", transport: "cancelled" };
149
+ }
150
+ // Expo's fetch rejects with "fetch failed: <native exception>" when no
151
+ // response arrives, and names a canceled request.
152
+ if (error instanceof Error && error.message.startsWith("fetch failed:")) {
153
+ return {
154
+ ...scope,
155
+ reason: "network",
156
+ ...(EXPO_FETCH_CANCELED.test(error.message)
157
+ ? { transport: "cancelled" }
158
+ : {}),
159
+ };
160
+ }
161
+ if (name === "TypeError") {
162
+ // fetch rejects with a TypeError when no response arrives, without
163
+ // saying why.
164
+ return { ...scope, reason: "network" };
165
+ }
166
+ return { ...scope, reason: "unknown" };
167
+ };
package/src/wrap.tsx CHANGED
@@ -1,11 +1,12 @@
1
1
  import React, { useEffect, useState } from "react";
2
2
 
3
+ import { handleNotifyAppReady } from "./appReady";
3
4
  import { checkForUpdate } from "./checkForUpdate";
4
5
  import { useEventCallback } from "./hooks/useEventCallback";
5
6
  import { getUpdateId, reload } from "./native";
6
- import { handleNotifyAppReady } from "./notifyAppReadyInsights";
7
7
  import { useHotUpdaterStore } from "./store";
8
8
  import type {
9
+ HotUpdaterFallbackComponentProps,
9
10
  InternalInitOptions,
10
11
  InternalWrapOptions,
11
12
  UpdateStatus,
@@ -32,11 +33,46 @@ export function wrap(
32
33
  ) => React.ComponentType<P> {
33
34
  const { reloadOnForceUpdate = true, ...restOptions } = options;
34
35
 
36
+ // Progress is subscribed only where it is rendered or reported, so progress
37
+ // events don't re-render the wrapped app.
38
+ const ProgressReporter = ({
39
+ onProgress,
40
+ }: {
41
+ onProgress: (progress: number) => void;
42
+ }) => {
43
+ const progress = useHotUpdaterStore((state) => state.progress);
44
+
45
+ useEffect(() => {
46
+ onProgress(progress);
47
+ }, [progress]);
48
+
49
+ return null;
50
+ };
51
+
52
+ const FallbackWithProgress = ({
53
+ Fallback,
54
+ status,
55
+ message,
56
+ }: {
57
+ Fallback: React.FC<HotUpdaterFallbackComponentProps>;
58
+ status: HotUpdaterFallbackComponentProps["status"];
59
+ message: string | null;
60
+ }) => {
61
+ const progressState = useHotUpdaterStore((state) => state);
62
+
63
+ return (
64
+ <Fallback
65
+ artifactType={progressState.artifactType}
66
+ details={progressState.details}
67
+ progress={progressState.progress}
68
+ status={status}
69
+ message={message}
70
+ />
71
+ );
72
+ };
73
+
35
74
  return <P extends object>(WrappedComponent: React.ComponentType<P>) => {
36
75
  const HotUpdaterHOC: React.FC<P> = (props: P) => {
37
- const progressState = useHotUpdaterStore((state) => state);
38
- const progress = progressState.progress;
39
-
40
76
  const [message, setMessage] = useState<string | null>(null);
41
77
  const [updateStatus, setUpdateStatus] =
42
78
  useState<UpdateStatus>("CHECK_FOR_UPDATE");
@@ -45,8 +81,8 @@ export function wrap(
45
81
  try {
46
82
  setUpdateStatus("CHECK_FOR_UPDATE");
47
83
 
84
+ const readiness = handleNotifyAppReady(restOptions);
48
85
  const updateInfo = await checkForUpdate({
49
- insights: restOptions.insights,
50
86
  client: restOptions.client,
51
87
  updateStrategy: restOptions.updateStrategy,
52
88
  requestHeaders: restOptions.requestHeaders,
@@ -54,6 +90,7 @@ export function wrap(
54
90
  onError: restOptions.onError,
55
91
  });
56
92
 
93
+ await readiness;
57
94
  setMessage(updateInfo?.message ?? null);
58
95
 
59
96
  if (!updateInfo) {
@@ -111,39 +148,33 @@ export function wrap(
111
148
  }
112
149
  });
113
150
 
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
151
  // Start update check
124
152
  useEffect(() => {
125
153
  initHotUpdater();
126
154
  }, []);
127
155
 
128
- if (
156
+ const content =
129
157
  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}
158
+ updateStatus !== "UPDATE_PROCESS_COMPLETED" ? (
159
+ <FallbackWithProgress
160
+ Fallback={restOptions.fallbackComponent}
139
161
  status={updateStatus}
140
162
  message={message}
141
- totalBytes={progressState.totalBytes}
142
163
  />
164
+ ) : (
165
+ <WrappedComponent {...props} />
143
166
  );
167
+
168
+ if (!restOptions.onProgress) {
169
+ return content;
144
170
  }
145
171
 
146
- return <WrappedComponent {...props} />;
172
+ return (
173
+ <>
174
+ {content}
175
+ <ProgressReporter onProgress={restOptions.onProgress} />
176
+ </>
177
+ );
147
178
  };
148
179
 
149
180
  return HotUpdaterHOC as React.ComponentType<P>;
package/src/wrap.types.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type React from "react";
2
2
 
3
+ import type { HotUpdaterClientPlugin } from "./clientPlugin";
3
4
  import type { HotUpdaterError } from "./error";
4
5
  import type { HotUpdaterHttpClient } from "./httpClient";
5
6
  import type { NotifyAppReadyResult } from "./native";
@@ -21,8 +22,6 @@ export type UpdateStatus =
21
22
  export type HotUpdaterFallbackComponentProps = {
22
23
  status: Exclude<UpdateStatus, "UPDATE_PROCESS_COMPLETED">;
23
24
  progress: number;
24
- downloadedBytes: HotUpdaterState["downloadedBytes"];
25
- totalBytes: HotUpdaterState["totalBytes"];
26
25
  message: string | null;
27
26
  artifactType: HotUpdaterState["artifactType"];
28
27
  details: HotUpdaterState["details"];
@@ -30,11 +29,12 @@ export type HotUpdaterFallbackComponentProps = {
30
29
 
31
30
  interface CommonHotUpdaterOptions {
32
31
  /**
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.
32
+ * Client plugins, such as `insights()` from `@hot-updater/react-native`.
33
+ * Each plugin's `setup` runs
34
+ * once, and its hooks observe launches, update checks, downloads, and
35
+ * update failures. Plugin ids must be unique.
36
36
  */
37
- insights?: boolean;
37
+ plugins?: readonly HotUpdaterClientPlugin[];
38
38
  /** Base URL of a server exposing the Hot Updater v1 client HTTP protocol. */
39
39
  baseURL: HotUpdaterBaseURL;
40
40
  requestHeaders?: Record<string, string>;
@@ -56,7 +56,6 @@ export type HotUpdaterInitOptions = CommonHotUpdaterOptions;
56
56
  export type HotUpdaterOptions = AutoUpdateOptions;
57
57
 
58
58
  type InternalCommonOptions = {
59
- insights?: boolean;
60
59
  client: HotUpdaterHttpClient;
61
60
  requestHeaders?: Record<string, string>;
62
61
  requestTimeout?: number;
@@ -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
- }