@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
|
@@ -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
|
-
/**
|
|
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.
|
|
32
|
-
*/
|
|
33
|
-
fileHash: string | null;
|
|
34
8
|
/**
|
|
35
|
-
*
|
|
9
|
+
* Signed manifest URL for installation.
|
|
36
10
|
*/
|
|
37
|
-
manifestUrl
|
|
11
|
+
manifestUrl: string;
|
|
38
12
|
/**
|
|
39
13
|
* File hash/signature for the manifest file itself.
|
|
40
14
|
*/
|
|
41
|
-
manifestFileHash
|
|
42
|
-
/**
|
|
43
|
-
|
|
44
|
-
|
|
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
|
}
|
|
@@ -66,13 +39,12 @@ export interface Spec extends TurboModule {
|
|
|
66
39
|
*
|
|
67
40
|
* Parameter validation:
|
|
68
41
|
* - MISSING_BUNDLE_ID: Missing or empty bundleId
|
|
69
|
-
* - INVALID_FILE_URL: Invalid
|
|
42
|
+
* - INVALID_FILE_URL: Invalid manifest or asset URL provided
|
|
70
43
|
*
|
|
71
44
|
* Bundle storage:
|
|
72
45
|
* - DIRECTORY_CREATION_FAILED: Failed to create bundle directory
|
|
73
46
|
* - DOWNLOAD_FAILED: Failed to download bundle
|
|
74
47
|
* - INCOMPLETE_DOWNLOAD: Download incomplete (size mismatch)
|
|
75
|
-
* - EXTRACTION_FORMAT_ERROR: Invalid or corrupted archive format
|
|
76
48
|
* - INVALID_BUNDLE: Bundle missing required platform files
|
|
77
49
|
* - INSUFFICIENT_DISK_SPACE: Insufficient disk space
|
|
78
50
|
* - MOVE_OPERATION_FAILED: Failed to move bundle files
|
|
@@ -61,10 +61,20 @@ describe("hotUpdaterStore notification scheduling", () => {
|
|
|
61
61
|
|
|
62
62
|
const nextProgress = Math.min(1, progress + 0.01);
|
|
63
63
|
emitProgress?.({
|
|
64
|
-
artifactType: "
|
|
65
|
-
|
|
64
|
+
artifactType: "diff",
|
|
65
|
+
details: {
|
|
66
|
+
completedFilesCount: nextProgress === 1 ? 1 : 0,
|
|
67
|
+
files: [
|
|
68
|
+
{
|
|
69
|
+
order: 0,
|
|
70
|
+
path: "index.ios.bundle",
|
|
71
|
+
progress: nextProgress,
|
|
72
|
+
status: nextProgress === 1 ? "downloaded" : "downloading",
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
totalFilesCount: 1,
|
|
76
|
+
},
|
|
66
77
|
progress: nextProgress,
|
|
67
|
-
totalBytes: 1_000_000,
|
|
68
78
|
});
|
|
69
79
|
}, [progress]);
|
|
70
80
|
|
package/src/store.spec.ts
CHANGED
|
@@ -41,75 +41,6 @@ describe("hotUpdaterStore", () => {
|
|
|
41
41
|
unsubscribe();
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
it("notifies subscribers only when progress events change the snapshot", async () => {
|
|
45
|
-
const store = await importStore();
|
|
46
|
-
const listener = vi.fn();
|
|
47
|
-
const emitProgress = listeners.get("onProgress");
|
|
48
|
-
|
|
49
|
-
expect(emitProgress).toBeTypeOf("function");
|
|
50
|
-
|
|
51
|
-
const unsubscribe = store.subscribe(listener);
|
|
52
|
-
|
|
53
|
-
emitProgress?.({
|
|
54
|
-
artifactType: "archive",
|
|
55
|
-
progress: 0.5,
|
|
56
|
-
});
|
|
57
|
-
emitProgress?.({
|
|
58
|
-
artifactType: "archive",
|
|
59
|
-
progress: 0.5,
|
|
60
|
-
});
|
|
61
|
-
emitProgress?.({
|
|
62
|
-
artifactType: "archive",
|
|
63
|
-
progress: 1,
|
|
64
|
-
});
|
|
65
|
-
store.setState({ isUpdateDownloaded: true });
|
|
66
|
-
|
|
67
|
-
expect(listener).toHaveBeenCalledTimes(2);
|
|
68
|
-
expect(store.getSnapshot()).toEqual({
|
|
69
|
-
artifactType: "archive",
|
|
70
|
-
details: null,
|
|
71
|
-
downloadedBytes: undefined,
|
|
72
|
-
isUpdateDownloaded: true,
|
|
73
|
-
progress: 1,
|
|
74
|
-
totalBytes: undefined,
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
unsubscribe();
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it("stores archive byte metadata and notifies when only bytes change", async () => {
|
|
81
|
-
const store = await importStore();
|
|
82
|
-
const listener = vi.fn();
|
|
83
|
-
const emitProgress = listeners.get("onProgress");
|
|
84
|
-
|
|
85
|
-
const unsubscribe = store.subscribe(listener);
|
|
86
|
-
|
|
87
|
-
emitProgress?.({
|
|
88
|
-
artifactType: "archive",
|
|
89
|
-
downloadedBytes: 100.4,
|
|
90
|
-
progress: 0.5,
|
|
91
|
-
totalBytes: 1_000,
|
|
92
|
-
});
|
|
93
|
-
emitProgress?.({
|
|
94
|
-
artifactType: "archive",
|
|
95
|
-
downloadedBytes: 250,
|
|
96
|
-
progress: 0.5,
|
|
97
|
-
totalBytes: 1_000,
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
expect(listener).toHaveBeenCalledTimes(2);
|
|
101
|
-
expect(store.getSnapshot()).toEqual({
|
|
102
|
-
artifactType: "archive",
|
|
103
|
-
details: null,
|
|
104
|
-
downloadedBytes: 250,
|
|
105
|
-
isUpdateDownloaded: false,
|
|
106
|
-
progress: 0.5,
|
|
107
|
-
totalBytes: 1_000,
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
unsubscribe();
|
|
111
|
-
});
|
|
112
|
-
|
|
113
44
|
it("stores manifest progress metadata while keeping overall progress", async () => {
|
|
114
45
|
const store = await importStore();
|
|
115
46
|
const emitProgress = listeners.get("onProgress");
|
|
@@ -163,10 +94,8 @@ describe("hotUpdaterStore", () => {
|
|
|
163
94
|
],
|
|
164
95
|
totalFilesCount: 2,
|
|
165
96
|
},
|
|
166
|
-
downloadedBytes: undefined,
|
|
167
97
|
isUpdateDownloaded: false,
|
|
168
98
|
progress: 0.42,
|
|
169
|
-
totalBytes: undefined,
|
|
170
99
|
});
|
|
171
100
|
});
|
|
172
101
|
|
|
@@ -279,94 +208,8 @@ describe("hotUpdaterStore", () => {
|
|
|
279
208
|
],
|
|
280
209
|
totalFilesCount: 2,
|
|
281
210
|
},
|
|
282
|
-
downloadedBytes: undefined,
|
|
283
211
|
isUpdateDownloaded: false,
|
|
284
212
|
progress: 0.6,
|
|
285
|
-
totalBytes: undefined,
|
|
286
|
-
});
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
it("clears manifest metadata when archive progress events arrive", async () => {
|
|
290
|
-
const store = await importStore();
|
|
291
|
-
const emitProgress = listeners.get("onProgress");
|
|
292
|
-
|
|
293
|
-
emitProgress?.({
|
|
294
|
-
artifactType: "diff",
|
|
295
|
-
details: {
|
|
296
|
-
completedFilesCount: 2,
|
|
297
|
-
files: [
|
|
298
|
-
{
|
|
299
|
-
order: 0,
|
|
300
|
-
path: "index.ios.bundle",
|
|
301
|
-
progress: 1,
|
|
302
|
-
status: "downloaded",
|
|
303
|
-
},
|
|
304
|
-
{
|
|
305
|
-
order: 1,
|
|
306
|
-
path: "assets/logo.png",
|
|
307
|
-
progress: 1,
|
|
308
|
-
status: "downloaded",
|
|
309
|
-
},
|
|
310
|
-
{
|
|
311
|
-
order: 2,
|
|
312
|
-
path: "assets/bg.png",
|
|
313
|
-
progress: 0,
|
|
314
|
-
status: "pending",
|
|
315
|
-
},
|
|
316
|
-
],
|
|
317
|
-
totalFilesCount: 3,
|
|
318
|
-
},
|
|
319
|
-
progress: 0.9,
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
emitProgress?.({
|
|
323
|
-
artifactType: "archive",
|
|
324
|
-
progress: 0.25,
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
expect(store.getSnapshot()).toEqual({
|
|
328
|
-
artifactType: "archive",
|
|
329
|
-
details: null,
|
|
330
|
-
downloadedBytes: undefined,
|
|
331
|
-
isUpdateDownloaded: false,
|
|
332
|
-
progress: 0.25,
|
|
333
|
-
totalBytes: undefined,
|
|
334
|
-
});
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
it("clears stale manifest metadata even when archive events omit optional fields", async () => {
|
|
338
|
-
const store = await importStore();
|
|
339
|
-
const emitProgress = listeners.get("onProgress");
|
|
340
|
-
|
|
341
|
-
emitProgress?.({
|
|
342
|
-
artifactType: "diff",
|
|
343
|
-
details: {
|
|
344
|
-
completedFilesCount: 0,
|
|
345
|
-
files: [
|
|
346
|
-
{
|
|
347
|
-
order: 0,
|
|
348
|
-
path: "manifest.asset.png",
|
|
349
|
-
progress: 0,
|
|
350
|
-
status: "failed",
|
|
351
|
-
},
|
|
352
|
-
],
|
|
353
|
-
totalFilesCount: 1,
|
|
354
|
-
},
|
|
355
|
-
progress: 0.2,
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
emitProgress?.({
|
|
359
|
-
artifactType: "archive",
|
|
360
|
-
progress: 0.4,
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
expect(store.getSnapshot()).toEqual({
|
|
364
|
-
artifactType: "archive",
|
|
365
|
-
details: null,
|
|
366
|
-
downloadedBytes: undefined,
|
|
367
|
-
isUpdateDownloaded: false,
|
|
368
|
-
progress: 0.4,
|
|
369
|
-
totalBytes: undefined,
|
|
370
213
|
});
|
|
371
214
|
});
|
|
372
215
|
});
|
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: "
|
|
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/wrap.spec.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
|
|
3
|
+
import { cleanup, render, waitFor } from "@testing-library/react";
|
|
4
|
+
import { createElement, type ComponentType } from "react";
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
6
|
|
|
4
7
|
import type {
|
|
5
|
-
|
|
8
|
+
ActiveUpdateState,
|
|
9
|
+
NotifyAppReadyInsightsEvent,
|
|
6
10
|
NotifyAppReadyResult,
|
|
7
11
|
} from "./native";
|
|
8
12
|
import type { HotUpdaterOptions } from "./wrap";
|
|
@@ -15,14 +19,14 @@ vi.mock("react-native", () => ({
|
|
|
15
19
|
|
|
16
20
|
const createNotifyReadResult = (
|
|
17
21
|
result: NotifyAppReadyResult = { status: "UNCHANGED" },
|
|
18
|
-
|
|
22
|
+
insightsEvent: NotifyAppReadyInsightsEvent | null = null,
|
|
19
23
|
pending = false,
|
|
20
24
|
): {
|
|
21
|
-
|
|
25
|
+
insightsEvent: NotifyAppReadyInsightsEvent | null;
|
|
22
26
|
pending: boolean;
|
|
23
27
|
result: NotifyAppReadyResult;
|
|
24
28
|
} => ({
|
|
25
|
-
|
|
29
|
+
insightsEvent,
|
|
26
30
|
pending,
|
|
27
31
|
result,
|
|
28
32
|
});
|
|
@@ -32,14 +36,16 @@ const mocks = vi.hoisted(() => ({
|
|
|
32
36
|
checkForUpdate: vi.fn(),
|
|
33
37
|
getAppVersion: vi.fn(() => "1.0.0"),
|
|
34
38
|
getBundleId: vi.fn(() => "bundle-id"),
|
|
39
|
+
getUpdateId: vi.fn(() => "release-id"),
|
|
35
40
|
getChannel: vi.fn(() => "production"),
|
|
41
|
+
getActiveUpdateState: vi.fn<() => ActiveUpdateState>(),
|
|
36
42
|
getCohort: vi.fn(() => "123"),
|
|
37
43
|
getFingerprintHash: vi.fn(() => "fingerprint-hash"),
|
|
38
44
|
getInstallId: vi.fn(() => "install-id"),
|
|
39
45
|
getPersistedUserIdentity: vi.fn(() => ({})),
|
|
40
46
|
readNotifyAppReady: vi.fn<
|
|
41
47
|
() => {
|
|
42
|
-
|
|
48
|
+
insightsEvent: NotifyAppReadyInsightsEvent | null;
|
|
43
49
|
pending: boolean;
|
|
44
50
|
result: NotifyAppReadyResult;
|
|
45
51
|
}
|
|
@@ -55,7 +61,9 @@ vi.mock("./native", () => ({
|
|
|
55
61
|
addListener: mocks.addListener,
|
|
56
62
|
getAppVersion: mocks.getAppVersion,
|
|
57
63
|
getBundleId: mocks.getBundleId,
|
|
64
|
+
getUpdateId: mocks.getUpdateId,
|
|
58
65
|
getChannel: mocks.getChannel,
|
|
66
|
+
getActiveUpdateState: mocks.getActiveUpdateState,
|
|
59
67
|
getCohort: mocks.getCohort,
|
|
60
68
|
getFingerprintHash: mocks.getFingerprintHash,
|
|
61
69
|
getInstallId: mocks.getInstallId,
|
|
@@ -65,16 +73,16 @@ vi.mock("./native", () => ({
|
|
|
65
73
|
}));
|
|
66
74
|
|
|
67
75
|
const createClient = (
|
|
68
|
-
|
|
76
|
+
sendInsightsEvent = vi.fn().mockResolvedValue(undefined),
|
|
69
77
|
) => ({
|
|
70
78
|
client: {
|
|
71
79
|
createSession: vi.fn(async () => ({
|
|
72
80
|
fetchReleaseCatalog: vi.fn(),
|
|
73
81
|
resolveArtifact: vi.fn(),
|
|
74
|
-
|
|
82
|
+
sendInsightsEvent,
|
|
75
83
|
})),
|
|
76
84
|
},
|
|
77
|
-
|
|
85
|
+
sendInsightsEvent,
|
|
78
86
|
});
|
|
79
87
|
|
|
80
88
|
describe("HotUpdater wrap initialization", () => {
|
|
@@ -92,13 +100,83 @@ describe("HotUpdater wrap initialization", () => {
|
|
|
92
100
|
mocks.getAppVersion.mockReturnValue("1.0.0");
|
|
93
101
|
mocks.getPersistedUserIdentity.mockReturnValue({});
|
|
94
102
|
mocks.getBundleId.mockReturnValue("bundle-id");
|
|
103
|
+
mocks.getUpdateId.mockReturnValue("release-id");
|
|
95
104
|
mocks.getChannel.mockReturnValue("production");
|
|
105
|
+
mocks.getActiveUpdateState.mockReturnValue({
|
|
106
|
+
activeSelection: null,
|
|
107
|
+
stableSelection: null,
|
|
108
|
+
verificationPending: false,
|
|
109
|
+
});
|
|
96
110
|
mocks.getCohort.mockReturnValue("123");
|
|
97
111
|
mocks.getFingerprintHash.mockReturnValue("fingerprint-hash");
|
|
98
112
|
mocks.getInstallId.mockReturnValue("install-id");
|
|
99
113
|
mocks.readNotifyAppReady.mockReturnValue(createNotifyReadResult());
|
|
100
114
|
});
|
|
101
115
|
|
|
116
|
+
afterEach(cleanup);
|
|
117
|
+
|
|
118
|
+
it("does not report No change while an optional download is in progress", async () => {
|
|
119
|
+
const { client, sendInsightsEvent } = createClient();
|
|
120
|
+
let complete!: (success: boolean) => void;
|
|
121
|
+
const download = vi.fn(
|
|
122
|
+
() =>
|
|
123
|
+
new Promise<boolean>((resolve) => {
|
|
124
|
+
complete = resolve;
|
|
125
|
+
}),
|
|
126
|
+
);
|
|
127
|
+
mocks.checkForUpdate.mockResolvedValue({
|
|
128
|
+
id: "next",
|
|
129
|
+
status: "UPDATE",
|
|
130
|
+
shouldForceUpdate: false,
|
|
131
|
+
message: null,
|
|
132
|
+
updateBundle: download,
|
|
133
|
+
});
|
|
134
|
+
const { wrap } = await import("./wrap");
|
|
135
|
+
const onUpdateProcessCompleted = vi.fn();
|
|
136
|
+
const Wrapped = wrap({
|
|
137
|
+
client,
|
|
138
|
+
insights: true,
|
|
139
|
+
updateStrategy: "appVersion",
|
|
140
|
+
onUpdateProcessCompleted,
|
|
141
|
+
})(() => null);
|
|
142
|
+
render(createElement(Wrapped));
|
|
143
|
+
await waitFor(() => expect(download).toHaveBeenCalledOnce());
|
|
144
|
+
expect(onUpdateProcessCompleted).toHaveBeenCalledOnce();
|
|
145
|
+
expect(sendInsightsEvent).not.toHaveBeenCalled();
|
|
146
|
+
complete(true);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("reports the console ID when up to date while retaining file IDs in insights", async () => {
|
|
150
|
+
const onUpdateProcessCompleted = vi.fn();
|
|
151
|
+
const { client, sendInsightsEvent } = createClient();
|
|
152
|
+
const { wrap } = await import("./wrap");
|
|
153
|
+
const WrappedComponent = wrap({
|
|
154
|
+
insights: true,
|
|
155
|
+
client,
|
|
156
|
+
onUpdateProcessCompleted,
|
|
157
|
+
updateStrategy: "appVersion",
|
|
158
|
+
})(() => null);
|
|
159
|
+
|
|
160
|
+
render(createElement(WrappedComponent));
|
|
161
|
+
|
|
162
|
+
await waitFor(() =>
|
|
163
|
+
expect(onUpdateProcessCompleted).toHaveBeenCalledWith({
|
|
164
|
+
id: "release-id",
|
|
165
|
+
message: null,
|
|
166
|
+
shouldForceUpdate: false,
|
|
167
|
+
status: "UP_TO_DATE",
|
|
168
|
+
}),
|
|
169
|
+
);
|
|
170
|
+
await waitFor(() =>
|
|
171
|
+
expect(sendInsightsEvent).toHaveBeenCalledWith(
|
|
172
|
+
expect.objectContaining({
|
|
173
|
+
toBundleId: "bundle-id",
|
|
174
|
+
type: "UNCHANGED",
|
|
175
|
+
}),
|
|
176
|
+
),
|
|
177
|
+
);
|
|
178
|
+
});
|
|
179
|
+
|
|
102
180
|
it("returns void from init and defers notifyAppReady to the next frame", async () => {
|
|
103
181
|
vi.useFakeTimers();
|
|
104
182
|
|
|
@@ -110,7 +188,7 @@ describe("HotUpdater wrap initialization", () => {
|
|
|
110
188
|
);
|
|
111
189
|
vi.stubGlobal("requestAnimationFrame", requestAnimationFrame);
|
|
112
190
|
|
|
113
|
-
const { client,
|
|
191
|
+
const { client, sendInsightsEvent } = createClient();
|
|
114
192
|
const { init } = await import("./wrap");
|
|
115
193
|
|
|
116
194
|
const result = init({
|
|
@@ -123,17 +201,17 @@ describe("HotUpdater wrap initialization", () => {
|
|
|
123
201
|
|
|
124
202
|
expect(result).toBeUndefined();
|
|
125
203
|
expect(mocks.readNotifyAppReady).not.toHaveBeenCalled();
|
|
126
|
-
expect(
|
|
204
|
+
expect(sendInsightsEvent).not.toHaveBeenCalled();
|
|
127
205
|
|
|
128
206
|
expect(requestAnimationFrame).toHaveBeenCalled();
|
|
129
207
|
|
|
130
208
|
await vi.runOnlyPendingTimersAsync();
|
|
131
209
|
|
|
132
210
|
expect(mocks.readNotifyAppReady).toHaveBeenCalledWith();
|
|
133
|
-
expect(
|
|
211
|
+
expect(sendInsightsEvent).not.toHaveBeenCalled();
|
|
134
212
|
});
|
|
135
213
|
|
|
136
|
-
it("waits for native launch verification before sending
|
|
214
|
+
it("waits for native launch verification before sending insights", async () => {
|
|
137
215
|
vi.useFakeTimers();
|
|
138
216
|
|
|
139
217
|
vi.stubGlobal(
|
|
@@ -162,18 +240,18 @@ describe("HotUpdater wrap initialization", () => {
|
|
|
162
240
|
),
|
|
163
241
|
);
|
|
164
242
|
|
|
165
|
-
const { client,
|
|
243
|
+
const { client, sendInsightsEvent } = createClient();
|
|
166
244
|
const { init } = await import("./wrap");
|
|
167
245
|
|
|
168
|
-
init({
|
|
246
|
+
init({ insights: true, client });
|
|
169
247
|
|
|
170
248
|
await vi.runAllTimersAsync();
|
|
171
249
|
|
|
172
250
|
expect(mocks.readNotifyAppReady).toHaveBeenCalledTimes(2);
|
|
173
|
-
expect(
|
|
251
|
+
expect(sendInsightsEvent).toHaveBeenCalledTimes(1);
|
|
174
252
|
});
|
|
175
253
|
|
|
176
|
-
it("sends automatic
|
|
254
|
+
it("sends automatic insights only from init when enabled", async () => {
|
|
177
255
|
vi.useFakeTimers();
|
|
178
256
|
|
|
179
257
|
vi.stubGlobal(
|
|
@@ -205,11 +283,11 @@ describe("HotUpdater wrap initialization", () => {
|
|
|
205
283
|
username: "alice",
|
|
206
284
|
});
|
|
207
285
|
|
|
208
|
-
const { client,
|
|
286
|
+
const { client, sendInsightsEvent } = createClient();
|
|
209
287
|
const { init } = await import("./wrap");
|
|
210
288
|
|
|
211
289
|
init({
|
|
212
|
-
|
|
290
|
+
insights: true,
|
|
213
291
|
requestHeaders: {
|
|
214
292
|
Authorization: "Bearer token",
|
|
215
293
|
},
|
|
@@ -219,7 +297,7 @@ describe("HotUpdater wrap initialization", () => {
|
|
|
219
297
|
|
|
220
298
|
await vi.runOnlyPendingTimersAsync();
|
|
221
299
|
|
|
222
|
-
expect(
|
|
300
|
+
expect(sendInsightsEvent).toHaveBeenCalledWith({
|
|
223
301
|
appVersion: "1.0.0",
|
|
224
302
|
channel: "production",
|
|
225
303
|
cohort: "123",
|
|
@@ -241,7 +319,7 @@ describe("HotUpdater wrap initialization", () => {
|
|
|
241
319
|
});
|
|
242
320
|
});
|
|
243
321
|
|
|
244
|
-
it("guards automatic
|
|
322
|
+
it("guards automatic insights to a single delivery attempt per runtime", async () => {
|
|
245
323
|
vi.useFakeTimers();
|
|
246
324
|
|
|
247
325
|
vi.stubGlobal(
|
|
@@ -268,18 +346,18 @@ describe("HotUpdater wrap initialization", () => {
|
|
|
268
346
|
),
|
|
269
347
|
);
|
|
270
348
|
|
|
271
|
-
const { client,
|
|
349
|
+
const { client, sendInsightsEvent } = createClient();
|
|
272
350
|
const { init } = await import("./wrap");
|
|
273
351
|
|
|
274
|
-
init({
|
|
275
|
-
init({
|
|
352
|
+
init({ insights: true, client });
|
|
353
|
+
init({ insights: true, client });
|
|
276
354
|
|
|
277
355
|
await vi.runOnlyPendingTimersAsync();
|
|
278
356
|
|
|
279
|
-
expect(
|
|
357
|
+
expect(sendInsightsEvent).toHaveBeenCalledTimes(1);
|
|
280
358
|
});
|
|
281
359
|
|
|
282
|
-
it("warns without interrupting app readiness when
|
|
360
|
+
it("warns without interrupting app readiness when insights transport fails", async () => {
|
|
283
361
|
vi.useFakeTimers();
|
|
284
362
|
|
|
285
363
|
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
@@ -312,7 +390,7 @@ describe("HotUpdater wrap initialization", () => {
|
|
|
312
390
|
const { init } = await import("./wrap");
|
|
313
391
|
|
|
314
392
|
init({
|
|
315
|
-
|
|
393
|
+
insights: true,
|
|
316
394
|
onError,
|
|
317
395
|
onNotifyAppReady,
|
|
318
396
|
client,
|
|
@@ -322,7 +400,7 @@ describe("HotUpdater wrap initialization", () => {
|
|
|
322
400
|
|
|
323
401
|
expect(onError).not.toHaveBeenCalled();
|
|
324
402
|
expect(warn).toHaveBeenCalledWith(
|
|
325
|
-
"[HotUpdater] Automatic notifyAppReady
|
|
403
|
+
"[HotUpdater] Automatic notifyAppReady insights failed:",
|
|
326
404
|
error,
|
|
327
405
|
);
|
|
328
406
|
expect(onNotifyAppReady).toHaveBeenCalledWith({
|
|
@@ -344,14 +422,14 @@ describe("HotUpdater wrap initialization", () => {
|
|
|
344
422
|
|
|
345
423
|
it("preserves wrapped component prop inference", async () => {
|
|
346
424
|
const { wrap } = await import("./wrap");
|
|
347
|
-
const Component:
|
|
425
|
+
const Component: ComponentType<{ title: string }> = () => null;
|
|
348
426
|
|
|
349
427
|
const WrappedComponent = wrap({
|
|
350
428
|
client: createClient().client,
|
|
351
429
|
updateStrategy: "appVersion",
|
|
352
430
|
})(Component);
|
|
353
431
|
|
|
354
|
-
const acceptsTitleProps:
|
|
432
|
+
const acceptsTitleProps: ComponentType<{ title: string }> =
|
|
355
433
|
WrappedComponent;
|
|
356
434
|
expect(acceptsTitleProps).toBe(WrappedComponent);
|
|
357
435
|
});
|