@hot-updater/react-native 0.0.5 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,220 @@
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
+ });
@@ -0,0 +1,80 @@
1
+ import * as _hot_updater_utils from '@hot-updater/utils';
2
+ import { UpdateSourceArg } from '@hot-updater/utils';
3
+
4
+ type UpdateStatus = "ROLLBACK" | "UPDATE";
5
+ declare const checkForUpdate: (updateSources: UpdateSourceArg) => Promise<{
6
+ bundleVersion: number;
7
+ forceUpdate: boolean;
8
+ file: null;
9
+ hash: null;
10
+ status: UpdateStatus;
11
+ } | {
12
+ bundleVersion: number;
13
+ forceUpdate: boolean;
14
+ file: string;
15
+ hash: string;
16
+ status: UpdateStatus;
17
+ } | null>;
18
+
19
+ declare class HotUpdaterError extends Error {
20
+ constructor(message: string);
21
+ }
22
+
23
+ type HotUpdaterStatus = "INSTALLING_UPDATE" | "UP_TO_DATE";
24
+ interface HotUpdaterInitConfig {
25
+ source: UpdateSourceArg;
26
+ onSuccess?: (status: HotUpdaterStatus) => void;
27
+ onError?: (error: HotUpdaterError) => void;
28
+ }
29
+ declare const init: (config: HotUpdaterInitConfig) => Promise<void>;
30
+
31
+ /**
32
+ * Fetches the current bundle version id.
33
+ *
34
+ * @async
35
+ * @returns {Promise<number>} Resolves with the current version id or null if not available.
36
+ */
37
+ declare const getBundleVersion: () => Promise<number>;
38
+ /**
39
+ * Downloads files from given URLs.
40
+ *
41
+ * @async
42
+ * @param {string} bundleVersion - identifier for the bundle version.
43
+ * @param {string | null} zipUrl - zip file URL.
44
+ * @returns {Promise<boolean>} Resolves with true if download was successful, otherwise rejects with an error.
45
+ */
46
+ declare const updateBundle: (bundleVersion: number, zipUrl: string | null) => Promise<boolean>;
47
+ /**
48
+ * Fetches the current app version.
49
+ */
50
+ declare const getAppVersion: () => Promise<string | null>;
51
+ /**
52
+ * Reloads the app.
53
+ */
54
+ declare const reload: () => void;
55
+ /**
56
+ * Initializes the HotUpdater.
57
+ */
58
+ declare const initializeOnAppUpdate: () => void;
59
+
60
+ declare const HotUpdater: {
61
+ init: (config: HotUpdaterInitConfig) => Promise<void>;
62
+ reload: () => void;
63
+ checkForUpdate: (updateSources: _hot_updater_utils.UpdateSourceArg) => Promise<{
64
+ bundleVersion: number;
65
+ forceUpdate: boolean;
66
+ file: null;
67
+ hash: null;
68
+ status: UpdateStatus;
69
+ } | {
70
+ bundleVersion: number;
71
+ forceUpdate: boolean;
72
+ file: string;
73
+ hash: string;
74
+ status: UpdateStatus;
75
+ } | null>;
76
+ getAppVersion: () => Promise<string | null>;
77
+ getBundleVersion: () => Promise<number>;
78
+ };
79
+
80
+ export { HotUpdater, type HotUpdaterInitConfig, type HotUpdaterStatus, type UpdateStatus, checkForUpdate, getAppVersion, getBundleVersion, init, initializeOnAppUpdate, reload, updateBundle };
@@ -0,0 +1,80 @@
1
+ import * as _hot_updater_utils from '@hot-updater/utils';
2
+ import { UpdateSourceArg } from '@hot-updater/utils';
3
+
4
+ type UpdateStatus = "ROLLBACK" | "UPDATE";
5
+ declare const checkForUpdate: (updateSources: UpdateSourceArg) => Promise<{
6
+ bundleVersion: number;
7
+ forceUpdate: boolean;
8
+ file: null;
9
+ hash: null;
10
+ status: UpdateStatus;
11
+ } | {
12
+ bundleVersion: number;
13
+ forceUpdate: boolean;
14
+ file: string;
15
+ hash: string;
16
+ status: UpdateStatus;
17
+ } | null>;
18
+
19
+ declare class HotUpdaterError extends Error {
20
+ constructor(message: string);
21
+ }
22
+
23
+ type HotUpdaterStatus = "INSTALLING_UPDATE" | "UP_TO_DATE";
24
+ interface HotUpdaterInitConfig {
25
+ source: UpdateSourceArg;
26
+ onSuccess?: (status: HotUpdaterStatus) => void;
27
+ onError?: (error: HotUpdaterError) => void;
28
+ }
29
+ declare const init: (config: HotUpdaterInitConfig) => Promise<void>;
30
+
31
+ /**
32
+ * Fetches the current bundle version id.
33
+ *
34
+ * @async
35
+ * @returns {Promise<number>} Resolves with the current version id or null if not available.
36
+ */
37
+ declare const getBundleVersion: () => Promise<number>;
38
+ /**
39
+ * Downloads files from given URLs.
40
+ *
41
+ * @async
42
+ * @param {string} bundleVersion - identifier for the bundle version.
43
+ * @param {string | null} zipUrl - zip file URL.
44
+ * @returns {Promise<boolean>} Resolves with true if download was successful, otherwise rejects with an error.
45
+ */
46
+ declare const updateBundle: (bundleVersion: number, zipUrl: string | null) => Promise<boolean>;
47
+ /**
48
+ * Fetches the current app version.
49
+ */
50
+ declare const getAppVersion: () => Promise<string | null>;
51
+ /**
52
+ * Reloads the app.
53
+ */
54
+ declare const reload: () => void;
55
+ /**
56
+ * Initializes the HotUpdater.
57
+ */
58
+ declare const initializeOnAppUpdate: () => void;
59
+
60
+ declare const HotUpdater: {
61
+ init: (config: HotUpdaterInitConfig) => Promise<void>;
62
+ reload: () => void;
63
+ checkForUpdate: (updateSources: _hot_updater_utils.UpdateSourceArg) => Promise<{
64
+ bundleVersion: number;
65
+ forceUpdate: boolean;
66
+ file: null;
67
+ hash: null;
68
+ status: UpdateStatus;
69
+ } | {
70
+ bundleVersion: number;
71
+ forceUpdate: boolean;
72
+ file: string;
73
+ hash: string;
74
+ status: UpdateStatus;
75
+ } | null>;
76
+ getAppVersion: () => Promise<string | null>;
77
+ getBundleVersion: () => Promise<number>;
78
+ };
79
+
80
+ export { HotUpdater, type HotUpdaterInitConfig, type HotUpdaterStatus, type UpdateStatus, checkForUpdate, getAppVersion, getBundleVersion, init, initializeOnAppUpdate, reload, updateBundle };
package/dist/index.js ADDED
@@ -0,0 +1,193 @@
1
+ // src/checkForUpdate.ts
2
+ import { filterTargetVersion } from "@hot-updater/utils";
3
+ import { Platform } from "react-native";
4
+
5
+ // src/native.ts
6
+ import { NativeModules } from "react-native";
7
+
8
+ // src/error.ts
9
+ var HotUpdaterError = class extends Error {
10
+ constructor(message) {
11
+ super(message);
12
+ this.name = "HotUpdaterError";
13
+ }
14
+ };
15
+
16
+ // src/native.ts
17
+ var { HotUpdater } = NativeModules;
18
+ var getBundleVersion = async () => {
19
+ return new Promise((resolve) => {
20
+ HotUpdater.getBundleVersion((version) => {
21
+ resolve(version ?? -1);
22
+ });
23
+ });
24
+ };
25
+ var updateBundle = (bundleVersion, zipUrl) => {
26
+ return new Promise((resolve, reject) => {
27
+ HotUpdater.updateBundle(
28
+ String(bundleVersion),
29
+ zipUrl,
30
+ (success) => {
31
+ if (success) {
32
+ resolve(success);
33
+ } else {
34
+ reject(
35
+ new HotUpdaterError("Failed to download and install the update")
36
+ );
37
+ }
38
+ }
39
+ );
40
+ });
41
+ };
42
+ var getAppVersion = async () => {
43
+ return new Promise((resolve) => {
44
+ HotUpdater.getAppVersion((version) => {
45
+ resolve(version);
46
+ });
47
+ });
48
+ };
49
+ var reload = () => {
50
+ HotUpdater.reload();
51
+ };
52
+ var initializeOnAppUpdate = () => {
53
+ HotUpdater.initializeOnAppUpdate();
54
+ };
55
+
56
+ // src/utils.ts
57
+ var isNullable = (value) => value === null || value === void 0;
58
+
59
+ // src/checkForUpdate.ts
60
+ var findLatestSources = (sources) => {
61
+ return sources?.filter((item) => item.enabled)?.sort((a, b) => b.bundleVersion - a.bundleVersion)?.[0] ?? null;
62
+ };
63
+ var checkForRollback = (sources, currentBundleVersion) => {
64
+ const enabled = sources?.find(
65
+ (item) => item.bundleVersion === currentBundleVersion
66
+ )?.enabled;
67
+ const availableOldVersion = sources?.find(
68
+ (item) => item.bundleVersion < currentBundleVersion && item.enabled
69
+ )?.enabled;
70
+ if (isNullable(enabled)) {
71
+ return availableOldVersion;
72
+ }
73
+ return !enabled;
74
+ };
75
+ var ensureUpdateSource = async (updateSource) => {
76
+ let source = null;
77
+ if (typeof updateSource === "string") {
78
+ if (updateSource.startsWith("http")) {
79
+ const response = await fetch(updateSource);
80
+ source = await response.json();
81
+ }
82
+ } else if (typeof updateSource === "function") {
83
+ source = await updateSource();
84
+ } else {
85
+ source = updateSource;
86
+ }
87
+ if (!source) {
88
+ throw new Error("Invalid source");
89
+ }
90
+ return source;
91
+ };
92
+ var checkForUpdate = async (updateSources) => {
93
+ const sources = await ensureUpdateSource(updateSources);
94
+ const currentAppVersion = await getAppVersion();
95
+ const platform = Platform.OS;
96
+ const appVersionSources = currentAppVersion ? filterTargetVersion(sources, currentAppVersion, platform) : [];
97
+ const currentBundleVersion = await getBundleVersion();
98
+ const isRollback = checkForRollback(appVersionSources, currentBundleVersion);
99
+ const latestSource = await findLatestSources(appVersionSources);
100
+ if (!latestSource) {
101
+ if (isRollback) {
102
+ return {
103
+ bundleVersion: 0,
104
+ forceUpdate: true,
105
+ file: null,
106
+ hash: null,
107
+ status: "ROLLBACK"
108
+ };
109
+ }
110
+ return null;
111
+ }
112
+ if (latestSource.file) {
113
+ if (isRollback) {
114
+ if (latestSource.bundleVersion === currentBundleVersion) {
115
+ return null;
116
+ }
117
+ if (latestSource.bundleVersion > currentBundleVersion) {
118
+ return {
119
+ bundleVersion: latestSource.bundleVersion,
120
+ forceUpdate: latestSource.forceUpdate,
121
+ file: latestSource.file,
122
+ hash: latestSource.hash,
123
+ status: "UPDATE"
124
+ };
125
+ }
126
+ return {
127
+ bundleVersion: latestSource.bundleVersion,
128
+ forceUpdate: true,
129
+ file: latestSource.file,
130
+ hash: latestSource.hash,
131
+ status: "ROLLBACK"
132
+ };
133
+ }
134
+ }
135
+ if (latestSource.bundleVersion > currentBundleVersion) {
136
+ return {
137
+ bundleVersion: latestSource.bundleVersion,
138
+ forceUpdate: latestSource.forceUpdate,
139
+ file: latestSource.file,
140
+ hash: latestSource.hash,
141
+ status: "UPDATE"
142
+ };
143
+ }
144
+ return null;
145
+ };
146
+
147
+ // src/init.tsx
148
+ import { Platform as Platform2 } from "react-native";
149
+ var init = async (config) => {
150
+ if (__DEV__) {
151
+ console.warn(
152
+ "[HotUpdater] __DEV__ is true, HotUpdater is only supported in production"
153
+ );
154
+ return;
155
+ }
156
+ if (!["ios", "android"].includes(Platform2.OS)) {
157
+ const error = new HotUpdaterError(
158
+ "HotUpdater is only supported on iOS and Android"
159
+ );
160
+ config?.onError?.(error);
161
+ throw error;
162
+ }
163
+ await initializeOnAppUpdate();
164
+ const update = await checkForUpdate(config.source);
165
+ if (!update) {
166
+ config?.onSuccess?.("UP_TO_DATE");
167
+ return;
168
+ }
169
+ try {
170
+ const isSuccess = await updateBundle(update.bundleVersion, update.file);
171
+ if (isSuccess && update.forceUpdate) {
172
+ reload();
173
+ config?.onSuccess?.("INSTALLING_UPDATE");
174
+ }
175
+ } catch (error) {
176
+ if (error instanceof HotUpdaterError) {
177
+ config?.onError?.(error);
178
+ }
179
+ throw error;
180
+ }
181
+ };
182
+
183
+ // src/index.ts
184
+ var HotUpdater2 = {
185
+ init,
186
+ reload,
187
+ checkForUpdate,
188
+ getAppVersion,
189
+ getBundleVersion
190
+ };
191
+ export {
192
+ HotUpdater2 as HotUpdater
193
+ };
@@ -6,6 +6,5 @@
6
6
  @interface HotUpdater : NSObject <RCTBridgeModule>
7
7
 
8
8
  + (NSURL *)bundleURL;
9
- + (NSURL *)bundleURLWithoutFallback;
10
9
 
11
10
  @end