@hot-updater/react-native 0.36.7 → 1.0.0-rc.1
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 +47 -70
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.spec.js +115 -159
- 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 -53
- 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 +48 -65
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.spec.js +115 -159
- 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 -49
- 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 +31 -40
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/native.d.ts +84 -17
- 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 +31 -40
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/native.d.ts +84 -17
- 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 +367 -96
- 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 +108 -201
- package/src/index.ts +68 -91
- package/src/iosInterop.spec.ts +30 -0
- package/src/native.spec.ts +226 -10
- package/src/native.ts +385 -81
- 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)) {
|
|
@@ -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,20 @@ export function setReloadBehavior(
|
|
|
515
588
|
}
|
|
516
589
|
|
|
517
590
|
/**
|
|
518
|
-
* Fetches the minimum bundle id
|
|
519
|
-
*
|
|
591
|
+
* Fetches the minimum bundle id created from the native app build time.
|
|
592
|
+
*
|
|
593
|
+
* Release Catalog selection uses this value as its minimum Release id.
|
|
520
594
|
*
|
|
521
|
-
* @returns {string}
|
|
595
|
+
* @returns {string} The minimum bundle id.
|
|
522
596
|
*/
|
|
523
597
|
export const getMinBundleId = (): string => {
|
|
524
598
|
const constants = HotUpdaterNative.getConstants();
|
|
525
599
|
return constants.MIN_BUNDLE_ID;
|
|
526
600
|
};
|
|
527
601
|
|
|
602
|
+
export const getReleaseId = async (): Promise<string | null> =>
|
|
603
|
+
getActiveUpdateState().activeSelection?.releaseId ?? null;
|
|
604
|
+
|
|
528
605
|
/**
|
|
529
606
|
* Fetches the current bundle version id.
|
|
530
607
|
*
|
|
@@ -613,12 +690,264 @@ export const getFingerprintHash = (): string | null => {
|
|
|
613
690
|
return constants.FINGERPRINT_HASH;
|
|
614
691
|
};
|
|
615
692
|
|
|
693
|
+
export const getInstallId = (): string => {
|
|
694
|
+
const nativeModule = HotUpdaterNative as typeof HotUpdaterNative & {
|
|
695
|
+
getInstallId?: () => string;
|
|
696
|
+
};
|
|
697
|
+
|
|
698
|
+
if (typeof nativeModule.getInstallId !== "function") {
|
|
699
|
+
throw new Error(
|
|
700
|
+
"[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.",
|
|
701
|
+
);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
return nativeModule.getInstallId();
|
|
705
|
+
};
|
|
706
|
+
|
|
707
|
+
export type PersistedUserIdentity = {
|
|
708
|
+
userId?: string;
|
|
709
|
+
username?: string;
|
|
710
|
+
};
|
|
711
|
+
|
|
712
|
+
export const getPersistedUserIdentity = (): PersistedUserIdentity => {
|
|
713
|
+
const nativeModule = HotUpdaterNative as typeof HotUpdaterNative & {
|
|
714
|
+
getUserId?: () => string | null;
|
|
715
|
+
getUsername?: () => string | null;
|
|
716
|
+
};
|
|
717
|
+
|
|
718
|
+
if (
|
|
719
|
+
typeof nativeModule.getUserId !== "function" ||
|
|
720
|
+
typeof nativeModule.getUsername !== "function"
|
|
721
|
+
) {
|
|
722
|
+
throw new Error(
|
|
723
|
+
"[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.",
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
const userId = nativeModule.getUserId();
|
|
728
|
+
const username = nativeModule.getUsername();
|
|
729
|
+
|
|
730
|
+
return {
|
|
731
|
+
...(userId != null ? { userId } : {}),
|
|
732
|
+
...(username != null ? { username } : {}),
|
|
733
|
+
};
|
|
734
|
+
};
|
|
735
|
+
|
|
736
|
+
export type SetUserParams = {
|
|
737
|
+
userId?: string | number | null;
|
|
738
|
+
username?: string | null;
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
export function setUser(params: SetUserParams): void;
|
|
742
|
+
export function setUser(params: null): void;
|
|
743
|
+
export function setUser(params: SetUserParams | null): void {
|
|
744
|
+
const nativeModule = HotUpdaterNative as typeof HotUpdaterNative & {
|
|
745
|
+
setUser?: (userId: string | null, username: string | null) => void;
|
|
746
|
+
};
|
|
747
|
+
|
|
748
|
+
if (typeof nativeModule.setUser !== "function") {
|
|
749
|
+
throw new Error(
|
|
750
|
+
"[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.",
|
|
751
|
+
);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
if (params === null) {
|
|
755
|
+
nativeModule.setUser(null, null);
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
const normalizedUserId =
|
|
760
|
+
params.userId === null || params.userId === undefined
|
|
761
|
+
? null
|
|
762
|
+
: String(params.userId);
|
|
763
|
+
nativeModule.setUser(normalizedUserId, params.username ?? null);
|
|
764
|
+
}
|
|
765
|
+
|
|
616
766
|
/**
|
|
617
767
|
* Result returned by notifyAppReady()
|
|
618
768
|
*/
|
|
619
|
-
export type NotifyAppReadyResult =
|
|
620
|
-
status: "
|
|
769
|
+
export type NotifyAppReadyResult =
|
|
770
|
+
| { status: "UNCHANGED" }
|
|
771
|
+
| {
|
|
772
|
+
status: "UPDATE_APPLIED";
|
|
773
|
+
fromBundleId: string;
|
|
774
|
+
toBundleId: string;
|
|
775
|
+
fromReleaseId?: string;
|
|
776
|
+
toReleaseId?: string;
|
|
777
|
+
}
|
|
778
|
+
| {
|
|
779
|
+
status: "RECOVERED";
|
|
780
|
+
fromBundleId: string;
|
|
781
|
+
toBundleId: string;
|
|
782
|
+
fromReleaseId?: string;
|
|
783
|
+
toReleaseId?: string;
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
export type NotifyAppReadyAnalyticsEvent = {
|
|
787
|
+
type: "UPDATE_APPLIED" | "RECOVERED";
|
|
788
|
+
fromBundleId: string;
|
|
789
|
+
toBundleId: string;
|
|
790
|
+
fromReleaseId?: string | null;
|
|
791
|
+
toReleaseId?: string | null;
|
|
792
|
+
updateStrategy: PersistedUpdateStrategy;
|
|
793
|
+
};
|
|
794
|
+
|
|
795
|
+
type RawNotifyAppReadyResult = {
|
|
796
|
+
status?: string;
|
|
621
797
|
crashedBundleId?: string;
|
|
798
|
+
fromReleaseId?: string;
|
|
799
|
+
fromBundleId?: string;
|
|
800
|
+
toReleaseId?: string;
|
|
801
|
+
toBundleId?: string;
|
|
802
|
+
updateStrategy?: PersistedUpdateStrategy;
|
|
803
|
+
};
|
|
804
|
+
|
|
805
|
+
const isPersistedUpdateStrategy = (
|
|
806
|
+
value: unknown,
|
|
807
|
+
): value is PersistedUpdateStrategy => {
|
|
808
|
+
return value === "appVersion" || value === "fingerprint";
|
|
809
|
+
};
|
|
810
|
+
|
|
811
|
+
const readRawNotifyAppReadyResult = (): RawNotifyAppReadyResult => {
|
|
812
|
+
const result = HotUpdaterNative.notifyAppReady();
|
|
813
|
+
|
|
814
|
+
if (typeof result === "string") {
|
|
815
|
+
try {
|
|
816
|
+
const parsed = JSON.parse(result) as unknown;
|
|
817
|
+
if (
|
|
818
|
+
typeof parsed !== "object" ||
|
|
819
|
+
parsed === null ||
|
|
820
|
+
Array.isArray(parsed)
|
|
821
|
+
) {
|
|
822
|
+
return {};
|
|
823
|
+
}
|
|
824
|
+
return parsed as RawNotifyAppReadyResult;
|
|
825
|
+
} catch {
|
|
826
|
+
return {};
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
if (typeof result !== "object" || result === null || Array.isArray(result)) {
|
|
831
|
+
return {};
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
return result as RawNotifyAppReadyResult;
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
const readDirectionalBundleId = (bundleId: unknown): string | null => {
|
|
838
|
+
if (typeof bundleId !== "string") {
|
|
839
|
+
return null;
|
|
840
|
+
}
|
|
841
|
+
const normalizedBundleId = bundleId.trim();
|
|
842
|
+
if (normalizedBundleId.length === 0) {
|
|
843
|
+
return null;
|
|
844
|
+
}
|
|
845
|
+
return resolveBundleId(normalizedBundleId);
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
const readDirectionalReleaseId = (releaseId: unknown): string | null => {
|
|
849
|
+
if (typeof releaseId !== "string") return null;
|
|
850
|
+
const normalizedReleaseId = releaseId.trim();
|
|
851
|
+
return normalizedReleaseId.length === 0 ? null : normalizedReleaseId;
|
|
852
|
+
};
|
|
853
|
+
|
|
854
|
+
const getNotifyAppReadyTransition = (
|
|
855
|
+
result: RawNotifyAppReadyResult,
|
|
856
|
+
): {
|
|
857
|
+
status: "UPDATE_APPLIED" | "RECOVERED";
|
|
858
|
+
fromBundleId: string;
|
|
859
|
+
toBundleId: string;
|
|
860
|
+
fromReleaseId: string | null;
|
|
861
|
+
toReleaseId: string | null;
|
|
862
|
+
} | null => {
|
|
863
|
+
if (result.status === "UPDATE_APPLIED" || result.status === "PROMOTED") {
|
|
864
|
+
const fromBundleId = readDirectionalBundleId(result.fromBundleId);
|
|
865
|
+
const toBundleId = readDirectionalBundleId(result.toBundleId);
|
|
866
|
+
if (fromBundleId && toBundleId) {
|
|
867
|
+
return {
|
|
868
|
+
status: "UPDATE_APPLIED",
|
|
869
|
+
fromBundleId,
|
|
870
|
+
toBundleId,
|
|
871
|
+
fromReleaseId: readDirectionalReleaseId(result.fromReleaseId),
|
|
872
|
+
toReleaseId: readDirectionalReleaseId(result.toReleaseId),
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
if (result.status === "RECOVERED") {
|
|
878
|
+
const fromBundleId = readDirectionalBundleId(result.fromBundleId);
|
|
879
|
+
const toBundleId = readDirectionalBundleId(result.toBundleId);
|
|
880
|
+
if (fromBundleId && toBundleId) {
|
|
881
|
+
return {
|
|
882
|
+
status: "RECOVERED",
|
|
883
|
+
fromBundleId,
|
|
884
|
+
toBundleId,
|
|
885
|
+
fromReleaseId: readDirectionalReleaseId(result.fromReleaseId),
|
|
886
|
+
toReleaseId: readDirectionalReleaseId(result.toReleaseId),
|
|
887
|
+
};
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
return null;
|
|
892
|
+
};
|
|
893
|
+
|
|
894
|
+
const getNotifyAppReadyAnalyticsEvent = (
|
|
895
|
+
result: RawNotifyAppReadyResult,
|
|
896
|
+
): NotifyAppReadyAnalyticsEvent | null => {
|
|
897
|
+
const transition = getNotifyAppReadyTransition(result);
|
|
898
|
+
|
|
899
|
+
if (!transition || !isPersistedUpdateStrategy(result.updateStrategy)) {
|
|
900
|
+
return null;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
return {
|
|
904
|
+
type: transition.status,
|
|
905
|
+
fromBundleId: transition.fromBundleId,
|
|
906
|
+
toBundleId: transition.toBundleId,
|
|
907
|
+
...(transition.fromReleaseId === null
|
|
908
|
+
? {}
|
|
909
|
+
: { fromReleaseId: transition.fromReleaseId }),
|
|
910
|
+
...(transition.toReleaseId === null
|
|
911
|
+
? {}
|
|
912
|
+
: { toReleaseId: transition.toReleaseId }),
|
|
913
|
+
updateStrategy: result.updateStrategy,
|
|
914
|
+
};
|
|
915
|
+
};
|
|
916
|
+
|
|
917
|
+
const normalizeNotifyAppReadyResult = (
|
|
918
|
+
result: RawNotifyAppReadyResult,
|
|
919
|
+
): NotifyAppReadyResult => {
|
|
920
|
+
const transition = getNotifyAppReadyTransition(result);
|
|
921
|
+
|
|
922
|
+
if (transition) {
|
|
923
|
+
return {
|
|
924
|
+
status: transition.status,
|
|
925
|
+
fromBundleId: transition.fromBundleId,
|
|
926
|
+
toBundleId: transition.toBundleId,
|
|
927
|
+
...(transition.fromReleaseId === null
|
|
928
|
+
? {}
|
|
929
|
+
: { fromReleaseId: transition.fromReleaseId }),
|
|
930
|
+
...(transition.toReleaseId === null
|
|
931
|
+
? {}
|
|
932
|
+
: { toReleaseId: transition.toReleaseId }),
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
return { status: "UNCHANGED" };
|
|
937
|
+
};
|
|
938
|
+
|
|
939
|
+
export const readNotifyAppReady = (): {
|
|
940
|
+
result: NotifyAppReadyResult;
|
|
941
|
+
analyticsEvent: NotifyAppReadyAnalyticsEvent | null;
|
|
942
|
+
pending: boolean;
|
|
943
|
+
} => {
|
|
944
|
+
const rawResult = readRawNotifyAppReadyResult();
|
|
945
|
+
|
|
946
|
+
return {
|
|
947
|
+
result: normalizeNotifyAppReadyResult(rawResult),
|
|
948
|
+
analyticsEvent: getNotifyAppReadyAnalyticsEvent(rawResult),
|
|
949
|
+
pending: rawResult.status === "PENDING",
|
|
950
|
+
};
|
|
622
951
|
};
|
|
623
952
|
|
|
624
953
|
/**
|
|
@@ -627,46 +956,21 @@ export type NotifyAppReadyResult = {
|
|
|
627
956
|
* This function is called automatically after the app has rendered.
|
|
628
957
|
*
|
|
629
958
|
* @returns {NotifyAppReadyResult} Bundle state information
|
|
630
|
-
* - `status: "
|
|
631
|
-
* - `status: "
|
|
632
|
-
* - `
|
|
959
|
+
* - `status: "UNCHANGED"` - No qualifying OTA transition to report
|
|
960
|
+
* - `status: "UPDATE_APPLIED"` - A pending update became active
|
|
961
|
+
* - `status: "RECOVERED"` - Crash recovery rolled back to another bundle
|
|
633
962
|
*
|
|
634
963
|
* @example
|
|
635
964
|
* ```ts
|
|
636
965
|
* const result = HotUpdater.notifyAppReady();
|
|
637
966
|
*
|
|
638
967
|
* if (result.status === "RECOVERED") {
|
|
639
|
-
*
|
|
640
|
-
* analytics.track("bundle_rollback", {
|
|
641
|
-
* crashedBundleId: result.crashedBundleId,
|
|
642
|
-
* });
|
|
968
|
+
* console.log(result.fromBundleId, result.toBundleId);
|
|
643
969
|
* }
|
|
644
970
|
* ```
|
|
645
971
|
*/
|
|
646
972
|
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" };
|
|
973
|
+
return readNotifyAppReady().result;
|
|
670
974
|
};
|
|
671
975
|
|
|
672
976
|
const createEmptyManifest = (): Manifest => ({
|