@hot-updater/react-native 0.16.0 → 0.16.2

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.
@@ -1,6 +1,12 @@
1
+ import { type UpdateSource } from "./fetchUpdateInfo";
1
2
  export interface CheckForUpdateOptions {
2
- source: string;
3
+ source: UpdateSource;
3
4
  requestHeaders?: Record<string, string>;
4
5
  onError?: (error: Error) => void;
6
+ /**
7
+ * The timeout duration for the request.
8
+ * @default 5000
9
+ */
10
+ requestTimeout?: number;
5
11
  }
6
12
  export declare function checkForUpdate(options: CheckForUpdateOptions): Promise<import("@hot-updater/core").AppUpdateInfo | null>;
@@ -1,2 +1,3 @@
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>, onError?: (error: Error) => void) => Promise<AppUpdateInfo | null>;
2
+ export type UpdateSource = string | (() => Promise<AppUpdateInfo | null>);
3
+ export declare const fetchUpdateInfo: (source: UpdateSource, { appVersion, bundleId, platform, minBundleId, channel }: GetBundlesArgs, requestHeaders?: Record<string, string>, onError?: (error: Error) => void, requestTimeout?: number) => Promise<AppUpdateInfo | null>;
package/dist/index.js CHANGED
@@ -66,9 +66,15 @@ var __webpack_exports__ = {};
66
66
  this.name = "HotUpdaterError";
67
67
  }
68
68
  }
69
- const fetchUpdateInfo = async (source, { appVersion, bundleId, platform, minBundleId, channel }, requestHeaders, onError)=>{
69
+ const fetchUpdateInfo = async (source, { appVersion, bundleId, platform, minBundleId, channel }, requestHeaders, onError, requestTimeout = 5000)=>{
70
+ if ("function" == typeof source) return source();
71
+ const controller = new AbortController();
72
+ const timeoutId = setTimeout(()=>{
73
+ controller.abort();
74
+ }, requestTimeout);
70
75
  try {
71
76
  const response = await fetch(source, {
77
+ signal: controller.signal,
72
78
  headers: {
73
79
  "Content-Type": "application/json",
74
80
  "x-app-platform": platform,
@@ -83,9 +89,14 @@ var __webpack_exports__ = {};
83
89
  ...requestHeaders
84
90
  }
85
91
  });
92
+ clearTimeout(timeoutId);
86
93
  if (200 !== response.status) throw new Error(response.statusText);
87
94
  return response.json();
88
95
  } catch (error) {
96
+ if ("AbortError" === error.name) {
97
+ onError?.(new Error("Request timed out"));
98
+ return null;
99
+ }
89
100
  onError?.(error);
90
101
  return null;
91
102
  }
@@ -157,7 +168,7 @@ var __webpack_exports__ = {};
157
168
  platform,
158
169
  minBundleId,
159
170
  channel: channel ?? void 0
160
- }, options.requestHeaders, options.onError);
171
+ }, options.requestHeaders, options.onError, options.requestTimeout);
161
172
  }
162
173
  const runUpdateProcess = async ({ reloadOnForceUpdate = true, ...checkForUpdateOptions })=>{
163
174
  const updateInfo = await checkForUpdate(checkForUpdateOptions);
@@ -227,7 +238,7 @@ var __webpack_exports__ = {};
227
238
  function wrap(options) {
228
239
  const { reloadOnForceUpdate = true, ...restOptions } = options;
229
240
  return (WrappedComponent)=>{
230
- const HotUpdaterHOC = ()=>{
241
+ const HotUpdaterHOC = (props)=>{
231
242
  const progress = useHotUpdaterStore((state)=>state.progress);
232
243
  const [message, setMessage] = (0, external_react_namespaceObject.useState)(null);
233
244
  const [updateStatus, setUpdateStatus] = (0, external_react_namespaceObject.useState)("CHECK_FOR_UPDATE");
@@ -294,7 +305,7 @@ var __webpack_exports__ = {};
294
305
  message: message
295
306
  });
296
307
  }
297
- return /*#__PURE__*/ external_react_default().createElement(WrappedComponent, null);
308
+ return /*#__PURE__*/ external_react_default().createElement(WrappedComponent, props);
298
309
  };
299
310
  return HotUpdaterHOC;
300
311
  };
package/dist/index.mjs CHANGED
@@ -41,9 +41,15 @@ class HotUpdaterError extends Error {
41
41
  this.name = "HotUpdaterError";
42
42
  }
43
43
  }
