@hot-updater/react-native 1.0.0-rc.14 → 1.0.0-rc.16
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 +2 -2
- package/android/src/main/java/com/hotupdater/BuiltInAssetResolver.kt +286 -0
- package/android/src/main/java/com/hotupdater/BundleFileStorageService.kt +650 -636
- package/android/src/main/java/com/hotupdater/BundleMetadata.kt +3 -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/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/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 +47 -31
- 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/lib/commonjs/checkForUpdate.js +7 -10
- package/lib/commonjs/checkForUpdate.js.map +1 -1
- package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js +9 -4
- 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 +151 -39
- package/lib/commonjs/httpClient.js.map +1 -1
- package/lib/commonjs/httpClient.spec.js +247 -5
- package/lib/commonjs/httpClient.spec.js.map +1 -1
- package/lib/commonjs/index.js +15 -8
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.spec.js +101 -0
- package/lib/commonjs/index.spec.js.map +1 -1
- package/lib/commonjs/native.js +7 -8
- package/lib/commonjs/native.js.map +1 -1
- package/lib/commonjs/native.spec.js +21 -16
- package/lib/commonjs/native.spec.js.map +1 -1
- package/lib/commonjs/notifyAppReadyInsights.boundary.spec.js +7 -0
- package/lib/commonjs/notifyAppReadyInsights.boundary.spec.js.map +1 -1
- package/lib/commonjs/notifyAppReadyInsights.js +4 -1
- package/lib/commonjs/notifyAppReadyInsights.js.map +1 -1
- package/lib/commonjs/notifyAppReadyInsights.spec.js +59 -0
- package/lib/commonjs/notifyAppReadyInsights.spec.js.map +1 -1
- package/lib/commonjs/notifyAppReadyInsights.transport.spec.js +55 -1
- package/lib/commonjs/notifyAppReadyInsights.transport.spec.js.map +1 -1
- package/lib/commonjs/sdkVersion.js +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/uuidv7.js +41 -0
- package/lib/commonjs/uuidv7.js.map +1 -0
- package/lib/commonjs/uuidv7.spec.js +30 -0
- package/lib/commonjs/uuidv7.spec.js.map +1 -0
- package/lib/commonjs/wrap.js +1 -3
- package/lib/commonjs/wrap.js.map +1 -1
- package/lib/commonjs/wrap.spec.js +7 -0
- package/lib/commonjs/wrap.spec.js.map +1 -1
- package/lib/module/checkForUpdate.js +7 -10
- package/lib/module/checkForUpdate.js.map +1 -1
- package/lib/module/checkForUpdate.releaseCatalog.spec.js +9 -4
- 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 +153 -41
- package/lib/module/httpClient.js.map +1 -1
- package/lib/module/httpClient.spec.js +248 -6
- package/lib/module/httpClient.spec.js.map +1 -1
- package/lib/module/index.js +15 -8
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.spec.js +102 -1
- package/lib/module/index.spec.js.map +1 -1
- package/lib/module/native.js +7 -8
- package/lib/module/native.js.map +1 -1
- package/lib/module/native.spec.js +21 -16
- package/lib/module/native.spec.js.map +1 -1
- package/lib/module/notifyAppReadyInsights.boundary.spec.js +7 -0
- package/lib/module/notifyAppReadyInsights.boundary.spec.js.map +1 -1
- package/lib/module/notifyAppReadyInsights.js +5 -2
- package/lib/module/notifyAppReadyInsights.js.map +1 -1
- package/lib/module/notifyAppReadyInsights.spec.js +59 -0
- package/lib/module/notifyAppReadyInsights.spec.js.map +1 -1
- package/lib/module/notifyAppReadyInsights.transport.spec.js +55 -1
- package/lib/module/notifyAppReadyInsights.transport.spec.js.map +1 -1
- package/lib/module/sdkVersion.js +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/uuidv7.js +36 -0
- package/lib/module/uuidv7.js.map +1 -0
- package/lib/module/uuidv7.spec.js +30 -0
- package/lib/module/uuidv7.spec.js.map +1 -0
- package/lib/module/wrap.js +1 -3
- package/lib/module/wrap.js.map +1 -1
- package/lib/module/wrap.spec.js +7 -0
- package/lib/module/wrap.spec.js.map +1 -1
- package/lib/typescript/commonjs/checkForUpdate.d.ts +1 -2
- 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 -0
- package/lib/typescript/commonjs/httpClient.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +0 -2
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/native.d.ts +1 -6
- package/lib/typescript/commonjs/native.d.ts.map +1 -1
- package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts +1 -1
- package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts.map +1 -1
- package/lib/typescript/commonjs/sdkVersion.d.ts +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/uuidv7.d.ts +10 -0
- package/lib/typescript/commonjs/uuidv7.d.ts.map +1 -0
- package/lib/typescript/commonjs/wrap.d.ts.map +1 -1
- package/lib/typescript/commonjs/wrap.types.d.ts +7 -4
- package/lib/typescript/commonjs/wrap.types.d.ts.map +1 -1
- package/lib/typescript/module/checkForUpdate.d.ts +1 -2
- 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 -0
- package/lib/typescript/module/httpClient.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +0 -2
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/native.d.ts +1 -6
- package/lib/typescript/module/native.d.ts.map +1 -1
- package/lib/typescript/module/notifyAppReadyInsights.d.ts +1 -1
- package/lib/typescript/module/notifyAppReadyInsights.d.ts.map +1 -1
- package/lib/typescript/module/sdkVersion.d.ts +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/uuidv7.d.ts +10 -0
- package/lib/typescript/module/uuidv7.d.ts.map +1 -0
- package/lib/typescript/module/wrap.d.ts.map +1 -1
- package/lib/typescript/module/wrap.types.d.ts +7 -4
- package/lib/typescript/module/wrap.types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/checkForUpdate.releaseCatalog.spec.ts +10 -4
- package/src/checkForUpdate.ts +5 -11
- package/src/error.ts +4 -14
- package/src/fetchJSON.ts +12 -1
- package/src/httpClient.spec.ts +289 -8
- package/src/httpClient.ts +224 -67
- package/src/index.spec.ts +70 -1
- package/src/index.ts +18 -7
- package/src/native.spec.ts +23 -16
- package/src/native.ts +12 -24
- package/src/notifyAppReadyInsights.boundary.spec.ts +8 -0
- package/src/notifyAppReadyInsights.spec.ts +60 -0
- package/src/notifyAppReadyInsights.transport.spec.ts +66 -0
- package/src/notifyAppReadyInsights.ts +13 -1
- 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/uuidv7.spec.ts +25 -0
- package/src/uuidv7.ts +38 -0
- package/src/wrap.spec.ts +8 -0
- package/src/wrap.tsx +0 -2
- package/src/wrap.types.ts +9 -4
- 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/src/index.spec.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
2
|
|
|
3
3
|
import type { HotUpdaterInitOptions, HotUpdaterOptions } from "./wrap";
|
|
4
4
|
|
|
@@ -31,6 +31,7 @@ const mocks = vi.hoisted(() => {
|
|
|
31
31
|
getInstallId: vi.fn(() => "install-id"),
|
|
32
32
|
getManifest: vi.fn(() => null),
|
|
33
33
|
getMinBundleId: vi.fn(() => "min-bundle-id"),
|
|
34
|
+
getPersistedUserIdentity: vi.fn(() => ({})),
|
|
34
35
|
init: vi.fn(),
|
|
35
36
|
isChannelSwitched: vi.fn(() => false),
|
|
36
37
|
notifyAppReady: vi.fn(() => ({ status: "UNCHANGED" as const })),
|
|
@@ -71,6 +72,7 @@ vi.mock("./native", () => ({
|
|
|
71
72
|
getInstallId: mocks.getInstallId,
|
|
72
73
|
getManifest: mocks.getManifest,
|
|
73
74
|
getMinBundleId: mocks.getMinBundleId,
|
|
75
|
+
getPersistedUserIdentity: mocks.getPersistedUserIdentity,
|
|
74
76
|
isChannelSwitched: mocks.isChannelSwitched,
|
|
75
77
|
notifyAppReady: mocks.notifyAppReady,
|
|
76
78
|
reload: mocks.reload,
|
|
@@ -99,6 +101,11 @@ describe("HotUpdater client initialization", () => {
|
|
|
99
101
|
mocks.wrap.mockImplementation((Component: unknown) => Component);
|
|
100
102
|
});
|
|
101
103
|
|
|
104
|
+
afterEach(() => {
|
|
105
|
+
vi.unstubAllGlobals();
|
|
106
|
+
vi.restoreAllMocks();
|
|
107
|
+
});
|
|
108
|
+
|
|
102
109
|
it("exposes the console ID through the existing getter only", async () => {
|
|
103
110
|
const HotUpdater = await importHotUpdater();
|
|
104
111
|
|
|
@@ -178,6 +185,68 @@ describe("HotUpdater client initialization", () => {
|
|
|
178
185
|
);
|
|
179
186
|
});
|
|
180
187
|
|
|
188
|
+
it.each([
|
|
189
|
+
{ dev: true, insights: undefined, expected: false },
|
|
190
|
+
{ dev: true, insights: true, expected: false },
|
|
191
|
+
{ dev: true, insights: false, expected: false },
|
|
192
|
+
{ dev: true, insights: { debug: true }, expected: true },
|
|
193
|
+
{ dev: false, insights: { debug: true }, expected: true },
|
|
194
|
+
{ dev: false, insights: { debug: false }, expected: true },
|
|
195
|
+
{ dev: false, insights: false, expected: false },
|
|
196
|
+
] as const)(
|
|
197
|
+
"resolves insights $insights to $expected when __DEV__ is $dev",
|
|
198
|
+
async ({ dev, insights, expected }) => {
|
|
199
|
+
vi.stubGlobal("__DEV__", dev);
|
|
200
|
+
vi.spyOn(console, "error").mockImplementation(() => undefined);
|
|
201
|
+
const HotUpdater = await importHotUpdater();
|
|
202
|
+
|
|
203
|
+
HotUpdater.init({ baseURL: "https://updates.example.com", insights });
|
|
204
|
+
HotUpdater.wrap({
|
|
205
|
+
baseURL: "https://updates.example.com",
|
|
206
|
+
insights,
|
|
207
|
+
updateStrategy: "appVersion",
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
expect(mocks.init).toHaveBeenCalledWith(
|
|
211
|
+
expect.objectContaining({ insights: expected }),
|
|
212
|
+
);
|
|
213
|
+
expect(mocks.wrap).toHaveBeenCalledWith(
|
|
214
|
+
expect.objectContaining({ insights: expected }),
|
|
215
|
+
);
|
|
216
|
+
},
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
it.each([
|
|
220
|
+
{ dev: true, reports: false },
|
|
221
|
+
{ dev: false, reports: true },
|
|
222
|
+
])(
|
|
223
|
+
"gates manual checks and downloads on the build type (__DEV__: $dev)",
|
|
224
|
+
async ({ dev, reports }) => {
|
|
225
|
+
vi.stubGlobal("__DEV__", dev);
|
|
226
|
+
const sendInsightsEvent = vi.fn(async () => undefined);
|
|
227
|
+
mocks.createHttpClient.mockReturnValue({
|
|
228
|
+
createSession: vi.fn(async () => ({ sendInsightsEvent })),
|
|
229
|
+
} as never);
|
|
230
|
+
mocks.updateBundle.mockResolvedValueOnce(true);
|
|
231
|
+
const HotUpdater = await importHotUpdater();
|
|
232
|
+
HotUpdater.init({ baseURL: "https://updates.example.com" });
|
|
233
|
+
|
|
234
|
+
await HotUpdater.checkForUpdate({ updateStrategy: "appVersion" });
|
|
235
|
+
await HotUpdater.updateBundle({
|
|
236
|
+
assets: {},
|
|
237
|
+
bundleId: "next-bundle-id",
|
|
238
|
+
manifestFileHash: "manifest-hash",
|
|
239
|
+
manifestUrl: "https://updates.example.com/manifest.json",
|
|
240
|
+
status: "UPDATE",
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
expect(mocks.checkForUpdate).toHaveBeenCalledWith(
|
|
244
|
+
expect.objectContaining({ insights: reports }),
|
|
245
|
+
);
|
|
246
|
+
expect(sendInsightsEvent).toHaveBeenCalledTimes(reports ? 1 : 0);
|
|
247
|
+
},
|
|
248
|
+
);
|
|
249
|
+
|
|
181
250
|
it("requires baseURL and rejects the removed resolver shape", async () => {
|
|
182
251
|
const HotUpdater = await importHotUpdater();
|
|
183
252
|
|
package/src/index.ts
CHANGED
|
@@ -93,6 +93,21 @@ type HotUpdaterWrap = {
|
|
|
93
93
|
(options: HotUpdaterOptions): ReturnType<typeof wrap>;
|
|
94
94
|
};
|
|
95
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Debug builds report only with `insights: { debug: true }`, so development
|
|
98
|
+
* sessions do not mix into production Insights. `__DEV__` is defined only in
|
|
99
|
+
* a React Native bundle; anywhere else, such as unit tests, counts as release.
|
|
100
|
+
*/
|
|
101
|
+
const resolveInsights = (
|
|
102
|
+
insights: HotUpdaterInitOptions["insights"],
|
|
103
|
+
): boolean => {
|
|
104
|
+
if (insights === false) return false;
|
|
105
|
+
const isDebugBuild = typeof __DEV__ !== "undefined" && __DEV__;
|
|
106
|
+
return (
|
|
107
|
+
!isDebugBuild || (typeof insights === "object" && insights?.debug === true)
|
|
108
|
+
);
|
|
109
|
+
};
|
|
110
|
+
|
|
96
111
|
/**
|
|
97
112
|
* Creates a HotUpdater client instance with all update management methods.
|
|
98
113
|
* This function is called once on module initialization to create a singleton instance.
|
|
@@ -161,7 +176,7 @@ function createHotUpdaterClient() {
|
|
|
161
176
|
const { baseURL, ...rest } = autoOptions;
|
|
162
177
|
return {
|
|
163
178
|
...rest,
|
|
164
|
-
insights: rest.insights
|
|
179
|
+
insights: resolveInsights(rest.insights),
|
|
165
180
|
client: createHttpClient(baseURL),
|
|
166
181
|
};
|
|
167
182
|
}
|
|
@@ -181,7 +196,7 @@ function createHotUpdaterClient() {
|
|
|
181
196
|
const { baseURL, ...baseURLRest } = rest;
|
|
182
197
|
return {
|
|
183
198
|
...baseURLRest,
|
|
184
|
-
insights: baseURLRest.insights
|
|
199
|
+
insights: resolveInsights(baseURLRest.insights),
|
|
185
200
|
client: createHttpClient(baseURL),
|
|
186
201
|
};
|
|
187
202
|
}
|
|
@@ -469,8 +484,6 @@ function createHotUpdaterClient() {
|
|
|
469
484
|
*
|
|
470
485
|
* @param {UpdateBundleParams} params - Parameters object required for bundle update
|
|
471
486
|
* @param {string} params.bundleId - The bundle ID of the app
|
|
472
|
-
* @param {string|null} params.fileUrl - The URL of the zip file
|
|
473
|
-
*
|
|
474
487
|
* @returns {Promise<boolean>} Whether the update was successful
|
|
475
488
|
*
|
|
476
489
|
* @example
|
|
@@ -500,7 +513,7 @@ function createHotUpdaterClient() {
|
|
|
500
513
|
const state = getActiveUpdateState();
|
|
501
514
|
const active = state.activeSelection;
|
|
502
515
|
const downloaded = await updateBundle(params);
|
|
503
|
-
if (downloaded
|
|
516
|
+
if (downloaded) {
|
|
504
517
|
const selection = getActiveUpdateState().activeSelection;
|
|
505
518
|
await reportBundleDownloaded(
|
|
506
519
|
{ ...globalConfig, client },
|
|
@@ -535,10 +548,8 @@ function createHotUpdaterClient() {
|
|
|
535
548
|
hotUpdaterStore.setState({
|
|
536
549
|
artifactType: null,
|
|
537
550
|
details: null,
|
|
538
|
-
downloadedBytes: undefined,
|
|
539
551
|
isUpdateDownloaded: false,
|
|
540
552
|
progress: 0,
|
|
541
|
-
totalBytes: undefined,
|
|
542
553
|
});
|
|
543
554
|
}
|
|
544
555
|
return ok;
|
package/src/native.spec.ts
CHANGED
|
@@ -538,13 +538,20 @@ describe("notifyAppReady", () => {
|
|
|
538
538
|
expect(getBaseURL()).toBe("file:///bundle-123");
|
|
539
539
|
|
|
540
540
|
await updateBundle({
|
|
541
|
+
assets: {},
|
|
541
542
|
bundleId: "bundle-456",
|
|
542
|
-
|
|
543
|
-
|
|
543
|
+
archiveUrl: "https://example.com/bundle.tar.br",
|
|
544
|
+
manifestFileHash: "manifest-hash",
|
|
545
|
+
manifestUrl: "https://example.com/manifest.json",
|
|
544
546
|
status: "UPDATE",
|
|
545
547
|
});
|
|
546
548
|
|
|
547
549
|
expect(getBundleId()).toBe("bundle-123");
|
|
550
|
+
expect(nativeModuleMock.updateBundle).toHaveBeenCalledWith(
|
|
551
|
+
expect.objectContaining({
|
|
552
|
+
archiveUrl: "https://example.com/bundle.tar.br",
|
|
553
|
+
}),
|
|
554
|
+
);
|
|
548
555
|
expect(getManifest()).toEqual({
|
|
549
556
|
assets: {},
|
|
550
557
|
bundleId: "bundle-123",
|
|
@@ -571,9 +578,10 @@ describe("notifyAppReady", () => {
|
|
|
571
578
|
const { getBundleId, updateBundle } = await import("./native");
|
|
572
579
|
|
|
573
580
|
await updateBundle({
|
|
581
|
+
assets: {},
|
|
574
582
|
bundleId: "00000000-0000-0000-0000-000000000003",
|
|
575
|
-
|
|
576
|
-
|
|
583
|
+
manifestFileHash: "manifest-hash",
|
|
584
|
+
manifestUrl: "https://example.com/manifest.json",
|
|
577
585
|
status: "UPDATE",
|
|
578
586
|
});
|
|
579
587
|
|
|
@@ -586,9 +594,10 @@ describe("notifyAppReady", () => {
|
|
|
586
594
|
|
|
587
595
|
await expect(
|
|
588
596
|
updateBundle({
|
|
597
|
+
assets: {},
|
|
589
598
|
bundleId: "00000000-0000-0000-0000-000000000003",
|
|
590
|
-
|
|
591
|
-
|
|
599
|
+
manifestFileHash: "manifest-hash",
|
|
600
|
+
manifestUrl: "https://example.com/manifest.json",
|
|
592
601
|
status: "UPDATE",
|
|
593
602
|
}),
|
|
594
603
|
).resolves.toBe(true);
|
|
@@ -612,9 +621,10 @@ describe("notifyAppReady", () => {
|
|
|
612
621
|
const { updateBundle } = await import("./native");
|
|
613
622
|
|
|
614
623
|
await updateBundle({
|
|
624
|
+
assets: {},
|
|
615
625
|
bundleId: "00000000-0000-0000-0000-000000000003",
|
|
616
|
-
|
|
617
|
-
|
|
626
|
+
manifestFileHash: "manifest-hash",
|
|
627
|
+
manifestUrl: "https://example.com/manifest.json",
|
|
618
628
|
status: "UPDATE",
|
|
619
629
|
});
|
|
620
630
|
|
|
@@ -624,9 +634,10 @@ describe("notifyAppReady", () => {
|
|
|
624
634
|
|
|
625
635
|
await expect(
|
|
626
636
|
updateBundle({
|
|
637
|
+
assets: {},
|
|
627
638
|
bundleId: "00000000-0000-0000-0000-000000000003",
|
|
628
|
-
|
|
629
|
-
|
|
639
|
+
manifestFileHash: "manifest-hash",
|
|
640
|
+
manifestUrl: "https://example.com/manifest.json",
|
|
630
641
|
status: "UPDATE",
|
|
631
642
|
}),
|
|
632
643
|
).resolves.toBe(true);
|
|
@@ -642,7 +653,7 @@ describe("notifyAppReady", () => {
|
|
|
642
653
|
|
|
643
654
|
await updateBundle({
|
|
644
655
|
bundleId: "bundle-789",
|
|
645
|
-
|
|
656
|
+
assets: {
|
|
646
657
|
"index.ios.bundle": {
|
|
647
658
|
file: {
|
|
648
659
|
compression: "br",
|
|
@@ -658,8 +669,6 @@ describe("notifyAppReady", () => {
|
|
|
658
669
|
},
|
|
659
670
|
},
|
|
660
671
|
},
|
|
661
|
-
fileHash: "sig:archive",
|
|
662
|
-
fileUrl: "https://example.com/bundle.zip",
|
|
663
672
|
manifestFileHash: "sig:manifest",
|
|
664
673
|
manifestUrl: "https://example.com/manifest.json",
|
|
665
674
|
status: "UPDATE",
|
|
@@ -667,7 +676,7 @@ describe("notifyAppReady", () => {
|
|
|
667
676
|
|
|
668
677
|
expect(nativeModuleMock.updateBundle).toHaveBeenCalledWith({
|
|
669
678
|
bundleId: "bundle-789",
|
|
670
|
-
|
|
679
|
+
assets: {
|
|
671
680
|
"index.ios.bundle": {
|
|
672
681
|
file: {
|
|
673
682
|
compression: "br",
|
|
@@ -684,8 +693,6 @@ describe("notifyAppReady", () => {
|
|
|
684
693
|
},
|
|
685
694
|
},
|
|
686
695
|
channel: undefined,
|
|
687
|
-
fileHash: "sig:archive",
|
|
688
|
-
fileUrl: "https://example.com/bundle.zip",
|
|
689
696
|
manifestFileHash: "sig:manifest",
|
|
690
697
|
manifestUrl: "https://example.com/manifest.json",
|
|
691
698
|
});
|
package/src/native.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
-
type
|
|
2
|
+
type ArtifactAsset,
|
|
3
3
|
type CatalogHighWater,
|
|
4
4
|
INVALID_COHORT_ERROR_MESSAGE,
|
|
5
5
|
isValidCohort,
|
|
@@ -234,7 +234,7 @@ const getReloadProcess = (): (() => Promise<void>) | null => {
|
|
|
234
234
|
: null;
|
|
235
235
|
};
|
|
236
236
|
|
|
237
|
-
export type HotUpdaterProgressArtifactType = "
|
|
237
|
+
export type HotUpdaterProgressArtifactType = "diff";
|
|
238
238
|
|
|
239
239
|
export type HotUpdaterDiffFileStatus =
|
|
240
240
|
| "pending"
|
|
@@ -286,18 +286,11 @@ export interface HotUpdaterDiffProgressDetails {
|
|
|
286
286
|
files: HotUpdaterDiffFileSnapshot[];
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
-
export type HotUpdaterProgressEvent =
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
totalBytes?: number;
|
|
295
|
-
}
|
|
296
|
-
| {
|
|
297
|
-
progress: number;
|
|
298
|
-
artifactType: "diff";
|
|
299
|
-
details: HotUpdaterDiffProgressDetails;
|
|
300
|
-
};
|
|
289
|
+
export type HotUpdaterProgressEvent = {
|
|
290
|
+
progress: number;
|
|
291
|
+
artifactType: "diff";
|
|
292
|
+
details: HotUpdaterDiffProgressDetails;
|
|
293
|
+
};
|
|
301
294
|
|
|
302
295
|
export type HotUpdaterEvent = {
|
|
303
296
|
onProgress: HotUpdaterProgressEvent;
|
|
@@ -434,8 +427,6 @@ export const commitReleaseSelection = async (input: {
|
|
|
434
427
|
export async function updateBundle(params: UpdateParams): Promise<boolean> {
|
|
435
428
|
const updateBundleId = params.bundleId;
|
|
436
429
|
const status = params.status;
|
|
437
|
-
const targetFileUrl = params.fileUrl;
|
|
438
|
-
|
|
439
430
|
const currentBundleId = status === "UPDATE" ? getFreshBundleId() : undefined;
|
|
440
431
|
|
|
441
432
|
// If native is still on the same bundle we installed in this session,
|
|
@@ -467,11 +458,10 @@ export async function updateBundle(params: UpdateParams): Promise<boolean> {
|
|
|
467
458
|
const existing = sessionState.getInflightUpdate(updateBundleId);
|
|
468
459
|
if (existing) return existing;
|
|
469
460
|
|
|
470
|
-
const targetFileHash = params.fileHash;
|
|
471
461
|
const targetChannel = params.channel;
|
|
472
462
|
const targetManifestUrl = params.manifestUrl;
|
|
473
463
|
const targetManifestFileHash = params.manifestFileHash;
|
|
474
|
-
const
|
|
464
|
+
const targetAssets = params.assets;
|
|
475
465
|
|
|
476
466
|
const promise = (async () => {
|
|
477
467
|
try {
|
|
@@ -479,12 +469,10 @@ export async function updateBundle(params: UpdateParams): Promise<boolean> {
|
|
|
479
469
|
const ok = await HotUpdaterNative.updateBundle({
|
|
480
470
|
bundleId: updateBundleId,
|
|
481
471
|
channel: targetChannel,
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
manifestFileHash: targetManifestFileHash ?? null,
|
|
487
|
-
manifestUrl: targetManifestUrl ?? null,
|
|
472
|
+
assets: targetAssets as Record<string, ArtifactAsset>,
|
|
473
|
+
manifestFileHash: targetManifestFileHash,
|
|
474
|
+
manifestUrl: targetManifestUrl,
|
|
475
|
+
...(params.archiveUrl ? { archiveUrl: params.archiveUrl } : {}),
|
|
488
476
|
...(selection === undefined ? {} : { selection }),
|
|
489
477
|
});
|
|
490
478
|
if (ok) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
2
|
|
|
3
3
|
import type {
|
|
4
|
+
ActiveUpdateState,
|
|
4
5
|
NotifyAppReadyInsightsEvent,
|
|
5
6
|
NotifyAppReadyResult,
|
|
6
7
|
} from "./native";
|
|
@@ -42,6 +43,7 @@ const mocks = vi.hoisted(() => ({
|
|
|
42
43
|
getAppVersion: vi.fn<() => string | undefined>(() => "1.0.0"),
|
|
43
44
|
getBundleId: vi.fn<() => string | undefined>(() => "bundle-id"),
|
|
44
45
|
getChannel: vi.fn(() => "production"),
|
|
46
|
+
getActiveUpdateState: vi.fn<() => ActiveUpdateState>(),
|
|
45
47
|
getCohort: vi.fn(() => "123"),
|
|
46
48
|
getFingerprintHash: vi.fn(() => "fingerprint-hash"),
|
|
47
49
|
getInstallId: vi.fn<() => string | undefined>(() => "install-id"),
|
|
@@ -65,6 +67,7 @@ vi.mock("./native", () => ({
|
|
|
65
67
|
getAppVersion: mocks.getAppVersion,
|
|
66
68
|
getBundleId: mocks.getBundleId,
|
|
67
69
|
getChannel: mocks.getChannel,
|
|
70
|
+
getActiveUpdateState: mocks.getActiveUpdateState,
|
|
68
71
|
getCohort: mocks.getCohort,
|
|
69
72
|
getFingerprintHash: mocks.getFingerprintHash,
|
|
70
73
|
getInstallId: mocks.getInstallId,
|
|
@@ -106,6 +109,11 @@ describe("automatic notifyAppReady insights boundaries", () => {
|
|
|
106
109
|
mocks.getAppVersion.mockReturnValue("1.0.0");
|
|
107
110
|
mocks.getBundleId.mockReturnValue("bundle-id");
|
|
108
111
|
mocks.getChannel.mockReturnValue("production");
|
|
112
|
+
mocks.getActiveUpdateState.mockReturnValue({
|
|
113
|
+
activeSelection: null,
|
|
114
|
+
stableSelection: null,
|
|
115
|
+
verificationPending: false,
|
|
116
|
+
});
|
|
109
117
|
mocks.getCohort.mockReturnValue("123");
|
|
110
118
|
mocks.getFingerprintHash.mockReturnValue("fingerprint-hash");
|
|
111
119
|
mocks.getInstallId.mockReturnValue("install-id");
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
2
|
|
|
3
3
|
import type {
|
|
4
|
+
ActiveUpdateState,
|
|
4
5
|
NotifyAppReadyInsightsEvent,
|
|
5
6
|
NotifyAppReadyResult,
|
|
6
7
|
} from "./native";
|
|
@@ -19,6 +20,7 @@ const mocks = vi.hoisted(() => ({
|
|
|
19
20
|
getAppVersion: vi.fn(() => "1.0.0"),
|
|
20
21
|
getBundleId: vi.fn(() => "bundle-id"),
|
|
21
22
|
getChannel: vi.fn(() => "production"),
|
|
23
|
+
getActiveUpdateState: vi.fn<() => ActiveUpdateState>(),
|
|
22
24
|
getCohort: vi.fn(() => "123"),
|
|
23
25
|
getFingerprintHash: vi.fn(() => "fingerprint-hash"),
|
|
24
26
|
getInstallId: vi.fn(() => "install-id"),
|
|
@@ -42,6 +44,7 @@ vi.mock("./native", () => ({
|
|
|
42
44
|
getAppVersion: mocks.getAppVersion,
|
|
43
45
|
getBundleId: mocks.getBundleId,
|
|
44
46
|
getChannel: mocks.getChannel,
|
|
47
|
+
getActiveUpdateState: mocks.getActiveUpdateState,
|
|
45
48
|
getCohort: mocks.getCohort,
|
|
46
49
|
getFingerprintHash: mocks.getFingerprintHash,
|
|
47
50
|
getInstallId: mocks.getInstallId,
|
|
@@ -78,6 +81,11 @@ describe("automatic notifyAppReady insights", () => {
|
|
|
78
81
|
mocks.addListener.mockReturnValue(() => {});
|
|
79
82
|
mocks.getBundleId.mockReturnValue("bundle-id");
|
|
80
83
|
mocks.getChannel.mockReturnValue("production");
|
|
84
|
+
mocks.getActiveUpdateState.mockReturnValue({
|
|
85
|
+
activeSelection: null,
|
|
86
|
+
stableSelection: null,
|
|
87
|
+
verificationPending: false,
|
|
88
|
+
});
|
|
81
89
|
mocks.getCohort.mockReturnValue("123");
|
|
82
90
|
mocks.getFingerprintHash.mockReturnValue("fingerprint-hash");
|
|
83
91
|
mocks.getInstallId.mockReturnValue("install-id");
|
|
@@ -85,6 +93,58 @@ describe("automatic notifyAppReady insights", () => {
|
|
|
85
93
|
mocks.readNotifyAppReady.mockReturnValue(createNotifyReadResult());
|
|
86
94
|
});
|
|
87
95
|
|
|
96
|
+
it.each([
|
|
97
|
+
{
|
|
98
|
+
label: "running selection",
|
|
99
|
+
pending: false,
|
|
100
|
+
channel: "production",
|
|
101
|
+
expected: "release-running",
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
label: "staged selection",
|
|
105
|
+
pending: true,
|
|
106
|
+
channel: "production",
|
|
107
|
+
expected: "release-running",
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
label: "another channel",
|
|
111
|
+
pending: false,
|
|
112
|
+
channel: "preview",
|
|
113
|
+
expected: null,
|
|
114
|
+
},
|
|
115
|
+
])(
|
|
116
|
+
"attributes an unchanged launch with $label",
|
|
117
|
+
async ({ pending, channel, expected }) => {
|
|
118
|
+
const running = {
|
|
119
|
+
kind: "BUNDLE" as const,
|
|
120
|
+
releaseId: "release-running",
|
|
121
|
+
bundleId: "bundle-id",
|
|
122
|
+
channel,
|
|
123
|
+
};
|
|
124
|
+
mocks.getActiveUpdateState.mockReturnValue({
|
|
125
|
+
activeSelection: pending
|
|
126
|
+
? {
|
|
127
|
+
...running,
|
|
128
|
+
releaseId: "release-pending",
|
|
129
|
+
bundleId: "bundle-pending",
|
|
130
|
+
}
|
|
131
|
+
: running,
|
|
132
|
+
stableSelection: pending ? running : null,
|
|
133
|
+
verificationPending: pending,
|
|
134
|
+
});
|
|
135
|
+
const { reportNoChange } = await import("./notifyAppReadyInsights");
|
|
136
|
+
const { client, sendInsightsEvent } = createClient();
|
|
137
|
+
await reportNoChange({ client, insights: true });
|
|
138
|
+
expect(sendInsightsEvent).toHaveBeenCalledWith(
|
|
139
|
+
expect.objectContaining({
|
|
140
|
+
type: "UNCHANGED",
|
|
141
|
+
toBundleId: "bundle-id",
|
|
142
|
+
toReleaseId: expected,
|
|
143
|
+
}),
|
|
144
|
+
);
|
|
145
|
+
},
|
|
146
|
+
);
|
|
147
|
+
|
|
88
148
|
it("orders download after in-flight startup reporting and suppresses a later no-change report", async () => {
|
|
89
149
|
const { handleNotifyAppReady, reportBundleDownloaded, reportNoChange } =
|
|
90
150
|
await import("./notifyAppReadyInsights");
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
2
|
|
|
3
3
|
import type {
|
|
4
|
+
ActiveUpdateState,
|
|
4
5
|
NotifyAppReadyInsightsEvent,
|
|
5
6
|
NotifyAppReadyResult,
|
|
6
7
|
} from "./native";
|
|
@@ -16,6 +17,9 @@ vi.mock("react-native", () => ({
|
|
|
16
17
|
const failureCases = [
|
|
17
18
|
{ label: "400", responseStatus: 400 },
|
|
18
19
|
{ label: "404", responseStatus: 404 },
|
|
20
|
+
] as const;
|
|
21
|
+
|
|
22
|
+
const retryableFailureCases = [
|
|
19
23
|
{ label: "500", responseStatus: 500 },
|
|
20
24
|
{
|
|
21
25
|
error: Object.assign(new Error("request aborted"), { name: "AbortError" }),
|
|
@@ -30,6 +34,7 @@ const mocks = vi.hoisted(() => ({
|
|
|
30
34
|
getAppVersion: vi.fn(() => "1.0.0"),
|
|
31
35
|
getBundleId: vi.fn(() => "bundle-id"),
|
|
32
36
|
getChannel: vi.fn(() => "production"),
|
|
37
|
+
getActiveUpdateState: vi.fn<() => ActiveUpdateState>(),
|
|
33
38
|
getCohort: vi.fn(() => "123"),
|
|
34
39
|
getFingerprintHash: vi.fn(() => "fingerprint-hash"),
|
|
35
40
|
getInstallId: vi.fn(() => "install-id"),
|
|
@@ -53,6 +58,7 @@ vi.mock("./native", () => ({
|
|
|
53
58
|
getAppVersion: mocks.getAppVersion,
|
|
54
59
|
getBundleId: mocks.getBundleId,
|
|
55
60
|
getChannel: mocks.getChannel,
|
|
61
|
+
getActiveUpdateState: mocks.getActiveUpdateState,
|
|
56
62
|
getCohort: mocks.getCohort,
|
|
57
63
|
getFingerprintHash: mocks.getFingerprintHash,
|
|
58
64
|
getInstallId: mocks.getInstallId,
|
|
@@ -75,6 +81,11 @@ describe("automatic notifyAppReady transport failures", () => {
|
|
|
75
81
|
mocks.getAppVersion.mockReturnValue("1.0.0");
|
|
76
82
|
mocks.getBundleId.mockReturnValue("bundle-id");
|
|
77
83
|
mocks.getChannel.mockReturnValue("production");
|
|
84
|
+
mocks.getActiveUpdateState.mockReturnValue({
|
|
85
|
+
activeSelection: null,
|
|
86
|
+
stableSelection: null,
|
|
87
|
+
verificationPending: false,
|
|
88
|
+
});
|
|
78
89
|
mocks.getCohort.mockReturnValue("123");
|
|
79
90
|
mocks.getFingerprintHash.mockReturnValue("fingerprint-hash");
|
|
80
91
|
mocks.getInstallId.mockReturnValue("install-id");
|
|
@@ -127,4 +138,59 @@ describe("automatic notifyAppReady transport failures", () => {
|
|
|
127
138
|
}
|
|
128
139
|
},
|
|
129
140
|
);
|
|
141
|
+
|
|
142
|
+
it.each(retryableFailureCases)(
|
|
143
|
+
"retries a $label failure in the background without delaying UNCHANGED readiness",
|
|
144
|
+
async (failureCase) => {
|
|
145
|
+
stubNotifyFrame();
|
|
146
|
+
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
147
|
+
const onError = vi.fn();
|
|
148
|
+
const onNotifyAppReady = vi.fn();
|
|
149
|
+
const fetchMock = vi.fn<typeof fetch>(async () => {
|
|
150
|
+
if ("error" in failureCase) {
|
|
151
|
+
throw failureCase.error;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return new Response(null, { status: failureCase.responseStatus });
|
|
155
|
+
});
|
|
156
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
157
|
+
Reflect.set(globalThis, "HotUpdater", {
|
|
158
|
+
SDK_VERSION: "test-sdk-version",
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
try {
|
|
162
|
+
const [{ createHttpClient }, { init }] = await Promise.all([
|
|
163
|
+
import("./httpClient"),
|
|
164
|
+
import("./wrap"),
|
|
165
|
+
]);
|
|
166
|
+
const client = createHttpClient(
|
|
167
|
+
"https://updates.example.test/hot-updater",
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
init({ insights: true, client, onError, onNotifyAppReady });
|
|
171
|
+
await vi.runOnlyPendingTimersAsync();
|
|
172
|
+
|
|
173
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
174
|
+
expect(onNotifyAppReady).toHaveBeenCalledWith({
|
|
175
|
+
status: "UNCHANGED",
|
|
176
|
+
});
|
|
177
|
+
expect(warn).not.toHaveBeenCalled();
|
|
178
|
+
|
|
179
|
+
await vi.runAllTimersAsync();
|
|
180
|
+
|
|
181
|
+
const eventIds = fetchMock.mock.calls.map(
|
|
182
|
+
([, request]) => JSON.parse(String(request?.body)).eventId,
|
|
183
|
+
);
|
|
184
|
+
expect(eventIds).toHaveLength(3);
|
|
185
|
+
expect(new Set(eventIds).size).toBe(1);
|
|
186
|
+
expect(onError).not.toHaveBeenCalled();
|
|
187
|
+
expect(warn).toHaveBeenCalledExactlyOnceWith(
|
|
188
|
+
"[HotUpdater] Insights UNCHANGED event was not delivered:",
|
|
189
|
+
expect.any(Error),
|
|
190
|
+
);
|
|
191
|
+
} finally {
|
|
192
|
+
warn.mockRestore();
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
);
|
|
130
196
|
});
|
|
@@ -3,6 +3,7 @@ import { Platform } from "react-native";
|
|
|
3
3
|
import type { HotUpdaterError } from "./error";
|
|
4
4
|
import type { InsightsEventParams, HotUpdaterHttpClient } from "./httpClient";
|
|
5
5
|
import {
|
|
6
|
+
getActiveUpdateState,
|
|
6
7
|
getAppVersion,
|
|
7
8
|
getBundleId,
|
|
8
9
|
getChannel,
|
|
@@ -101,10 +102,21 @@ const buildNotifyAppReadyInsightsParams = (
|
|
|
101
102
|
);
|
|
102
103
|
}
|
|
103
104
|
|
|
105
|
+
const state = getActiveUpdateState();
|
|
106
|
+
const runningSelection = [
|
|
107
|
+
state.activeSelection,
|
|
108
|
+
state.stableSelection,
|
|
109
|
+
].find(
|
|
110
|
+
(selection) =>
|
|
111
|
+
selection?.bundleId === bundleId &&
|
|
112
|
+
selection.channel === commonParams.channel,
|
|
113
|
+
);
|
|
114
|
+
|
|
104
115
|
return {
|
|
105
116
|
...commonParams,
|
|
106
117
|
fromBundleId: null,
|
|
107
118
|
toBundleId: bundleId,
|
|
119
|
+
toReleaseId: runningSelection?.releaseId ?? null,
|
|
108
120
|
type: "UNCHANGED",
|
|
109
121
|
updateStrategy: null,
|
|
110
122
|
};
|
|
@@ -237,7 +249,7 @@ export const reportNoChange = async (
|
|
|
237
249
|
|
|
238
250
|
let lastDownloadedSelection: string | undefined;
|
|
239
251
|
|
|
240
|
-
/** Report only after the
|
|
252
|
+
/** Report only after the manifest update has been verified and staged successfully. */
|
|
241
253
|
export const reportBundleDownloaded = async (
|
|
242
254
|
options: Pick<
|
|
243
255
|
NotifyAppReadyOptions,
|
package/src/sdkVersion.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const HOT_UPDATER_SDK_VERSION = "1.0.0-rc.
|
|
1
|
+
export const HOT_UPDATER_SDK_VERSION = "1.0.0-rc.16";
|