@hot-updater/react-native 0.2.0 → 0.3.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/dist/ensureUpdateInfo.d.ts +2 -0
- package/dist/index.d.ts +4 -7
- package/dist/index.js +102 -62
- package/dist/index.mjs +102 -62
- package/dist/native.d.ts +7 -7
- package/dist/wrap.d.ts +20 -0
- package/package.json +5 -5
- package/src/{ensureBundles.ts → ensureUpdateInfo.ts} +8 -8
- package/src/index.ts +6 -10
- package/src/native.ts +14 -10
- package/src/wrap.tsx +148 -0
- package/dist/ensureBundles.d.ts +0 -2
- package/dist/init.d.ts +0 -10
- package/src/init.tsx +0 -88
package/dist/index.d.ts
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
import { wrap } from "./wrap";
|
|
2
|
+
export type * from "./wrap";
|
|
2
3
|
export type * from "./native";
|
|
3
4
|
export * from "./store";
|
|
4
5
|
export declare const HotUpdater: {
|
|
5
|
-
|
|
6
|
+
wrap: typeof wrap;
|
|
6
7
|
reload: () => void;
|
|
7
8
|
getAppVersion: () => Promise<string | null>;
|
|
8
9
|
getBundleId: () => string;
|
|
9
10
|
addListener: <T extends keyof import("./native").HotUpdaterEvent>(eventName: T, listener: (event: import("./native").HotUpdaterEvent[T]) => void) => void;
|
|
10
|
-
|
|
11
|
+
ensureUpdateInfo: (source: import("@hot-updater/core").BundleArg, { appVersion, bundleId, platform }: import("@hot-updater/core").GetBundlesArgs, requestHeaders?: Record<string, string>) => Promise<import("@hot-updater/core").Bundle[] | import("@hot-updater/core").UpdateInfo>;
|
|
11
12
|
updateBundle: (bundleId: string, zipUrl: string | null) => Promise<boolean>;
|
|
12
13
|
getUpdateInfo: (bundles: import("@hot-updater/core").Bundle[], { platform, bundleId, appVersion }: import("@hot-updater/core").GetBundlesArgs) => Promise<import("@hot-updater/core").UpdateInfo | null>;
|
|
13
|
-
/**
|
|
14
|
-
* In production environment, this value will be replaced with a uuidv7.
|
|
15
|
-
*/
|
|
16
|
-
HOT_UPDATER_BUNDLE_ID: string;
|
|
17
14
|
};
|
package/dist/index.js
CHANGED
|
@@ -1582,6 +1582,12 @@ var __webpack_modules__ = {
|
|
|
1582
1582
|
}, V = {
|
|
1583
1583
|
transition: null
|
|
1584
1584
|
};
|
|
1585
|
+
exports1.useEffect = function(a, b) {
|
|
1586
|
+
return U.current.useEffect(a, b);
|
|
1587
|
+
};
|
|
1588
|
+
exports1.useState = function(a) {
|
|
1589
|
+
return U.current.useState(a);
|
|
1590
|
+
};
|
|
1585
1591
|
exports1.useSyncExternalStore = function(a, b, e) {
|
|
1586
1592
|
return U.current.useSyncExternalStore(a, b, e);
|
|
1587
1593
|
};
|
|
@@ -3078,11 +3084,11 @@ const getUpdateInfo = async (bundles, { platform, bundleId, appVersion })=>{
|
|
|
3078
3084
|
};
|
|
3079
3085
|
return null;
|
|
3080
3086
|
};
|
|
3081
|
-
const
|
|
3087
|
+
const ensureUpdateInfo = async (source, { appVersion, bundleId, platform }, requestHeaders)=>{
|
|
3082
3088
|
try {
|
|
3083
3089
|
let bundles = null;
|
|
3084
|
-
if ("string" == typeof
|
|
3085
|
-
if (
|
|
3090
|
+
if ("string" == typeof source) {
|
|
3091
|
+
if (source.startsWith("http")) return await fetch(source, {
|
|
3086
3092
|
headers: {
|
|
3087
3093
|
"x-app-platform": platform,
|
|
3088
3094
|
"x-app-version": appVersion,
|
|
@@ -3090,19 +3096,16 @@ const ensureBundles = async (bundle, { appVersion, bundleId, platform }, request
|
|
|
3090
3096
|
...requestHeaders
|
|
3091
3097
|
}
|
|
3092
3098
|
}).then((res)=>res.json());
|
|
3093
|
-
} else bundles = "function" == typeof
|
|
3099
|
+
} else bundles = "function" == typeof source ? await source() : source;
|
|
3094
3100
|
return bundles ?? [];
|
|
3095
3101
|
} catch {
|
|
3096
3102
|
return [];
|
|
3097
3103
|
}
|
|
3098
3104
|
};
|
|
3099
3105
|
var external_react_native_ = __webpack_require__("react-native");
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
this.name = "HotUpdaterError";
|
|
3104
|
-
}
|
|
3105
|
-
}
|
|
3106
|
+
const HotUpdater = {
|
|
3107
|
+
HOT_UPDATER_BUNDLE_ID: core_namespaceObject.NIL_UUID
|
|
3108
|
+
};
|
|
3106
3109
|
const LINKING_ERROR = `The package '@hot-updater/react-native' doesn't seem to be linked. Make sure: \n\n` + external_react_native_.Platform.select({
|
|
3107
3110
|
ios: "- You have run 'pod install'\n",
|
|
3108
3111
|
default: ""
|
|
@@ -3118,59 +3121,12 @@ const addListener = (eventName, listener)=>{
|
|
|
3118
3121
|
const eventEmitter = new external_react_native_.NativeEventEmitter(HotUpdaterNative);
|
|
3119
3122
|
eventEmitter?.addListener(eventName, listener);
|
|
3120
3123
|
};
|
|
3121
|
-
const getBundleId = ()=>HotUpdater.HOT_UPDATER_BUNDLE_ID ?? core_namespaceObject.NIL_UUID;
|
|
3122
3124
|
const updateBundle = (bundleId, zipUrl)=>HotUpdaterNative.updateBundle(bundleId, zipUrl);
|
|
3123
3125
|
const getAppVersion = ()=>HotUpdaterNative.getAppVersion();
|
|
3124
3126
|
const reload = ()=>{
|
|
3125
3127
|
HotUpdaterNative.reload();
|
|
3126
3128
|
};
|
|
3127
|
-
const
|
|
3128
|
-
if (__DEV__) {
|
|
3129
|
-
console.warn("[HotUpdater] __DEV__ is true, HotUpdater is only supported in production");
|
|
3130
|
-
return;
|
|
3131
|
-
}
|
|
3132
|
-
if (![
|
|
3133
|
-
"ios",
|
|
3134
|
-
"android"
|
|
3135
|
-
].includes(external_react_native_.Platform.OS)) {
|
|
3136
|
-
const error = new HotUpdaterError("HotUpdater is only supported on iOS and Android");
|
|
3137
|
-
config?.onError?.(error);
|
|
3138
|
-
throw error;
|
|
3139
|
-
}
|
|
3140
|
-
const currentAppVersion = await getAppVersion();
|
|
3141
|
-
const platform = external_react_native_.Platform.OS;
|
|
3142
|
-
const currentBundleId = await getBundleId();
|
|
3143
|
-
if (!currentAppVersion) {
|
|
3144
|
-
const error = new HotUpdaterError("Failed to get app version");
|
|
3145
|
-
config?.onError?.(error);
|
|
3146
|
-
throw error;
|
|
3147
|
-
}
|
|
3148
|
-
const bundles = await ensureBundles(config.source, {
|
|
3149
|
-
appVersion: currentAppVersion,
|
|
3150
|
-
bundleId: currentBundleId,
|
|
3151
|
-
platform
|
|
3152
|
-
}, config.requestHeaders);
|
|
3153
|
-
let updateInfo = null;
|
|
3154
|
-
updateInfo = Array.isArray(bundles) ? await getUpdateInfo(bundles, {
|
|
3155
|
-
appVersion: currentAppVersion,
|
|
3156
|
-
bundleId: currentBundleId,
|
|
3157
|
-
platform
|
|
3158
|
-
}) : bundles;
|
|
3159
|
-
if (!updateInfo) {
|
|
3160
|
-
config?.onSuccess?.("UP_TO_DATE");
|
|
3161
|
-
return;
|
|
3162
|
-
}
|
|
3163
|
-
try {
|
|
3164
|
-
const isSuccess = await updateBundle(updateInfo.id, updateInfo.fileUrl || "");
|
|
3165
|
-
if (isSuccess && updateInfo.forceUpdate) {
|
|
3166
|
-
reload();
|
|
3167
|
-
config?.onSuccess?.("INSTALLING_UPDATE");
|
|
3168
|
-
}
|
|
3169
|
-
} catch (error) {
|
|
3170
|
-
if (error instanceof HotUpdaterError) config?.onError?.(error);
|
|
3171
|
-
throw error;
|
|
3172
|
-
}
|
|
3173
|
-
};
|
|
3129
|
+
const getBundleId = ()=>HotUpdater.HOT_UPDATER_BUNDLE_ID;
|
|
3174
3130
|
var react = __webpack_require__("../../node_modules/.pnpm/react@18.3.1/node_modules/react/index.js");
|
|
3175
3131
|
const createHotUpdaterStore = ()=>{
|
|
3176
3132
|
let state = {
|
|
@@ -3200,21 +3156,105 @@ const createHotUpdaterStore = ()=>{
|
|
|
3200
3156
|
};
|
|
3201
3157
|
const hotUpdaterStore = createHotUpdaterStore();
|
|
3202
3158
|
const useHotUpdaterStore = ()=>(0, react.useSyncExternalStore)(hotUpdaterStore.subscribe, hotUpdaterStore.getState, hotUpdaterStore.getState);
|
|
3159
|
+
class HotUpdaterError extends Error {
|
|
3160
|
+
constructor(message){
|
|
3161
|
+
super(message);
|
|
3162
|
+
this.name = "HotUpdaterError";
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
async function checkUpdate(config) {
|
|
3166
|
+
if (__DEV__) {
|
|
3167
|
+
console.warn("[HotUpdater] __DEV__ is true, HotUpdater is only supported in production");
|
|
3168
|
+
return null;
|
|
3169
|
+
}
|
|
3170
|
+
if (![
|
|
3171
|
+
"ios",
|
|
3172
|
+
"android"
|
|
3173
|
+
].includes(external_react_native_.Platform.OS)) throw new HotUpdaterError("HotUpdater is only supported on iOS and Android");
|
|
3174
|
+
const currentAppVersion = await getAppVersion();
|
|
3175
|
+
const platform = external_react_native_.Platform.OS;
|
|
3176
|
+
const currentBundleId = await getBundleId();
|
|
3177
|
+
if (!currentAppVersion) throw new HotUpdaterError("Failed to get app version");
|
|
3178
|
+
const ensuredUpdateInfo = await ensureUpdateInfo(config.source, {
|
|
3179
|
+
appVersion: currentAppVersion,
|
|
3180
|
+
bundleId: currentBundleId,
|
|
3181
|
+
platform
|
|
3182
|
+
}, config.requestHeaders);
|
|
3183
|
+
let updateInfo = null;
|
|
3184
|
+
if (Array.isArray(ensuredUpdateInfo)) {
|
|
3185
|
+
const bundles = ensuredUpdateInfo;
|
|
3186
|
+
updateInfo = await getUpdateInfo(bundles, {
|
|
3187
|
+
appVersion: currentAppVersion,
|
|
3188
|
+
bundleId: currentBundleId,
|
|
3189
|
+
platform
|
|
3190
|
+
});
|
|
3191
|
+
} else updateInfo = ensuredUpdateInfo;
|
|
3192
|
+
return updateInfo;
|
|
3193
|
+
}
|
|
3194
|
+
async function installUpdate(updateInfo) {
|
|
3195
|
+
const isSuccess = await updateBundle(updateInfo.id, updateInfo.fileUrl || "");
|
|
3196
|
+
if (isSuccess && updateInfo.forceUpdate) {
|
|
3197
|
+
reload();
|
|
3198
|
+
return true;
|
|
3199
|
+
}
|
|
3200
|
+
return isSuccess;
|
|
3201
|
+
}
|
|
3202
|
+
function wrap(config) {
|
|
3203
|
+
return (WrappedComponent)=>{
|
|
3204
|
+
const HotUpdaterHOC = (props)=>{
|
|
3205
|
+
const [updateStatus, setUpdateStatus] = (0, react.useState)(null);
|
|
3206
|
+
const [updateError, setUpdateError] = (0, react.useState)(null);
|
|
3207
|
+
const { progress } = useHotUpdaterStore();
|
|
3208
|
+
(0, react.useEffect)(()=>{
|
|
3209
|
+
const initHotUpdater = async ()=>{
|
|
3210
|
+
try {
|
|
3211
|
+
const updateInfo = await checkUpdate(config);
|
|
3212
|
+
if (!updateInfo) {
|
|
3213
|
+
setUpdateStatus("UP_TO_DATE");
|
|
3214
|
+
return;
|
|
3215
|
+
}
|
|
3216
|
+
setUpdateStatus("UPDATING");
|
|
3217
|
+
const isSuccess = await installUpdate(updateInfo);
|
|
3218
|
+
if (isSuccess) setUpdateStatus("INSTALLING_UPDATE");
|
|
3219
|
+
} catch (error) {
|
|
3220
|
+
if (error instanceof HotUpdaterError) setUpdateError(error);
|
|
3221
|
+
throw error;
|
|
3222
|
+
}
|
|
3223
|
+
};
|
|
3224
|
+
initHotUpdater();
|
|
3225
|
+
}, [
|
|
3226
|
+
config.source,
|
|
3227
|
+
config.requestHeaders
|
|
3228
|
+
]);
|
|
3229
|
+
if ("UPDATING" === updateStatus && config.fallbackComponent) {
|
|
3230
|
+
const Fallback = config.fallbackComponent;
|
|
3231
|
+
return /*#__PURE__*/ React.createElement(Fallback, {
|
|
3232
|
+
progress: progress
|
|
3233
|
+
});
|
|
3234
|
+
}
|
|
3235
|
+
return /*#__PURE__*/ React.createElement(WrappedComponent, {
|
|
3236
|
+
...props,
|
|
3237
|
+
updateStatus: updateStatus,
|
|
3238
|
+
updateError: updateError
|
|
3239
|
+
});
|
|
3240
|
+
};
|
|
3241
|
+
return HotUpdaterHOC;
|
|
3242
|
+
};
|
|
3243
|
+
}
|
|
3203
3244
|
addListener("onProgress", ({ progress })=>{
|
|
3204
3245
|
hotUpdaterStore.setState({
|
|
3205
3246
|
progress
|
|
3206
3247
|
});
|
|
3207
3248
|
});
|
|
3208
3249
|
const src_HotUpdater = {
|
|
3209
|
-
|
|
3250
|
+
wrap: wrap,
|
|
3210
3251
|
reload: reload,
|
|
3211
3252
|
getAppVersion: getAppVersion,
|
|
3212
3253
|
getBundleId: getBundleId,
|
|
3213
3254
|
addListener: addListener,
|
|
3214
|
-
|
|
3255
|
+
ensureUpdateInfo: ensureUpdateInfo,
|
|
3215
3256
|
updateBundle: updateBundle,
|
|
3216
|
-
getUpdateInfo: getUpdateInfo
|
|
3217
|
-
HOT_UPDATER_BUNDLE_ID: core_namespaceObject.NIL_UUID
|
|
3257
|
+
getUpdateInfo: getUpdateInfo
|
|
3218
3258
|
};
|
|
3219
3259
|
var __webpack_export_target__ = exports;
|
|
3220
3260
|
for(var __webpack_i__ in __webpack_exports__)__webpack_export_target__[__webpack_i__] = __webpack_exports__[__webpack_i__];
|
package/dist/index.mjs
CHANGED
|
@@ -1583,6 +1583,12 @@ var __webpack_modules__ = {
|
|
|
1583
1583
|
}, V = {
|
|
1584
1584
|
transition: null
|
|
1585
1585
|
};
|
|
1586
|
+
exports.useEffect = function(a, b) {
|
|
1587
|
+
return U.current.useEffect(a, b);
|
|
1588
|
+
};
|
|
1589
|
+
exports.useState = function(a) {
|
|
1590
|
+
return U.current.useState(a);
|
|
1591
|
+
};
|
|
1586
1592
|
exports.useSyncExternalStore = function(a, b, e) {
|
|
1587
1593
|
return U.current.useSyncExternalStore(a, b, e);
|
|
1588
1594
|
};
|
|
@@ -3046,11 +3052,11 @@ const getUpdateInfo = async (bundles, { platform, bundleId, appVersion })=>{
|
|
|
3046
3052
|
};
|
|
3047
3053
|
return null;
|
|
3048
3054
|
};
|
|
3049
|
-
const
|
|
3055
|
+
const ensureUpdateInfo = async (source, { appVersion, bundleId, platform }, requestHeaders)=>{
|
|
3050
3056
|
try {
|
|
3051
3057
|
let bundles = null;
|
|
3052
|
-
if ("string" == typeof
|
|
3053
|
-
if (
|
|
3058
|
+
if ("string" == typeof source) {
|
|
3059
|
+
if (source.startsWith("http")) return await fetch(source, {
|
|
3054
3060
|
headers: {
|
|
3055
3061
|
"x-app-platform": platform,
|
|
3056
3062
|
"x-app-version": appVersion,
|
|
@@ -3058,19 +3064,16 @@ const ensureBundles = async (bundle, { appVersion, bundleId, platform }, request
|
|
|
3058
3064
|
...requestHeaders
|
|
3059
3065
|
}
|
|
3060
3066
|
}).then((res)=>res.json());
|
|
3061
|
-
} else bundles = "function" == typeof
|
|
3067
|
+
} else bundles = "function" == typeof source ? await source() : source;
|
|
3062
3068
|
return bundles ?? [];
|
|
3063
3069
|
} catch {
|
|
3064
3070
|
return [];
|
|
3065
3071
|
}
|
|
3066
3072
|
};
|
|
3067
3073
|
var external_react_native_ = __webpack_require__("react-native");
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
this.name = "HotUpdaterError";
|
|
3072
|
-
}
|
|
3073
|
-
}
|
|
3074
|
+
const HotUpdater = {
|
|
3075
|
+
HOT_UPDATER_BUNDLE_ID: __WEBPACK_EXTERNAL_MODULE__hot_updater_core__.NIL_UUID
|
|
3076
|
+
};
|
|
3074
3077
|
const LINKING_ERROR = `The package '@hot-updater/react-native' doesn't seem to be linked. Make sure: \n\n` + external_react_native_.Platform.select({
|
|
3075
3078
|
ios: "- You have run 'pod install'\n",
|
|
3076
3079
|
default: ""
|
|
@@ -3086,59 +3089,12 @@ const addListener = (eventName, listener)=>{
|
|
|
3086
3089
|
const eventEmitter = new external_react_native_.NativeEventEmitter(HotUpdaterNative);
|
|
3087
3090
|
eventEmitter?.addListener(eventName, listener);
|
|
3088
3091
|
};
|
|
3089
|
-
const getBundleId = ()=>HotUpdater.HOT_UPDATER_BUNDLE_ID ?? __WEBPACK_EXTERNAL_MODULE__hot_updater_core__.NIL_UUID;
|
|
3090
3092
|
const updateBundle = (bundleId, zipUrl)=>HotUpdaterNative.updateBundle(bundleId, zipUrl);
|
|
3091
3093
|
const getAppVersion = ()=>HotUpdaterNative.getAppVersion();
|
|
3092
3094
|
const reload = ()=>{
|
|
3093
3095
|
HotUpdaterNative.reload();
|
|
3094
3096
|
};
|
|
3095
|
-
const
|
|
3096
|
-
if (__DEV__) {
|
|
3097
|
-
console.warn("[HotUpdater] __DEV__ is true, HotUpdater is only supported in production");
|
|
3098
|
-
return;
|
|
3099
|
-
}
|
|
3100
|
-
if (![
|
|
3101
|
-
"ios",
|
|
3102
|
-
"android"
|
|
3103
|
-
].includes(external_react_native_.Platform.OS)) {
|
|
3104
|
-
const error = new HotUpdaterError("HotUpdater is only supported on iOS and Android");
|
|
3105
|
-
config?.onError?.(error);
|
|
3106
|
-
throw error;
|
|
3107
|
-
}
|
|
3108
|
-
const currentAppVersion = await getAppVersion();
|
|
3109
|
-
const platform = external_react_native_.Platform.OS;
|
|
3110
|
-
const currentBundleId = await getBundleId();
|
|
3111
|
-
if (!currentAppVersion) {
|
|
3112
|
-
const error = new HotUpdaterError("Failed to get app version");
|
|
3113
|
-
config?.onError?.(error);
|
|
3114
|
-
throw error;
|
|
3115
|
-
}
|
|
3116
|
-
const bundles = await ensureBundles(config.source, {
|
|
3117
|
-
appVersion: currentAppVersion,
|
|
3118
|
-
bundleId: currentBundleId,
|
|
3119
|
-
platform
|
|
3120
|
-
}, config.requestHeaders);
|
|
3121
|
-
let updateInfo = null;
|
|
3122
|
-
updateInfo = Array.isArray(bundles) ? await getUpdateInfo(bundles, {
|
|
3123
|
-
appVersion: currentAppVersion,
|
|
3124
|
-
bundleId: currentBundleId,
|
|
3125
|
-
platform
|
|
3126
|
-
}) : bundles;
|
|
3127
|
-
if (!updateInfo) {
|
|
3128
|
-
config?.onSuccess?.("UP_TO_DATE");
|
|
3129
|
-
return;
|
|
3130
|
-
}
|
|
3131
|
-
try {
|
|
3132
|
-
const isSuccess = await updateBundle(updateInfo.id, updateInfo.fileUrl || "");
|
|
3133
|
-
if (isSuccess && updateInfo.forceUpdate) {
|
|
3134
|
-
reload();
|
|
3135
|
-
config?.onSuccess?.("INSTALLING_UPDATE");
|
|
3136
|
-
}
|
|
3137
|
-
} catch (error) {
|
|
3138
|
-
if (error instanceof HotUpdaterError) config?.onError?.(error);
|
|
3139
|
-
throw error;
|
|
3140
|
-
}
|
|
3141
|
-
};
|
|
3097
|
+
const getBundleId = ()=>HotUpdater.HOT_UPDATER_BUNDLE_ID;
|
|
3142
3098
|
var react = __webpack_require__("../../node_modules/.pnpm/react@18.3.1/node_modules/react/index.js");
|
|
3143
3099
|
const createHotUpdaterStore = ()=>{
|
|
3144
3100
|
let state = {
|
|
@@ -3168,20 +3124,104 @@ const createHotUpdaterStore = ()=>{
|
|
|
3168
3124
|
};
|
|
3169
3125
|
const hotUpdaterStore = createHotUpdaterStore();
|
|
3170
3126
|
const useHotUpdaterStore = ()=>(0, react.useSyncExternalStore)(hotUpdaterStore.subscribe, hotUpdaterStore.getState, hotUpdaterStore.getState);
|
|
3127
|
+
class HotUpdaterError extends Error {
|
|
3128
|
+
constructor(message){
|
|
3129
|
+
super(message);
|
|
3130
|
+
this.name = "HotUpdaterError";
|
|
3131
|
+
}
|
|
3132
|
+
}
|
|
3133
|
+
async function checkUpdate(config) {
|
|
3134
|
+
if (__DEV__) {
|
|
3135
|
+
console.warn("[HotUpdater] __DEV__ is true, HotUpdater is only supported in production");
|
|
3136
|
+
return null;
|
|
3137
|
+
}
|
|
3138
|
+
if (![
|
|
3139
|
+
"ios",
|
|
3140
|
+
"android"
|
|
3141
|
+
].includes(external_react_native_.Platform.OS)) throw new HotUpdaterError("HotUpdater is only supported on iOS and Android");
|
|
3142
|
+
const currentAppVersion = await getAppVersion();
|
|
3143
|
+
const platform = external_react_native_.Platform.OS;
|
|
3144
|
+
const currentBundleId = await getBundleId();
|
|
3145
|
+
if (!currentAppVersion) throw new HotUpdaterError("Failed to get app version");
|
|
3146
|
+
const ensuredUpdateInfo = await ensureUpdateInfo(config.source, {
|
|
3147
|
+
appVersion: currentAppVersion,
|
|
3148
|
+
bundleId: currentBundleId,
|
|
3149
|
+
platform
|
|
3150
|
+
}, config.requestHeaders);
|
|
3151
|
+
let updateInfo = null;
|
|
3152
|
+
if (Array.isArray(ensuredUpdateInfo)) {
|
|
3153
|
+
const bundles = ensuredUpdateInfo;
|
|
3154
|
+
updateInfo = await getUpdateInfo(bundles, {
|
|
3155
|
+
appVersion: currentAppVersion,
|
|
3156
|
+
bundleId: currentBundleId,
|
|
3157
|
+
platform
|
|
3158
|
+
});
|
|
3159
|
+
} else updateInfo = ensuredUpdateInfo;
|
|
3160
|
+
return updateInfo;
|
|
3161
|
+
}
|
|
3162
|
+
async function installUpdate(updateInfo) {
|
|
3163
|
+
const isSuccess = await updateBundle(updateInfo.id, updateInfo.fileUrl || "");
|
|
3164
|
+
if (isSuccess && updateInfo.forceUpdate) {
|
|
3165
|
+
reload();
|
|
3166
|
+
return true;
|
|
3167
|
+
}
|
|
3168
|
+
return isSuccess;
|
|
3169
|
+
}
|
|
3170
|
+
function wrap(config) {
|
|
3171
|
+
return (WrappedComponent)=>{
|
|
3172
|
+
const HotUpdaterHOC = (props)=>{
|
|
3173
|
+
const [updateStatus, setUpdateStatus] = (0, react.useState)(null);
|
|
3174
|
+
const [updateError, setUpdateError] = (0, react.useState)(null);
|
|
3175
|
+
const { progress } = useHotUpdaterStore();
|
|
3176
|
+
(0, react.useEffect)(()=>{
|
|
3177
|
+
const initHotUpdater = async ()=>{
|
|
3178
|
+
try {
|
|
3179
|
+
const updateInfo = await checkUpdate(config);
|
|
3180
|
+
if (!updateInfo) {
|
|
3181
|
+
setUpdateStatus("UP_TO_DATE");
|
|
3182
|
+
return;
|
|
3183
|
+
}
|
|
3184
|
+
setUpdateStatus("UPDATING");
|
|
3185
|
+
const isSuccess = await installUpdate(updateInfo);
|
|
3186
|
+
if (isSuccess) setUpdateStatus("INSTALLING_UPDATE");
|
|
3187
|
+
} catch (error) {
|
|
3188
|
+
if (error instanceof HotUpdaterError) setUpdateError(error);
|
|
3189
|
+
throw error;
|
|
3190
|
+
}
|
|
3191
|
+
};
|
|
3192
|
+
initHotUpdater();
|
|
3193
|
+
}, [
|
|
3194
|
+
config.source,
|
|
3195
|
+
config.requestHeaders
|
|
3196
|
+
]);
|
|
3197
|
+
if ("UPDATING" === updateStatus && config.fallbackComponent) {
|
|
3198
|
+
const Fallback = config.fallbackComponent;
|
|
3199
|
+
return /*#__PURE__*/ React.createElement(Fallback, {
|
|
3200
|
+
progress: progress
|
|
3201
|
+
});
|
|
3202
|
+
}
|
|
3203
|
+
return /*#__PURE__*/ React.createElement(WrappedComponent, {
|
|
3204
|
+
...props,
|
|
3205
|
+
updateStatus: updateStatus,
|
|
3206
|
+
updateError: updateError
|
|
3207
|
+
});
|
|
3208
|
+
};
|
|
3209
|
+
return HotUpdaterHOC;
|
|
3210
|
+
};
|
|
3211
|
+
}
|
|
3171
3212
|
addListener("onProgress", ({ progress })=>{
|
|
3172
3213
|
hotUpdaterStore.setState({
|
|
3173
3214
|
progress
|
|
3174
3215
|
});
|
|
3175
3216
|
});
|
|
3176
3217
|
const src_HotUpdater = {
|
|
3177
|
-
|
|
3218
|
+
wrap: wrap,
|
|
3178
3219
|
reload: reload,
|
|
3179
3220
|
getAppVersion: getAppVersion,
|
|
3180
3221
|
getBundleId: getBundleId,
|
|
3181
3222
|
addListener: addListener,
|
|
3182
|
-
|
|
3223
|
+
ensureUpdateInfo: ensureUpdateInfo,
|
|
3183
3224
|
updateBundle: updateBundle,
|
|
3184
|
-
getUpdateInfo: getUpdateInfo
|
|
3185
|
-
HOT_UPDATER_BUNDLE_ID: __WEBPACK_EXTERNAL_MODULE__hot_updater_core__.NIL_UUID
|
|
3225
|
+
getUpdateInfo: getUpdateInfo
|
|
3186
3226
|
};
|
|
3187
3227
|
export { src_HotUpdater as HotUpdater, hotUpdaterStore, useHotUpdaterStore };
|
package/dist/native.d.ts
CHANGED
|
@@ -4,13 +4,6 @@ export type HotUpdaterEvent = {
|
|
|
4
4
|
};
|
|
5
5
|
};
|
|
6
6
|
export declare const addListener: <T extends keyof HotUpdaterEvent>(eventName: T, listener: (event: HotUpdaterEvent[T]) => void) => void;
|
|
7
|
-
/**
|
|
8
|
-
* Fetches the current bundle version id.
|
|
9
|
-
*
|
|
10
|
-
* @async
|
|
11
|
-
* @returns {Promise<string>} Resolves with the current version id or null if not available.
|
|
12
|
-
*/
|
|
13
|
-
export declare const getBundleId: () => string;
|
|
14
7
|
/**
|
|
15
8
|
* Downloads files from given URLs.
|
|
16
9
|
*
|
|
@@ -27,3 +20,10 @@ export declare const getAppVersion: () => Promise<string | null>;
|
|
|
27
20
|
* Reloads the app.
|
|
28
21
|
*/
|
|
29
22
|
export declare const reload: () => void;
|
|
23
|
+
/**
|
|
24
|
+
* Fetches the current bundle version id.
|
|
25
|
+
*
|
|
26
|
+
* @async
|
|
27
|
+
* @returns {Promise<string>} Resolves with the current version id or null if not available.
|
|
28
|
+
*/
|
|
29
|
+
export declare const getBundleId: () => string;
|
package/dist/wrap.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { BundleArg, UpdateInfo } from "@hot-updater/core";
|
|
2
|
+
import type React from "react";
|
|
3
|
+
import { HotUpdaterError } from "./error";
|
|
4
|
+
export type HotUpdaterStatus = "INSTALLING_UPDATE" | "UP_TO_DATE" | "UPDATING";
|
|
5
|
+
export interface CheckUpdateConfig {
|
|
6
|
+
source: BundleArg;
|
|
7
|
+
requestHeaders?: Record<string, string>;
|
|
8
|
+
}
|
|
9
|
+
export interface HotUpdaterConfig extends CheckUpdateConfig {
|
|
10
|
+
fallbackComponent?: React.FC<HotUpdaterFallbackProps>;
|
|
11
|
+
}
|
|
12
|
+
export interface HotUpdaterFallbackProps {
|
|
13
|
+
progress: number;
|
|
14
|
+
}
|
|
15
|
+
export interface WithHotUpdaterProps {
|
|
16
|
+
updateStatus: HotUpdaterStatus | null;
|
|
17
|
+
updateError: HotUpdaterError | null;
|
|
18
|
+
}
|
|
19
|
+
export declare function checkUpdate(config: CheckUpdateConfig): Promise<UpdateInfo | null>;
|
|
20
|
+
export declare function wrap<P>(config: HotUpdaterConfig): (WrappedComponent: React.ComponentType<P & WithHotUpdaterProps>) => React.ComponentType<P>;
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/react-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "React Native OTA solution for self-hosted",
|
|
5
|
-
"main": "dist/index.
|
|
6
|
-
"module": "dist/index.
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
7
|
"source": "src/index.ts",
|
|
8
8
|
"react-native": "src/index.ts",
|
|
9
9
|
"types": "dist/index.d.ts",
|
|
@@ -73,10 +73,10 @@
|
|
|
73
73
|
"react": "18.3.1",
|
|
74
74
|
"react-native": "0.76.2",
|
|
75
75
|
"react-native-builder-bob": "^0.33.1",
|
|
76
|
-
"@hot-updater/js": "0.
|
|
76
|
+
"@hot-updater/js": "0.3.0"
|
|
77
77
|
},
|
|
78
78
|
"dependencies": {
|
|
79
|
-
"@hot-updater/core": "0.
|
|
79
|
+
"@hot-updater/core": "0.3.0"
|
|
80
80
|
},
|
|
81
81
|
"scripts": {
|
|
82
82
|
"build": "rslib build",
|
|
@@ -5,16 +5,16 @@ import type {
|
|
|
5
5
|
UpdateInfo,
|
|
6
6
|
} from "@hot-updater/core";
|
|
7
7
|
|
|
8
|
-
export const
|
|
9
|
-
|
|
8
|
+
export const ensureUpdateInfo = async (
|
|
9
|
+
source: BundleArg,
|
|
10
10
|
{ appVersion, bundleId, platform }: GetBundlesArgs,
|
|
11
11
|
requestHeaders?: Record<string, string>,
|
|
12
12
|
): Promise<Bundle[] | UpdateInfo> => {
|
|
13
13
|
try {
|
|
14
14
|
let bundles: Bundle[] | null = null;
|
|
15
|
-
if (typeof
|
|
16
|
-
if (
|
|
17
|
-
return await fetch(
|
|
15
|
+
if (typeof source === "string") {
|
|
16
|
+
if (source.startsWith("http")) {
|
|
17
|
+
return await fetch(source, {
|
|
18
18
|
headers: {
|
|
19
19
|
"x-app-platform": platform,
|
|
20
20
|
"x-app-version": appVersion,
|
|
@@ -23,10 +23,10 @@ export const ensureBundles = async (
|
|
|
23
23
|
},
|
|
24
24
|
}).then((res) => res.json());
|
|
25
25
|
}
|
|
26
|
-
} else if (typeof
|
|
27
|
-
bundles = await
|
|
26
|
+
} else if (typeof source === "function") {
|
|
27
|
+
bundles = await source();
|
|
28
28
|
} else {
|
|
29
|
-
bundles =
|
|
29
|
+
bundles = source;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
return bundles ?? [];
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { NIL_UUID } from "@hot-updater/core";
|
|
2
1
|
import { getUpdateInfo } from "@hot-updater/js";
|
|
3
|
-
import {
|
|
4
|
-
import { init } from "./init";
|
|
2
|
+
import { ensureUpdateInfo } from "./ensureUpdateInfo";
|
|
5
3
|
import {
|
|
6
4
|
addListener,
|
|
7
5
|
getAppVersion,
|
|
@@ -10,8 +8,9 @@ import {
|
|
|
10
8
|
updateBundle,
|
|
11
9
|
} from "./native";
|
|
12
10
|
import { hotUpdaterStore } from "./store";
|
|
11
|
+
import { wrap } from "./wrap";
|
|
13
12
|
|
|
14
|
-
export type * from "./
|
|
13
|
+
export type * from "./wrap";
|
|
15
14
|
export type * from "./native";
|
|
16
15
|
|
|
17
16
|
export * from "./store";
|
|
@@ -21,17 +20,14 @@ addListener("onProgress", ({ progress }) => {
|
|
|
21
20
|
});
|
|
22
21
|
|
|
23
22
|
export const HotUpdater = {
|
|
24
|
-
|
|
23
|
+
wrap,
|
|
24
|
+
|
|
25
25
|
reload,
|
|
26
26
|
getAppVersion,
|
|
27
27
|
getBundleId,
|
|
28
28
|
addListener,
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
ensureUpdateInfo,
|
|
31
31
|
updateBundle,
|
|
32
32
|
getUpdateInfo,
|
|
33
|
-
/**
|
|
34
|
-
* In production environment, this value will be replaced with a uuidv7.
|
|
35
|
-
*/
|
|
36
|
-
HOT_UPDATER_BUNDLE_ID: NIL_UUID,
|
|
37
33
|
};
|
package/src/native.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { NIL_UUID } from "@hot-updater/core";
|
|
2
2
|
import { NativeEventEmitter, NativeModules, Platform } from "react-native";
|
|
3
3
|
|
|
4
|
+
const HotUpdater = {
|
|
5
|
+
HOT_UPDATER_BUNDLE_ID: NIL_UUID,
|
|
6
|
+
};
|
|
7
|
+
|
|
4
8
|
const LINKING_ERROR =
|
|
5
9
|
// biome-ignore lint/style/useTemplate: <explanation>
|
|
6
10
|
`The package '@hot-updater/react-native' doesn't seem to be linked. Make sure: \n\n` +
|
|
@@ -41,16 +45,6 @@ export const addListener = <T extends keyof HotUpdaterEvent>(
|
|
|
41
45
|
eventEmitter?.addListener(eventName, listener);
|
|
42
46
|
};
|
|
43
47
|
|
|
44
|
-
/**
|
|
45
|
-
* Fetches the current bundle version id.
|
|
46
|
-
*
|
|
47
|
-
* @async
|
|
48
|
-
* @returns {Promise<string>} Resolves with the current version id or null if not available.
|
|
49
|
-
*/
|
|
50
|
-
export const getBundleId = (): string => {
|
|
51
|
-
return HotUpdater.HOT_UPDATER_BUNDLE_ID ?? NIL_UUID;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
48
|
/**
|
|
55
49
|
* Downloads files from given URLs.
|
|
56
50
|
*
|
|
@@ -78,3 +72,13 @@ export const getAppVersion = (): Promise<string | null> => {
|
|
|
78
72
|
export const reload = () => {
|
|
79
73
|
HotUpdaterNative.reload();
|
|
80
74
|
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Fetches the current bundle version id.
|
|
78
|
+
*
|
|
79
|
+
* @async
|
|
80
|
+
* @returns {Promise<string>} Resolves with the current version id or null if not available.
|
|
81
|
+
*/
|
|
82
|
+
export const getBundleId = (): string => {
|
|
83
|
+
return HotUpdater.HOT_UPDATER_BUNDLE_ID;
|
|
84
|
+
};
|
package/src/wrap.tsx
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import type { Bundle, BundleArg, UpdateInfo } from "@hot-updater/core";
|
|
2
|
+
import { getUpdateInfo } from "@hot-updater/js";
|
|
3
|
+
import type React from "react";
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
import { Platform } from "react-native";
|
|
6
|
+
import { ensureUpdateInfo } from "./ensureUpdateInfo";
|
|
7
|
+
import { HotUpdaterError } from "./error";
|
|
8
|
+
import { getAppVersion, getBundleId, reload, updateBundle } from "./native";
|
|
9
|
+
import { useHotUpdaterStore } from "./store";
|
|
10
|
+
|
|
11
|
+
export type HotUpdaterStatus = "INSTALLING_UPDATE" | "UP_TO_DATE" | "UPDATING";
|
|
12
|
+
|
|
13
|
+
export interface CheckUpdateConfig {
|
|
14
|
+
source: BundleArg;
|
|
15
|
+
requestHeaders?: Record<string, string>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface HotUpdaterConfig extends CheckUpdateConfig {
|
|
19
|
+
fallbackComponent?: React.FC<HotUpdaterFallbackProps>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface HotUpdaterFallbackProps {
|
|
23
|
+
progress: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface WithHotUpdaterProps {
|
|
27
|
+
updateStatus: HotUpdaterStatus | null;
|
|
28
|
+
updateError: HotUpdaterError | null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function checkUpdate(config: CheckUpdateConfig) {
|
|
32
|
+
if (__DEV__) {
|
|
33
|
+
console.warn(
|
|
34
|
+
"[HotUpdater] __DEV__ is true, HotUpdater is only supported in production",
|
|
35
|
+
);
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (!["ios", "android"].includes(Platform.OS)) {
|
|
40
|
+
throw new HotUpdaterError(
|
|
41
|
+
"HotUpdater is only supported on iOS and Android",
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const currentAppVersion = await getAppVersion();
|
|
46
|
+
const platform = Platform.OS as "ios" | "android";
|
|
47
|
+
const currentBundleId = await getBundleId();
|
|
48
|
+
|
|
49
|
+
if (!currentAppVersion) {
|
|
50
|
+
throw new HotUpdaterError("Failed to get app version");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const ensuredUpdateInfo = await ensureUpdateInfo(
|
|
54
|
+
config.source,
|
|
55
|
+
{
|
|
56
|
+
appVersion: currentAppVersion,
|
|
57
|
+
bundleId: currentBundleId,
|
|
58
|
+
platform,
|
|
59
|
+
},
|
|
60
|
+
config.requestHeaders,
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
let updateInfo: UpdateInfo | null = null;
|
|
64
|
+
if (Array.isArray(ensuredUpdateInfo)) {
|
|
65
|
+
const bundles: Bundle[] = ensuredUpdateInfo;
|
|
66
|
+
|
|
67
|
+
updateInfo = await getUpdateInfo(bundles, {
|
|
68
|
+
appVersion: currentAppVersion,
|
|
69
|
+
bundleId: currentBundleId,
|
|
70
|
+
platform,
|
|
71
|
+
});
|
|
72
|
+
} else {
|
|
73
|
+
updateInfo = ensuredUpdateInfo;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return updateInfo;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function installUpdate(updateInfo: UpdateInfo) {
|
|
80
|
+
const isSuccess = await updateBundle(updateInfo.id, updateInfo.fileUrl || "");
|
|
81
|
+
|
|
82
|
+
if (isSuccess && updateInfo.forceUpdate) {
|
|
83
|
+
reload();
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return isSuccess;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function wrap<P>(
|
|
91
|
+
config: HotUpdaterConfig,
|
|
92
|
+
): (
|
|
93
|
+
WrappedComponent: React.ComponentType<P & WithHotUpdaterProps>,
|
|
94
|
+
) => React.ComponentType<P> {
|
|
95
|
+
return (WrappedComponent) => {
|
|
96
|
+
const HotUpdaterHOC: React.FC<P> = (props) => {
|
|
97
|
+
const [updateStatus, setUpdateStatus] = useState<HotUpdaterStatus | null>(
|
|
98
|
+
null,
|
|
99
|
+
);
|
|
100
|
+
const [updateError, setUpdateError] = useState<HotUpdaterError | null>(
|
|
101
|
+
null,
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const { progress } = useHotUpdaterStore();
|
|
105
|
+
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
const initHotUpdater = async () => {
|
|
108
|
+
try {
|
|
109
|
+
const updateInfo = await checkUpdate(config);
|
|
110
|
+
|
|
111
|
+
if (!updateInfo) {
|
|
112
|
+
setUpdateStatus("UP_TO_DATE");
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
setUpdateStatus("UPDATING");
|
|
117
|
+
const isSuccess = await installUpdate(updateInfo);
|
|
118
|
+
if (isSuccess) {
|
|
119
|
+
setUpdateStatus("INSTALLING_UPDATE");
|
|
120
|
+
}
|
|
121
|
+
} catch (error) {
|
|
122
|
+
if (error instanceof HotUpdaterError) {
|
|
123
|
+
setUpdateError(error);
|
|
124
|
+
}
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
initHotUpdater();
|
|
130
|
+
}, [config.source, config.requestHeaders]);
|
|
131
|
+
|
|
132
|
+
if (updateStatus === "UPDATING" && config.fallbackComponent) {
|
|
133
|
+
const Fallback = config.fallbackComponent;
|
|
134
|
+
return <Fallback progress={progress} />;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<WrappedComponent
|
|
139
|
+
{...props}
|
|
140
|
+
updateStatus={updateStatus}
|
|
141
|
+
updateError={updateError}
|
|
142
|
+
/>
|
|
143
|
+
);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
return HotUpdaterHOC;
|
|
147
|
+
};
|
|
148
|
+
}
|
package/dist/ensureBundles.d.ts
DELETED
package/dist/init.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { BundleArg } from "@hot-updater/core";
|
|
2
|
-
import { HotUpdaterError } from "./error";
|
|
3
|
-
export type HotUpdaterStatus = "INSTALLING_UPDATE" | "UP_TO_DATE";
|
|
4
|
-
export interface HotUpdaterInitConfig {
|
|
5
|
-
source: BundleArg;
|
|
6
|
-
requestHeaders?: Record<string, string>;
|
|
7
|
-
onSuccess?: (status: HotUpdaterStatus) => void;
|
|
8
|
-
onError?: (error: HotUpdaterError) => void;
|
|
9
|
-
}
|
|
10
|
-
export declare const init: (config: HotUpdaterInitConfig) => Promise<void>;
|
package/src/init.tsx
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import type { BundleArg, UpdateInfo } from "@hot-updater/core";
|
|
2
|
-
import { getUpdateInfo } from "@hot-updater/js";
|
|
3
|
-
import { Platform } from "react-native";
|
|
4
|
-
import { ensureBundles } from "./ensureBundles";
|
|
5
|
-
import { HotUpdaterError } from "./error";
|
|
6
|
-
import { getAppVersion, getBundleId, reload, updateBundle } from "./native";
|
|
7
|
-
|
|
8
|
-
export type HotUpdaterStatus = "INSTALLING_UPDATE" | "UP_TO_DATE";
|
|
9
|
-
|
|
10
|
-
export interface HotUpdaterInitConfig {
|
|
11
|
-
source: BundleArg;
|
|
12
|
-
requestHeaders?: Record<string, string>;
|
|
13
|
-
onSuccess?: (status: HotUpdaterStatus) => void;
|
|
14
|
-
onError?: (error: HotUpdaterError) => void;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const init = async (config: HotUpdaterInitConfig) => {
|
|
18
|
-
if (__DEV__) {
|
|
19
|
-
console.warn(
|
|
20
|
-
"[HotUpdater] __DEV__ is true, HotUpdater is only supported in production",
|
|
21
|
-
);
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (!["ios", "android"].includes(Platform.OS)) {
|
|
26
|
-
const error = new HotUpdaterError(
|
|
27
|
-
"HotUpdater is only supported on iOS and Android",
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
config?.onError?.(error);
|
|
31
|
-
throw error;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const currentAppVersion = await getAppVersion();
|
|
35
|
-
const platform = Platform.OS as "ios" | "android";
|
|
36
|
-
const currentBundleId = await getBundleId();
|
|
37
|
-
|
|
38
|
-
if (!currentAppVersion) {
|
|
39
|
-
const error = new HotUpdaterError("Failed to get app version");
|
|
40
|
-
config?.onError?.(error);
|
|
41
|
-
throw error;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const bundles = await ensureBundles(
|
|
45
|
-
config.source,
|
|
46
|
-
{
|
|
47
|
-
appVersion: currentAppVersion,
|
|
48
|
-
bundleId: currentBundleId,
|
|
49
|
-
platform,
|
|
50
|
-
},
|
|
51
|
-
config.requestHeaders,
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
let updateInfo: UpdateInfo | null = null;
|
|
55
|
-
if (Array.isArray(bundles)) {
|
|
56
|
-
// Direct comparison
|
|
57
|
-
updateInfo = await getUpdateInfo(bundles, {
|
|
58
|
-
appVersion: currentAppVersion,
|
|
59
|
-
bundleId: currentBundleId,
|
|
60
|
-
platform,
|
|
61
|
-
});
|
|
62
|
-
} else {
|
|
63
|
-
// Already verified from server
|
|
64
|
-
updateInfo = bundles;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (!updateInfo) {
|
|
68
|
-
config?.onSuccess?.("UP_TO_DATE");
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
try {
|
|
73
|
-
const isSuccess = await updateBundle(
|
|
74
|
-
updateInfo.id,
|
|
75
|
-
updateInfo.fileUrl || "",
|
|
76
|
-
);
|
|
77
|
-
if (isSuccess && updateInfo.forceUpdate) {
|
|
78
|
-
reload();
|
|
79
|
-
|
|
80
|
-
config?.onSuccess?.("INSTALLING_UPDATE");
|
|
81
|
-
}
|
|
82
|
-
} catch (error) {
|
|
83
|
-
if (error instanceof HotUpdaterError) {
|
|
84
|
-
config?.onError?.(error);
|
|
85
|
-
}
|
|
86
|
-
throw error;
|
|
87
|
-
}
|
|
88
|
-
};
|