44
- const fetchUpdateInfo = async (source, { appVersion, bundleId, platform, minBundleId, channel }, requestHeaders, onError)=>{
44
+ const fetchUpdateInfo = async (source, { appVersion, bundleId, platform, minBundleId, channel }, requestHeaders, onError, requestTimeout = 5000)=>{
45
+ if ("function" == typeof source) return source();
46
+ const controller = new AbortController();
47
+ const timeoutId = setTimeout(()=>{
48
+ controller.abort();
49
+ }, requestTimeout);
45
50
  try {
46
51
  const response = await fetch(source, {
52
+ signal: controller.signal,
47
53
  headers: {
48
54
  "Content-Type": "application/json",
49
55
  "x-app-platform": platform,
@@ -58,9 +64,14 @@ const fetchUpdateInfo = async (source, { appVersion, bundleId, platform, minBund
58
64
  ...requestHeaders
59
65
  }
60
66
  });
67
+ clearTimeout(timeoutId);
61
68
  if (200 !== response.status) throw new Error(response.statusText);
62
69
  return response.json();
63
70
  } catch (error) {
71
+ if ("AbortError" === error.name) {
72
+ onError?.(new Error("Request timed out"));
73
+ return null;
74
+ }
64
75
  onError?.(error);
65
76
  return null;
66
77
  }
@@ -132,7 +143,7 @@ async function checkForUpdate(options) {
132
143
  platform,
133
144
  minBundleId,
134
145
  channel: channel ?? void 0
135
- }, options.requestHeaders, options.onError);
146
+ }, options.requestHeaders, options.onError, options.requestTimeout);
136
147
  }
137
148
  const runUpdateProcess = async ({ reloadOnForceUpdate = true, ...checkForUpdateOptions })=>{
138
149
  const updateInfo = await checkForUpdate(checkForUpdateOptions);
@@ -198,7 +209,7 @@ function useEventCallback(fn) {
198
209
  function wrap(options) {
199
210
  const { reloadOnForceUpdate = true, ...restOptions } = options;
200
211
  return (WrappedComponent)=>{
201
- const HotUpdaterHOC = ()=>{
212
+ const HotUpdaterHOC = (props)=>{
202
213
  const progress = useHotUpdaterStore((state)=>state.progress);
203
214
  const [message, setMessage] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(null);
204
215
  const [updateStatus, setUpdateStatus] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)("CHECK_FOR_UPDATE");
@@ -265,7 +276,7 @@ function wrap(options) {
265
276
  message: message
266
277
  });
267
278
  }
268
- return /*#__PURE__*/ __WEBPACK_EXTERNAL_MODULE_react__["default"].createElement(WrappedComponent, null);
279
+ return /*#__PURE__*/ __WEBPACK_EXTERNAL_MODULE_react__["default"].createElement(WrappedComponent, props);
269
280
  };
270
281
  return HotUpdaterHOC;
271
282
  };
package/dist/wrap.d.ts CHANGED
@@ -46,5 +46,5 @@ export interface HotUpdaterOptions extends CheckForUpdateOptions {
46
46
  */
47
47
  onUpdateProcessCompleted?: (response: RunUpdateProcessResponse) => void;
48
48
  }
49
- export declare function wrap<P>(options: HotUpdaterOptions): (WrappedComponent: React.ComponentType) => React.ComponentType<P>;
49
+ export declare function wrap<P extends React.JSX.IntrinsicAttributes = object>(options: HotUpdaterOptions): (WrappedComponent: React.ComponentType<P>) => React.ComponentType<P>;
50
50
  export {};
@@ -32,7 +32,7 @@ RCT_EXPORT_MODULE();
32
32
  uuid = @"00000000-0000-0000-0000-000000000000";
33
33
  return;
34
34
  #else
35
- // __DATE__, __TIME__ 컴파일 타임 값입니다.
35
+ // __DATE__, __TIME__ is compile-time
36
36
  NSString *compileDateStr = [NSString stringWithFormat:@"%s %s", __DATE__, __TIME__];
37
37
  NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
38
38
  [formatter setDateFormat:@"MMM d yyyy HH:mm:ss"];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hot-updater/react-native",
3
- "version": "0.16.0",
3
+ "version": "0.16.2",
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.16.0",
85
- "@hot-updater/core": "0.16.0"
84
+ "@hot-updater/js": "0.16.2",
85
+ "@hot-updater/core": "0.16.2"
86
86
  },
