@hot-updater/react-native 0.13.4-rc.0 → 0.13.5-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/checkForUpdate.d.ts +3 -2
- package/dist/fetchUpdateInfo.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +33 -22
- package/dist/index.mjs +33 -22
- package/dist/runUpdateProcess.d.ts +3 -3
- package/dist/wrap.d.ts +3 -3
- package/package.json +3 -3
- package/src/checkForUpdate.ts +11 -7
- package/src/fetchUpdateInfo.ts +12 -3
- package/src/index.ts +1 -1
- package/src/runUpdateProcess.ts +5 -5
- package/src/wrap.tsx +14 -13
package/dist/checkForUpdate.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export interface
|
|
1
|
+
export interface CheckForUpdateOptions {
|
|
2
2
|
source: string;
|
|
3
3
|
requestHeaders?: Record<string, string>;
|
|
4
|
+
onError?: (error: Error) => void;
|
|
4
5
|
}
|
|
5
|
-
export declare function checkForUpdate(
|
|
6
|
+
export declare function checkForUpdate(options: CheckForUpdateOptions): Promise<import("@hot-updater/core").AppUpdateInfo | null>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { AppUpdateInfo, GetBundlesArgs } from "@hot-updater/core";
|
|
2
|
-
export declare const fetchUpdateInfo: (source: string, { appVersion, bundleId, platform, minBundleId, channel }: GetBundlesArgs, requestHeaders?: Record<string, string
|
|
2
|
+
export declare const fetchUpdateInfo: (source: string, { appVersion, bundleId, platform, minBundleId, channel }: GetBundlesArgs, requestHeaders?: Record<string, string>, onError?: (error: Error) => void) => Promise<AppUpdateInfo | null>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { checkForUpdate } from "./checkForUpdate";
|
|
2
2
|
import { wrap } from "./wrap";
|
|
3
|
-
export type {
|
|
3
|
+
export type { HotUpdaterOptions } from "./wrap";
|
|
4
4
|
export type { HotUpdaterEvent } from "./native";
|
|
5
5
|
export * from "./store";
|
|
6
6
|
export declare const HotUpdater: {
|
|
@@ -137,7 +137,7 @@ export declare const HotUpdater: {
|
|
|
137
137
|
*
|
|
138
138
|
* @returns {Promise<RunUpdateProcessResponse>} The result of the update process
|
|
139
139
|
*/
|
|
140
|
-
runUpdateProcess: ({ reloadOnForceUpdate, ...
|
|
140
|
+
runUpdateProcess: ({ reloadOnForceUpdate, ...checkForUpdateOptions }: import("./runUpdateProcess").RunUpdateProcessOptions) => Promise<import("./runUpdateProcess").RunUpdateProcessResponse>;
|
|
141
141
|
/**
|
|
142
142
|
* Updates the bundle of the app.
|
|
143
143
|
*
|
package/dist/index.js
CHANGED
|
@@ -66,10 +66,11 @@ var __webpack_exports__ = {};
|
|
|
66
66
|
this.name = "HotUpdaterError";
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
-
const fetchUpdateInfo = async (source, { appVersion, bundleId, platform, minBundleId, channel }, requestHeaders)=>{
|
|
69
|
+
const fetchUpdateInfo = async (source, { appVersion, bundleId, platform, minBundleId, channel }, requestHeaders, onError)=>{
|
|
70
70
|
try {
|
|
71
|
-
|
|
71
|
+
const response = await fetch(source, {
|
|
72
72
|
headers: {
|
|
73
|
+
"Content-Type": "application/json",
|
|
73
74
|
"x-app-platform": platform,
|
|
74
75
|
"x-app-version": appVersion,
|
|
75
76
|
"x-bundle-id": bundleId,
|
|
@@ -81,8 +82,11 @@ var __webpack_exports__ = {};
|
|
|
81
82
|
} : {},
|
|
82
83
|
...requestHeaders
|
|
83
84
|
}
|
|
84
|
-
})
|
|
85
|
-
|
|
85
|
+
});
|
|
86
|
+
if (200 !== response.status) throw new Error(response.statusText);
|
|
87
|
+
return response.json();
|
|
88
|
+
} catch (error) {
|
|
89
|
+
onError?.(error);
|
|
86
90
|
return null;
|
|
87
91
|
}
|
|
88
92
|
};
|
|
@@ -125,28 +129,34 @@ var __webpack_exports__ = {};
|
|
|
125
129
|
return minBundleId.localeCompare(HotUpdater.HOT_UPDATER_BUNDLE_ID) >= 0 ? minBundleId : HotUpdater.HOT_UPDATER_BUNDLE_ID;
|
|
126
130
|
};
|
|
127
131
|
const getChannel = ()=>HotUpdater.CHANNEL;
|
|
128
|
-
async function checkForUpdate(
|
|
132
|
+
async function checkForUpdate(options) {
|
|
129
133
|
if (__DEV__) return null;
|
|
130
134
|
if (![
|
|
131
135
|
"ios",
|
|
132
136
|
"android"
|
|
133
|
-
].includes(external_react_native_.Platform.OS))
|
|
137
|
+
].includes(external_react_native_.Platform.OS)) {
|
|
138
|
+
options.onError?.(new HotUpdaterError("HotUpdater is only supported on iOS and Android"));
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
134
141
|
const currentAppVersion = await getAppVersion();
|
|
135
142
|
const platform = external_react_native_.Platform.OS;
|
|
136
143
|
const currentBundleId = getBundleId();
|
|
137
144
|
const minBundleId = getMinBundleId();
|
|
138
145
|
const channel = getChannel();
|
|
139
|
-
if (!currentAppVersion)
|
|
140
|
-
|
|
146
|
+
if (!currentAppVersion) {
|
|
147
|
+
options.onError?.(new HotUpdaterError("Failed to get app version"));
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
return fetchUpdateInfo(options.source, {
|
|
141
151
|
appVersion: currentAppVersion,
|
|
142
152
|
bundleId: currentBundleId,
|
|
143
153
|
platform,
|
|
144
154
|
minBundleId,
|
|
145
155
|
channel
|
|
146
|
-
},
|
|
156
|
+
}, options.requestHeaders, options.onError);
|
|
147
157
|
}
|
|
148
|
-
const runUpdateProcess = async ({ reloadOnForceUpdate = true, ...
|
|
149
|
-
const updateInfo = await checkForUpdate(
|
|
158
|
+
const runUpdateProcess = async ({ reloadOnForceUpdate = true, ...checkForUpdateOptions })=>{
|
|
159
|
+
const updateInfo = await checkForUpdate(checkForUpdateOptions);
|
|
150
160
|
if (!updateInfo) return {
|
|
151
161
|
status: "UP_TO_DATE",
|
|
152
162
|
shouldForceUpdate: false,
|
|
@@ -210,8 +220,8 @@ var __webpack_exports__ = {};
|
|
|
210
220
|
callbackRef
|
|
211
221
|
]);
|
|
212
222
|
}
|
|
213
|
-
function wrap(
|
|
214
|
-
const { reloadOnForceUpdate = true, ...
|
|
223
|
+
function wrap(options) {
|
|
224
|
+
const { reloadOnForceUpdate = true, ...restOptions } = options;
|
|
215
225
|
return (WrappedComponent)=>{
|
|
216
226
|
const HotUpdaterHOC = ()=>{
|
|
217
227
|
const progress = useHotUpdaterStore((state)=>state.progress);
|
|
@@ -221,12 +231,13 @@ var __webpack_exports__ = {};
|
|
|
221
231
|
try {
|
|
222
232
|
setUpdateStatus("CHECK_FOR_UPDATE");
|
|
223
233
|
const updateInfo = await checkForUpdate({
|
|
224
|
-
source:
|
|
225
|
-
requestHeaders:
|
|
234
|
+
source: restOptions.source,
|
|
235
|
+
requestHeaders: restOptions.requestHeaders,
|
|
236
|
+
onError: restOptions.onError
|
|
226
237
|
});
|
|
227
238
|
setMessage(updateInfo?.message ?? null);
|
|
228
239
|
if (!updateInfo) {
|
|
229
|
-
|
|
240
|
+
restOptions.onUpdateProcessCompleted?.({
|
|
230
241
|
status: "UP_TO_DATE",
|
|
231
242
|
shouldForceUpdate: false,
|
|
232
243
|
message: null,
|
|
@@ -237,7 +248,7 @@ var __webpack_exports__ = {};
|
|
|
237
248
|
}
|
|
238
249
|
if (false === updateInfo.shouldForceUpdate) {
|
|
239
250
|
updateBundle(updateInfo.id, updateInfo.fileUrl);
|
|
240
|
-
|
|
251
|
+
restOptions.onUpdateProcessCompleted?.({
|
|
241
252
|
id: updateInfo.id,
|
|
242
253
|
status: updateInfo.status,
|
|
243
254
|
shouldForceUpdate: updateInfo.shouldForceUpdate,
|
|
@@ -250,7 +261,7 @@ var __webpack_exports__ = {};
|
|
|
250
261
|
const isSuccess = await updateBundle(updateInfo.id, updateInfo.fileUrl);
|
|
251
262
|
if (!isSuccess) throw new Error("New update was found but failed to download the bundle.");
|
|
252
263
|
if (reloadOnForceUpdate) reload();
|
|
253
|
-
|
|
264
|
+
restOptions.onUpdateProcessCompleted?.({
|
|
254
265
|
id: updateInfo.id,
|
|
255
266
|
status: updateInfo.status,
|
|
256
267
|
shouldForceUpdate: updateInfo.shouldForceUpdate,
|
|
@@ -258,21 +269,21 @@ var __webpack_exports__ = {};
|
|
|
258
269
|
});
|
|
259
270
|
setUpdateStatus("UPDATE_PROCESS_COMPLETED");
|
|
260
271
|
} catch (error) {
|
|
261
|
-
if (error instanceof HotUpdaterError)
|
|
272
|
+
if (error instanceof HotUpdaterError) restOptions.onError?.(error);
|
|
262
273
|
setUpdateStatus("UPDATE_PROCESS_COMPLETED");
|
|
263
274
|
throw error;
|
|
264
275
|
}
|
|
265
276
|
});
|
|
266
277
|
(0, external_react_namespaceObject.useEffect)(()=>{
|
|
267
|
-
|
|
278
|
+
restOptions.onProgress?.(progress);
|
|
268
279
|
}, [
|
|
269
280
|
progress
|
|
270
281
|
]);
|
|
271
282
|
(0, external_react_namespaceObject.useLayoutEffect)(()=>{
|
|
272
283
|
initHotUpdater();
|
|
273
284
|
}, []);
|
|
274
|
-
if (
|
|
275
|
-
const Fallback =
|
|
285
|
+
if (restOptions.fallbackComponent && "UPDATE_PROCESS_COMPLETED" !== updateStatus) {
|
|
286
|
+
const Fallback = restOptions.fallbackComponent;
|
|
276
287
|
return /*#__PURE__*/ external_react_default().createElement(Fallback, {
|
|
277
288
|
progress: progress,
|
|
278
289
|
status: updateStatus,
|
package/dist/index.mjs
CHANGED
|
@@ -41,10 +41,11 @@ class HotUpdaterError extends Error {
|
|
|
41
41
|
this.name = "HotUpdaterError";
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
-
const fetchUpdateInfo = async (source, { appVersion, bundleId, platform, minBundleId, channel }, requestHeaders)=>{
|
|
44
|
+
const fetchUpdateInfo = async (source, { appVersion, bundleId, platform, minBundleId, channel }, requestHeaders, onError)=>{
|
|
45
45
|
try {
|
|
46
|
-
|
|
46
|
+
const response = await fetch(source, {
|
|
47
47
|
headers: {
|
|
48
|
+
"Content-Type": "application/json",
|
|
48
49
|
"x-app-platform": platform,
|
|
49
50
|
"x-app-version": appVersion,
|
|
50
51
|
"x-bundle-id": bundleId,
|
|
@@ -56,8 +57,11 @@ const fetchUpdateInfo = async (source, { appVersion, bundleId, platform, minBund
|
|
|
56
57
|
} : {},
|
|
57
58
|
...requestHeaders
|
|
58
59
|
}
|
|
59
|
-
})
|
|
60
|
-
|
|
60
|
+
});
|
|
61
|
+
if (200 !== response.status) throw new Error(response.statusText);
|
|
62
|
+
return response.json();
|
|
63
|
+
} catch (error) {
|
|
64
|
+
onError?.(error);
|
|
61
65
|
return null;
|
|
62
66
|
}
|
|
63
67
|
};
|
|
@@ -100,28 +104,34 @@ const getBundleId = ()=>{
|
|
|
100
104
|
return minBundleId.localeCompare(HotUpdater.HOT_UPDATER_BUNDLE_ID) >= 0 ? minBundleId : HotUpdater.HOT_UPDATER_BUNDLE_ID;
|
|
101
105
|
};
|
|
102
106
|
const getChannel = ()=>HotUpdater.CHANNEL;
|
|
103
|
-
async function checkForUpdate(
|
|
107
|
+
async function checkForUpdate(options) {
|
|
104
108
|
if (__DEV__) return null;
|
|
105
109
|
if (![
|
|
106
110
|
"ios",
|
|
107
111
|
"android"
|
|
108
|
-
].includes(external_react_native_.Platform.OS))
|
|
112
|
+
].includes(external_react_native_.Platform.OS)) {
|
|
113
|
+
options.onError?.(new HotUpdaterError("HotUpdater is only supported on iOS and Android"));
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
109
116
|
const currentAppVersion = await getAppVersion();
|
|
110
117
|
const platform = external_react_native_.Platform.OS;
|
|
111
118
|
const currentBundleId = getBundleId();
|
|
112
119
|
const minBundleId = getMinBundleId();
|
|
113
120
|
const channel = getChannel();
|
|
114
|
-
if (!currentAppVersion)
|
|
115
|
-
|
|
121
|
+
if (!currentAppVersion) {
|
|
122
|
+
options.onError?.(new HotUpdaterError("Failed to get app version"));
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
return fetchUpdateInfo(options.source, {
|
|
116
126
|
appVersion: currentAppVersion,
|
|
117
127
|
bundleId: currentBundleId,
|
|
118
128
|
platform,
|
|
119
129
|
minBundleId,
|
|
120
130
|
channel
|
|
121
|
-
},
|
|
131
|
+
}, options.requestHeaders, options.onError);
|
|
122
132
|
}
|
|
123
|
-
const runUpdateProcess = async ({ reloadOnForceUpdate = true, ...
|
|
124
|
-
const updateInfo = await checkForUpdate(
|
|
133
|
+
const runUpdateProcess = async ({ reloadOnForceUpdate = true, ...checkForUpdateOptions })=>{
|
|
134
|
+
const updateInfo = await checkForUpdate(checkForUpdateOptions);
|
|
125
135
|
if (!updateInfo) return {
|
|
126
136
|
status: "UP_TO_DATE",
|
|
127
137
|
shouldForceUpdate: false,
|
|
@@ -181,8 +191,8 @@ function useEventCallback(fn) {
|
|
|
181
191
|
callbackRef
|
|
182
192
|
]);
|
|
183
193
|
}
|
|
184
|
-
function wrap(
|
|
185
|
-
const { reloadOnForceUpdate = true, ...
|
|
194
|
+
function wrap(options) {
|
|
195
|
+
const { reloadOnForceUpdate = true, ...restOptions } = options;
|
|
186
196
|
return (WrappedComponent)=>{
|
|
187
197
|
const HotUpdaterHOC = ()=>{
|
|
188
198
|
const progress = useHotUpdaterStore((state)=>state.progress);
|
|
@@ -192,12 +202,13 @@ function wrap(config) {
|
|
|
192
202
|
try {
|
|
193
203
|
setUpdateStatus("CHECK_FOR_UPDATE");
|
|
194
204
|
const updateInfo = await checkForUpdate({
|
|
195
|
-
source:
|
|
196
|
-
requestHeaders:
|
|
205
|
+
source: restOptions.source,
|
|
206
|
+
requestHeaders: restOptions.requestHeaders,
|
|
207
|
+
onError: restOptions.onError
|
|
197
208
|
});
|
|
198
209
|
setMessage(updateInfo?.message ?? null);
|
|
199
210
|
if (!updateInfo) {
|
|
200
|
-
|
|
211
|
+
restOptions.onUpdateProcessCompleted?.({
|
|
201
212
|
status: "UP_TO_DATE",
|
|
202
213
|
shouldForceUpdate: false,
|
|
203
214
|
message: null,
|
|
@@ -208,7 +219,7 @@ function wrap(config) {
|
|
|
208
219
|
}
|
|
209
220
|
if (false === updateInfo.shouldForceUpdate) {
|
|
210
221
|
updateBundle(updateInfo.id, updateInfo.fileUrl);
|
|
211
|
-
|
|
222
|
+
restOptions.onUpdateProcessCompleted?.({
|
|
212
223
|
id: updateInfo.id,
|
|
213
224
|
status: updateInfo.status,
|
|
214
225
|
shouldForceUpdate: updateInfo.shouldForceUpdate,
|
|
@@ -221,7 +232,7 @@ function wrap(config) {
|
|
|
221
232
|
const isSuccess = await updateBundle(updateInfo.id, updateInfo.fileUrl);
|
|
222
233
|
if (!isSuccess) throw new Error("New update was found but failed to download the bundle.");
|
|
223
234
|
if (reloadOnForceUpdate) reload();
|
|
224
|
-
|
|
235
|
+
restOptions.onUpdateProcessCompleted?.({
|
|
225
236
|
id: updateInfo.id,
|
|
226
237
|
status: updateInfo.status,
|
|
227
238
|
shouldForceUpdate: updateInfo.shouldForceUpdate,
|
|
@@ -229,21 +240,21 @@ function wrap(config) {
|
|
|
229
240
|
});
|
|
230
241
|
setUpdateStatus("UPDATE_PROCESS_COMPLETED");
|
|
231
242
|
} catch (error) {
|
|
232
|
-
if (error instanceof HotUpdaterError)
|
|
243
|
+
if (error instanceof HotUpdaterError) restOptions.onError?.(error);
|
|
233
244
|
setUpdateStatus("UPDATE_PROCESS_COMPLETED");
|
|
234
245
|
throw error;
|
|
235
246
|
}
|
|
236
247
|
});
|
|
237
248
|
(0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
|
|
238
|
-
|
|
249
|
+
restOptions.onProgress?.(progress);
|
|
239
250
|
}, [
|
|
240
251
|
progress
|
|
241
252
|
]);
|
|
242
253
|
(0, __WEBPACK_EXTERNAL_MODULE_react__.useLayoutEffect)(()=>{
|
|
243
254
|
initHotUpdater();
|
|
244
255
|
}, []);
|
|
245
|
-
if (
|
|
246
|
-
const Fallback =
|
|
256
|
+
if (restOptions.fallbackComponent && "UPDATE_PROCESS_COMPLETED" !== updateStatus) {
|
|
257
|
+
const Fallback = restOptions.fallbackComponent;
|
|
247
258
|
return /*#__PURE__*/ __WEBPACK_EXTERNAL_MODULE_react__["default"].createElement(Fallback, {
|
|
248
259
|
progress: progress,
|
|
249
260
|
status: updateStatus,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type CheckForUpdateOptions } from "./checkForUpdate";
|
|
2
2
|
export interface RunUpdateProcessResponse {
|
|
3
3
|
status: "ROLLBACK" | "UPDATE" | "UP_TO_DATE";
|
|
4
4
|
shouldForceUpdate: boolean;
|
|
5
5
|
message: string | null;
|
|
6
6
|
id: string;
|
|
7
7
|
}
|
|
8
|
-
export interface
|
|
8
|
+
export interface RunUpdateProcessOptions extends CheckForUpdateOptions {
|
|
9
9
|
/**
|
|
10
10
|
* If `true`, the app will be reloaded when the downloaded bundle is a force update.
|
|
11
11
|
* If `false`, shouldForceUpdate will be returned as true but the app won't reload.
|
|
@@ -45,4 +45,4 @@ export interface RunUpdateProcessConfig extends CheckForUpdateConfig {
|
|
|
45
45
|
*
|
|
46
46
|
* @returns {Promise<RunUpdateProcessResponse>} The result of the update process
|
|
47
47
|
*/
|
|
48
|
-
export declare const runUpdateProcess: ({ reloadOnForceUpdate, ...
|
|
48
|
+
export declare const runUpdateProcess: ({ reloadOnForceUpdate, ...checkForUpdateOptions }: RunUpdateProcessOptions) => Promise<RunUpdateProcessResponse>;
|
package/dist/wrap.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { type
|
|
2
|
+
import { type CheckForUpdateOptions } from "./checkForUpdate";
|
|
3
3
|
import { HotUpdaterError } from "./error";
|
|
4
4
|
import type { RunUpdateProcessResponse } from "./runUpdateProcess";
|
|
5
5
|
type UpdateStatus = "CHECK_FOR_UPDATE" | "UPDATING" | "UPDATE_PROCESS_COMPLETED";
|
|
6
|
-
export interface
|
|
6
|
+
export interface HotUpdaterOptions extends CheckForUpdateOptions {
|
|
7
7
|
/**
|
|
8
8
|
* Component to show while downloading a new bundle update.
|
|
9
9
|
*
|
|
@@ -46,5 +46,5 @@ export interface HotUpdaterConfig extends CheckForUpdateConfig {
|
|
|
46
46
|
*/
|
|
47
47
|
onUpdateProcessCompleted?: (response: RunUpdateProcessResponse) => void;
|
|
48
48
|
}
|
|
49
|
-
export declare function wrap<P>(
|
|
49
|
+
export declare function wrap<P>(options: HotUpdaterOptions): (WrappedComponent: React.ComponentType) => React.ComponentType<P>;
|
|
50
50
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/react-native",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.5-rc.0",
|
|
4
4
|
"description": "React Native OTA solution for self-hosted",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -81,8 +81,8 @@
|
|
|
81
81
|
},
|
|
82
82
|
"dependencies": {
|
|
83
83
|
"use-sync-external-store": "1.4.0",
|
|
84
|
-
"@hot-updater/js": "0.13.
|
|
85
|
-
"@hot-updater/core": "0.13.
|
|
84
|
+
"@hot-updater/js": "0.13.5-rc.0",
|
|
85
|
+
"@hot-updater/core": "0.13.5-rc.0"
|
|
86
86
|
},
|
|
87
87
|
"scripts": {
|
|
88
88
|
"build": "rslib build",
|
package/src/checkForUpdate.ts
CHANGED
|
@@ -8,20 +8,22 @@ import {
|
|
|
8
8
|
getMinBundleId,
|
|
9
9
|
} from "./native";
|
|
10
10
|
|
|
11
|
-
export interface
|
|
11
|
+
export interface CheckForUpdateOptions {
|
|
12
12
|
source: string;
|
|
13
13
|
requestHeaders?: Record<string, string>;
|
|
14
|
+
onError?: (error: Error) => void;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
export async function checkForUpdate(
|
|
17
|
+
export async function checkForUpdate(options: CheckForUpdateOptions) {
|
|
17
18
|
if (__DEV__) {
|
|
18
19
|
return null;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
if (!["ios", "android"].includes(Platform.OS)) {
|
|
22
|
-
|
|
23
|
-
"HotUpdater is only supported on iOS and Android",
|
|
23
|
+
options.onError?.(
|
|
24
|
+
new HotUpdaterError("HotUpdater is only supported on iOS and Android"),
|
|
24
25
|
);
|
|
26
|
+
return null;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
const currentAppVersion = await getAppVersion();
|
|
@@ -31,11 +33,12 @@ export async function checkForUpdate(config: CheckForUpdateConfig) {
|
|
|
31
33
|
const channel = getChannel();
|
|
32
34
|
|
|
33
35
|
if (!currentAppVersion) {
|
|
34
|
-
|
|
36
|
+
options.onError?.(new HotUpdaterError("Failed to get app version"));
|
|
37
|
+
return null;
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
return fetchUpdateInfo(
|
|
38
|
-
|
|
41
|
+
options.source,
|
|
39
42
|
{
|
|
40
43
|
appVersion: currentAppVersion,
|
|
41
44
|
bundleId: currentBundleId,
|
|
@@ -43,6 +46,7 @@ export async function checkForUpdate(config: CheckForUpdateConfig) {
|
|
|
43
46
|
minBundleId,
|
|
44
47
|
channel,
|
|
45
48
|
},
|
|
46
|
-
|
|
49
|
+
options.requestHeaders,
|
|
50
|
+
options.onError,
|
|
47
51
|
);
|
|
48
52
|
}
|
package/src/fetchUpdateInfo.ts
CHANGED
|
@@ -4,10 +4,13 @@ export const fetchUpdateInfo = async (
|
|
|
4
4
|
source: string,
|
|
5
5
|
{ appVersion, bundleId, platform, minBundleId, channel }: GetBundlesArgs,
|
|
6
6
|
requestHeaders?: Record<string, string>,
|
|
7
|
+
onError?: (error: Error) => void,
|
|
7
8
|
): Promise<AppUpdateInfo | null> => {
|
|
8
9
|
try {
|
|
9
|
-
|
|
10
|
+
const response = await fetch(source, {
|
|
10
11
|
headers: {
|
|
12
|
+
"Content-Type": "application/json",
|
|
13
|
+
|
|
11
14
|
"x-app-platform": platform,
|
|
12
15
|
"x-app-version": appVersion,
|
|
13
16
|
"x-bundle-id": bundleId,
|
|
@@ -15,8 +18,14 @@ export const fetchUpdateInfo = async (
|
|
|
15
18
|
...(channel ? { "x-channel": channel } : {}),
|
|
16
19
|
...requestHeaders,
|
|
17
20
|
},
|
|
18
|
-
})
|
|
19
|
-
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
if (response.status !== 200) {
|
|
24
|
+
throw new Error(response.statusText);
|
|
25
|
+
}
|
|
26
|
+
return response.json();
|
|
27
|
+
} catch (error) {
|
|
28
|
+
onError?.(error as Error);
|
|
20
29
|
return null;
|
|
21
30
|
}
|
|
22
31
|
};
|
package/src/index.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { runUpdateProcess } from "./runUpdateProcess";
|
|
|
12
12
|
import { hotUpdaterStore } from "./store";
|
|
13
13
|
import { wrap } from "./wrap";
|
|
14
14
|
|
|
15
|
-
export type {
|
|
15
|
+
export type { HotUpdaterOptions } from "./wrap";
|
|
16
16
|
export type { HotUpdaterEvent } from "./native";
|
|
17
17
|
|
|
18
18
|
export * from "./store";
|
package/src/runUpdateProcess.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type CheckForUpdateOptions, checkForUpdate } from "./checkForUpdate";
|
|
2
2
|
import { getBundleId, reload, updateBundle } from "./native";
|
|
3
3
|
|
|
4
4
|
export interface RunUpdateProcessResponse {
|
|
@@ -8,7 +8,7 @@ export interface RunUpdateProcessResponse {
|
|
|
8
8
|
id: string;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export interface
|
|
11
|
+
export interface RunUpdateProcessOptions extends CheckForUpdateOptions {
|
|
12
12
|
/**
|
|
13
13
|
* If `true`, the app will be reloaded when the downloaded bundle is a force update.
|
|
14
14
|
* If `false`, shouldForceUpdate will be returned as true but the app won't reload.
|
|
@@ -51,9 +51,9 @@ export interface RunUpdateProcessConfig extends CheckForUpdateConfig {
|
|
|
51
51
|
*/
|
|
52
52
|
export const runUpdateProcess = async ({
|
|
53
53
|
reloadOnForceUpdate = true,
|
|
54
|
-
...
|
|
55
|
-
}:
|
|
56
|
-
const updateInfo = await checkForUpdate(
|
|
54
|
+
...checkForUpdateOptions
|
|
55
|
+
}: RunUpdateProcessOptions): Promise<RunUpdateProcessResponse> => {
|
|
56
|
+
const updateInfo = await checkForUpdate(checkForUpdateOptions);
|
|
57
57
|
if (!updateInfo) {
|
|
58
58
|
return {
|
|
59
59
|
status: "UP_TO_DATE",
|
package/src/wrap.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { useEffect, useLayoutEffect, useState } from "react";
|
|
3
|
-
import { type
|
|
3
|
+
import { type CheckForUpdateOptions, checkForUpdate } from "./checkForUpdate";
|
|
4
4
|
import { HotUpdaterError } from "./error";
|
|
5
5
|
import { useEventCallback } from "./hooks/useEventCallback";
|
|
6
6
|
import { getBundleId, reload, updateBundle } from "./native";
|
|
@@ -12,7 +12,7 @@ type UpdateStatus =
|
|
|
12
12
|
| "UPDATING"
|
|
13
13
|
| "UPDATE_PROCESS_COMPLETED";
|
|
14
14
|
|
|
15
|
-
export interface
|
|
15
|
+
export interface HotUpdaterOptions extends CheckForUpdateOptions {
|
|
16
16
|
/**
|
|
17
17
|
* Component to show while downloading a new bundle update.
|
|
18
18
|
*
|
|
@@ -57,9 +57,9 @@ export interface HotUpdaterConfig extends CheckForUpdateConfig {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
export function wrap<P>(
|
|
60
|
-
|
|
60
|
+
options: HotUpdaterOptions,
|
|
61
61
|
): (WrappedComponent: React.ComponentType) => React.ComponentType<P> {
|
|
62
|
-
const { reloadOnForceUpdate = true, ...
|
|
62
|
+
const { reloadOnForceUpdate = true, ...restOptions } = options;
|
|
63
63
|
return (WrappedComponent) => {
|
|
64
64
|
const HotUpdaterHOC: React.FC<P> = () => {
|
|
65
65
|
const progress = useHotUpdaterStore((state) => state.progress);
|
|
@@ -71,13 +71,14 @@ export function wrap<P>(
|
|
|
71
71
|
try {
|
|
72
72
|
setUpdateStatus("CHECK_FOR_UPDATE");
|
|
73
73
|
const updateInfo = await checkForUpdate({
|
|
74
|
-
source:
|
|
75
|
-
requestHeaders:
|
|
74
|
+
source: restOptions.source,
|
|
75
|
+
requestHeaders: restOptions.requestHeaders,
|
|
76
|
+
onError: restOptions.onError,
|
|
76
77
|
});
|
|
77
78
|
setMessage(updateInfo?.message ?? null);
|
|
78
79
|
|
|
79
80
|
if (!updateInfo) {
|
|
80
|
-
|
|
81
|
+
restOptions.onUpdateProcessCompleted?.({
|
|
81
82
|
status: "UP_TO_DATE",
|
|
82
83
|
shouldForceUpdate: false,
|
|
83
84
|
message: null,
|
|
@@ -89,7 +90,7 @@ export function wrap<P>(
|
|
|
89
90
|
|
|
90
91
|
if (updateInfo.shouldForceUpdate === false) {
|
|
91
92
|
void updateBundle(updateInfo.id, updateInfo.fileUrl);
|
|
92
|
-
|
|
93
|
+
restOptions.onUpdateProcessCompleted?.({
|
|
93
94
|
id: updateInfo.id,
|
|
94
95
|
status: updateInfo.status,
|
|
95
96
|
shouldForceUpdate: updateInfo.shouldForceUpdate,
|
|
@@ -115,7 +116,7 @@ export function wrap<P>(
|
|
|
115
116
|
reload();
|
|
116
117
|
}
|
|
117
118
|
|
|
118
|
-
|
|
119
|
+
restOptions.onUpdateProcessCompleted?.({
|
|
119
120
|
id: updateInfo.id,
|
|
120
121
|
status: updateInfo.status,
|
|
121
122
|
shouldForceUpdate: updateInfo.shouldForceUpdate,
|
|
@@ -124,7 +125,7 @@ export function wrap<P>(
|
|
|
124
125
|
setUpdateStatus("UPDATE_PROCESS_COMPLETED");
|
|
125
126
|
} catch (error) {
|
|
126
127
|
if (error instanceof HotUpdaterError) {
|
|
127
|
-
|
|
128
|
+
restOptions.onError?.(error);
|
|
128
129
|
}
|
|
129
130
|
setUpdateStatus("UPDATE_PROCESS_COMPLETED");
|
|
130
131
|
throw error;
|
|
@@ -132,7 +133,7 @@ export function wrap<P>(
|
|
|
132
133
|
});
|
|
133
134
|
|
|
134
135
|
useEffect(() => {
|
|
135
|
-
|
|
136
|
+
restOptions.onProgress?.(progress);
|
|
136
137
|
}, [progress]);
|
|
137
138
|
|
|
138
139
|
useLayoutEffect(() => {
|
|
@@ -140,10 +141,10 @@ export function wrap<P>(
|
|
|
140
141
|
}, []);
|
|
141
142
|
|
|
142
143
|
if (
|
|
143
|
-
|
|
144
|
+
restOptions.fallbackComponent &&
|
|
144
145
|
updateStatus !== "UPDATE_PROCESS_COMPLETED"
|
|
145
146
|
) {
|
|
146
|
-
const Fallback =
|
|
147
|
+
const Fallback = restOptions.fallbackComponent;
|
|
147
148
|
return (
|
|
148
149
|
<Fallback
|
|
149
150
|
progress={progress}
|