@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.
- package/android/build.gradle +13 -2
- package/android/proguard-rules.pro +8 -2
- package/android/src/bridge/BridgeReactInstance.kt +38 -0
- package/android/src/bridgeless/BridgeReactInstance.kt +24 -0
- package/android/src/main/java/com/hotupdater/ActivityStartGate.kt +94 -0
- package/android/src/main/java/com/hotupdater/BuiltInAssetResolver.kt +286 -0
- package/android/src/main/java/com/hotupdater/BundleFileStorageService.kt +1064 -844
- package/android/src/main/java/com/hotupdater/BundleMetadata.kt +50 -11
- package/android/src/main/java/com/hotupdater/FileManagerService.kt +45 -0
- package/android/src/main/java/com/hotupdater/HotUpdaterException.kt +287 -22
- package/android/src/main/java/com/hotupdater/HotUpdaterImpl.kt +46 -30
- package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryManager.kt +75 -192
- package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryState.kt +64 -0
- package/android/src/main/java/com/hotupdater/InstallIdentityService.kt +37 -0
- package/android/src/main/java/com/hotupdater/KeyValueStorageService.kt +86 -0
- package/android/src/main/java/com/hotupdater/NetworkState.kt +31 -0
- package/android/src/main/java/com/hotupdater/NoBackupStorage.kt +17 -0
- package/android/src/main/java/com/hotupdater/OkHttpDownloadService.kt +127 -50
- package/android/src/main/java/com/hotupdater/ReactNativeValueConverters.kt +34 -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 +109 -84
- package/android/src/newarch/JavaScriptExceptionHooks.kt +48 -0
- package/android/src/newarch/ReactIntegrationManager.kt +6 -32
- package/android/src/oldarch/HotUpdater.kt +7 -9
- package/android/src/oldarch/HotUpdaterModule.kt +98 -74
- package/android/src/oldarch/HotUpdaterSpec.kt +4 -6
- package/android/src/oldarch/JavaScriptExceptionHooks.kt +71 -0
- package/ios/HotUpdater/Internal/BrotliFileDecompressor.swift +167 -0
- package/ios/HotUpdater/Internal/BuiltInAssetResolver.swift +196 -0
- package/ios/HotUpdater/Internal/BundleFileStorageService.swift +1032 -1116
- package/ios/HotUpdater/Internal/BundleMetadata.swift +61 -54
- package/ios/HotUpdater/Internal/FileManagerService.swift +48 -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 +32 -67
- package/ios/HotUpdater/Internal/HotUpdaterImpl.swift +229 -73
- package/ios/HotUpdater/Internal/KeyValueStorageService.swift +71 -0
- package/ios/HotUpdater/Internal/NotificationExtension.swift +0 -2
- package/ios/HotUpdater/Internal/TarArchiveExtractor.swift +182 -311
- package/ios/HotUpdater/Internal/URLSessionDownloadService.swift +119 -71
- package/ios/HotUpdater/Internal/UpdateFailure.swift +390 -0
- 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/appReady.js +102 -0
- package/lib/commonjs/appReady.js.map +1 -0
- package/lib/commonjs/checkForUpdate.js +120 -68
- package/lib/commonjs/checkForUpdate.js.map +1 -1
- package/lib/commonjs/clientPlugin.js +13 -0
- package/lib/commonjs/clientPlugin.js.map +1 -0
- package/lib/commonjs/error.js +4 -13
- package/lib/commonjs/error.js.map +1 -1
- package/lib/commonjs/fetchJSON.js +16 -27
- package/lib/commonjs/fetchJSON.js.map +1 -1
- package/lib/commonjs/fetchUpdateResponse.js +60 -0
- package/lib/commonjs/fetchUpdateResponse.js.map +1 -0
- package/lib/commonjs/httpClient.js +63 -94
- package/lib/commonjs/httpClient.js.map +1 -1
- package/lib/commonjs/index.js +71 -18
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/native.js +74 -60
- package/lib/commonjs/native.js.map +1 -1
- package/lib/commonjs/pluginHost.js +45 -0
- package/lib/commonjs/pluginHost.js.map +1 -0
- package/lib/commonjs/releaseCatalogCache.js +36 -87
- package/lib/commonjs/releaseCatalogCache.js.map +1 -1
- 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/updateError.js +145 -0
- package/lib/commonjs/updateError.js.map +1 -0
- package/lib/commonjs/wrap.js +43 -26
- package/lib/commonjs/wrap.js.map +1 -1
- package/lib/module/appReady.js +95 -0
- package/lib/module/appReady.js.map +1 -0
- package/lib/module/checkForUpdate.js +113 -63
- package/lib/module/checkForUpdate.js.map +1 -1
- package/lib/module/clientPlugin.js +4 -0
- package/lib/module/clientPlugin.js.map +1 -0
- package/lib/module/error.js +4 -13
- package/lib/module/error.js.map +1 -1
- package/lib/module/fetchJSON.js +14 -26
- package/lib/module/fetchJSON.js.map +1 -1
- package/lib/module/fetchUpdateResponse.js +55 -0
- package/lib/module/fetchUpdateResponse.js.map +1 -0
- package/lib/module/httpClient.js +62 -93
- package/lib/module/httpClient.js.map +1 -1
- package/lib/module/index.js +58 -20
- package/lib/module/index.js.map +1 -1
- package/lib/module/native.js +67 -53
- package/lib/module/native.js.map +1 -1
- package/lib/module/pluginHost.js +36 -0
- package/lib/module/pluginHost.js.map +1 -0
- package/lib/module/releaseCatalogCache.js +32 -82
- package/lib/module/releaseCatalogCache.js.map +1 -1
- 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/updateError.js +139 -0
- package/lib/module/updateError.js.map +1 -0
- package/lib/module/wrap.js +43 -26
- package/lib/module/wrap.js.map +1 -1
- package/lib/typescript/commonjs/appReady.d.ts +21 -0
- package/lib/typescript/commonjs/appReady.d.ts.map +1 -0
- package/lib/typescript/commonjs/checkForUpdate.d.ts +16 -4
- package/lib/typescript/commonjs/checkForUpdate.d.ts.map +1 -1
- package/lib/typescript/commonjs/clientPlugin.d.ts +2 -0
- package/lib/typescript/commonjs/clientPlugin.d.ts.map +1 -0
- 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 +5 -5
- package/lib/typescript/commonjs/fetchJSON.d.ts.map +1 -1
- package/lib/typescript/commonjs/fetchUpdateResponse.d.ts +14 -0
- package/lib/typescript/commonjs/fetchUpdateResponse.d.ts.map +1 -0
- package/lib/typescript/commonjs/httpClient.d.ts +4 -33
- package/lib/typescript/commonjs/httpClient.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +4 -8
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/native.d.ts +29 -22
- package/lib/typescript/commonjs/native.d.ts.map +1 -1
- package/lib/typescript/commonjs/pluginHost.d.ts +4 -0
- package/lib/typescript/commonjs/pluginHost.d.ts.map +1 -0
- package/lib/typescript/commonjs/releaseCatalogCache.d.ts +8 -14
- package/lib/typescript/commonjs/releaseCatalogCache.d.ts.map +1 -1
- 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 +35 -47
- 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/types.d.ts +1 -1
- package/lib/typescript/commonjs/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/updateError.d.ts +26 -0
- package/lib/typescript/commonjs/updateError.d.ts.map +1 -0
- package/lib/typescript/commonjs/wrap.d.ts.map +1 -1
- package/lib/typescript/commonjs/wrap.types.d.ts +6 -7
- package/lib/typescript/commonjs/wrap.types.d.ts.map +1 -1
- package/lib/typescript/module/appReady.d.ts +21 -0
- package/lib/typescript/module/appReady.d.ts.map +1 -0
- package/lib/typescript/module/checkForUpdate.d.ts +16 -4
- package/lib/typescript/module/checkForUpdate.d.ts.map +1 -1
- package/lib/typescript/module/clientPlugin.d.ts +2 -0
- package/lib/typescript/module/clientPlugin.d.ts.map +1 -0
- 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 +5 -5
- package/lib/typescript/module/fetchJSON.d.ts.map +1 -1
- package/lib/typescript/module/fetchUpdateResponse.d.ts +14 -0
- package/lib/typescript/module/fetchUpdateResponse.d.ts.map +1 -0
- package/lib/typescript/module/httpClient.d.ts +4 -33
- package/lib/typescript/module/httpClient.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +4 -8
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/native.d.ts +29 -22
- package/lib/typescript/module/native.d.ts.map +1 -1
- package/lib/typescript/module/pluginHost.d.ts +4 -0
- package/lib/typescript/module/pluginHost.d.ts.map +1 -0
- package/lib/typescript/module/releaseCatalogCache.d.ts +8 -14
- package/lib/typescript/module/releaseCatalogCache.d.ts.map +1 -1
- 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 +35 -47
- 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/types.d.ts +1 -1
- package/lib/typescript/module/types.d.ts.map +1 -1
- package/lib/typescript/module/updateError.d.ts +26 -0
- package/lib/typescript/module/updateError.d.ts.map +1 -0
- package/lib/typescript/module/wrap.d.ts.map +1 -1
- package/lib/typescript/module/wrap.types.d.ts +6 -7
- package/lib/typescript/module/wrap.types.d.ts.map +1 -1
- package/package.json +7 -4
- package/src/appReady.ts +141 -0
- package/src/checkForUpdate.ts +145 -86
- package/src/clientPlugin.ts +18 -0
- package/src/error.ts +4 -14
- package/src/fetchJSON.ts +14 -30
- package/src/fetchUpdateResponse.ts +60 -0
- package/src/httpClient.ts +88 -159
- package/src/index.ts +90 -24
- package/src/native.ts +98 -102
- package/src/pluginHost.ts +47 -0
- package/src/releaseCatalogCache.ts +43 -172
- package/src/sdkVersion.ts +1 -1
- package/src/specs/NativeHotUpdater.ts +34 -48
- package/src/store.ts +2 -23
- package/src/types.ts +1 -1
- package/src/updateError.ts +167 -0
- package/src/wrap.tsx +57 -26
- package/src/wrap.types.ts +6 -7
- 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/BsdiffPatchTest.kt +0 -46
- package/android/src/test/java/com/hotupdater/BundleFileStorageServiceTest.kt +0 -799
- package/android/src/test/java/com/hotupdater/HotUpdaterImplTest.kt +0 -273
- package/android/src/test/java/com/hotupdater/NativeConfigUtilsTest.kt +0 -20
- package/android/src/test/java/com/hotupdater/OkHttpDownloadServiceTest.kt +0 -111
- package/android/src/test/java/com/hotupdater/RelativePathResolverTest.kt +0 -41
- package/android/src/test/java/com/hotupdater/ReleaseCatalogCacheServiceTest.kt +0 -118
- 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/catalogCacheNative.spec.js +0 -31
- package/lib/commonjs/catalogCacheNative.spec.js.map +0 -1
- package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js +0 -616
- package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js.map +0 -1
- package/lib/commonjs/httpClient.spec.js +0 -102
- package/lib/commonjs/httpClient.spec.js.map +0 -1
- package/lib/commonjs/index.spec.js +0 -302
- package/lib/commonjs/index.spec.js.map +0 -1
- package/lib/commonjs/iosInterop.spec.js +0 -18
- package/lib/commonjs/iosInterop.spec.js.map +0 -1
- package/lib/commonjs/native.spec.js +0 -883
- package/lib/commonjs/native.spec.js.map +0 -1
- package/lib/commonjs/notifyAppReadyInsights.boundary.spec.js +0 -218
- package/lib/commonjs/notifyAppReadyInsights.boundary.spec.js.map +0 -1
- package/lib/commonjs/notifyAppReadyInsights.js +0 -133
- package/lib/commonjs/notifyAppReadyInsights.js.map +0 -1
- package/lib/commonjs/notifyAppReadyInsights.spec.js +0 -246
- package/lib/commonjs/notifyAppReadyInsights.spec.js.map +0 -1
- package/lib/commonjs/notifyAppReadyInsights.test-utils.js +0 -24
- package/lib/commonjs/notifyAppReadyInsights.test-utils.js.map +0 -1
- package/lib/commonjs/notifyAppReadyInsights.transport.spec.js +0 -117
- package/lib/commonjs/notifyAppReadyInsights.transport.spec.js.map +0 -1
- package/lib/commonjs/releaseCatalogCache.spec.js +0 -195
- package/lib/commonjs/releaseCatalogCache.spec.js.map +0 -1
- package/lib/commonjs/releaseCatalogCacheNativeContract.spec.js +0 -64
- package/lib/commonjs/releaseCatalogCacheNativeContract.spec.js.map +0 -1
- package/lib/commonjs/store.notification.spec.js +0 -76
- package/lib/commonjs/store.notification.spec.js.map +0 -1
- package/lib/commonjs/store.spec.js +0 -316
- package/lib/commonjs/store.spec.js.map +0 -1
- package/lib/commonjs/wrap.spec.js +0 -329
- package/lib/commonjs/wrap.spec.js.map +0 -1
- package/lib/module/catalogCacheNative.spec.js +0 -31
- package/lib/module/catalogCacheNative.spec.js.map +0 -1
- package/lib/module/checkForUpdate.releaseCatalog.spec.js +0 -615
- package/lib/module/checkForUpdate.releaseCatalog.spec.js.map +0 -1
- package/lib/module/httpClient.spec.js +0 -102
- package/lib/module/httpClient.spec.js.map +0 -1
- package/lib/module/index.spec.js +0 -301
- package/lib/module/index.spec.js.map +0 -1
- package/lib/module/iosInterop.spec.js +0 -18
- package/lib/module/iosInterop.spec.js.map +0 -1
- package/lib/module/native.spec.js +0 -882
- package/lib/module/native.spec.js.map +0 -1
- package/lib/module/notifyAppReadyInsights.boundary.spec.js +0 -217
- package/lib/module/notifyAppReadyInsights.boundary.spec.js.map +0 -1
- package/lib/module/notifyAppReadyInsights.js +0 -128
- package/lib/module/notifyAppReadyInsights.js.map +0 -1
- package/lib/module/notifyAppReadyInsights.spec.js +0 -245
- package/lib/module/notifyAppReadyInsights.spec.js.map +0 -1
- package/lib/module/notifyAppReadyInsights.test-utils.js +0 -18
- package/lib/module/notifyAppReadyInsights.test-utils.js.map +0 -1
- package/lib/module/notifyAppReadyInsights.transport.spec.js +0 -116
- package/lib/module/notifyAppReadyInsights.transport.spec.js.map +0 -1
- package/lib/module/releaseCatalogCache.spec.js +0 -195
- package/lib/module/releaseCatalogCache.spec.js.map +0 -1
- package/lib/module/releaseCatalogCacheNativeContract.spec.js +0 -64
- package/lib/module/releaseCatalogCacheNativeContract.spec.js.map +0 -1
- package/lib/module/store.notification.spec.js +0 -77
- package/lib/module/store.notification.spec.js.map +0 -1
- package/lib/module/store.spec.js +0 -315
- package/lib/module/store.spec.js.map +0 -1
- package/lib/module/wrap.spec.js +0 -330
- package/lib/module/wrap.spec.js.map +0 -1
- package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts +0 -13
- package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts.map +0 -1
- package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts +0 -8
- package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts.map +0 -1
- package/lib/typescript/module/notifyAppReadyInsights.d.ts +0 -13
- package/lib/typescript/module/notifyAppReadyInsights.d.ts.map +0 -1
- package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts +0 -8
- package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts.map +0 -1
- package/src/catalogCacheNative.spec.ts +0 -63
- package/src/checkForUpdate.releaseCatalog.spec.ts +0 -612
- package/src/httpClient.spec.ts +0 -132
- package/src/index.spec.ts +0 -337
- package/src/iosInterop.spec.ts +0 -30
- package/src/native.spec.ts +0 -945
- package/src/notifyAppReadyInsights.boundary.spec.ts +0 -234
- package/src/notifyAppReadyInsights.spec.ts +0 -243
- package/src/notifyAppReadyInsights.test-utils.ts +0 -31
- package/src/notifyAppReadyInsights.transport.spec.ts +0 -130
- package/src/notifyAppReadyInsights.ts +0 -194
- package/src/releaseCatalogCache.spec.ts +0 -282
- package/src/releaseCatalogCacheNativeContract.spec.ts +0 -80
- package/src/store.notification.spec.ts +0 -92
- package/src/store.spec.ts +0 -372
- package/src/wrap.spec.ts +0 -406
package/src/checkForUpdate.ts
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
import {
|
|
2
2
|
authorizeReleaseTransition,
|
|
3
|
+
canonicalizeAppVersion,
|
|
3
4
|
createReleaseSelectionContextHash,
|
|
4
5
|
encodeChannelKey,
|
|
6
|
+
type ExpectedReleaseCatalogScope,
|
|
7
|
+
hasExpectedReleaseCatalogScope,
|
|
5
8
|
selectDesiredRelease,
|
|
6
|
-
type ArtifactInfo,
|
|
7
9
|
type PersistedSelectionReceipt,
|
|
8
10
|
type ReleaseCatalog,
|
|
9
|
-
} from "@hot-updater/
|
|
10
|
-
import { canonicalizeAppVersion } from "@hot-updater/plugin-core";
|
|
11
|
+
} from "@hot-updater/protocol";
|
|
11
12
|
import { Platform } from "react-native";
|
|
12
13
|
|
|
14
|
+
import { emitAfterAppReady, getRunningReleaseId } from "./appReady";
|
|
15
|
+
import type {
|
|
16
|
+
ReleaseTransitionKind,
|
|
17
|
+
UpdateErrorResource,
|
|
18
|
+
UpdateErrorStage,
|
|
19
|
+
} from "./clientPlugin";
|
|
13
20
|
import { HotUpdaterError, StaleReleaseCatalogError } from "./error";
|
|
14
|
-
import type { HotUpdaterHttpClient
|
|
21
|
+
import type { HotUpdaterHttpClient } from "./httpClient";
|
|
15
22
|
import {
|
|
16
23
|
acceptReleaseCatalog,
|
|
17
24
|
commitReleaseSelection,
|
|
@@ -22,19 +29,16 @@ import {
|
|
|
22
29
|
getCohort,
|
|
23
30
|
getDefaultChannel,
|
|
24
31
|
getFingerprintHash,
|
|
25
|
-
getInstallId,
|
|
26
32
|
getMinBundleId,
|
|
27
33
|
getCrashHistory,
|
|
28
|
-
getPersistedUserIdentity,
|
|
29
34
|
isReleaseSelectionCurrent,
|
|
30
35
|
isChannelSwitched,
|
|
31
|
-
|
|
36
|
+
stageBundle,
|
|
32
37
|
} from "./native";
|
|
33
|
-
import {
|
|
34
|
-
hasExpectedReleaseCatalogScope,
|
|
35
|
-
type ExpectedReleaseCatalogScope,
|
|
36
|
-
} from "./releaseCatalogCache";
|
|
37
38
|
import { hotUpdaterStore } from "./store";
|
|
39
|
+
import { classifyUpdateError, InvalidUpdateResponseError } from "./updateError";
|
|
40
|
+
|
|
41
|
+
export type { ReleaseTransitionKind };
|
|
38
42
|
|
|
39
43
|
export interface CheckForUpdateOptions {
|
|
40
44
|
/**
|
|
@@ -60,7 +64,7 @@ export interface CheckForUpdateOptions {
|
|
|
60
64
|
requestTimeout?: number;
|
|
61
65
|
}
|
|
62
66
|
|
|
63
|
-
export type CheckForUpdateResult =
|
|
67
|
+
export type CheckForUpdateResult = {
|
|
64
68
|
readonly id: string;
|
|
65
69
|
readonly message: string | null;
|
|
66
70
|
readonly rolloutCohortCount: number;
|
|
@@ -76,14 +80,7 @@ export type CheckForUpdateResult = ArtifactInfo & {
|
|
|
76
80
|
updateBundle: () => Promise<boolean>;
|
|
77
81
|
};
|
|
78
82
|
|
|
79
|
-
export type ReleaseTransitionKind =
|
|
80
|
-
| "INSTALL"
|
|
81
|
-
| "ADOPT_RELEASE"
|
|
82
|
-
| "USE_EMBEDDED"
|
|
83
|
-
| "USE_BUILTIN";
|
|
84
|
-
|
|
85
83
|
export interface InternalCheckForUpdateOptions extends CheckForUpdateOptions {
|
|
86
|
-
insights?: boolean;
|
|
87
84
|
client: HotUpdaterHttpClient;
|
|
88
85
|
}
|
|
89
86
|
|
|
@@ -113,7 +110,7 @@ const validateCatalog = (
|
|
|
113
110
|
!/^sha256:[0-9a-f]{64}$/.test(catalog.catalogHash) ||
|
|
114
111
|
!hasExpectedReleaseCatalogScope(catalog, expectedScope)
|
|
115
112
|
) {
|
|
116
|
-
throw new
|
|
113
|
+
throw new InvalidUpdateResponseError("Received an invalid Release catalog");
|
|
117
114
|
}
|
|
118
115
|
};
|
|
119
116
|
|
|
@@ -121,47 +118,48 @@ const resetProgress = () => {
|
|
|
121
118
|
hotUpdaterStore.setState({
|
|
122
119
|
artifactType: null,
|
|
123
120
|
details: null,
|
|
124
|
-
downloadedBytes: undefined,
|
|
125
121
|
isUpdateDownloaded: false,
|
|
126
122
|
progress: 0,
|
|
127
|
-
totalBytes: undefined,
|
|
128
123
|
});
|
|
129
124
|
};
|
|
130
125
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
readonly
|
|
134
|
-
readonly
|
|
135
|
-
readonly
|
|
136
|
-
readonly
|
|
137
|
-
readonly
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
updateStrategy:
|
|
159
|
-
...(
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
126
|
+
/** The running bundle, the channel checked, and the update's target. */
|
|
127
|
+
type UpdateErrorScope = {
|
|
128
|
+
readonly channel: string;
|
|
129
|
+
readonly bundleId: string;
|
|
130
|
+
readonly updateStrategy: "fingerprint" | "appVersion";
|
|
131
|
+
readonly targetBundleId?: string;
|
|
132
|
+
readonly targetReleaseId?: string | null;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Tells plugins why an update failed, when it failed as an update. An error
|
|
137
|
+
* the SDK's JavaScript raised happened in `stage`, fetching `resource`.
|
|
138
|
+
*/
|
|
139
|
+
export const reportUpdateError = (
|
|
140
|
+
error: unknown,
|
|
141
|
+
stage: UpdateErrorStage,
|
|
142
|
+
resource: UpdateErrorResource | undefined,
|
|
143
|
+
scope: UpdateErrorScope,
|
|
144
|
+
): void => {
|
|
145
|
+
emitAfterAppReady("onUpdateError", () => {
|
|
146
|
+
const classification = classifyUpdateError(error, stage, resource);
|
|
147
|
+
if (classification === null) return null;
|
|
148
|
+
return {
|
|
149
|
+
...classification,
|
|
150
|
+
channel: scope.channel,
|
|
151
|
+
bundleId: scope.bundleId,
|
|
152
|
+
releaseId: getRunningReleaseId(scope.bundleId, getChannel()),
|
|
153
|
+
updateStrategy: scope.updateStrategy,
|
|
154
|
+
...(scope.targetBundleId === undefined
|
|
155
|
+
? {}
|
|
156
|
+
: { targetBundleId: scope.targetBundleId }),
|
|
157
|
+
...(scope.targetReleaseId == null
|
|
158
|
+
? {}
|
|
159
|
+
: { targetReleaseId: scope.targetReleaseId }),
|
|
160
|
+
cause: error,
|
|
161
|
+
};
|
|
162
|
+
});
|
|
165
163
|
};
|
|
166
164
|
|
|
167
165
|
async function checkForReleaseCatalogUpdate(input: {
|
|
@@ -212,12 +210,15 @@ async function checkForReleaseCatalogUpdate(input: {
|
|
|
212
210
|
requestTimeout: options.requestTimeout,
|
|
213
211
|
updateStrategy: options.updateStrategy,
|
|
214
212
|
});
|
|
213
|
+
// The server says this scope has no catalog yet: no update, not a failure.
|
|
214
|
+
if (catalog === null) return null;
|
|
215
215
|
validateCatalog(catalog, expectedScope);
|
|
216
216
|
const catalogId = catalog.catalogId;
|
|
217
217
|
const scopeKey = catalog.scopeKey;
|
|
218
218
|
|
|
219
219
|
const crashedBundleIds = getCrashHistory();
|
|
220
|
-
const
|
|
220
|
+
const activeState = getActiveUpdateState();
|
|
221
|
+
const active = activeState.activeSelection;
|
|
221
222
|
const explicitScopeSwitch =
|
|
222
223
|
input.explicitChannel !== undefined &&
|
|
223
224
|
input.explicitChannel !== input.currentChannel;
|
|
@@ -264,7 +265,7 @@ async function checkForReleaseCatalogUpdate(input: {
|
|
|
264
265
|
scopeKey,
|
|
265
266
|
})
|
|
266
267
|
) {
|
|
267
|
-
throw new
|
|
268
|
+
throw new InvalidUpdateResponseError(
|
|
268
269
|
"Rejected a stale or inconsistent Release catalog",
|
|
269
270
|
);
|
|
270
271
|
}
|
|
@@ -328,7 +329,20 @@ async function checkForReleaseCatalogUpdate(input: {
|
|
|
328
329
|
scopeKey,
|
|
329
330
|
selectionContextHash,
|
|
330
331
|
};
|
|
331
|
-
const
|
|
332
|
+
const fromReleaseId =
|
|
333
|
+
active?.bundleId === input.currentBundleId
|
|
334
|
+
? active.releaseId
|
|
335
|
+
: activeState.stableSelection?.bundleId === input.currentBundleId
|
|
336
|
+
? activeState.stableSelection.releaseId
|
|
337
|
+
: null;
|
|
338
|
+
const errorScope = {
|
|
339
|
+
bundleId: input.currentBundleId,
|
|
340
|
+
channel: input.targetChannel,
|
|
341
|
+
targetBundleId: desired.bundleId,
|
|
342
|
+
targetReleaseId: desired.releaseId,
|
|
343
|
+
updateStrategy: options.updateStrategy,
|
|
344
|
+
};
|
|
345
|
+
const installSelection = async (): Promise<boolean> => {
|
|
332
346
|
resetProgress();
|
|
333
347
|
if (!isReleaseSelectionCurrent(guard)) {
|
|
334
348
|
throw new StaleReleaseCatalogError();
|
|
@@ -339,18 +353,14 @@ async function checkForReleaseCatalogUpdate(input: {
|
|
|
339
353
|
guard,
|
|
340
354
|
selection: receipt,
|
|
341
355
|
});
|
|
342
|
-
if (committed && transitionKind === "ADOPT_RELEASE"
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
requestHeaders: options.requestHeaders,
|
|
351
|
-
requestTimeout: options.requestTimeout,
|
|
352
|
-
session,
|
|
353
|
-
});
|
|
356
|
+
if (committed && transitionKind === "ADOPT_RELEASE") {
|
|
357
|
+
emitAfterAppReady("onUpdateCheck", () => ({
|
|
358
|
+
status: "UNCHANGED",
|
|
359
|
+
channel: receipt.channel,
|
|
360
|
+
bundleId: receipt.bundleId,
|
|
361
|
+
releaseId: receipt.releaseId,
|
|
362
|
+
previousReleaseId: active?.releaseId ?? null,
|
|
363
|
+
}));
|
|
354
364
|
}
|
|
355
365
|
return committed;
|
|
356
366
|
}
|
|
@@ -364,33 +374,64 @@ async function checkForReleaseCatalogUpdate(input: {
|
|
|
364
374
|
if (!isReleaseSelectionCurrent(guard)) {
|
|
365
375
|
throw new StaleReleaseCatalogError();
|
|
366
376
|
}
|
|
367
|
-
|
|
377
|
+
const delivery = await stageBundle({
|
|
378
|
+
assets: artifact.assets,
|
|
368
379
|
bundleId: desired.bundleId,
|
|
369
|
-
changedAssets: artifact.changedAssets ?? null,
|
|
370
380
|
channel: input.targetChannel,
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
manifestUrl: artifact.manifestUrl ?? null,
|
|
381
|
+
manifestFileHash: artifact.manifestFileHash,
|
|
382
|
+
manifestUrl: artifact.manifestUrl,
|
|
383
|
+
...(artifact.archiveUrl ? { archiveUrl: artifact.archiveUrl } : {}),
|
|
375
384
|
selection: receipt,
|
|
376
385
|
shouldSkipCurrentBundleIdCheck: true,
|
|
377
386
|
status: desired.status,
|
|
378
387
|
});
|
|
388
|
+
if (delivery !== null && desired.bundleId !== input.currentBundleId) {
|
|
389
|
+
emitAfterAppReady("onBundleDownloaded", () => ({
|
|
390
|
+
channel: input.targetChannel,
|
|
391
|
+
fromBundleId: input.currentBundleId,
|
|
392
|
+
fromReleaseId,
|
|
393
|
+
toBundleId: desired.bundleId,
|
|
394
|
+
toReleaseId: desired.releaseId,
|
|
395
|
+
updateStrategy: options.updateStrategy,
|
|
396
|
+
...delivery,
|
|
397
|
+
}));
|
|
398
|
+
}
|
|
399
|
+
return true;
|
|
400
|
+
};
|
|
401
|
+
const updateBundleForSelection = async (): Promise<boolean> => {
|
|
402
|
+
try {
|
|
403
|
+
return await installSelection();
|
|
404
|
+
} catch (error) {
|
|
405
|
+
reportUpdateError(error, "download", "artifact", errorScope);
|
|
406
|
+
throw error;
|
|
407
|
+
}
|
|
379
408
|
};
|
|
380
409
|
|
|
410
|
+
const shouldForceUpdate =
|
|
411
|
+
transitionKind === "ADOPT_RELEASE"
|
|
412
|
+
? false
|
|
413
|
+
: desired.status === "ROLLBACK"
|
|
414
|
+
? true
|
|
415
|
+
: (release?.shouldForceUpdate ?? false);
|
|
416
|
+
emitAfterAppReady("onUpdateCheck", () => ({
|
|
417
|
+
status: "UPDATE_AVAILABLE",
|
|
418
|
+
channel: input.targetChannel,
|
|
419
|
+
fromBundleId: input.currentBundleId,
|
|
420
|
+
fromReleaseId,
|
|
421
|
+
toBundleId: desired.bundleId,
|
|
422
|
+
toReleaseId: desired.releaseId,
|
|
423
|
+
transitionKind,
|
|
424
|
+
updateStatus: desired.status,
|
|
425
|
+
shouldForceUpdate,
|
|
426
|
+
updateStrategy: options.updateStrategy,
|
|
427
|
+
}));
|
|
428
|
+
|
|
381
429
|
return {
|
|
382
|
-
fileHash: null,
|
|
383
|
-
fileUrl: null,
|
|
384
430
|
id: desired.releaseId ?? desired.bundleId,
|
|
385
431
|
message: release?.message ?? null,
|
|
386
432
|
releaseId: desired.releaseId,
|
|
387
433
|
rolloutCohortCount: release?.rolloutCohortCount ?? 1000,
|
|
388
|
-
shouldForceUpdate
|
|
389
|
-
transitionKind === "ADOPT_RELEASE"
|
|
390
|
-
? false
|
|
391
|
-
: desired.status === "ROLLBACK"
|
|
392
|
-
? true
|
|
393
|
-
: (release?.shouldForceUpdate ?? false),
|
|
434
|
+
shouldForceUpdate,
|
|
394
435
|
status: desired.status,
|
|
395
436
|
targetCohorts: release?.targetCohorts ? [...release.targetCohorts] : [],
|
|
396
437
|
transitionKind,
|
|
@@ -439,7 +480,7 @@ export async function checkForUpdate(
|
|
|
439
480
|
const fingerprintHash = getFingerprintHash();
|
|
440
481
|
|
|
441
482
|
try {
|
|
442
|
-
|
|
483
|
+
const result = await checkForReleaseCatalogUpdate({
|
|
443
484
|
cohort,
|
|
444
485
|
currentAppVersion,
|
|
445
486
|
currentBundleId,
|
|
@@ -453,7 +494,25 @@ export async function checkForUpdate(
|
|
|
453
494
|
platform,
|
|
454
495
|
targetChannel,
|
|
455
496
|
});
|
|
497
|
+
if (result === null) {
|
|
498
|
+
emitAfterAppReady("onUpdateCheck", () => {
|
|
499
|
+
const releaseId = getRunningReleaseId(currentBundleId, currentChannel);
|
|
500
|
+
return {
|
|
501
|
+
status: "UNCHANGED",
|
|
502
|
+
channel: currentChannel,
|
|
503
|
+
bundleId: currentBundleId,
|
|
504
|
+
releaseId,
|
|
505
|
+
previousReleaseId: releaseId,
|
|
506
|
+
};
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
return result;
|
|
456
510
|
} catch (error) {
|
|
511
|
+
reportUpdateError(error, "check", "catalog", {
|
|
512
|
+
bundleId: currentBundleId,
|
|
513
|
+
channel: targetChannel,
|
|
514
|
+
updateStrategy: options.updateStrategy,
|
|
515
|
+
});
|
|
457
516
|
options.onError?.(error as Error);
|
|
458
517
|
return null;
|
|
459
518
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export {
|
|
2
|
+
defineClientPlugin,
|
|
3
|
+
type AppReadyResult,
|
|
4
|
+
type BundleDownloadedInfo,
|
|
5
|
+
type HotUpdaterClientContext,
|
|
6
|
+
type HotUpdaterClientHooks,
|
|
7
|
+
type HotUpdaterClientPlugin,
|
|
8
|
+
type HotUpdaterClientStorage,
|
|
9
|
+
type ReleaseTransitionKind,
|
|
10
|
+
type UpdateCheckResult,
|
|
11
|
+
type UpdateError,
|
|
12
|
+
type UpdateErrorReason,
|
|
13
|
+
type UpdateErrorResource,
|
|
14
|
+
type UpdateErrorStage,
|
|
15
|
+
type UpdateErrorTransport,
|
|
16
|
+
type UpdateHttpResponse,
|
|
17
|
+
type UpdateStrategy,
|
|
18
|
+
} from "@hot-updater/protocol";
|
package/src/error.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Error Classification:
|
|
9
9
|
* - Parameter Validation: Invalid or missing function parameters
|
|
10
|
-
* - Bundle Storage: Errors during download,
|
|
10
|
+
* - Bundle Storage: Errors during download, verification, and storage
|
|
11
11
|
* - Signature Verification: Cryptographic verification failures (collapsed to a single public code)
|
|
12
12
|
* - Internal: Platform-specific or unexpected errors
|
|
13
13
|
*
|
|
@@ -27,8 +27,7 @@ export enum HotUpdaterErrorCode {
|
|
|
27
27
|
MISSING_BUNDLE_ID = "MISSING_BUNDLE_ID",
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
*
|
|
31
|
-
* Thrown when fileUrl parameter cannot be parsed as a valid URL.
|
|
30
|
+
* Manifest or asset URL is invalid or malformed.
|
|
32
31
|
* @retryable false
|
|
33
32
|
*/
|
|
34
33
|
INVALID_FILE_URL = "INVALID_FILE_URL",
|
|
@@ -58,25 +57,16 @@ export enum HotUpdaterErrorCode {
|
|
|
58
57
|
*/
|
|
59
58
|
INCOMPLETE_DOWNLOAD = "INCOMPLETE_DOWNLOAD",
|
|
60
59
|
|
|
61
|
-
/**
|
|
62
|
-
* Bundle archive format is invalid or corrupted.
|
|
63
|
-
* Thrown when ZIP file has wrong magic bytes, invalid structure, or unsupported format.
|
|
64
|
-
* Also thrown for path traversal attempts during extraction.
|
|
65
|
-
* @retryable false - Indicates corrupted or malicious bundle
|
|
66
|
-
*/
|
|
67
|
-
EXTRACTION_FORMAT_ERROR = "EXTRACTION_FORMAT_ERROR",
|
|
68
|
-
|
|
69
60
|
/**
|
|
70
61
|
* Bundle missing required platform files.
|
|
71
|
-
* Thrown when
|
|
62
|
+
* Thrown when the staged bundle doesn't contain index.android.bundle (Android)
|
|
72
63
|
* or main.jsbundle (iOS).
|
|
73
64
|
* @retryable false - Indicates incorrectly built bundle
|
|
74
65
|
*/
|
|
75
66
|
INVALID_BUNDLE = "INVALID_BUNDLE",
|
|
76
67
|
|
|
77
68
|
/**
|
|
78
|
-
* Insufficient disk space for bundle
|
|
79
|
-
* Thrown when available disk space is less than required (file size * 2).
|
|
69
|
+
* Insufficient disk space for bundle staging.
|
|
80
70
|
* Error message includes required and available bytes.
|
|
81
71
|
* @retryable false - User must free up disk space
|
|
82
72
|
*/
|
package/src/fetchJSON.ts
CHANGED
|
@@ -1,33 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
requestHeaders,
|
|
4
|
-
requestTimeout = 5000,
|
|
5
|
-
}: {
|
|
6
|
-
url: string;
|
|
7
|
-
requestHeaders?: Record<string, string>;
|
|
8
|
-
requestTimeout?: number;
|
|
9
|
-
}): Promise<T> => {
|
|
10
|
-
const controller = new AbortController();
|
|
11
|
-
const timeoutId = setTimeout(() => controller.abort(), requestTimeout);
|
|
1
|
+
import { fetchUpdateResponse, type UpdateRequest } from "./fetchUpdateResponse";
|
|
2
|
+
import { UpdateHttpError } from "./updateError";
|
|
12
3
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return (await response.json()) as T;
|
|
25
|
-
} catch (error: unknown) {
|
|
26
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
27
|
-
throw new Error("Request timed out");
|
|
28
|
-
}
|
|
29
|
-
throw error;
|
|
30
|
-
} finally {
|
|
31
|
-
clearTimeout(timeoutId);
|
|
4
|
+
export class FetchJSONResponseError extends UpdateHttpError {}
|
|
5
|
+
|
|
6
|
+
export const fetchJSON = async <T>(
|
|
7
|
+
input: Omit<UpdateRequest, "resource">,
|
|
8
|
+
): Promise<T> => {
|
|
9
|
+
const { response, body } = await fetchUpdateResponse({
|
|
10
|
+
...input,
|
|
11
|
+
resource: "artifact",
|
|
12
|
+
});
|
|
13
|
+
if (response.status !== 200) {
|
|
14
|
+
throw new FetchJSONResponseError(response.status, response.statusText);
|
|
32
15
|
}
|
|
16
|
+
return JSON.parse(body!) as T;
|
|
33
17
|
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { UpdateHttpResponse } from "@hot-updater/protocol";
|
|
2
|
+
|
|
3
|
+
export interface UpdateRequest {
|
|
4
|
+
readonly url: string;
|
|
5
|
+
readonly resource: UpdateHttpResponse["resource"];
|
|
6
|
+
readonly requestHeaders?: Record<string, string>;
|
|
7
|
+
readonly requestTimeout?: number;
|
|
8
|
+
readonly onResponse?: (response: UpdateHttpResponse) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Read once for parsing and diagnostics, under the same request timeout. */
|
|
12
|
+
export const fetchUpdateResponse = async ({
|
|
13
|
+
url,
|
|
14
|
+
resource,
|
|
15
|
+
requestHeaders,
|
|
16
|
+
requestTimeout = 5000,
|
|
17
|
+
onResponse,
|
|
18
|
+
}: UpdateRequest): Promise<{ response: Response; body: string | null }> => {
|
|
19
|
+
const controller = new AbortController();
|
|
20
|
+
let timedOut = false;
|
|
21
|
+
const timeoutId = setTimeout(() => {
|
|
22
|
+
timedOut = true;
|
|
23
|
+
controller.abort();
|
|
24
|
+
}, requestTimeout);
|
|
25
|
+
try {
|
|
26
|
+
const headers = new Headers(requestHeaders);
|
|
27
|
+
if (!headers.has("Accept")) headers.set("Accept", "application/json");
|
|
28
|
+
const response = await fetch(url, {
|
|
29
|
+
headers,
|
|
30
|
+
signal: controller.signal,
|
|
31
|
+
});
|
|
32
|
+
let body: string | null = null;
|
|
33
|
+
try {
|
|
34
|
+
body = await response.text();
|
|
35
|
+
} catch (error) {
|
|
36
|
+
// A broken error body must not hide an HTTP error already received.
|
|
37
|
+
if (response.status === 200) throw error;
|
|
38
|
+
} finally {
|
|
39
|
+
onResponse?.({
|
|
40
|
+
resource,
|
|
41
|
+
// React Native URL implementations do not all expose pathname.
|
|
42
|
+
path:
|
|
43
|
+
url.replace(/^https?:\/\/[^/?#]*/i, "").split(/[?#]/, 1)[0] || "/",
|
|
44
|
+
status: response.status,
|
|
45
|
+
body,
|
|
46
|
+
bodyTruncated: false,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return { response, body };
|
|
50
|
+
} catch (error: unknown) {
|
|
51
|
+
// Whatever the fetch rejects with once its timeout aborts it: an
|
|
52
|
+
// AbortError, or Expo's "fetch failed: FetchRequestCanceledException".
|
|
53
|
+
if (timedOut || (error instanceof Error && error.name === "AbortError")) {
|
|
54
|
+
throw new Error("Request timed out");
|
|
55
|
+
}
|
|
56
|
+
throw error;
|
|
57
|
+
} finally {
|
|
58
|
+
clearTimeout(timeoutId);
|
|
59
|
+
}
|
|
60
|
+
};
|