@hot-updater/react-native 1.0.0-rc.1 → 1.0.0-rc.15
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.
- package/android/proguard-rules.pro +17 -2
- package/android/src/main/java/com/hotupdater/BuiltInAssetResolver.kt +286 -0
- package/android/src/main/java/com/hotupdater/BundleFileStorageService.kt +651 -637
- package/android/src/main/java/com/hotupdater/BundleMetadata.kt +10 -0
- package/android/src/main/java/com/hotupdater/HotUpdaterException.kt +0 -13
- package/android/src/main/java/com/hotupdater/HotUpdaterImpl.kt +10 -14
- package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryManager.kt +37 -54
- package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryState.kt +64 -0
- package/android/src/main/java/com/hotupdater/OkHttpDownloadService.kt +19 -0
- package/android/src/main/java/com/hotupdater/TarArchiveInputStream.kt +214 -375
- package/android/src/main/java/com/hotupdater/TarBrArchiveExtractor.kt +119 -0
- package/android/src/newarch/HotUpdater.kt +7 -9
- package/android/src/newarch/HotUpdaterModule.kt +40 -20
- package/android/src/oldarch/HotUpdater.kt +7 -9
- package/android/src/oldarch/HotUpdaterModule.kt +40 -20
- package/android/src/test/java/com/hotupdater/BundleFileStorageServiceTest.kt +1126 -74
- package/android/src/test/java/com/hotupdater/HotUpdaterImplTest.kt +4 -5
- package/android/src/test/java/com/hotupdater/HotUpdaterRecoveryStateTest.kt +97 -0
- package/android/src/test/java/com/hotupdater/PendingCrashRecoveryTest.kt +44 -0
- package/android/src/test/java/com/hotupdater/TarBrArchiveExtractorTest.kt +206 -0
- package/ios/HotUpdater/Internal/BrotliFileDecompressor.swift +167 -0
- package/ios/HotUpdater/Internal/BuiltInAssetResolver.swift +196 -0
- package/ios/HotUpdater/Internal/BundleFileStorageService.swift +773 -1016
- package/ios/HotUpdater/Internal/BundleMetadata.swift +5 -0
- package/ios/HotUpdater/Internal/FileUtilities.swift +64 -0
- package/ios/HotUpdater/Internal/HotUpdater-Bridging-Header.h +0 -1
- package/ios/HotUpdater/Internal/HotUpdater.mm +5 -27
- package/ios/HotUpdater/Internal/HotUpdaterImpl.swift +149 -51
- package/ios/HotUpdater/Internal/NotificationExtension.swift +0 -2
- package/ios/HotUpdater/Internal/TarArchiveExtractor.swift +182 -311
- package/ios/HotUpdater/Internal/URLSessionDownloadService.swift +13 -72
- package/ios/HotUpdater/Recovery/HotUpdaterRecovery.h +16 -0
- package/ios/HotUpdater/Recovery/HotUpdaterRecovery.mm +83 -0
- package/ios/HotUpdater/Recovery/HotUpdaterRecoveryHooks.mm +49 -0
- package/lib/commonjs/checkForUpdate.js +32 -23
- package/lib/commonjs/checkForUpdate.js.map +1 -1
- package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js +97 -28
- package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js.map +1 -1
- package/lib/commonjs/error.js +4 -13
- package/lib/commonjs/error.js.map +1 -1
- package/lib/commonjs/fetchJSON.js +9 -2
- package/lib/commonjs/fetchJSON.js.map +1 -1
- package/lib/commonjs/httpClient.js +46 -29
- package/lib/commonjs/httpClient.js.map +1 -1
- package/lib/commonjs/httpClient.spec.js +57 -5
- package/lib/commonjs/httpClient.spec.js.map +1 -1
- package/lib/commonjs/index.js +31 -14
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.spec.js +56 -11
- package/lib/commonjs/index.spec.js.map +1 -1
- package/lib/commonjs/native.js +15 -14
- package/lib/commonjs/native.js.map +1 -1
- package/lib/commonjs/native.spec.js +128 -22
- package/lib/commonjs/native.spec.js.map +1 -1
- package/lib/commonjs/{notifyAppReadyAnalytics.boundary.spec.js → notifyAppReadyInsights.boundary.spec.js} +28 -21
- package/lib/commonjs/notifyAppReadyInsights.boundary.spec.js.map +1 -0
- package/lib/commonjs/notifyAppReadyInsights.js +188 -0
- package/lib/commonjs/notifyAppReadyInsights.js.map +1 -0
- package/lib/commonjs/{notifyAppReadyAnalytics.spec.js → notifyAppReadyInsights.spec.js} +161 -29
- package/lib/commonjs/notifyAppReadyInsights.spec.js.map +1 -0
- package/lib/commonjs/{notifyAppReadyAnalytics.test-utils.js → notifyAppReadyInsights.test-utils.js} +3 -3
- package/lib/commonjs/notifyAppReadyInsights.test-utils.js.map +1 -0
- package/lib/commonjs/{notifyAppReadyAnalytics.transport.spec.js → notifyAppReadyInsights.transport.spec.js} +14 -7
- package/lib/commonjs/notifyAppReadyInsights.transport.spec.js.map +1 -0
- package/lib/commonjs/sdkVersion.js +1 -1
- package/lib/commonjs/sdkVersion.js.map +1 -1
- package/lib/commonjs/specs/NativeHotUpdater.js.map +1 -1
- package/lib/commonjs/store.js +3 -10
- package/lib/commonjs/store.js.map +1 -1
- package/lib/commonjs/store.notification.spec.js +12 -4
- package/lib/commonjs/store.notification.spec.js.map +1 -1
- package/lib/commonjs/store.spec.js +2 -136
- package/lib/commonjs/store.spec.js.map +1 -1
- package/lib/commonjs/wrap.js +11 -12
- package/lib/commonjs/wrap.js.map +1 -1
- package/lib/commonjs/wrap.spec.js +97 -25
- package/lib/commonjs/wrap.spec.js.map +1 -1
- package/lib/module/checkForUpdate.js +32 -23
- package/lib/module/checkForUpdate.js.map +1 -1
- package/lib/module/checkForUpdate.releaseCatalog.spec.js +97 -28
- package/lib/module/checkForUpdate.releaseCatalog.spec.js.map +1 -1
- package/lib/module/error.js +4 -13
- package/lib/module/error.js.map +1 -1
- package/lib/module/fetchJSON.js +7 -1
- package/lib/module/fetchJSON.js.map +1 -1
- package/lib/module/httpClient.js +48 -31
- package/lib/module/httpClient.js.map +1 -1
- package/lib/module/httpClient.spec.js +57 -5
- package/lib/module/httpClient.spec.js.map +1 -1
- package/lib/module/index.js +32 -15
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.spec.js +56 -11
- package/lib/module/index.spec.js.map +1 -1
- package/lib/module/native.js +13 -12
- package/lib/module/native.js.map +1 -1
- package/lib/module/native.spec.js +128 -22
- package/lib/module/native.spec.js.map +1 -1
- package/lib/module/{notifyAppReadyAnalytics.boundary.spec.js → notifyAppReadyInsights.boundary.spec.js} +23 -16
- package/lib/module/notifyAppReadyInsights.boundary.spec.js.map +1 -0
- package/lib/module/notifyAppReadyInsights.js +181 -0
- package/lib/module/notifyAppReadyInsights.js.map +1 -0
- package/lib/module/{notifyAppReadyAnalytics.spec.js → notifyAppReadyInsights.spec.js} +153 -21
- package/lib/module/notifyAppReadyInsights.spec.js.map +1 -0
- package/lib/module/{notifyAppReadyAnalytics.test-utils.js → notifyAppReadyInsights.test-utils.js} +3 -3
- package/lib/module/notifyAppReadyInsights.test-utils.js.map +1 -0
- package/lib/module/{notifyAppReadyAnalytics.transport.spec.js → notifyAppReadyInsights.transport.spec.js} +11 -4
- package/lib/module/notifyAppReadyInsights.transport.spec.js.map +1 -0
- package/lib/module/sdkVersion.js +1 -1
- package/lib/module/sdkVersion.js.map +1 -1
- package/lib/module/specs/NativeHotUpdater.js.map +1 -1
- package/lib/module/store.js +3 -10
- package/lib/module/store.js.map +1 -1
- package/lib/module/store.notification.spec.js +12 -4
- package/lib/module/store.notification.spec.js.map +1 -1
- package/lib/module/store.spec.js +2 -136
- package/lib/module/store.spec.js.map +1 -1
- package/lib/module/wrap.js +11 -12
- package/lib/module/wrap.js.map +1 -1
- package/lib/module/wrap.spec.js +99 -25
- package/lib/module/wrap.spec.js.map +1 -1
- package/lib/typescript/commonjs/checkForUpdate.d.ts +2 -3
- package/lib/typescript/commonjs/checkForUpdate.d.ts.map +1 -1
- package/lib/typescript/commonjs/error.d.ts +4 -13
- package/lib/typescript/commonjs/error.d.ts.map +1 -1
- package/lib/typescript/commonjs/fetchJSON.d.ts +4 -0
- package/lib/typescript/commonjs/fetchJSON.d.ts.map +1 -1
- package/lib/typescript/commonjs/httpClient.d.ts +6 -6
- package/lib/typescript/commonjs/httpClient.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +4 -7
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/native.d.ts +5 -9
- package/lib/typescript/commonjs/native.d.ts.map +1 -1
- package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts +25 -0
- package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts.map +1 -0
- package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts +8 -0
- package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts.map +1 -0
- package/lib/typescript/commonjs/sdkVersion.d.ts +1 -1
- package/lib/typescript/commonjs/sdkVersion.d.ts.map +1 -1
- package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts +8 -35
- package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts.map +1 -1
- package/lib/typescript/commonjs/store.d.ts +1 -3
- package/lib/typescript/commonjs/store.d.ts.map +1 -1
- package/lib/typescript/commonjs/wrap.types.d.ts +5 -8
- package/lib/typescript/commonjs/wrap.types.d.ts.map +1 -1
- package/lib/typescript/module/checkForUpdate.d.ts +2 -3
- package/lib/typescript/module/checkForUpdate.d.ts.map +1 -1
- package/lib/typescript/module/error.d.ts +4 -13
- package/lib/typescript/module/error.d.ts.map +1 -1
- package/lib/typescript/module/fetchJSON.d.ts +4 -0
- package/lib/typescript/module/fetchJSON.d.ts.map +1 -1
- package/lib/typescript/module/httpClient.d.ts +6 -6
- package/lib/typescript/module/httpClient.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +4 -7
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/native.d.ts +5 -9
- package/lib/typescript/module/native.d.ts.map +1 -1
- package/lib/typescript/module/notifyAppReadyInsights.d.ts +25 -0
- package/lib/typescript/module/notifyAppReadyInsights.d.ts.map +1 -0
- package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts +8 -0
- package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts.map +1 -0
- package/lib/typescript/module/sdkVersion.d.ts +1 -1
- package/lib/typescript/module/sdkVersion.d.ts.map +1 -1
- package/lib/typescript/module/specs/NativeHotUpdater.d.ts +8 -35
- package/lib/typescript/module/specs/NativeHotUpdater.d.ts.map +1 -1
- package/lib/typescript/module/store.d.ts +1 -3
- package/lib/typescript/module/store.d.ts.map +1 -1
- package/lib/typescript/module/wrap.types.d.ts +5 -8
- package/lib/typescript/module/wrap.types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/checkForUpdate.releaseCatalog.spec.ts +137 -61
- package/src/checkForUpdate.ts +35 -29
- package/src/error.ts +4 -14
- package/src/fetchJSON.ts +12 -1
- package/src/httpClient.spec.ts +70 -5
- package/src/httpClient.ts +78 -64
- package/src/index.spec.ts +59 -11
- package/src/index.ts +41 -17
- package/src/native.spec.ts +133 -22
- package/src/native.ts +21 -32
- package/src/{notifyAppReadyAnalytics.boundary.spec.ts → notifyAppReadyInsights.boundary.spec.ts} +25 -17
- package/src/{notifyAppReadyAnalytics.spec.ts → notifyAppReadyInsights.spec.ts} +141 -22
- package/src/{notifyAppReadyAnalytics.test-utils.ts → notifyAppReadyInsights.test-utils.ts} +4 -4
- package/src/{notifyAppReadyAnalytics.transport.spec.ts → notifyAppReadyInsights.transport.spec.ts} +13 -5
- package/src/notifyAppReadyInsights.ts +293 -0
- package/src/sdkVersion.ts +1 -1
- package/src/specs/NativeHotUpdater.ts +8 -36
- package/src/store.notification.spec.ts +13 -3
- package/src/store.spec.ts +0 -157
- package/src/store.ts +2 -23
- package/src/wrap.spec.ts +109 -31
- package/src/wrap.tsx +11 -11
- package/src/wrap.types.ts +5 -8
- package/android/src/main/java/com/hotupdater/DecompressService.kt +0 -89
- package/android/src/main/java/com/hotupdater/DecompressionStrategy.kt +0 -26
- package/android/src/main/java/com/hotupdater/TarBrDecompressionStrategy.kt +0 -117
- package/android/src/main/java/com/hotupdater/TarGzDecompressionStrategy.kt +0 -117
- package/android/src/main/java/com/hotupdater/ZipDecompressionStrategy.kt +0 -192
- package/android/src/test/java/com/hotupdater/TarArchiveInputStreamTest.kt +0 -68
- package/ios/HotUpdater/Internal/ArchiveExtractionUtilities.swift +0 -178
- package/ios/HotUpdater/Internal/DecompressService.swift +0 -112
- package/ios/HotUpdater/Internal/DecompressionStrategy.swift +0 -22
- package/ios/HotUpdater/Internal/StreamingTarArchiveExtractor.swift +0 -370
- package/ios/HotUpdater/Internal/TarBrDecompressionStrategy.swift +0 -39
- package/ios/HotUpdater/Internal/TarGzDecompressionStrategy.swift +0 -59
- package/ios/HotUpdater/Internal/ZipArchiveExtractor.swift +0 -482
- package/ios/HotUpdater/Internal/ZipDecompressionStrategy.swift +0 -56
- package/lib/commonjs/notifyAppReadyAnalytics.boundary.spec.js.map +0 -1
- package/lib/commonjs/notifyAppReadyAnalytics.js +0 -133
- package/lib/commonjs/notifyAppReadyAnalytics.js.map +0 -1
- package/lib/commonjs/notifyAppReadyAnalytics.spec.js.map +0 -1
- package/lib/commonjs/notifyAppReadyAnalytics.test-utils.js.map +0 -1
- package/lib/commonjs/notifyAppReadyAnalytics.transport.spec.js.map +0 -1
- package/lib/module/notifyAppReadyAnalytics.boundary.spec.js.map +0 -1
- package/lib/module/notifyAppReadyAnalytics.js +0 -128
- package/lib/module/notifyAppReadyAnalytics.js.map +0 -1
- package/lib/module/notifyAppReadyAnalytics.spec.js.map +0 -1
- package/lib/module/notifyAppReadyAnalytics.test-utils.js.map +0 -1
- package/lib/module/notifyAppReadyAnalytics.transport.spec.js.map +0 -1
- package/lib/typescript/commonjs/notifyAppReadyAnalytics.d.ts +0 -13
- package/lib/typescript/commonjs/notifyAppReadyAnalytics.d.ts.map +0 -1
- package/lib/typescript/commonjs/notifyAppReadyAnalytics.test-utils.d.ts +0 -8
- package/lib/typescript/commonjs/notifyAppReadyAnalytics.test-utils.d.ts.map +0 -1
- package/lib/typescript/module/notifyAppReadyAnalytics.d.ts +0 -13
- package/lib/typescript/module/notifyAppReadyAnalytics.d.ts.map +0 -1
- package/lib/typescript/module/notifyAppReadyAnalytics.test-utils.d.ts +0 -8
- package/lib/typescript/module/notifyAppReadyAnalytics.test-utils.d.ts.map +0 -1
- package/src/notifyAppReadyAnalytics.ts +0 -194
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
package com.hotupdater
|
|
2
|
+
|
|
3
|
+
import com.hotupdater.vendor.brotli.dec.BrotliInputStream
|
|
4
|
+
import java.io.File
|
|
5
|
+
import java.io.FileInputStream
|
|
6
|
+
import java.io.IOException
|
|
7
|
+
import java.io.InputStream
|
|
8
|
+
|
|
9
|
+
internal object TarBrArchiveExtractor {
|
|
10
|
+
fun extract(
|
|
11
|
+
archiveFile: File,
|
|
12
|
+
destination: File,
|
|
13
|
+
expectedTarByteSize: Long,
|
|
14
|
+
expectedFiles: Map<String, Long>,
|
|
15
|
+
) {
|
|
16
|
+
require(expectedTarByteSize >= 0) { "Invalid TAR byte size" }
|
|
17
|
+
if (destination.exists() && !destination.deleteRecursively()) {
|
|
18
|
+
throw IOException("Cannot clear archive extraction directory")
|
|
19
|
+
}
|
|
20
|
+
if (!destination.mkdirs()) throw IOException("Cannot create archive extraction directory")
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
FileInputStream(archiveFile).use { compressedInput ->
|
|
24
|
+
BrotliInputStream(compressedInput).use { brotliInput ->
|
|
25
|
+
val boundedInput = ExactSizeInputStream(brotliInput, expectedTarByteSize)
|
|
26
|
+
TarArchiveInputStream(boundedInput).use { tarInput ->
|
|
27
|
+
val extractedPaths = linkedSetOf<String>()
|
|
28
|
+
var entry = tarInput.getNextEntry()
|
|
29
|
+
while (entry != null) {
|
|
30
|
+
if (!entry.isRegularFile) {
|
|
31
|
+
throw IOException("Unsupported TAR entry type for ${entry.name}")
|
|
32
|
+
}
|
|
33
|
+
val normalizedPath = RelativePathResolver.normalizeRelativePath(entry.name)
|
|
34
|
+
if (normalizedPath == null || normalizedPath != entry.name) {
|
|
35
|
+
throw IOException("Unsafe TAR entry path: ${entry.name}")
|
|
36
|
+
}
|
|
37
|
+
val expectedSize =
|
|
38
|
+
expectedFiles[normalizedPath]
|
|
39
|
+
?: throw IOException("Unexpected TAR entry: $normalizedPath")
|
|
40
|
+
if (!extractedPaths.add(normalizedPath)) {
|
|
41
|
+
throw IOException("Duplicate TAR entry: $normalizedPath")
|
|
42
|
+
}
|
|
43
|
+
if (entry.size != expectedSize) {
|
|
44
|
+
throw IOException("TAR entry size mismatch: $normalizedPath")
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
val outputFile =
|
|
48
|
+
RelativePathResolver.resolveInside(destination, normalizedPath)
|
|
49
|
+
?: throw IOException("Unsafe TAR entry path: $normalizedPath")
|
|
50
|
+
if (outputFile.exists()) throw IOException("TAR output already exists: $normalizedPath")
|
|
51
|
+
val parentDirectory = outputFile.parentFile
|
|
52
|
+
if (parentDirectory != null && !parentDirectory.isDirectory && !parentDirectory.mkdirs()) {
|
|
53
|
+
throw IOException("Cannot create TAR output directory: $normalizedPath")
|
|
54
|
+
}
|
|
55
|
+
outputFile.outputStream().use { output ->
|
|
56
|
+
val buffer = ByteArray(8192)
|
|
57
|
+
var written = 0L
|
|
58
|
+
while (true) {
|
|
59
|
+
val count = tarInput.read(buffer)
|
|
60
|
+
if (count < 0) break
|
|
61
|
+
output.write(buffer, 0, count)
|
|
62
|
+
written += count
|
|
63
|
+
}
|
|
64
|
+
if (written != expectedSize) {
|
|
65
|
+
throw IOException("TAR entry was truncated: $normalizedPath")
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
entry = tarInput.getNextEntry()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (extractedPaths != expectedFiles.keys) {
|
|
72
|
+
throw IOException("TAR file set does not match manifest")
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
boundedInput.requireExactSize()
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
} catch (error: Throwable) {
|
|
79
|
+
destination.deleteRecursively()
|
|
80
|
+
throw error
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private class ExactSizeInputStream(
|
|
85
|
+
private val input: InputStream,
|
|
86
|
+
private val expectedSize: Long,
|
|
87
|
+
) : InputStream() {
|
|
88
|
+
private var byteCount = 0L
|
|
89
|
+
|
|
90
|
+
override fun read(): Int {
|
|
91
|
+
val result = input.read()
|
|
92
|
+
if (result >= 0) recordRead(1)
|
|
93
|
+
return result
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
override fun read(
|
|
97
|
+
buffer: ByteArray,
|
|
98
|
+
offset: Int,
|
|
99
|
+
length: Int,
|
|
100
|
+
): Int {
|
|
101
|
+
val count = input.read(buffer, offset, length)
|
|
102
|
+
if (count > 0) recordRead(count.toLong())
|
|
103
|
+
return count
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
fun requireExactSize() {
|
|
107
|
+
if (byteCount != expectedSize) {
|
|
108
|
+
throw IOException("TAR stream size mismatch: expected $expectedSize, got $byteCount")
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private fun recordRead(count: Long) {
|
|
113
|
+
if (byteCount > expectedSize - count) {
|
|
114
|
+
throw IOException("TAR stream exceeds declared size")
|
|
115
|
+
}
|
|
116
|
+
byteCount += count
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -36,7 +36,7 @@ class HotUpdater {
|
|
|
36
36
|
* Updates the bundle using the default singleton instance
|
|
37
37
|
* @param context Application context
|
|
38
38
|
* @param bundleId ID of the bundle to update
|
|
39
|
-
* @param
|
|
39
|
+
* @param params Manifest and asset descriptors for the target bundle
|
|
40
40
|
* @param fileHash Combined hash string for verification (sig:<signature> or <hex_hash>)
|
|
41
41
|
* @param progressCallback Callback for download progress updates
|
|
42
42
|
* @throws HotUpdaterException if the update fails
|
|
@@ -44,22 +44,20 @@ class HotUpdater {
|
|
|
44
44
|
suspend fun updateBundle(
|
|
45
45
|
context: Context,
|
|
46
46
|
bundleId: String,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
manifestFileHash: String?,
|
|
51
|
-
changedAssets: Map<String, ChangedAssetDescriptor>?,
|
|
47
|
+
manifestUrl: String,
|
|
48
|
+
manifestFileHash: String,
|
|
49
|
+
assets: Map<String, ChangedAssetDescriptor>,
|
|
52
50
|
channel: String?,
|
|
51
|
+
archiveUrl: String? = null,
|
|
53
52
|
progressCallback: (UpdateProgressPayload) -> Unit,
|
|
54
53
|
) {
|
|
55
54
|
getInstance(context).updateBundle(
|
|
56
55
|
bundleId,
|
|
57
|
-
fileUrl,
|
|
58
|
-
fileHash,
|
|
59
56
|
manifestUrl,
|
|
60
57
|
manifestFileHash,
|
|
61
|
-
|
|
58
|
+
assets,
|
|
62
59
|
channel,
|
|
60
|
+
archiveUrl = archiveUrl,
|
|
63
61
|
progressCallback = progressCallback,
|
|
64
62
|
)
|
|
65
63
|
}
|
|
@@ -26,6 +26,16 @@ class HotUpdaterModule internal constructor(
|
|
|
26
26
|
|
|
27
27
|
override fun getName(): String = NAME
|
|
28
28
|
|
|
29
|
+
private fun readSafeInteger(
|
|
30
|
+
map: ReadableMap,
|
|
31
|
+
key: String,
|
|
32
|
+
): Long? {
|
|
33
|
+
if (!map.hasKey(key) || map.isNull(key)) return null
|
|
34
|
+
val value = runCatching { map.getDouble(key) }.getOrNull() ?: return null
|
|
35
|
+
if (!value.isFinite() || value % 1.0 != 0.0) return null
|
|
36
|
+
return value.toLong().takeIf { it in 0..9_007_199_254_740_991L }
|
|
37
|
+
}
|
|
38
|
+
|
|
29
39
|
override fun invalidate() {
|
|
30
40
|
super.invalidate()
|
|
31
41
|
// Cancel all ongoing coroutines when module is destroyed
|
|
@@ -37,12 +47,12 @@ class HotUpdaterModule internal constructor(
|
|
|
37
47
|
*/
|
|
38
48
|
private fun getInstance(): HotUpdaterImpl = HotUpdater.getInstance(mReactApplicationContext)
|
|
39
49
|
|
|
40
|
-
private fun
|
|
41
|
-
if (!params.hasKey("
|
|
50
|
+
private fun parseAssets(params: ReadableMap): Map<String, ChangedAssetDescriptor>? {
|
|
51
|
+
if (!params.hasKey("assets") || params.isNull("assets")) {
|
|
42
52
|
return null
|
|
43
53
|
}
|
|
44
54
|
|
|
45
|
-
val changedAssetsMap = params.getMap("
|
|
55
|
+
val changedAssetsMap = params.getMap("assets") ?: return null
|
|
46
56
|
val parsedAssets = linkedMapOf<String, ChangedAssetDescriptor>()
|
|
47
57
|
val iterator = changedAssetsMap.keySetIterator()
|
|
48
58
|
|
|
@@ -58,6 +68,7 @@ class HotUpdaterModule internal constructor(
|
|
|
58
68
|
val baseFileHash = patchMap.getString("baseFileHash")
|
|
59
69
|
val patchFileHash = patchMap.getString("patchFileHash")
|
|
60
70
|
val patchUrl = patchMap.getString("patchUrl")
|
|
71
|
+
val byteSize = readSafeInteger(patchMap, "byteSize")
|
|
61
72
|
|
|
62
73
|
if (
|
|
63
74
|
algorithm != null &&
|
|
@@ -72,6 +83,7 @@ class HotUpdaterModule internal constructor(
|
|
|
72
83
|
baseFileHash = baseFileHash,
|
|
73
84
|
patchFileHash = patchFileHash,
|
|
74
85
|
patchUrl = patchUrl,
|
|
86
|
+
byteSize = byteSize,
|
|
75
87
|
)
|
|
76
88
|
} else {
|
|
77
89
|
null
|
|
@@ -166,36 +178,46 @@ class HotUpdaterModule internal constructor(
|
|
|
166
178
|
return@launch
|
|
167
179
|
}
|
|
168
180
|
|
|
169
|
-
val
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if (
|
|
181
|
+
val manifestUrl = params.getString("manifestUrl")
|
|
182
|
+
val manifestFileHash = params.getString("manifestFileHash")
|
|
183
|
+
val assets = parseAssets(params)
|
|
184
|
+
if (manifestUrl.isNullOrEmpty() || manifestFileHash.isNullOrEmpty() || assets == null) {
|
|
185
|
+
promise.reject("INVALID_MANIFEST", "Manifest URL, hash, and assets are required")
|
|
186
|
+
return@launch
|
|
187
|
+
}
|
|
188
|
+
try {
|
|
189
|
+
java.net.URL(manifestUrl)
|
|
190
|
+
} catch (e: java.net.MalformedURLException) {
|
|
191
|
+
promise.reject("INVALID_FILE_URL", "Invalid 'manifestUrl' provided: $manifestUrl")
|
|
192
|
+
return@launch
|
|
193
|
+
}
|
|
194
|
+
val channel = params.getString("channel")
|
|
195
|
+
val archiveUrl =
|
|
196
|
+
if (params.hasKey("archiveUrl") && !params.isNull("archiveUrl")) {
|
|
197
|
+
params.getString("archiveUrl")
|
|
198
|
+
} else {
|
|
199
|
+
null
|
|
200
|
+
}
|
|
201
|
+
if (archiveUrl != null) {
|
|
173
202
|
try {
|
|
174
|
-
java.net.URL(
|
|
203
|
+
java.net.URL(archiveUrl)
|
|
175
204
|
} catch (e: java.net.MalformedURLException) {
|
|
176
|
-
promise.reject("INVALID_FILE_URL", "Invalid '
|
|
205
|
+
promise.reject("INVALID_FILE_URL", "Invalid 'archiveUrl' provided: $archiveUrl")
|
|
177
206
|
return@launch
|
|
178
207
|
}
|
|
179
208
|
}
|
|
180
|
-
|
|
181
|
-
val fileHash = params.getString("fileHash")
|
|
182
|
-
val manifestUrl = params.getString("manifestUrl")
|
|
183
|
-
val manifestFileHash = params.getString("manifestFileHash")
|
|
184
|
-
val changedAssets = parseChangedAssets(params)
|
|
185
|
-
val channel = params.getString("channel")
|
|
186
209
|
val selection = parseSelection(params)
|
|
187
210
|
|
|
188
211
|
val impl = getInstance()
|
|
189
212
|
|
|
190
213
|
impl.updateBundle(
|
|
191
214
|
bundleId,
|
|
192
|
-
fileUrl,
|
|
193
|
-
fileHash,
|
|
194
215
|
manifestUrl,
|
|
195
216
|
manifestFileHash,
|
|
196
|
-
|
|
217
|
+
assets,
|
|
197
218
|
channel,
|
|
198
219
|
selection,
|
|
220
|
+
archiveUrl,
|
|
199
221
|
) { progress ->
|
|
200
222
|
// Post to Main thread for React Native event emission
|
|
201
223
|
Handler(Looper.getMainLooper()).post {
|
|
@@ -204,8 +226,6 @@ class HotUpdaterModule internal constructor(
|
|
|
204
226
|
WritableNativeMap().apply {
|
|
205
227
|
putDouble("progress", progress.progress)
|
|
206
228
|
putString("artifactType", progress.artifactType)
|
|
207
|
-
progress.downloadedBytes?.let { putDouble("downloadedBytes", it.toDouble()) }
|
|
208
|
-
progress.totalBytes?.let { putDouble("totalBytes", it.toDouble()) }
|
|
209
229
|
progress.details?.let { details ->
|
|
210
230
|
putMap(
|
|
211
231
|
"details",
|
|
@@ -35,7 +35,7 @@ class HotUpdater {
|
|
|
35
35
|
* Updates the bundle using the default singleton instance
|
|
36
36
|
* @param context Application context
|
|
37
37
|
* @param bundleId ID of the bundle to update
|
|
38
|
-
* @param
|
|
38
|
+
* @param params Manifest and asset descriptors for the target bundle
|
|
39
39
|
* @param fileHash Combined hash string for verification (sig:<signature> or <hex_hash>)
|
|
40
40
|
* @param progressCallback Callback for download progress updates
|
|
41
41
|
* @throws HotUpdaterException if the update fails
|
|
@@ -43,22 +43,20 @@ class HotUpdater {
|
|
|
43
43
|
suspend fun updateBundle(
|
|
44
44
|
context: Context,
|
|
45
45
|
bundleId: String,
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
manifestFileHash: String?,
|
|
50
|
-
changedAssets: Map<String, ChangedAssetDescriptor>?,
|
|
46
|
+
manifestUrl: String,
|
|
47
|
+
manifestFileHash: String,
|
|
48
|
+
assets: Map<String, ChangedAssetDescriptor>,
|
|
51
49
|
channel: String?,
|
|
50
|
+
archiveUrl: String? = null,
|
|
52
51
|
progressCallback: (UpdateProgressPayload) -> Unit,
|
|
53
52
|
) {
|
|
54
53
|
getInstance(context).updateBundle(
|
|
55
54
|
bundleId,
|
|
56
|
-
fileUrl,
|
|
57
|
-
fileHash,
|
|
58
55
|
manifestUrl,
|
|
59
56
|
manifestFileHash,
|
|
60
|
-
|
|
57
|
+
assets,
|
|
61
58
|
channel,
|
|
59
|
+
archiveUrl = archiveUrl,
|
|
62
60
|
progressCallback = progressCallback,
|
|
63
61
|
)
|
|
64
62
|
}
|
|
@@ -26,6 +26,16 @@ class HotUpdaterModule internal constructor(
|
|
|
26
26
|
|
|
27
27
|
override fun getName(): String = NAME
|
|
28
28
|
|
|
29
|
+
private fun readSafeInteger(
|
|
30
|
+
map: ReadableMap,
|
|
31
|
+
key: String,
|
|
32
|
+
): Long? {
|
|
33
|
+
if (!map.hasKey(key) || map.isNull(key)) return null
|
|
34
|
+
val value = runCatching { map.getDouble(key) }.getOrNull() ?: return null
|
|
35
|
+
if (!value.isFinite() || value % 1.0 != 0.0) return null
|
|
36
|
+
return value.toLong().takeIf { it in 0..9_007_199_254_740_991L }
|
|
37
|
+
}
|
|
38
|
+
|
|
29
39
|
override fun onCatalystInstanceDestroy() {
|
|
30
40
|
super.onCatalystInstanceDestroy()
|
|
31
41
|
// Cancel all ongoing coroutines when module is destroyed
|
|
@@ -37,12 +47,12 @@ class HotUpdaterModule internal constructor(
|
|
|
37
47
|
*/
|
|
38
48
|
private fun getInstance(): HotUpdaterImpl = HotUpdater.getInstance(mReactApplicationContext)
|
|
39
49
|
|
|
40
|
-
private fun
|
|
41
|
-
if (!params.hasKey("
|
|
50
|
+
private fun parseAssets(params: ReadableMap): Map<String, ChangedAssetDescriptor>? {
|
|
51
|
+
if (!params.hasKey("assets") || params.isNull("assets")) {
|
|
42
52
|
return null
|
|
43
53
|
}
|
|
44
54
|
|
|
45
|
-
val changedAssetsMap = params.getMap("
|
|
55
|
+
val changedAssetsMap = params.getMap("assets") ?: return null
|
|
46
56
|
val parsedAssets = linkedMapOf<String, ChangedAssetDescriptor>()
|
|
47
57
|
val iterator = changedAssetsMap.keySetIterator()
|
|
48
58
|
|
|
@@ -58,6 +68,7 @@ class HotUpdaterModule internal constructor(
|
|
|
58
68
|
val baseFileHash = patchMap.getString("baseFileHash")
|
|
59
69
|
val patchFileHash = patchMap.getString("patchFileHash")
|
|
60
70
|
val patchUrl = patchMap.getString("patchUrl")
|
|
71
|
+
val byteSize = readSafeInteger(patchMap, "byteSize")
|
|
61
72
|
|
|
62
73
|
if (
|
|
63
74
|
algorithm != null &&
|
|
@@ -72,6 +83,7 @@ class HotUpdaterModule internal constructor(
|
|
|
72
83
|
baseFileHash = baseFileHash,
|
|
73
84
|
patchFileHash = patchFileHash,
|
|
74
85
|
patchUrl = patchUrl,
|
|
86
|
+
byteSize = byteSize,
|
|
75
87
|
)
|
|
76
88
|
} else {
|
|
77
89
|
null
|
|
@@ -170,36 +182,46 @@ class HotUpdaterModule internal constructor(
|
|
|
170
182
|
return@launch
|
|
171
183
|
}
|
|
172
184
|
|
|
173
|
-
val
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if (
|
|
185
|
+
val manifestUrl = params.getString("manifestUrl")
|
|
186
|
+
val manifestFileHash = params.getString("manifestFileHash")
|
|
187
|
+
val assets = parseAssets(params)
|
|
188
|
+
if (manifestUrl.isNullOrEmpty() || manifestFileHash.isNullOrEmpty() || assets == null) {
|
|
189
|
+
promise.reject("INVALID_MANIFEST", "Manifest URL, hash, and assets are required")
|
|
190
|
+
return@launch
|
|
191
|
+
}
|
|
192
|
+
try {
|
|
193
|
+
java.net.URL(manifestUrl)
|
|
194
|
+
} catch (e: java.net.MalformedURLException) {
|
|
195
|
+
promise.reject("INVALID_FILE_URL", "Invalid 'manifestUrl' provided: $manifestUrl")
|
|
196
|
+
return@launch
|
|
197
|
+
}
|
|
198
|
+
val channel = params.getString("channel")
|
|
199
|
+
val archiveUrl =
|
|
200
|
+
if (params.hasKey("archiveUrl") && !params.isNull("archiveUrl")) {
|
|
201
|
+
params.getString("archiveUrl")
|
|
202
|
+
} else {
|
|
203
|
+
null
|
|
204
|
+
}
|
|
205
|
+
if (archiveUrl != null) {
|
|
177
206
|
try {
|
|
178
|
-
java.net.URL(
|
|
207
|
+
java.net.URL(archiveUrl)
|
|
179
208
|
} catch (e: java.net.MalformedURLException) {
|
|
180
|
-
promise.reject("INVALID_FILE_URL", "Invalid '
|
|
209
|
+
promise.reject("INVALID_FILE_URL", "Invalid 'archiveUrl' provided: $archiveUrl")
|
|
181
210
|
return@launch
|
|
182
211
|
}
|
|
183
212
|
}
|
|
184
|
-
|
|
185
|
-
val fileHash = params.getString("fileHash")
|
|
186
|
-
val manifestUrl = params.getString("manifestUrl")
|
|
187
|
-
val manifestFileHash = params.getString("manifestFileHash")
|
|
188
|
-
val changedAssets = parseChangedAssets(params)
|
|
189
|
-
val channel = params.getString("channel")
|
|
190
213
|
val selection = parseSelection(params)
|
|
191
214
|
|
|
192
215
|
val impl = getInstance()
|
|
193
216
|
|
|
194
217
|
impl.updateBundle(
|
|
195
218
|
bundleId,
|
|
196
|
-
fileUrl,
|
|
197
|
-
fileHash,
|
|
198
219
|
manifestUrl,
|
|
199
220
|
manifestFileHash,
|
|
200
|
-
|
|
221
|
+
assets,
|
|
201
222
|
channel,
|
|
202
223
|
selection,
|
|
224
|
+
archiveUrl,
|
|
203
225
|
) { progress ->
|
|
204
226
|
// Post to Main thread for React Native event emission
|
|
205
227
|
Handler(Looper.getMainLooper()).post {
|
|
@@ -208,8 +230,6 @@ class HotUpdaterModule internal constructor(
|
|
|
208
230
|
Arguments.createMap().apply {
|
|
209
231
|
putDouble("progress", progress.progress)
|
|
210
232
|
putString("artifactType", progress.artifactType)
|
|
211
|
-
progress.downloadedBytes?.let { putDouble("downloadedBytes", it.toDouble()) }
|
|
212
|
-
progress.totalBytes?.let { putDouble("totalBytes", it.toDouble()) }
|
|
213
233
|
progress.details?.let { details ->
|
|
214
234
|
val files = Arguments.createArray()
|
|
215
235
|
details.files.forEach { file ->
|