87
87
  "scripts": {
88
88
  "build": "rslib build",
@@ -1,6 +1,6 @@
1
1
  import { Platform } from "react-native";
2
2
  import { HotUpdaterError } from "./error";
3
- import { fetchUpdateInfo } from "./fetchUpdateInfo";
3
+ import { type UpdateSource, fetchUpdateInfo } from "./fetchUpdateInfo";
4
4
  import {
5
5
  getAppVersion,
6
6
  getBundleId,
@@ -9,9 +9,14 @@ import {
9
9
  } from "./native";
10
10
 
11
11
  export interface CheckForUpdateOptions {
12
- source: string;
12
+ source: UpdateSource;
13
13
  requestHeaders?: Record<string, string>;
14
14
  onError?: (error: Error) => void;
15
+ /**
16
+ * The timeout duration for the request.
17
+ * @default 5000
18
+ */
19
+ requestTimeout?: number;
15
20
  }
16
21
 
17
22
  export async function checkForUpdate(options: CheckForUpdateOptions) {
@@ -48,5 +53,6 @@ export async function checkForUpdate(options: CheckForUpdateOptions) {
48
53
  },
49
54
  options.requestHeaders,
50
55
  options.onError,
56
+ options.requestTimeout,
51
57
  );
52
58
  }
@@ -1,16 +1,28 @@
1
1
  import type { AppUpdateInfo, GetBundlesArgs } from "@hot-updater/core";
2
2
 
3
+ export type UpdateSource = string | (() => Promise<AppUpdateInfo | null>);
4
+
3
5
  export const fetchUpdateInfo = async (
4
- source: string,
6
+ source: UpdateSource,
5
7
  { appVersion, bundleId, platform, minBundleId, channel }: GetBundlesArgs,
6
8
  requestHeaders?: Record<string, string>,
7
9
  onError?: (error: Error) => void,
10
+ requestTimeout = 5000,
8
11
  ): Promise<AppUpdateInfo | null> => {
12
+ if (typeof source === "function") {
13
+ return source();
14
+ }
15
+
16
+ const controller = new AbortController();
17
+ const timeoutId = setTimeout(() => {
18
+ controller.abort();
19
+ }, requestTimeout);
20
+
9
21
  try {
10
22
  const response = await fetch(source, {
23
+ signal: controller.signal,
11
24
  headers: {
12
25
  "Content-Type": "application/json",
13
-
14
26
  "x-app-platform": platform,
15
27
  "x-app-version": appVersion,
16
28
  "x-bundle-id": bundleId,
@@ -20,11 +32,17 @@ export const fetchUpdateInfo = async (
20
32
  },
21
33
  });
22
34
 
35
+ clearTimeout(timeoutId);
36
+
23
37
  if (response.status !== 200) {
24
38
  throw new Error(response.statusText);
25
39
  }
26
40
  return response.json();
27
- } catch (error) {
41
+ } catch (error: any) {
42
+ if (error.name === "AbortError") {
43
+ onError?.(new Error("Request timed out"));
44
+ return null;
45
+ }
28
46
  onError?.(error as Error);
29
47
  return null;
30
48
  }
package/src/wrap.tsx CHANGED
@@ -56,25 +56,29 @@ export interface HotUpdaterOptions extends CheckForUpdateOptions {
56
56
  onUpdateProcessCompleted?: (response: RunUpdateProcessResponse) => void;
57
57
  }
58
58
 
59
- export function wrap<P>(
59
+ export function wrap<P extends React.JSX.IntrinsicAttributes = object>(
60
60
  options: HotUpdaterOptions,
61
- ): (WrappedComponent: React.ComponentType) => React.ComponentType<P> {
61
+ ): (WrappedComponent: React.ComponentType<P>) => React.ComponentType<P> {
62
62
  const { reloadOnForceUpdate = true, ...restOptions } = options;
63
- return (WrappedComponent) => {
64
- const HotUpdaterHOC: React.FC<P> = () => {
63
+
64
+ return (WrappedComponent: React.ComponentType<P>) => {
65
+ const HotUpdaterHOC: React.FC<P> = (props: P) => {
65
66
  const progress = useHotUpdaterStore((state) => state.progress);
66
67
 
67
68
  const [message, setMessage] = useState<string | null>(null);
68
69
  const [updateStatus, setUpdateStatus] =
69
70
  useState<UpdateStatus>("CHECK_FOR_UPDATE");
71
+
70
72
  const initHotUpdater = useEventCallback(async () => {
71
73
  try {
72
74
  setUpdateStatus("CHECK_FOR_UPDATE");
75
+
73
76
  const updateInfo = await checkForUpdate({
74
77
  source: restOptions.source,
75
78
  requestHeaders: restOptions.requestHeaders,
76
79
  onError: restOptions.onError,
77
80
  });
81
+
78
82
  setMessage(updateInfo?.message ?? null);
79
83
 
80
84
  if (!updateInfo) {
@@ -106,6 +110,7 @@ export function wrap<P>(
106
110
  updateInfo.id,
107
111
  updateInfo.fileUrl,
108
112
  );
113
+
109
114
  if (!isSuccess) {
110
115
  throw new Error(
111
116
  "New update was found but failed to download the bundle.",
@@ -122,6 +127,7 @@ export function wrap<P>(
122
127
  shouldForceUpdate: updateInfo.shouldForceUpdate,
123
128
  message: updateInfo.message,
124
129
  });
130
+
125
131
  setUpdateStatus("UPDATE_PROCESS_COMPLETED");
126
132
  } catch (error) {
127
133
  if (error instanceof HotUpdaterError) {
@@ -154,9 +160,9 @@ export function wrap<P>(
154
160
  );
155
161
  }
156
162
 
157
- return <WrappedComponent />;
163
+ return <WrappedComponent {...props} />;
158
164
  };
159
165
 
160
- return HotUpdaterHOC;
166
+ return HotUpdaterHOC as React.ComponentType<P>;
161
167
  };
162
168
  }