@hot-updater/react-native 0.36.6 → 1.0.0-rc.0
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/src/main/java/com/hotupdater/BundleFileStorageService.kt +357 -6
- package/android/src/main/java/com/hotupdater/BundleMetadata.kt +268 -34
- package/android/src/main/java/com/hotupdater/HotUpdaterImpl.kt +75 -9
- package/android/src/main/java/com/hotupdater/NativeConfigUtils.kt +2 -16
- package/android/src/main/java/com/hotupdater/ReleaseCatalogCacheService.kt +166 -0
- package/android/src/main/java/com/hotupdater/SignatureVerifier.kt +1 -2
- package/android/src/newarch/HotUpdater.kt +1 -1
- package/android/src/newarch/HotUpdaterModule.kt +116 -0
- package/android/src/oldarch/HotUpdater.kt +1 -1
- package/android/src/oldarch/HotUpdaterModule.kt +128 -0
- package/android/src/oldarch/HotUpdaterSpec.kt +38 -0
- package/android/src/test/java/com/hotupdater/BundleFileStorageServiceTest.kt +280 -2
- package/android/src/test/java/com/hotupdater/HotUpdaterImplTest.kt +57 -2
- package/android/src/test/java/com/hotupdater/ReleaseCatalogCacheServiceTest.kt +118 -0
- package/ios/HotUpdater/Internal/BundleFileStorageService.swift +491 -30
- package/ios/HotUpdater/Internal/BundleMetadata.swift +229 -6
- package/ios/HotUpdater/Internal/HotUpdater.mm +122 -0
- package/ios/HotUpdater/Internal/HotUpdaterImpl.swift +176 -7
- package/ios/HotUpdater/Internal/ReleaseCatalogCacheService.swift +213 -0
- package/lib/commonjs/catalogCacheNative.js +44 -0
- package/lib/commonjs/catalogCacheNative.js.map +1 -0
- package/lib/commonjs/catalogCacheNative.spec.js +31 -0
- package/lib/commonjs/catalogCacheNative.spec.js.map +1 -0
- package/lib/commonjs/checkForUpdate.js +231 -60
- package/lib/commonjs/checkForUpdate.js.map +1 -1
- package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js +604 -0
- package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js.map +1 -0
- package/lib/commonjs/error.js +8 -1
- package/lib/commonjs/error.js.map +1 -1
- package/lib/commonjs/{fetchUpdateInfo.js → fetchJSON.js} +11 -14
- package/lib/commonjs/fetchJSON.js.map +1 -0
- package/lib/commonjs/httpClient.js +153 -0
- package/lib/commonjs/httpClient.js.map +1 -0
- package/lib/commonjs/httpClient.spec.js +102 -0
- package/lib/commonjs/httpClient.spec.js.map +1 -0
- package/lib/commonjs/index.js +48 -71
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.spec.js +117 -161
- package/lib/commonjs/index.spec.js.map +1 -1
- package/lib/commonjs/iosInterop.spec.js +18 -0
- package/lib/commonjs/iosInterop.spec.js.map +1 -0
- package/lib/commonjs/native.js +222 -55
- package/lib/commonjs/native.js.map +1 -1
- package/lib/commonjs/native.spec.js +226 -12
- package/lib/commonjs/native.spec.js.map +1 -1
- package/lib/commonjs/notifyAppReadyAnalytics.boundary.spec.js +218 -0
- package/lib/commonjs/notifyAppReadyAnalytics.boundary.spec.js.map +1 -0
- package/lib/commonjs/notifyAppReadyAnalytics.js +133 -0
- package/lib/commonjs/notifyAppReadyAnalytics.js.map +1 -0
- package/lib/commonjs/notifyAppReadyAnalytics.spec.js +246 -0
- package/lib/commonjs/notifyAppReadyAnalytics.spec.js.map +1 -0
- package/lib/commonjs/notifyAppReadyAnalytics.test-utils.js +24 -0
- package/lib/commonjs/notifyAppReadyAnalytics.test-utils.js.map +1 -0
- package/lib/commonjs/notifyAppReadyAnalytics.transport.spec.js +117 -0
- package/lib/commonjs/notifyAppReadyAnalytics.transport.spec.js.map +1 -0
- package/lib/commonjs/releaseCatalogCache.js +179 -0
- package/lib/commonjs/releaseCatalogCache.js.map +1 -0
- package/lib/commonjs/releaseCatalogCache.spec.js +195 -0
- package/lib/commonjs/releaseCatalogCache.spec.js.map +1 -0
- package/lib/commonjs/releaseCatalogCacheNativeContract.spec.js +64 -0
- package/lib/commonjs/releaseCatalogCacheNativeContract.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/types.js +0 -12
- package/lib/commonjs/types.js.map +1 -1
- package/lib/commonjs/wrap.js +7 -82
- package/lib/commonjs/wrap.js.map +1 -1
- package/lib/commonjs/wrap.spec.js +203 -56
- package/lib/commonjs/wrap.spec.js.map +1 -1
- package/lib/commonjs/wrap.types.js +6 -0
- package/lib/commonjs/wrap.types.js.map +1 -0
- package/lib/module/catalogCacheNative.js +36 -0
- package/lib/module/catalogCacheNative.js.map +1 -0
- package/lib/module/catalogCacheNative.spec.js +31 -0
- package/lib/module/catalogCacheNative.spec.js.map +1 -0
- package/lib/module/checkForUpdate.js +233 -62
- package/lib/module/checkForUpdate.js.map +1 -1
- package/lib/module/checkForUpdate.releaseCatalog.spec.js +603 -0
- package/lib/module/checkForUpdate.releaseCatalog.spec.js.map +1 -0
- package/lib/module/error.js +6 -0
- package/lib/module/error.js.map +1 -1
- package/lib/module/{fetchUpdateInfo.js → fetchJSON.js} +9 -12
- package/lib/module/fetchJSON.js.map +1 -0
- package/lib/module/httpClient.js +148 -0
- package/lib/module/httpClient.js.map +1 -0
- package/lib/module/httpClient.spec.js +102 -0
- package/lib/module/httpClient.spec.js.map +1 -0
- package/lib/module/index.js +49 -66
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.spec.js +117 -161
- package/lib/module/index.spec.js.map +1 -1
- package/lib/module/iosInterop.spec.js +18 -0
- package/lib/module/iosInterop.spec.js.map +1 -0
- package/lib/module/native.js +206 -51
- package/lib/module/native.js.map +1 -1
- package/lib/module/native.spec.js +226 -12
- package/lib/module/native.spec.js.map +1 -1
- package/lib/module/notifyAppReadyAnalytics.boundary.spec.js +217 -0
- package/lib/module/notifyAppReadyAnalytics.boundary.spec.js.map +1 -0
- package/lib/module/notifyAppReadyAnalytics.js +128 -0
- package/lib/module/notifyAppReadyAnalytics.js.map +1 -0
- package/lib/module/notifyAppReadyAnalytics.spec.js +245 -0
- package/lib/module/notifyAppReadyAnalytics.spec.js.map +1 -0
- package/lib/module/notifyAppReadyAnalytics.test-utils.js +18 -0
- package/lib/module/notifyAppReadyAnalytics.test-utils.js.map +1 -0
- package/lib/module/notifyAppReadyAnalytics.transport.spec.js +116 -0
- package/lib/module/notifyAppReadyAnalytics.transport.spec.js.map +1 -0
- package/lib/module/releaseCatalogCache.js +171 -0
- package/lib/module/releaseCatalogCache.js.map +1 -0
- package/lib/module/releaseCatalogCache.spec.js +195 -0
- package/lib/module/releaseCatalogCache.spec.js.map +1 -0
- package/lib/module/releaseCatalogCacheNativeContract.spec.js +64 -0
- package/lib/module/releaseCatalogCacheNativeContract.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/types.js +0 -12
- package/lib/module/types.js.map +1 -1
- package/lib/module/wrap.js +6 -81
- package/lib/module/wrap.js.map +1 -1
- package/lib/module/wrap.spec.js +203 -56
- package/lib/module/wrap.spec.js.map +1 -1
- package/lib/module/wrap.types.js +4 -0
- package/lib/module/wrap.types.js.map +1 -0
- package/lib/typescript/commonjs/catalogCacheNative.d.ts +4 -0
- package/lib/typescript/commonjs/catalogCacheNative.d.ts.map +1 -0
- package/lib/typescript/commonjs/checkForUpdate.d.ts +14 -4
- package/lib/typescript/commonjs/checkForUpdate.d.ts.map +1 -1
- package/lib/typescript/commonjs/error.d.ts +3 -0
- package/lib/typescript/commonjs/error.d.ts.map +1 -1
- package/lib/typescript/commonjs/fetchJSON.d.ts +6 -0
- package/lib/typescript/commonjs/fetchJSON.d.ts.map +1 -0
- package/lib/typescript/commonjs/httpClient.d.ts +56 -0
- package/lib/typescript/commonjs/httpClient.d.ts.map +1 -0
- package/lib/typescript/commonjs/index.d.ts +32 -41
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/native.d.ts +83 -18
- package/lib/typescript/commonjs/native.d.ts.map +1 -1
- package/lib/typescript/commonjs/notifyAppReadyAnalytics.d.ts +13 -0
- package/lib/typescript/commonjs/notifyAppReadyAnalytics.d.ts.map +1 -0
- package/lib/typescript/commonjs/notifyAppReadyAnalytics.test-utils.d.ts +8 -0
- package/lib/typescript/commonjs/notifyAppReadyAnalytics.test-utils.d.ts.map +1 -0
- package/lib/typescript/commonjs/releaseCatalogCache.d.ts +25 -0
- package/lib/typescript/commonjs/releaseCatalogCache.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 +40 -5
- package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts.map +1 -1
- package/lib/typescript/commonjs/types.d.ts +0 -118
- package/lib/typescript/commonjs/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/wrap.d.ts +2 -191
- package/lib/typescript/commonjs/wrap.d.ts.map +1 -1
- package/lib/typescript/commonjs/wrap.types.d.ts +65 -0
- package/lib/typescript/commonjs/wrap.types.d.ts.map +1 -0
- package/lib/typescript/module/catalogCacheNative.d.ts +4 -0
- package/lib/typescript/module/catalogCacheNative.d.ts.map +1 -0
- package/lib/typescript/module/checkForUpdate.d.ts +14 -4
- package/lib/typescript/module/checkForUpdate.d.ts.map +1 -1
- package/lib/typescript/module/error.d.ts +3 -0
- package/lib/typescript/module/error.d.ts.map +1 -1
- package/lib/typescript/module/fetchJSON.d.ts +6 -0
- package/lib/typescript/module/fetchJSON.d.ts.map +1 -0
- package/lib/typescript/module/httpClient.d.ts +56 -0
- package/lib/typescript/module/httpClient.d.ts.map +1 -0
- package/lib/typescript/module/index.d.ts +32 -41
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/native.d.ts +83 -18
- package/lib/typescript/module/native.d.ts.map +1 -1
- package/lib/typescript/module/notifyAppReadyAnalytics.d.ts +13 -0
- package/lib/typescript/module/notifyAppReadyAnalytics.d.ts.map +1 -0
- package/lib/typescript/module/notifyAppReadyAnalytics.test-utils.d.ts +8 -0
- package/lib/typescript/module/notifyAppReadyAnalytics.test-utils.d.ts.map +1 -0
- package/lib/typescript/module/releaseCatalogCache.d.ts +25 -0
- package/lib/typescript/module/releaseCatalogCache.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 +40 -5
- package/lib/typescript/module/specs/NativeHotUpdater.d.ts.map +1 -1
- package/lib/typescript/module/types.d.ts +0 -118
- package/lib/typescript/module/types.d.ts.map +1 -1
- package/lib/typescript/module/wrap.d.ts +2 -191
- package/lib/typescript/module/wrap.d.ts.map +1 -1
- package/lib/typescript/module/wrap.types.d.ts +65 -0
- package/lib/typescript/module/wrap.types.d.ts.map +1 -0
- package/package.json +6 -24
- package/src/catalogCacheNative.spec.ts +63 -0
- package/src/catalogCacheNative.ts +74 -0
- package/src/checkForUpdate.releaseCatalog.spec.ts +596 -0
- package/src/checkForUpdate.ts +368 -97
- package/src/error.ts +7 -0
- package/src/{fetchUpdateInfo.ts → fetchJSON.ts} +8 -15
- package/src/httpClient.spec.ts +132 -0
- package/src/httpClient.ts +261 -0
- package/src/index.spec.ts +110 -203
- package/src/index.ts +70 -93
- package/src/iosInterop.spec.ts +30 -0
- package/src/native.spec.ts +226 -10
- package/src/native.ts +385 -83
- package/src/notifyAppReadyAnalytics.boundary.spec.ts +234 -0
- package/src/notifyAppReadyAnalytics.spec.ts +243 -0
- package/src/notifyAppReadyAnalytics.test-utils.ts +31 -0
- package/src/notifyAppReadyAnalytics.transport.spec.ts +130 -0
- package/src/notifyAppReadyAnalytics.ts +194 -0
- package/src/releaseCatalogCache.spec.ts +282 -0
- package/src/releaseCatalogCache.ts +341 -0
- package/src/releaseCatalogCacheNativeContract.spec.ts +80 -0
- package/src/sdkVersion.ts +1 -1
- package/src/specs/NativeHotUpdater.ts +51 -5
- package/src/types.ts +0 -140
- package/src/wrap.spec.ts +251 -56
- package/src/wrap.tsx +23 -318
- package/src/wrap.types.ts +78 -0
- package/android/src/main/java/com/hotupdater/StringResourceUtils.kt +0 -45
- package/app.plugin.js +0 -1
- package/ios/HotUpdater/Internal/HotUpdaterCrashHandler.h +0 -7
- package/ios/HotUpdater/Internal/HotUpdaterCrashHandler.mm +0 -4
- package/lib/commonjs/DefaultResolver.js +0 -50
- package/lib/commonjs/DefaultResolver.js.map +0 -1
- package/lib/commonjs/DefaultResolver.spec.js +0 -144
- package/lib/commonjs/DefaultResolver.spec.js.map +0 -1
- package/lib/commonjs/fetchUpdateInfo.js.map +0 -1
- package/lib/module/DefaultResolver.js +0 -46
- package/lib/module/DefaultResolver.js.map +0 -1
- package/lib/module/DefaultResolver.spec.js +0 -144
- package/lib/module/DefaultResolver.spec.js.map +0 -1
- package/lib/module/fetchUpdateInfo.js.map +0 -1
- package/lib/typescript/commonjs/DefaultResolver.d.ts +0 -11
- package/lib/typescript/commonjs/DefaultResolver.d.ts.map +0 -1
- package/lib/typescript/commonjs/fetchUpdateInfo.d.ts +0 -7
- package/lib/typescript/commonjs/fetchUpdateInfo.d.ts.map +0 -1
- package/lib/typescript/module/DefaultResolver.d.ts +0 -11
- package/lib/typescript/module/DefaultResolver.d.ts.map +0 -1
- package/lib/typescript/module/fetchUpdateInfo.d.ts +0 -7
- package/lib/typescript/module/fetchUpdateInfo.d.ts.map +0 -1
- package/plugin/build/transformers.js +0 -314
- package/plugin/build/withHotUpdater.js +0 -228
- package/src/DefaultResolver.spec.ts +0 -193
- package/src/DefaultResolver.ts +0 -63
package/src/native.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type ChangedAsset,
|
|
3
|
+
type CatalogHighWater,
|
|
3
4
|
INVALID_COHORT_ERROR_MESSAGE,
|
|
4
5
|
isValidCohort,
|
|
5
6
|
normalizeCohortValue,
|
|
6
7
|
type UpdateStatus,
|
|
8
|
+
type PersistedSelectionReceipt,
|
|
7
9
|
} from "@hot-updater/core";
|
|
8
10
|
import { NativeEventEmitter, Platform } from "react-native";
|
|
9
11
|
|
|
@@ -15,6 +17,8 @@ import HotUpdaterNative, {
|
|
|
15
17
|
export { HotUpdaterErrorCode, isHotUpdaterError };
|
|
16
18
|
|
|
17
19
|
const NIL_UUID = "00000000-0000-0000-0000-000000000000";
|
|
20
|
+
type PersistedUpdateStrategy = "fingerprint" | "appVersion";
|
|
21
|
+
|
|
18
22
|
const normalizeAndValidateCohort = (cohort: string): string => {
|
|
19
23
|
const normalized = normalizeCohortValue(cohort);
|
|
20
24
|
if (!isValidCohort(normalized)) {
|
|
@@ -211,7 +215,7 @@ const getNativeBundleId = (): string | null => {
|
|
|
211
215
|
};
|
|
212
216
|
|
|
213
217
|
const resolveBundleId = (bundleId: string | null): string => {
|
|
214
|
-
return !bundleId || bundleId === NIL_UUID ?
|
|
218
|
+
return !bundleId || bundleId === NIL_UUID ? getMinimumReleaseId() : bundleId;
|
|
215
219
|
};
|
|
216
220
|
|
|
217
221
|
const getFreshBundleId = (): string => {
|
|
@@ -317,6 +321,109 @@ export type UpdateParams = UpdateBundleParams & {
|
|
|
317
321
|
shouldSkipCurrentBundleIdCheck?: boolean;
|
|
318
322
|
};
|
|
319
323
|
|
|
324
|
+
export interface ActiveUpdateState {
|
|
325
|
+
readonly activeSelection: ActiveUpdateSelection | null;
|
|
326
|
+
readonly stableSelection: ActiveUpdateSelection | null;
|
|
327
|
+
readonly verificationPending: boolean;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
type ActiveUpdateSelection = Pick<
|
|
331
|
+
PersistedSelectionReceipt,
|
|
332
|
+
"kind" | "releaseId" | "bundleId" | "channel"
|
|
333
|
+
>;
|
|
334
|
+
|
|
335
|
+
export interface InternalActiveUpdateState {
|
|
336
|
+
readonly activeSelection: PersistedSelectionReceipt | null;
|
|
337
|
+
readonly stableSelection: PersistedSelectionReceipt | null;
|
|
338
|
+
readonly verificationPending: boolean;
|
|
339
|
+
readonly highestSeenCatalogs: Readonly<Record<string, CatalogHighWater>>;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
export interface ReleaseSelectionGuard {
|
|
343
|
+
readonly catalogId: string;
|
|
344
|
+
readonly scopeKey: string;
|
|
345
|
+
readonly generation: number;
|
|
346
|
+
readonly catalogHash: string;
|
|
347
|
+
readonly selectionContextHash: string;
|
|
348
|
+
readonly channel: string;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const requireReleaseCatalogNativeMethod = <T extends (...args: any[]) => any>(
|
|
352
|
+
name: string,
|
|
353
|
+
): T => {
|
|
354
|
+
const method = (HotUpdaterNative as unknown as Record<string, unknown>)[name];
|
|
355
|
+
if (typeof method !== "function") {
|
|
356
|
+
throw new Error(
|
|
357
|
+
`[HotUpdater] Native module is missing '${name}()'. Rebuild the native app before using Release catalogs.`,
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
return method.bind(HotUpdaterNative) as T;
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
export const acceptReleaseCatalog = (input: {
|
|
364
|
+
readonly catalogId: string;
|
|
365
|
+
readonly scopeKey: string;
|
|
366
|
+
readonly generation: number;
|
|
367
|
+
readonly catalogHash: string;
|
|
368
|
+
readonly channel: string;
|
|
369
|
+
readonly selectionContextHash: string;
|
|
370
|
+
}): boolean =>
|
|
371
|
+
requireReleaseCatalogNativeMethod<(params: object) => boolean>(
|
|
372
|
+
"acceptReleaseCatalog",
|
|
373
|
+
)(input);
|
|
374
|
+
|
|
375
|
+
export const getActiveUpdateState = (): InternalActiveUpdateState => {
|
|
376
|
+
const value = requireReleaseCatalogNativeMethod<() => unknown>(
|
|
377
|
+
"getActiveUpdateState",
|
|
378
|
+
)();
|
|
379
|
+
if (typeof value === "string") {
|
|
380
|
+
return JSON.parse(value) as InternalActiveUpdateState;
|
|
381
|
+
}
|
|
382
|
+
return value as InternalActiveUpdateState;
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
export const getPublicActiveUpdateState = (): ActiveUpdateState => {
|
|
386
|
+
const state = getActiveUpdateState();
|
|
387
|
+
const selection = (
|
|
388
|
+
receipt: PersistedSelectionReceipt | null,
|
|
389
|
+
): ActiveUpdateSelection | null =>
|
|
390
|
+
receipt === null
|
|
391
|
+
? null
|
|
392
|
+
: {
|
|
393
|
+
kind: receipt.kind,
|
|
394
|
+
releaseId: receipt.releaseId,
|
|
395
|
+
bundleId: receipt.bundleId,
|
|
396
|
+
channel: receipt.channel,
|
|
397
|
+
};
|
|
398
|
+
return {
|
|
399
|
+
activeSelection: selection(state.activeSelection),
|
|
400
|
+
stableSelection: selection(state.stableSelection),
|
|
401
|
+
verificationPending: state.verificationPending,
|
|
402
|
+
};
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
export const isReleaseSelectionCurrent = (
|
|
406
|
+
input: ReleaseSelectionGuard,
|
|
407
|
+
): boolean =>
|
|
408
|
+
requireReleaseCatalogNativeMethod<(params: object) => boolean>(
|
|
409
|
+
"isReleaseSelectionCurrent",
|
|
410
|
+
)(input);
|
|
411
|
+
|
|
412
|
+
export const commitReleaseSelection = async (input: {
|
|
413
|
+
readonly selection: PersistedSelectionReceipt;
|
|
414
|
+
readonly guard: ReleaseSelectionGuard;
|
|
415
|
+
}): Promise<boolean> => {
|
|
416
|
+
const ok = await requireReleaseCatalogNativeMethod<
|
|
417
|
+
(params: object) => Promise<boolean>
|
|
418
|
+
>("commitReleaseSelection")(input);
|
|
419
|
+
if (ok)
|
|
420
|
+
sessionState.markBundleInstalled(
|
|
421
|
+
input.selection.bundleId,
|
|
422
|
+
input.selection.channel,
|
|
423
|
+
);
|
|
424
|
+
return ok;
|
|
425
|
+
};
|
|
426
|
+
|
|
320
427
|
/**
|
|
321
428
|
* Downloads files and applies them to the app.
|
|
322
429
|
*
|
|
@@ -324,30 +431,10 @@ export type UpdateParams = UpdateBundleParams & {
|
|
|
324
431
|
* @returns {Promise<boolean>} Resolves with true if download was successful
|
|
325
432
|
* @throws {Error} Rejects with error.code from HotUpdaterErrorCode enum and error.message
|
|
326
433
|
*/
|
|
327
|
-
export async function updateBundle(params: UpdateParams): Promise<boolean
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
export async function updateBundle(
|
|
332
|
-
bundleId: string,
|
|
333
|
-
fileUrl: string | null,
|
|
334
|
-
): Promise<boolean>;
|
|
335
|
-
export async function updateBundle(
|
|
336
|
-
paramsOrBundleId: UpdateParams | string,
|
|
337
|
-
fileUrl?: string | null,
|
|
338
|
-
): Promise<boolean> {
|
|
339
|
-
const updateBundleId =
|
|
340
|
-
typeof paramsOrBundleId === "string"
|
|
341
|
-
? paramsOrBundleId
|
|
342
|
-
: paramsOrBundleId.bundleId;
|
|
343
|
-
|
|
344
|
-
const status =
|
|
345
|
-
typeof paramsOrBundleId === "string" ? "UPDATE" : paramsOrBundleId.status;
|
|
346
|
-
|
|
347
|
-
const targetFileUrl =
|
|
348
|
-
typeof paramsOrBundleId === "string"
|
|
349
|
-
? (fileUrl ?? null)
|
|
350
|
-
: paramsOrBundleId.fileUrl;
|
|
434
|
+
export async function updateBundle(params: UpdateParams): Promise<boolean> {
|
|
435
|
+
const updateBundleId = params.bundleId;
|
|
436
|
+
const status = params.status;
|
|
437
|
+
const targetFileUrl = params.fileUrl;
|
|
351
438
|
|
|
352
439
|
const currentBundleId = status === "UPDATE" ? getFreshBundleId() : undefined;
|
|
353
440
|
|
|
@@ -363,9 +450,7 @@ export async function updateBundle(
|
|
|
363
450
|
}
|
|
364
451
|
|
|
365
452
|
const shouldSkipCurrentBundleIdCheck =
|
|
366
|
-
|
|
367
|
-
? false
|
|
368
|
-
: paramsOrBundleId.shouldSkipCurrentBundleIdCheck === true;
|
|
453
|
+
params.shouldSkipCurrentBundleIdCheck === true;
|
|
369
454
|
|
|
370
455
|
if (
|
|
371
456
|
!shouldSkipCurrentBundleIdCheck &&
|
|
@@ -382,28 +467,15 @@ export async function updateBundle(
|
|
|
382
467
|
const existing = sessionState.getInflightUpdate(updateBundleId);
|
|
383
468
|
if (existing) return existing;
|
|
384
469
|
|
|
385
|
-
const targetFileHash =
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
const targetChannel =
|
|
391
|
-
typeof paramsOrBundleId === "string" ? undefined : paramsOrBundleId.channel;
|
|
392
|
-
const targetManifestUrl =
|
|
393
|
-
typeof paramsOrBundleId === "string"
|
|
394
|
-
? undefined
|
|
395
|
-
: paramsOrBundleId.manifestUrl;
|
|
396
|
-
const targetManifestFileHash =
|
|
397
|
-
typeof paramsOrBundleId === "string"
|
|
398
|
-
? undefined
|
|
399
|
-
: paramsOrBundleId.manifestFileHash;
|
|
400
|
-
const targetChangedAssets =
|
|
401
|
-
typeof paramsOrBundleId === "string"
|
|
402
|
-
? undefined
|
|
403
|
-
: paramsOrBundleId.changedAssets;
|
|
470
|
+
const targetFileHash = params.fileHash;
|
|
471
|
+
const targetChannel = params.channel;
|
|
472
|
+
const targetManifestUrl = params.manifestUrl;
|
|
473
|
+
const targetManifestFileHash = params.manifestFileHash;
|
|
474
|
+
const targetChangedAssets = params.changedAssets;
|
|
404
475
|
|
|
405
476
|
const promise = (async () => {
|
|
406
477
|
try {
|
|
478
|
+
const selection = params.selection;
|
|
407
479
|
const ok = await HotUpdaterNative.updateBundle({
|
|
408
480
|
bundleId: updateBundleId,
|
|
409
481
|
channel: targetChannel,
|
|
@@ -413,6 +485,7 @@ export async function updateBundle(
|
|
|
413
485
|
fileHash: targetFileHash ?? null,
|
|
414
486
|
manifestFileHash: targetManifestFileHash ?? null,
|
|
415
487
|
manifestUrl: targetManifestUrl ?? null,
|
|
488
|
+
...(selection === undefined ? {} : { selection }),
|
|
416
489
|
});
|
|
417
490
|
if (ok) {
|
|
418
491
|
sessionState.markBundleInstalled(updateBundleId, targetChannel);
|
|
@@ -515,16 +588,18 @@ export function setReloadBehavior(
|
|
|
515
588
|
}
|
|
516
589
|
|
|
517
590
|
/**
|
|
518
|
-
* Fetches the minimum
|
|
519
|
-
* since it is created at build time.
|
|
591
|
+
* Fetches the build-time minimum Release id.
|
|
520
592
|
*
|
|
521
|
-
* @returns {string}
|
|
593
|
+
* @returns {string} The minimum Release id.
|
|
522
594
|
*/
|
|
523
|
-
export const
|
|
595
|
+
export const getMinimumReleaseId = (): string => {
|
|
524
596
|
const constants = HotUpdaterNative.getConstants();
|
|
525
597
|
return constants.MIN_BUNDLE_ID;
|
|
526
598
|
};
|
|
527
599
|
|
|
600
|
+
export const getReleaseId = async (): Promise<string | null> =>
|
|
601
|
+
getActiveUpdateState().activeSelection?.releaseId ?? null;
|
|
602
|
+
|
|
528
603
|
/**
|
|
529
604
|
* Fetches the current bundle version id.
|
|
530
605
|
*
|
|
@@ -613,12 +688,264 @@ export const getFingerprintHash = (): string | null => {
|
|
|
613
688
|
return constants.FINGERPRINT_HASH;
|
|
614
689
|
};
|
|
615
690
|
|
|
691
|
+
export const getInstallId = (): string => {
|
|
692
|
+
const nativeModule = HotUpdaterNative as typeof HotUpdaterNative & {
|
|
693
|
+
getInstallId?: () => string;
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
if (typeof nativeModule.getInstallId !== "function") {
|
|
697
|
+
throw new Error(
|
|
698
|
+
"[HotUpdater] Native module is missing 'getInstallId()'. This JS bundle requires a newer native @hot-updater/react-native SDK. Rebuild and release a new app version before delivering this OTA update.",
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
return nativeModule.getInstallId();
|
|
703
|
+
};
|
|
704
|
+
|
|
705
|
+
export type PersistedUserIdentity = {
|
|
706
|
+
userId?: string;
|
|
707
|
+
username?: string;
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
export const getPersistedUserIdentity = (): PersistedUserIdentity => {
|
|
711
|
+
const nativeModule = HotUpdaterNative as typeof HotUpdaterNative & {
|
|
712
|
+
getUserId?: () => string | null;
|
|
713
|
+
getUsername?: () => string | null;
|
|
714
|
+
};
|
|
715
|
+
|
|
716
|
+
if (
|
|
717
|
+
typeof nativeModule.getUserId !== "function" ||
|
|
718
|
+
typeof nativeModule.getUsername !== "function"
|
|
719
|
+
) {
|
|
720
|
+
throw new Error(
|
|
721
|
+
"[HotUpdater] Native module is missing 'getUserId()' or 'getUsername()'. This JS bundle requires a newer native @hot-updater/react-native SDK. Rebuild and release a new app version before delivering this OTA update.",
|
|
722
|
+
);
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
const userId = nativeModule.getUserId();
|
|
726
|
+
const username = nativeModule.getUsername();
|
|
727
|
+
|
|
728
|
+
return {
|
|
729
|
+
...(userId != null ? { userId } : {}),
|
|
730
|
+
...(username != null ? { username } : {}),
|
|
731
|
+
};
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
export type SetUserParams = {
|
|
735
|
+
userId?: string | number | null;
|
|
736
|
+
username?: string | null;
|
|
737
|
+
};
|
|
738
|
+
|
|
739
|
+
export function setUser(params: SetUserParams): void;
|
|
740
|
+
export function setUser(params: null): void;
|
|
741
|
+
export function setUser(params: SetUserParams | null): void {
|
|
742
|
+
const nativeModule = HotUpdaterNative as typeof HotUpdaterNative & {
|
|
743
|
+
setUser?: (userId: string | null, username: string | null) => void;
|
|
744
|
+
};
|
|
745
|
+
|
|
746
|
+
if (typeof nativeModule.setUser !== "function") {
|
|
747
|
+
throw new Error(
|
|
748
|
+
"[HotUpdater] Native module is missing 'setUser()'. This JS bundle requires a newer native @hot-updater/react-native SDK. Rebuild and release a new app version before delivering this OTA update.",
|
|
749
|
+
);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
if (params === null) {
|
|
753
|
+
nativeModule.setUser(null, null);
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
const normalizedUserId =
|
|
758
|
+
params.userId === null || params.userId === undefined
|
|
759
|
+
? null
|
|
760
|
+
: String(params.userId);
|
|
761
|
+
nativeModule.setUser(normalizedUserId, params.username ?? null);
|
|
762
|
+
}
|
|
763
|
+
|
|
616
764
|
/**
|
|
617
765
|
* Result returned by notifyAppReady()
|
|
618
766
|
*/
|
|
619
|
-
export type NotifyAppReadyResult =
|
|
620
|
-
status: "
|
|
767
|
+
export type NotifyAppReadyResult =
|
|
768
|
+
| { status: "UNCHANGED" }
|
|
769
|
+
| {
|
|
770
|
+
status: "UPDATE_APPLIED";
|
|
771
|
+
fromBundleId: string;
|
|
772
|
+
toBundleId: string;
|
|
773
|
+
fromReleaseId?: string;
|
|
774
|
+
toReleaseId?: string;
|
|
775
|
+
}
|
|
776
|
+
| {
|
|
777
|
+
status: "RECOVERED";
|
|
778
|
+
fromBundleId: string;
|
|
779
|
+
toBundleId: string;
|
|
780
|
+
fromReleaseId?: string;
|
|
781
|
+
toReleaseId?: string;
|
|
782
|
+
};
|
|
783
|
+
|
|
784
|
+
export type NotifyAppReadyAnalyticsEvent = {
|
|
785
|
+
type: "UPDATE_APPLIED" | "RECOVERED";
|
|
786
|
+
fromBundleId: string;
|
|
787
|
+
toBundleId: string;
|
|
788
|
+
fromReleaseId?: string | null;
|
|
789
|
+
toReleaseId?: string | null;
|
|
790
|
+
updateStrategy: PersistedUpdateStrategy;
|
|
791
|
+
};
|
|
792
|
+
|
|
793
|
+
type RawNotifyAppReadyResult = {
|
|
794
|
+
status?: string;
|
|
621
795
|
crashedBundleId?: string;
|
|
796
|
+
fromReleaseId?: string;
|
|
797
|
+
fromBundleId?: string;
|
|
798
|
+
toReleaseId?: string;
|
|
799
|
+
toBundleId?: string;
|
|
800
|
+
updateStrategy?: PersistedUpdateStrategy;
|
|
801
|
+
};
|
|
802
|
+
|
|
803
|
+
const isPersistedUpdateStrategy = (
|
|
804
|
+
value: unknown,
|
|
805
|
+
): value is PersistedUpdateStrategy => {
|
|
806
|
+
return value === "appVersion" || value === "fingerprint";
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
const readRawNotifyAppReadyResult = (): RawNotifyAppReadyResult => {
|
|
810
|
+
const result = HotUpdaterNative.notifyAppReady();
|
|
811
|
+
|
|
812
|
+
if (typeof result === "string") {
|
|
813
|
+
try {
|
|
814
|
+
const parsed = JSON.parse(result) as unknown;
|
|
815
|
+
if (
|
|
816
|
+
typeof parsed !== "object" ||
|
|
817
|
+
parsed === null ||
|
|
818
|
+
Array.isArray(parsed)
|
|
819
|
+
) {
|
|
820
|
+
return {};
|
|
821
|
+
}
|
|
822
|
+
return parsed as RawNotifyAppReadyResult;
|
|
823
|
+
} catch {
|
|
824
|
+
return {};
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
if (typeof result !== "object" || result === null || Array.isArray(result)) {
|
|
829
|
+
return {};
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
return result as RawNotifyAppReadyResult;
|
|
833
|
+
};
|
|
834
|
+
|
|
835
|
+
const readDirectionalBundleId = (bundleId: unknown): string | null => {
|
|
836
|
+
if (typeof bundleId !== "string") {
|
|
837
|
+
return null;
|
|
838
|
+
}
|
|
839
|
+
const normalizedBundleId = bundleId.trim();
|
|
840
|
+
if (normalizedBundleId.length === 0) {
|
|
841
|
+
return null;
|
|
842
|
+
}
|
|
843
|
+
return resolveBundleId(normalizedBundleId);
|
|
844
|
+
};
|
|
845
|
+
|
|
846
|
+
const readDirectionalReleaseId = (releaseId: unknown): string | null => {
|
|
847
|
+
if (typeof releaseId !== "string") return null;
|
|
848
|
+
const normalizedReleaseId = releaseId.trim();
|
|
849
|
+
return normalizedReleaseId.length === 0 ? null : normalizedReleaseId;
|
|
850
|
+
};
|
|
851
|
+
|
|
852
|
+
const getNotifyAppReadyTransition = (
|
|
853
|
+
result: RawNotifyAppReadyResult,
|
|
854
|
+
): {
|
|
855
|
+
status: "UPDATE_APPLIED" | "RECOVERED";
|
|
856
|
+
fromBundleId: string;
|
|
857
|
+
toBundleId: string;
|
|
858
|
+
fromReleaseId: string | null;
|
|
859
|
+
toReleaseId: string | null;
|
|
860
|
+
} | null => {
|
|
861
|
+
if (result.status === "UPDATE_APPLIED" || result.status === "PROMOTED") {
|
|
862
|
+
const fromBundleId = readDirectionalBundleId(result.fromBundleId);
|
|
863
|
+
const toBundleId = readDirectionalBundleId(result.toBundleId);
|
|
864
|
+
if (fromBundleId && toBundleId) {
|
|
865
|
+
return {
|
|
866
|
+
status: "UPDATE_APPLIED",
|
|
867
|
+
fromBundleId,
|
|
868
|
+
toBundleId,
|
|
869
|
+
fromReleaseId: readDirectionalReleaseId(result.fromReleaseId),
|
|
870
|
+
toReleaseId: readDirectionalReleaseId(result.toReleaseId),
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
if (result.status === "RECOVERED") {
|
|
876
|
+
const fromBundleId = readDirectionalBundleId(result.fromBundleId);
|
|
877
|
+
const toBundleId = readDirectionalBundleId(result.toBundleId);
|
|
878
|
+
if (fromBundleId && toBundleId) {
|
|
879
|
+
return {
|
|
880
|
+
status: "RECOVERED",
|
|
881
|
+
fromBundleId,
|
|
882
|
+
toBundleId,
|
|
883
|
+
fromReleaseId: readDirectionalReleaseId(result.fromReleaseId),
|
|
884
|
+
toReleaseId: readDirectionalReleaseId(result.toReleaseId),
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
return null;
|
|
890
|
+
};
|
|
891
|
+
|
|
892
|
+
const getNotifyAppReadyAnalyticsEvent = (
|
|
893
|
+
result: RawNotifyAppReadyResult,
|
|
894
|
+
): NotifyAppReadyAnalyticsEvent | null => {
|
|
895
|
+
const transition = getNotifyAppReadyTransition(result);
|
|
896
|
+
|
|
897
|
+
if (!transition || !isPersistedUpdateStrategy(result.updateStrategy)) {
|
|
898
|
+
return null;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
return {
|
|
902
|
+
type: transition.status,
|
|
903
|
+
fromBundleId: transition.fromBundleId,
|
|
904
|
+
toBundleId: transition.toBundleId,
|
|
905
|
+
...(transition.fromReleaseId === null
|
|
906
|
+
? {}
|
|
907
|
+
: { fromReleaseId: transition.fromReleaseId }),
|
|
908
|
+
...(transition.toReleaseId === null
|
|
909
|
+
? {}
|
|
910
|
+
: { toReleaseId: transition.toReleaseId }),
|
|
911
|
+
updateStrategy: result.updateStrategy,
|
|
912
|
+
};
|
|
913
|
+
};
|
|
914
|
+
|
|
915
|
+
const normalizeNotifyAppReadyResult = (
|
|
916
|
+
result: RawNotifyAppReadyResult,
|
|
917
|
+
): NotifyAppReadyResult => {
|
|
918
|
+
const transition = getNotifyAppReadyTransition(result);
|
|
919
|
+
|
|
920
|
+
if (transition) {
|
|
921
|
+
return {
|
|
922
|
+
status: transition.status,
|
|
923
|
+
fromBundleId: transition.fromBundleId,
|
|
924
|
+
toBundleId: transition.toBundleId,
|
|
925
|
+
...(transition.fromReleaseId === null
|
|
926
|
+
? {}
|
|
927
|
+
: { fromReleaseId: transition.fromReleaseId }),
|
|
928
|
+
...(transition.toReleaseId === null
|
|
929
|
+
? {}
|
|
930
|
+
: { toReleaseId: transition.toReleaseId }),
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
return { status: "UNCHANGED" };
|
|
935
|
+
};
|
|
936
|
+
|
|
937
|
+
export const readNotifyAppReady = (): {
|
|
938
|
+
result: NotifyAppReadyResult;
|
|
939
|
+
analyticsEvent: NotifyAppReadyAnalyticsEvent | null;
|
|
940
|
+
pending: boolean;
|
|
941
|
+
} => {
|
|
942
|
+
const rawResult = readRawNotifyAppReadyResult();
|
|
943
|
+
|
|
944
|
+
return {
|
|
945
|
+
result: normalizeNotifyAppReadyResult(rawResult),
|
|
946
|
+
analyticsEvent: getNotifyAppReadyAnalyticsEvent(rawResult),
|
|
947
|
+
pending: rawResult.status === "PENDING",
|
|
948
|
+
};
|
|
622
949
|
};
|
|
623
950
|
|
|
624
951
|
/**
|
|
@@ -627,46 +954,21 @@ export type NotifyAppReadyResult = {
|
|
|
627
954
|
* This function is called automatically after the app has rendered.
|
|
628
955
|
*
|
|
629
956
|
* @returns {NotifyAppReadyResult} Bundle state information
|
|
630
|
-
* - `status: "
|
|
631
|
-
* - `status: "
|
|
632
|
-
* - `
|
|
957
|
+
* - `status: "UNCHANGED"` - No qualifying OTA transition to report
|
|
958
|
+
* - `status: "UPDATE_APPLIED"` - A pending update became active
|
|
959
|
+
* - `status: "RECOVERED"` - Crash recovery rolled back to another bundle
|
|
633
960
|
*
|
|
634
961
|
* @example
|
|
635
962
|
* ```ts
|
|
636
963
|
* const result = HotUpdater.notifyAppReady();
|
|
637
964
|
*
|
|
638
965
|
* if (result.status === "RECOVERED") {
|
|
639
|
-
*
|
|
640
|
-
* analytics.track("bundle_rollback", {
|
|
641
|
-
* crashedBundleId: result.crashedBundleId,
|
|
642
|
-
* });
|
|
966
|
+
* console.log(result.fromBundleId, result.toBundleId);
|
|
643
967
|
* }
|
|
644
968
|
* ```
|
|
645
969
|
*/
|
|
646
970
|
export const notifyAppReady = (): NotifyAppReadyResult => {
|
|
647
|
-
|
|
648
|
-
// Older Android old-arch implementations returned JSON strings.
|
|
649
|
-
if (typeof result === "string") {
|
|
650
|
-
try {
|
|
651
|
-
return normalizeNotifyAppReadyResult(JSON.parse(result));
|
|
652
|
-
} catch {
|
|
653
|
-
return { status: "STABLE" };
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
return normalizeNotifyAppReadyResult(result);
|
|
657
|
-
};
|
|
658
|
-
|
|
659
|
-
const normalizeNotifyAppReadyResult = (
|
|
660
|
-
result: NotifyAppReadyResult | { status?: string; crashedBundleId?: string },
|
|
661
|
-
): NotifyAppReadyResult => {
|
|
662
|
-
if (result.status === "RECOVERED") {
|
|
663
|
-
return {
|
|
664
|
-
status: "RECOVERED",
|
|
665
|
-
crashedBundleId: result.crashedBundleId,
|
|
666
|
-
};
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
return { status: "STABLE" };
|
|
971
|
+
return readNotifyAppReady().result;
|
|
670
972
|
};
|
|
671
973
|
|
|
672
974
|
const createEmptyManifest = (): Manifest => ({
|