@hot-updater/react-native 0.1.4 → 0.1.6-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/HotUpdater.podspec +1 -2
- package/android/build.gradle +16 -3
- package/android/generated/java/com/hotupdater/NativeHotUpdaterSpec.java +54 -0
- package/android/generated/jni/CMakeLists.txt +36 -0
- package/android/generated/jni/HotUpdaterSpec-generated.cpp +56 -0
- package/android/generated/jni/HotUpdaterSpec.h +31 -0
- package/android/generated/jni/react/renderer/components/HotUpdaterSpec/HotUpdaterSpecJSI-generated.cpp +57 -0
- package/android/generated/jni/react/renderer/components/HotUpdaterSpec/HotUpdaterSpecJSI.h +103 -0
- package/android/react-native-helpers.gradle +42 -0
- package/android/src/main/java/com/hotupdater/HotUpdater.kt +151 -240
- package/android/src/main/java/com/hotupdater/HotUpdaterModule.kt +52 -40
- package/android/src/main/java/com/hotupdater/HotUpdaterPackage.kt +25 -24
- package/android/src/main/java/com/hotupdater/ReactIntegrationManagerBase.kt +34 -0
- package/android/src/newarch/HotUpdaterSpec.kt +3 -2
- package/android/src/newarch/ReactIntegrationManager.kt +46 -0
- package/android/src/oldarch/HotUpdaterSpec.kt +12 -8
- package/android/src/oldarch/ReactIntegrationManager.kt +41 -0
- package/dist/index.d.mts +71 -0
- package/dist/index.d.ts +44 -53
- package/dist/index.js +4310 -132
- package/dist/index.mjs +4362 -0
- package/ios/HotUpdater/HotUpdater.h +8 -4
- package/ios/HotUpdater/HotUpdater.mm +167 -116
- package/ios/generated/HotUpdaterSpec/HotUpdaterSpec-generated.mm +67 -0
- package/ios/generated/HotUpdaterSpec/HotUpdaterSpec.h +67 -0
- package/ios/generated/HotUpdaterSpecJSI-generated.cpp +57 -0
- package/ios/generated/HotUpdaterSpecJSI.h +103 -0
- package/package.json +27 -10
- package/react-native.config.js +12 -0
- package/src/ensureBundles.ts +21 -0
- package/src/global.d.ts +3 -0
- package/src/index.ts +27 -5
- package/src/init.tsx +25 -7
- package/src/native.ts +50 -42
- package/src/specs/{NativeHotUpdaterModule.ts → NativeHotUpdater.ts} +6 -7
- package/src/store.ts +48 -0
- package/dist/index.cjs +0 -220
- package/dist/index.d.cts +0 -80
- package/src/checkForUpdate.test.ts +0 -517
- package/src/checkForUpdate.ts +0 -111
- package/src/utils.ts +0 -2
package/package.json
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/react-native",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"type": "module",
|
|
3
|
+
"version": "0.1.6-0",
|
|
5
4
|
"description": "React Native OTA solution for self-hosted",
|
|
6
5
|
"main": "dist/index.cjs",
|
|
7
6
|
"module": "dist/index.js",
|
|
7
|
+
"source": "src/index.ts",
|
|
8
8
|
"react-native": "src/index.ts",
|
|
9
9
|
"types": "dist/index.d.ts",
|
|
10
10
|
"files": [
|
|
11
|
-
"dist",
|
|
12
11
|
"src",
|
|
12
|
+
"dist",
|
|
13
13
|
"android",
|
|
14
14
|
"ios",
|
|
15
15
|
"cpp",
|
|
16
16
|
"*.podspec",
|
|
17
|
+
"react-native.config.js",
|
|
17
18
|
"!ios/build",
|
|
18
19
|
"!android/build",
|
|
19
20
|
"!android/gradle",
|
|
@@ -42,29 +43,45 @@
|
|
|
42
43
|
"publishConfig": {
|
|
43
44
|
"access": "public"
|
|
44
45
|
},
|
|
46
|
+
"react-native-builder-bob": {
|
|
47
|
+
"source": "src",
|
|
48
|
+
"output": "dist",
|
|
49
|
+
"targets": [
|
|
50
|
+
"codegen"
|
|
51
|
+
]
|
|
52
|
+
},
|
|
45
53
|
"codegenConfig": {
|
|
46
54
|
"name": "HotUpdaterSpec",
|
|
47
55
|
"type": "modules",
|
|
48
|
-
"jsSrcsDir": "
|
|
56
|
+
"jsSrcsDir": "src/specs",
|
|
57
|
+
"outputDir": {
|
|
58
|
+
"ios": "ios/generated",
|
|
59
|
+
"android": "android/generated"
|
|
60
|
+
},
|
|
49
61
|
"android": {
|
|
50
62
|
"javaPackageName": "com.hotupdater"
|
|
51
|
-
}
|
|
63
|
+
},
|
|
64
|
+
"includesGeneratedCode": true
|
|
52
65
|
},
|
|
53
66
|
"peerDependencies": {
|
|
54
67
|
"react-native": "*"
|
|
55
68
|
},
|
|
56
69
|
"devDependencies": {
|
|
57
|
-
"@
|
|
58
|
-
"react": "^18.2.
|
|
59
|
-
"
|
|
70
|
+
"@react-native-community/cli": "15.0.1",
|
|
71
|
+
"@types/react": "^18.2.44",
|
|
72
|
+
"del-cli": "^6.0.0",
|
|
73
|
+
"react": "18.3.1",
|
|
74
|
+
"react-native": "0.76.2",
|
|
75
|
+
"react-native-builder-bob": "^0.33.1",
|
|
76
|
+
"@hot-updater/js": "0.1.6-0"
|
|
60
77
|
},
|
|
61
78
|
"dependencies": {
|
|
62
|
-
"@hot-updater/
|
|
79
|
+
"@hot-updater/core": "0.1.6-0"
|
|
63
80
|
},
|
|
64
81
|
"scripts": {
|
|
65
82
|
"build": "tsup src/index.ts --format esm,cjs --dts",
|
|
66
83
|
"test:type": "tsc --noEmit",
|
|
67
84
|
"test": "vitest",
|
|
68
|
-
"
|
|
85
|
+
"clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib"
|
|
69
86
|
}
|
|
70
87
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Bundle, BundleArg } from "@hot-updater/core";
|
|
2
|
+
|
|
3
|
+
export const ensureBundles = async (bundle: BundleArg) => {
|
|
4
|
+
try {
|
|
5
|
+
let bundles: Bundle[] | null = null;
|
|
6
|
+
if (typeof bundle === "string") {
|
|
7
|
+
if (bundle.startsWith("http")) {
|
|
8
|
+
const response = await fetch(bundle);
|
|
9
|
+
bundles = (await response.json()) as Bundle[];
|
|
10
|
+
}
|
|
11
|
+
} else if (typeof bundle === "function") {
|
|
12
|
+
bundles = await bundle();
|
|
13
|
+
} else {
|
|
14
|
+
bundles = bundle;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return bundles ?? [];
|
|
18
|
+
} catch {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
};
|
package/src/global.d.ts
ADDED
package/src/index.ts
CHANGED
|
@@ -1,15 +1,37 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NIL_UUID } from "@hot-updater/core";
|
|
2
|
+
import { getUpdateInfo } from "@hot-updater/js";
|
|
3
|
+
import { ensureBundles } from "./ensureBundles";
|
|
2
4
|
import { init } from "./init";
|
|
3
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
addListener,
|
|
7
|
+
getAppVersion,
|
|
8
|
+
getBundleId,
|
|
9
|
+
reload,
|
|
10
|
+
updateBundle,
|
|
11
|
+
} from "./native";
|
|
12
|
+
import { hotUpdaterStore } from "./store";
|
|
4
13
|
|
|
5
14
|
export type * from "./init";
|
|
6
|
-
export type * from "./checkForUpdate";
|
|
7
15
|
export type * from "./native";
|
|
8
16
|
|
|
17
|
+
export * from "./store";
|
|
18
|
+
|
|
19
|
+
addListener("onProgress", ({ progress }) => {
|
|
20
|
+
hotUpdaterStore.setState({ progress });
|
|
21
|
+
});
|
|
22
|
+
|
|
9
23
|
export const HotUpdater = {
|
|
10
24
|
init,
|
|
11
25
|
reload,
|
|
12
|
-
checkForUpdate,
|
|
13
26
|
getAppVersion,
|
|
14
|
-
|
|
27
|
+
getBundleId,
|
|
28
|
+
addListener,
|
|
29
|
+
|
|
30
|
+
ensureBundles,
|
|
31
|
+
updateBundle,
|
|
32
|
+
getUpdateInfo,
|
|
33
|
+
/**
|
|
34
|
+
* In production environment, this value will be replaced with a uuidv7.
|
|
35
|
+
*/
|
|
36
|
+
HOT_UPDATER_BUNDLE_ID: NIL_UUID,
|
|
15
37
|
};
|
package/src/init.tsx
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BundleArg } from "@hot-updater/core";
|
|
2
|
+
import { getUpdateInfo } from "@hot-updater/js";
|
|
2
3
|
import { Platform } from "react-native";
|
|
3
|
-
import {
|
|
4
|
+
import { ensureBundles } from "./ensureBundles";
|
|
4
5
|
import { HotUpdaterError } from "./error";
|
|
5
|
-
import {
|
|
6
|
+
import { getAppVersion, getBundleId, reload, updateBundle } from "./native";
|
|
6
7
|
|
|
7
8
|
export type HotUpdaterStatus = "INSTALLING_UPDATE" | "UP_TO_DATE";
|
|
8
9
|
|
|
9
10
|
export interface HotUpdaterInitConfig {
|
|
10
|
-
source:
|
|
11
|
+
source: BundleArg;
|
|
11
12
|
onSuccess?: (status: HotUpdaterStatus) => void;
|
|
12
13
|
onError?: (error: HotUpdaterError) => void;
|
|
13
14
|
}
|
|
@@ -28,18 +29,35 @@ export const init = async (config: HotUpdaterInitConfig) => {
|
|
|
28
29
|
config?.onError?.(error);
|
|
29
30
|
throw error;
|
|
30
31
|
}
|
|
31
|
-
await initializeOnAppUpdate();
|
|
32
32
|
|
|
33
|
-
const
|
|
33
|
+
const currentAppVersion = await getAppVersion();
|
|
34
|
+
const platform = Platform.OS as "ios" | "android";
|
|
35
|
+
const currentBundleId = await getBundleId();
|
|
36
|
+
|
|
37
|
+
if (!currentAppVersion) {
|
|
38
|
+
const error = new HotUpdaterError("Failed to get app version");
|
|
39
|
+
config?.onError?.(error);
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const bundles = await ensureBundles(config.source);
|
|
44
|
+
|
|
45
|
+
const update = await getUpdateInfo(bundles, {
|
|
46
|
+
appVersion: currentAppVersion,
|
|
47
|
+
bundleId: currentBundleId,
|
|
48
|
+
platform,
|
|
49
|
+
});
|
|
50
|
+
|
|
34
51
|
if (!update) {
|
|
35
52
|
config?.onSuccess?.("UP_TO_DATE");
|
|
36
53
|
return;
|
|
37
54
|
}
|
|
38
55
|
|
|
39
56
|
try {
|
|
40
|
-
const isSuccess = await updateBundle(update.
|
|
57
|
+
const isSuccess = await updateBundle(update.id, update.fileUrl || "");
|
|
41
58
|
if (isSuccess && update.forceUpdate) {
|
|
42
59
|
reload();
|
|
60
|
+
|
|
43
61
|
config?.onSuccess?.("INSTALLING_UPDATE");
|
|
44
62
|
}
|
|
45
63
|
} catch (error) {
|
package/src/native.ts
CHANGED
|
@@ -1,72 +1,80 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { NIL_UUID } from "@hot-updater/core";
|
|
2
|
+
import { NativeEventEmitter, NativeModules, Platform } from "react-native";
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const LINKING_ERROR =
|
|
5
|
+
// biome-ignore lint/style/useTemplate: <explanation>
|
|
6
|
+
`The package '@hot-updater/react-native' doesn't seem to be linked. Make sure: \n\n` +
|
|
7
|
+
Platform.select({ ios: "- You have run 'pod install'\n", default: "" }) +
|
|
8
|
+
"- You rebuilt the app after installing the package\n" +
|
|
9
|
+
"- You are not using Expo Go\n";
|
|
10
|
+
|
|
11
|
+
// @ts-expect-error
|
|
12
|
+
const isTurboModuleEnabled = global.__turboModuleProxy != null;
|
|
13
|
+
|
|
14
|
+
const HotUpdaterModule = isTurboModuleEnabled
|
|
15
|
+
? require("./specs/NativeHotUpdater").default
|
|
16
|
+
: NativeModules.HotUpdater;
|
|
17
|
+
|
|
18
|
+
const HotUpdaterNative = HotUpdaterModule
|
|
19
|
+
? HotUpdaterModule
|
|
20
|
+
: new Proxy(
|
|
21
|
+
{},
|
|
22
|
+
{
|
|
23
|
+
get() {
|
|
24
|
+
throw new Error(LINKING_ERROR);
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export type HotUpdaterEvent = {
|
|
30
|
+
onProgress: {
|
|
31
|
+
progress: number;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const addListener = <T extends keyof HotUpdaterEvent>(
|
|
36
|
+
eventName: T,
|
|
37
|
+
listener: (event: HotUpdaterEvent[T]) => void,
|
|
38
|
+
) => {
|
|
39
|
+
const eventEmitter = new NativeEventEmitter(HotUpdaterNative);
|
|
40
|
+
|
|
41
|
+
eventEmitter?.addListener(eventName, listener);
|
|
42
|
+
};
|
|
5
43
|
|
|
6
44
|
/**
|
|
7
45
|
* Fetches the current bundle version id.
|
|
8
46
|
*
|
|
9
47
|
* @async
|
|
10
|
-
* @returns {Promise<
|
|
48
|
+
* @returns {Promise<string>} Resolves with the current version id or null if not available.
|
|
11
49
|
*/
|
|
12
|
-
export const
|
|
13
|
-
return
|
|
14
|
-
HotUpdater.getBundleVersion((version: number | null) => {
|
|
15
|
-
resolve(version ?? -1);
|
|
16
|
-
});
|
|
17
|
-
});
|
|
50
|
+
export const getBundleId = (): string => {
|
|
51
|
+
return HotUpdater.HOT_UPDATER_BUNDLE_ID ?? NIL_UUID;
|
|
18
52
|
};
|
|
19
53
|
|
|
20
54
|
/**
|
|
21
55
|
* Downloads files from given URLs.
|
|
22
56
|
*
|
|
23
|
-
* @
|
|
24
|
-
* @param {string} bundleVersion - identifier for the bundle version.
|
|
57
|
+
* @param {string} bundleId - identifier for the bundle version.
|
|
25
58
|
* @param {string | null} zipUrl - zip file URL.
|
|
26
59
|
* @returns {Promise<boolean>} Resolves with true if download was successful, otherwise rejects with an error.
|
|
27
60
|
*/
|
|
28
61
|
export const updateBundle = (
|
|
29
|
-
|
|
62
|
+
bundleId: string,
|
|
30
63
|
zipUrl: string | null,
|
|
31
64
|
): Promise<boolean> => {
|
|
32
|
-
return
|
|
33
|
-
HotUpdater.updateBundle(
|
|
34
|
-
String(bundleVersion),
|
|
35
|
-
zipUrl,
|
|
36
|
-
(success: boolean) => {
|
|
37
|
-
if (success) {
|
|
38
|
-
resolve(success);
|
|
39
|
-
} else {
|
|
40
|
-
reject(
|
|
41
|
-
new HotUpdaterError("Failed to download and install the update"),
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
);
|
|
46
|
-
});
|
|
65
|
+
return HotUpdaterNative.updateBundle(bundleId, zipUrl);
|
|
47
66
|
};
|
|
48
67
|
|
|
49
68
|
/**
|
|
50
69
|
* Fetches the current app version.
|
|
51
70
|
*/
|
|
52
|
-
export const getAppVersion =
|
|
53
|
-
return
|
|
54
|
-
HotUpdater.getAppVersion((version: string | null) => {
|
|
55
|
-
resolve(version);
|
|
56
|
-
});
|
|
57
|
-
});
|
|
71
|
+
export const getAppVersion = (): Promise<string | null> => {
|
|
72
|
+
return HotUpdaterNative.getAppVersion();
|
|
58
73
|
};
|
|
59
74
|
|
|
60
75
|
/**
|
|
61
76
|
* Reloads the app.
|
|
62
77
|
*/
|
|
63
78
|
export const reload = () => {
|
|
64
|
-
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Initializes the HotUpdater.
|
|
69
|
-
*/
|
|
70
|
-
export const initializeOnAppUpdate = () => {
|
|
71
|
-
HotUpdater.initializeOnAppUpdate();
|
|
79
|
+
HotUpdaterNative.reload();
|
|
72
80
|
};
|
|
@@ -2,15 +2,14 @@ import type { TurboModule } from "react-native";
|
|
|
2
2
|
import { TurboModuleRegistry } from "react-native";
|
|
3
3
|
|
|
4
4
|
interface Spec extends TurboModule {
|
|
5
|
+
// Methods
|
|
5
6
|
reload(): void;
|
|
6
|
-
updateBundle(
|
|
7
|
-
prefix: string,
|
|
8
|
-
zipUrl: string | null,
|
|
9
|
-
callback: (success: boolean) => void,
|
|
10
|
-
): Promise<boolean>;
|
|
11
|
-
initializeOnAppUpdate(): void;
|
|
7
|
+
updateBundle(bundleId: string, zipUrl: string): Promise<boolean>;
|
|
12
8
|
getAppVersion(): Promise<string | null>;
|
|
13
|
-
|
|
9
|
+
|
|
10
|
+
// EventEmitter
|
|
11
|
+
addListener(eventName: string): void;
|
|
12
|
+
removeListeners(count: number): void;
|
|
14
13
|
}
|
|
15
14
|
|
|
16
15
|
export default TurboModuleRegistry.get<Spec>("HotUpdater");
|
package/src/store.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
|
|
3
|
+
export type HotUpdaterState = {
|
|
4
|
+
progress: number;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
const createHotUpdaterStore = () => {
|
|
8
|
+
let state: HotUpdaterState = {
|
|
9
|
+
progress: 0,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const getState = () => {
|
|
13
|
+
return state;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const listeners = new Set<() => void>();
|
|
17
|
+
|
|
18
|
+
const emitChange = () => {
|
|
19
|
+
for (const listener of listeners) {
|
|
20
|
+
listener();
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const setState = (newState: Partial<HotUpdaterState>) => {
|
|
25
|
+
state = {
|
|
26
|
+
...state,
|
|
27
|
+
...newState,
|
|
28
|
+
};
|
|
29
|
+
emitChange();
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const subscribe = (listener: () => void) => {
|
|
33
|
+
listeners.add(listener);
|
|
34
|
+
return () => listeners.delete(listener);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
return { getState, setState, subscribe };
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const hotUpdaterStore = createHotUpdaterStore();
|
|
41
|
+
|
|
42
|
+
export const useHotUpdaterStore = () => {
|
|
43
|
+
return useSyncExternalStore(
|
|
44
|
+
hotUpdaterStore.subscribe,
|
|
45
|
+
hotUpdaterStore.getState,
|
|
46
|
+
hotUpdaterStore.getState,
|
|
47
|
+
);
|
|
48
|
+
};
|
package/dist/index.cjs
DELETED
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/index.ts
|
|
21
|
-
var src_exports = {};
|
|
22
|
-
__export(src_exports, {
|
|
23
|
-
HotUpdater: () => HotUpdater2
|
|
24
|
-
});
|
|
25
|
-
module.exports = __toCommonJS(src_exports);
|
|
26
|
-
|
|
27
|
-
// src/checkForUpdate.ts
|
|
28
|
-
var import_utils = require("@hot-updater/utils");
|
|
29
|
-
var import_react_native2 = require("react-native");
|
|
30
|
-
|
|
31
|
-
// src/native.ts
|
|
32
|
-
var import_react_native = require("react-native");
|
|
33
|
-
|
|
34
|
-
// src/error.ts
|
|
35
|
-
var HotUpdaterError = class extends Error {
|
|
36
|
-
constructor(message) {
|
|
37
|
-
super(message);
|
|
38
|
-
this.name = "HotUpdaterError";
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
// src/native.ts
|
|
43
|
-
var { HotUpdater } = import_react_native.NativeModules;
|
|
44
|
-
var getBundleVersion = async () => {
|
|
45
|
-
return new Promise((resolve) => {
|
|
46
|
-
HotUpdater.getBundleVersion((version) => {
|
|
47
|
-
resolve(version ?? -1);
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
};
|
|
51
|
-
var updateBundle = (bundleVersion, zipUrl) => {
|
|
52
|
-
return new Promise((resolve, reject) => {
|
|
53
|
-
HotUpdater.updateBundle(
|
|
54
|
-
String(bundleVersion),
|
|
55
|
-
zipUrl,
|
|
56
|
-
(success) => {
|
|
57
|
-
if (success) {
|
|
58
|
-
resolve(success);
|
|
59
|
-
} else {
|
|
60
|
-
reject(
|
|
61
|
-
new HotUpdaterError("Failed to download and install the update")
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
);
|
|
66
|
-
});
|
|
67
|
-
};
|
|
68
|
-
var getAppVersion = async () => {
|
|
69
|
-
return new Promise((resolve) => {
|
|
70
|
-
HotUpdater.getAppVersion((version) => {
|
|
71
|
-
resolve(version);
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
};
|
|
75
|
-
var reload = () => {
|
|
76
|
-
HotUpdater.reload();
|
|
77
|
-
};
|
|
78
|
-
var initializeOnAppUpdate = () => {
|
|
79
|
-
HotUpdater.initializeOnAppUpdate();
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
// src/utils.ts
|
|
83
|
-
var isNullable = (value) => value === null || value === void 0;
|
|
84
|
-
|
|
85
|
-
// src/checkForUpdate.ts
|
|
86
|
-
var findLatestSources = (sources) => {
|
|
87
|
-
return sources?.filter((item) => item.enabled)?.sort((a, b) => b.bundleVersion - a.bundleVersion)?.[0] ?? null;
|
|
88
|
-
};
|
|
89
|
-
var checkForRollback = (sources, currentBundleVersion) => {
|
|
90
|
-
const enabled = sources?.find(
|
|
91
|
-
(item) => item.bundleVersion === currentBundleVersion
|
|
92
|
-
)?.enabled;
|
|
93
|
-
const availableOldVersion = sources?.find(
|
|
94
|
-
(item) => item.bundleVersion < currentBundleVersion && item.enabled
|
|
95
|
-
)?.enabled;
|
|
96
|
-
if (isNullable(enabled)) {
|
|
97
|
-
return availableOldVersion;
|
|
98
|
-
}
|
|
99
|
-
return !enabled;
|
|
100
|
-
};
|
|
101
|
-
var ensureUpdateSource = async (updateSource) => {
|
|
102
|
-
let source = null;
|
|
103
|
-
if (typeof updateSource === "string") {
|
|
104
|
-
if (updateSource.startsWith("http")) {
|
|
105
|
-
const response = await fetch(updateSource);
|
|
106
|
-
source = await response.json();
|
|
107
|
-
}
|
|
108
|
-
} else if (typeof updateSource === "function") {
|
|
109
|
-
source = await updateSource();
|
|
110
|
-
} else {
|
|
111
|
-
source = updateSource;
|
|
112
|
-
}
|
|
113
|
-
if (!source) {
|
|
114
|
-
throw new Error("Invalid source");
|
|
115
|
-
}
|
|
116
|
-
return source;
|
|
117
|
-
};
|
|
118
|
-
var checkForUpdate = async (updateSources) => {
|
|
119
|
-
const sources = await ensureUpdateSource(updateSources);
|
|
120
|
-
const currentAppVersion = await getAppVersion();
|
|
121
|
-
const platform = import_react_native2.Platform.OS;
|
|
122
|
-
const appVersionSources = currentAppVersion ? (0, import_utils.filterTargetVersion)(sources, currentAppVersion, platform) : [];
|
|
123
|
-
const currentBundleVersion = await getBundleVersion();
|
|
124
|
-
const isRollback = checkForRollback(appVersionSources, currentBundleVersion);
|
|
125
|
-
const latestSource = await findLatestSources(appVersionSources);
|
|
126
|
-
if (!latestSource) {
|
|
127
|
-
if (isRollback) {
|
|
128
|
-
return {
|
|
129
|
-
bundleVersion: 0,
|
|
130
|
-
forceUpdate: true,
|
|
131
|
-
file: null,
|
|
132
|
-
hash: null,
|
|
133
|
-
status: "ROLLBACK"
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
return null;
|
|
137
|
-
}
|
|
138
|
-
if (latestSource.file) {
|
|
139
|
-
if (isRollback) {
|
|
140
|
-
if (latestSource.bundleVersion === currentBundleVersion) {
|
|
141
|
-
return null;
|
|
142
|
-
}
|
|
143
|
-
if (latestSource.bundleVersion > currentBundleVersion) {
|
|
144
|
-
return {
|
|
145
|
-
bundleVersion: latestSource.bundleVersion,
|
|
146
|
-
forceUpdate: latestSource.forceUpdate,
|
|
147
|
-
file: latestSource.file,
|
|
148
|
-
hash: latestSource.hash,
|
|
149
|
-
status: "UPDATE"
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
return {
|
|
153
|
-
bundleVersion: latestSource.bundleVersion,
|
|
154
|
-
forceUpdate: true,
|
|
155
|
-
file: latestSource.file,
|
|
156
|
-
hash: latestSource.hash,
|
|
157
|
-
status: "ROLLBACK"
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
if (latestSource.bundleVersion > currentBundleVersion) {
|
|
162
|
-
return {
|
|
163
|
-
bundleVersion: latestSource.bundleVersion,
|
|
164
|
-
forceUpdate: latestSource.forceUpdate,
|
|
165
|
-
file: latestSource.file,
|
|
166
|
-
hash: latestSource.hash,
|
|
167
|
-
status: "UPDATE"
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
return null;
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
// src/init.tsx
|
|
174
|
-
var import_react_native3 = require("react-native");
|
|
175
|
-
var init = async (config) => {
|
|
176
|
-
if (__DEV__) {
|
|
177
|
-
console.warn(
|
|
178
|
-
"[HotUpdater] __DEV__ is true, HotUpdater is only supported in production"
|
|
179
|
-
);
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
if (!["ios", "android"].includes(import_react_native3.Platform.OS)) {
|
|
183
|
-
const error = new HotUpdaterError(
|
|
184
|
-
"HotUpdater is only supported on iOS and Android"
|
|
185
|
-
);
|
|
186
|
-
config?.onError?.(error);
|
|
187
|
-
throw error;
|
|
188
|
-
}
|
|
189
|
-
await initializeOnAppUpdate();
|
|
190
|
-
const update = await checkForUpdate(config.source);
|
|
191
|
-
if (!update) {
|
|
192
|
-
config?.onSuccess?.("UP_TO_DATE");
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
try {
|
|
196
|
-
const isSuccess = await updateBundle(update.bundleVersion, update.file);
|
|
197
|
-
if (isSuccess && update.forceUpdate) {
|
|
198
|
-
reload();
|
|
199
|
-
config?.onSuccess?.("INSTALLING_UPDATE");
|
|
200
|
-
}
|
|
201
|
-
} catch (error) {
|
|
202
|
-
if (error instanceof HotUpdaterError) {
|
|
203
|
-
config?.onError?.(error);
|
|
204
|
-
}
|
|
205
|
-
throw error;
|
|
206
|
-
}
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
// src/index.ts
|
|
210
|
-
var HotUpdater2 = {
|
|
211
|
-
init,
|
|
212
|
-
reload,
|
|
213
|
-
checkForUpdate,
|
|
214
|
-
getAppVersion,
|
|
215
|
-
getBundleVersion
|
|
216
|
-
};
|
|
217
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
218
|
-
0 && (module.exports = {
|
|
219
|
-
HotUpdater
|
|
220
|
-
});
|