@o/native-hot-update 0.16.19

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.
Files changed (44) hide show
  1. package/README.md +212 -0
  2. package/dist/cjs/createHotUpdater.cjs +224 -0
  3. package/dist/cjs/createHotUpdater.native.js +250 -0
  4. package/dist/cjs/createHotUpdater.native.js.map +1 -0
  5. package/dist/cjs/helpers.cjs +40 -0
  6. package/dist/cjs/helpers.native.js +43 -0
  7. package/dist/cjs/helpers.native.js.map +1 -0
  8. package/dist/cjs/index.cjs +31 -0
  9. package/dist/cjs/index.native.js +34 -0
  10. package/dist/cjs/index.native.js.map +1 -0
  11. package/dist/cjs/mmkv.cjs +34 -0
  12. package/dist/cjs/mmkv.native.js +43 -0
  13. package/dist/cjs/mmkv.native.js.map +1 -0
  14. package/dist/cjs/types.cjs +18 -0
  15. package/dist/cjs/types.native.js +21 -0
  16. package/dist/cjs/types.native.js.map +1 -0
  17. package/dist/esm/createHotUpdater.mjs +188 -0
  18. package/dist/esm/createHotUpdater.mjs.map +1 -0
  19. package/dist/esm/createHotUpdater.native.js +211 -0
  20. package/dist/esm/createHotUpdater.native.js.map +1 -0
  21. package/dist/esm/helpers.mjs +14 -0
  22. package/dist/esm/helpers.mjs.map +1 -0
  23. package/dist/esm/helpers.native.js +14 -0
  24. package/dist/esm/helpers.native.js.map +1 -0
  25. package/dist/esm/index.js +4 -0
  26. package/dist/esm/index.js.map +1 -0
  27. package/dist/esm/index.mjs +4 -0
  28. package/dist/esm/index.mjs.map +1 -0
  29. package/dist/esm/index.native.js +4 -0
  30. package/dist/esm/index.native.js.map +1 -0
  31. package/dist/esm/mmkv.mjs +9 -0
  32. package/dist/esm/mmkv.mjs.map +1 -0
  33. package/dist/esm/mmkv.native.js +15 -0
  34. package/dist/esm/mmkv.native.js.map +1 -0
  35. package/dist/esm/types.mjs +2 -0
  36. package/dist/esm/types.mjs.map +1 -0
  37. package/dist/esm/types.native.js +2 -0
  38. package/dist/esm/types.native.js.map +1 -0
  39. package/package.json +67 -0
  40. package/src/createHotUpdater.ts +250 -0
  41. package/src/helpers.ts +23 -0
  42. package/src/index.ts +6 -0
  43. package/src/mmkv.ts +20 -0
  44. package/src/types.ts +66 -0
package/README.md ADDED
@@ -0,0 +1,212 @@
1
+ # @o/native-hot-update
2
+
3
+ Minimal, headless React Native hot update library.
4
+
5
+ ## Features
6
+
7
+ - Simple instance-based API
8
+ - Pluggable storage (MMKV, AsyncStorage, custom)
9
+ - Timeout protection (5s + 20s hard limit)
10
+ - Pre-release testing workflow
11
+ - Works with Expo & React Native
12
+ - Zero UI - bring your own components
13
+
14
+ ## Prerequisites
15
+
16
+ The Takeout template ships with `HotUpdaterSplash` already wrapping your native
17
+ app. The app runs fine without a backend - updates are gated by PostHog feature
18
+ flags (off by default).
19
+
20
+ When ready to deploy OTA updates, set up a backend:
21
+
22
+ ```bash
23
+ npx -y supabase login
24
+ npx hot-updater init
25
+ ```
26
+
27
+ During `hot-updater init`, select:
28
+
29
+ - **Build plugin**: `Bare`
30
+ - **Storage/Database**: `Supabase`
31
+
32
+ This generates `hot-updater.config.ts` and `.env.hotupdater` with your Supabase
33
+ credentials. Then enable via PostHog feature flags.
34
+
35
+ See https://hot-updater.dev/docs/managed/supabase for full backend setup.
36
+
37
+ ## Installation
38
+
39
+ ```bash
40
+ bun add @o/native-hot-update react-native-mmkv
41
+ ```
42
+
43
+ ## Quick Start
44
+
45
+ ### 1. Create Hot Updater Instance
46
+
47
+ ```ts
48
+ // src/hotUpdater.ts
49
+ import { MMKV } from 'react-native-mmkv'
50
+ import { createHotUpdater } from '@o/native-hot-update'
51
+ import { createMMKVStorage } from '@o/native-hot-update/mmkv'
52
+
53
+ const mmkv = new MMKV({ id: 'hot-updater' })
54
+
55
+ const hotUpdaterInstance = createHotUpdater({
56
+ storage: createMMKVStorage(mmkv),
57
+ updateStrategy: 'appVersion',
58
+ })
59
+
60
+ // Export the hook and instance
61
+ export const useOtaUpdater = hotUpdaterInstance.useOtaUpdater
62
+ export const hotUpdater = hotUpdaterInstance
63
+ ```
64
+
65
+ ### 2. Wrap Your App
66
+
67
+ ```tsx
68
+ // app/index.tsx or App.tsx
69
+ import { HotUpdater } from '@o/native-hot-update'
70
+
71
+ function App() {
72
+ // Your app component
73
+ return <YourApp />
74
+ }
75
+
76
+ // IMPORTANT: wrap() initializes HotUpdater config - required for checkForUpdate
77
+ export default HotUpdater.wrap({
78
+ baseURL: 'https://your-update-server.com',
79
+ updateMode: 'manual', // Use manual mode with custom hooks
80
+ })(App)
81
+ ```
82
+
83
+ ### 3. Use in Your App
84
+
85
+ ```tsx
86
+ // app/_layout.tsx
87
+ import { useOtaUpdater } from './hotUpdater'
88
+
89
+ export default function RootLayout() {
90
+ const { userClearedForAccess, progress } = useOtaUpdater({
91
+ enabled: true,
92
+ onUpdateDownloaded: (info) => {
93
+ console.info('Update downloaded:', info.id)
94
+ },
95
+ onError: (error) => {
96
+ console.error('Update failed:', error)
97
+ },
98
+ })
99
+
100
+ if (!userClearedForAccess) {
101
+ return <SplashScreen progress={progress} />
102
+ }
103
+
104
+ return <YourApp />
105
+ }
106
+ ```
107
+
108
+ ### 4. Display Version Info
109
+
110
+ ```tsx
111
+ import { hotUpdater } from './hotUpdater'
112
+ import * as Application from 'expo-application'
113
+
114
+ export function VersionDisplay() {
115
+ const otaId = hotUpdater.getShortOtaId()
116
+ const channel = hotUpdater.getChannel()
117
+
118
+ return (
119
+ <Text>
120
+ v{Application.nativeApplicationVersion}
121
+ {otaId && ` (${otaId})`} • {channel}
122
+ </Text>
123
+ )
124
+ }
125
+ ```
126
+
127
+ ### 5. Dev Tools
128
+
129
+ ```tsx
130
+ import { hotUpdater } from './hotUpdater'
131
+ import { Button, View, Text, Alert } from 'react-native'
132
+
133
+ export function DevUpdateTools() {
134
+ const handleCheckUpdate = async () => {
135
+ const update = await hotUpdater.checkForUpdate()
136
+ if (update) {
137
+ Alert.alert('Update available', `ID: ${update.id}`, [
138
+ { text: 'Later' },
139
+ { text: 'Reload', onPress: () => hotUpdater.reload() },
140
+ ])
141
+ } else {
142
+ Alert.alert('No update available')
143
+ }
144
+ }
145
+
146
+ const handleCheckPreRelease = async () => {
147
+ const update = await hotUpdater.checkForUpdate({
148
+ channel: 'production-pre',
149
+ isPreRelease: true,
150
+ })
151
+ if (update) {
152
+ Alert.alert('Pre-release available', `ID: ${update.id}`, [
153
+ { text: 'Later' },
154
+ { text: 'Reload', onPress: () => hotUpdater.reload() },
155
+ ])
156
+ }
157
+ }
158
+
159
+ return (
160
+ <View>
161
+ <Text>Current: {hotUpdater.getAppliedOta() || 'Native build'}</Text>
162
+ <Text>Channel: {hotUpdater.getChannel()}</Text>
163
+ <Button title="Check for Update" onPress={handleCheckUpdate} />
164
+ <Button title="Check Pre-release" onPress={handleCheckPreRelease} />
165
+ <Button title="Reload App" onPress={() => hotUpdater.reload()} />
166
+ </View>
167
+ )
168
+ }
169
+ ```
170
+
171
+ ## API
172
+
173
+ ### `createHotUpdater(config)`
174
+
175
+ Creates a hot updater instance.
176
+
177
+ **Config:**
178
+
179
+ - `storage` (HotUpdateStorage): Storage adapter for persisting state
180
+ - `updateStrategy` ('appVersion' | 'fingerprint'): Update strategy (default:
181
+ 'appVersion')
182
+
183
+ **Returns:** `HotUpdaterInstance`
184
+
185
+ ### `useOtaUpdater(options?)`
186
+
187
+ React hook for automatic update checking.
188
+
189
+ **Options:**
190
+
191
+ - `enabled` (boolean): Enable/disable update checking (default: true)
192
+ - `onUpdateDownloaded` (function): Callback when update is downloaded
193
+ - `onError` (function): Callback on error
194
+
195
+ **Returns:**
196
+
197
+ - `userClearedForAccess` (boolean): Whether user can access app
198
+ - `progress` (number): Download progress (0-100)
199
+ - `isUpdatePending` (boolean): Whether update will apply on restart
200
+
201
+ ### Instance Methods
202
+
203
+ - `checkForUpdate(options?)` - Manually check for updates
204
+ - `getAppliedOta()` - Get current OTA bundle ID
205
+ - `getShortOtaId()` - Get short OTA ID
206
+ - `getIsUpdatePending()` - Check if update is pending
207
+ - `reload()` - Reload app
208
+ - `getBundleId()` - Get current bundle ID
209
+ - `getMinBundleId()` - Get minimum bundle ID
210
+ - `getChannel()` - Get current channel
211
+ - `clearCrashHistory()` - Clear crashed bundle history (allows retrying failed bundles)
212
+ - `getCrashHistory()` - Get list of crashed bundle IDs
@@ -0,0 +1,224 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all) __defProp(target, name, {
9
+ get: all[name],
10
+ enumerable: true
11
+ });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
16
+ get: () => from[key],
17
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
18
+ });
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
23
+ // If the importer is in node compatibility mode or this is not an ESM
24
+ // file that has been converted to a CommonJS file using a Babel-
25
+ // compatible transform (i.e. "__esModule" has not been set), then set
26
+ // "default" to the CommonJS "module.exports" for node compatibility.
27
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
28
+ value: mod,
29
+ enumerable: true
30
+ }) : target, mod));
31
+ var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
32
+ value: true
33
+ }), mod);
34
+ var createHotUpdater_exports = {};
35
+ __export(createHotUpdater_exports, {
36
+ createHotUpdater: () => createHotUpdater
37
+ });
38
+ module.exports = __toCommonJS(createHotUpdater_exports);
39
+ var import_react_native = require("@hot-updater/react-native");
40
+ var Application = __toESM(require("expo-application"), 1);
41
+ var import_react = require("react");
42
+ var import_react_native2 = require("react-native-web");
43
+ const INITIAL_OTA_ID = "00000000-0000-0000-0000-000000000000";
44
+ const BUNDLE_ID_KEY_PREFIX = "hotUpdater.bundleId";
45
+ const PRE_RELEASE_BUNDLE_ID_KEY = "hotUpdater.preReleaseBundleId";
46
+ function createHotUpdater(config) {
47
+ const {
48
+ storage,
49
+ updateStrategy = "appVersion"
50
+ } = config;
51
+ let isUpdatePending = false;
52
+ const getAppliedOta = () => {
53
+ const id = import_react_native.HotUpdater.getBundleId();
54
+ if (id === INITIAL_OTA_ID) return null;
55
+ if (id === import_react_native.HotUpdater.getMinBundleId()) return null;
56
+ return id;
57
+ };
58
+ const getShortOtaId = () => {
59
+ const fullId = getAppliedOta();
60
+ return fullId ? fullId.slice(-12) : null;
61
+ };
62
+ const getIsUpdatePending = () => {
63
+ return isUpdatePending;
64
+ };
65
+ const getPreReleaseBundleId = () => {
66
+ return storage.get(PRE_RELEASE_BUNDLE_ID_KEY);
67
+ };
68
+ const handleUpdateDownloaded = (id, options = {}) => {
69
+ const appVersion = Application.nativeApplicationVersion;
70
+ if (appVersion) {
71
+ storage.set(`${BUNDLE_ID_KEY_PREFIX}.${appVersion}`, id);
72
+ }
73
+ if (options.isPreRelease) {
74
+ storage.set(PRE_RELEASE_BUNDLE_ID_KEY, id);
75
+ } else {
76
+ storage.delete(PRE_RELEASE_BUNDLE_ID_KEY);
77
+ }
78
+ isUpdatePending = true;
79
+ };
80
+ const useOtaUpdater = (options = {}) => {
81
+ const {
82
+ enabled = true,
83
+ onUpdateDownloaded: onUpdateDownloadedCallback,
84
+ onError
85
+ } = options;
86
+ const progress = (0, import_react_native.useHotUpdaterStore)(state => state.progress);
87
+ const isUpdating = progress > 0.01;
88
+ const [isUserClearedForAccess, setIsUserClearedForAccess] = (0, import_react.useState)(false);
89
+ const isUserClearedForAccessRef = (0, import_react.useRef)(isUserClearedForAccess);
90
+ isUserClearedForAccessRef.current = isUserClearedForAccess;
91
+ (0, import_react.useEffect)(() => {
92
+ if (!isUpdating) {
93
+ const timer = setTimeout(() => {
94
+ if (!isUserClearedForAccessRef.current) {
95
+ setIsUserClearedForAccess(true);
96
+ }
97
+ }, 5e3);
98
+ return () => clearTimeout(timer);
99
+ }
100
+ return void 0;
101
+ }, [isUpdating]);
102
+ (0, import_react.useEffect)(() => {
103
+ const timer = setTimeout(() => {
104
+ if (!isUserClearedForAccessRef.current) {
105
+ setIsUserClearedForAccess(true);
106
+ }
107
+ }, 2e4);
108
+ return () => clearTimeout(timer);
109
+ }, []);
110
+ (0, import_react.useEffect)(() => {
111
+ let shouldContinue = true;
112
+ (async () => {
113
+ try {
114
+ if (!enabled) {
115
+ setIsUserClearedForAccess(true);
116
+ return;
117
+ }
118
+ if (!shouldContinue) return;
119
+ const updateInfo = await import_react_native.HotUpdater.checkForUpdate({
120
+ updateStrategy
121
+ });
122
+ if (!updateInfo) {
123
+ setIsUserClearedForAccess(true);
124
+ return;
125
+ }
126
+ if (!shouldContinue) return;
127
+ if (updateInfo.status === "ROLLBACK") {
128
+ const preReleaseBundleId = getPreReleaseBundleId();
129
+ const currentBundleId = import_react_native.HotUpdater.getBundleId();
130
+ if (preReleaseBundleId && preReleaseBundleId === currentBundleId && currentBundleId > updateInfo.id) {
131
+ import_react_native2.Alert.alert("Update Skipped", "Skipped rollback because you are using a newer pre-release bundle.");
132
+ setIsUserClearedForAccess(true);
133
+ return;
134
+ }
135
+ }
136
+ if (!updateInfo.shouldForceUpdate) {
137
+ setIsUserClearedForAccess(true);
138
+ }
139
+ if (!shouldContinue) return;
140
+ await updateInfo.updateBundle();
141
+ handleUpdateDownloaded(updateInfo.id);
142
+ const info = {
143
+ id: updateInfo.id,
144
+ isCriticalUpdate: updateInfo.shouldForceUpdate,
145
+ fileUrl: updateInfo.fileUrl,
146
+ message: updateInfo.message
147
+ };
148
+ onUpdateDownloadedCallback?.(info);
149
+ if (!shouldContinue) return;
150
+ if (updateInfo.shouldForceUpdate) {
151
+ if (!isUserClearedForAccessRef.current) {
152
+ import_react_native.HotUpdater.reload();
153
+ return;
154
+ }
155
+ import_react_native2.Alert.alert("Update Downloaded", "An important update has been downloaded. Reload now to apply it?", [{
156
+ text: "Later",
157
+ style: "cancel"
158
+ }, {
159
+ text: "Reload Now",
160
+ onPress: () => import_react_native.HotUpdater.reload()
161
+ }]);
162
+ }
163
+ } catch (error) {
164
+ onError?.(error);
165
+ setIsUserClearedForAccess(true);
166
+ } finally {
167
+ if (!isUserClearedForAccessRef.current) {
168
+ setIsUserClearedForAccess(true);
169
+ }
170
+ }
171
+ })();
172
+ return () => {
173
+ shouldContinue = false;
174
+ };
175
+ }, [enabled, onUpdateDownloadedCallback, onError]);
176
+ return {
177
+ userClearedForAccess: isUserClearedForAccess,
178
+ progress,
179
+ isUpdatePending: getIsUpdatePending()
180
+ };
181
+ };
182
+ const checkForUpdate = async (options = {}) => {
183
+ const {
184
+ channel,
185
+ isPreRelease = false
186
+ } = options;
187
+ const requestHeaders = {};
188
+ if (channel) {
189
+ requestHeaders["X-Channel"] = channel;
190
+ }
191
+ const updateInfo = await import_react_native.HotUpdater.checkForUpdate({
192
+ updateStrategy,
193
+ ...(Object.keys(requestHeaders).length > 0 && {
194
+ requestHeaders
195
+ })
196
+ });
197
+ if (updateInfo) {
198
+ await updateInfo.updateBundle();
199
+ handleUpdateDownloaded(updateInfo.id, {
200
+ isPreRelease
201
+ });
202
+ return {
203
+ id: updateInfo.id,
204
+ isCriticalUpdate: updateInfo.shouldForceUpdate,
205
+ fileUrl: updateInfo.fileUrl,
206
+ message: updateInfo.message
207
+ };
208
+ }
209
+ return null;
210
+ };
211
+ return {
212
+ useOtaUpdater,
213
+ checkForUpdate,
214
+ getAppliedOta,
215
+ getShortOtaId,
216
+ getIsUpdatePending,
217
+ reload: () => import_react_native.HotUpdater.reload(),
218
+ getBundleId: () => import_react_native.HotUpdater.getBundleId(),
219
+ getMinBundleId: () => import_react_native.HotUpdater.getMinBundleId(),
220
+ getChannel: () => import_react_native.HotUpdater.getChannel(),
221
+ clearCrashHistory: () => import_react_native.HotUpdater.clearCrashHistory(),
222
+ getCrashHistory: () => import_react_native.HotUpdater.getCrashHistory()
223
+ };
224
+ }
@@ -0,0 +1,250 @@
1
+ "use strict";
2
+
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all) __defProp(target, name, {
11
+ get: all[name],
12
+ enumerable: true
13
+ });
14
+ };
15
+ var __copyProps = (to, from, except, desc) => {
16
+ if (from && typeof from === "object" || typeof from === "function") {
17
+ for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
18
+ get: () => from[key],
19
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
20
+ });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
+ // If the importer is in node compatibility mode or this is not an ESM
26
+ // file that has been converted to a CommonJS file using a Babel-
27
+ // compatible transform (i.e. "__esModule" has not been set), then set
28
+ // "default" to the CommonJS "module.exports" for node compatibility.
29
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
30
+ value: mod,
31
+ enumerable: true
32
+ }) : target, mod));
33
+ var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
34
+ value: true
35
+ }), mod);
36
+ var createHotUpdater_exports = {};
37
+ __export(createHotUpdater_exports, {
38
+ createHotUpdater: () => createHotUpdater
39
+ });
40
+ module.exports = __toCommonJS(createHotUpdater_exports);
41
+ var import_react_native = require("@hot-updater/react-native");
42
+ var Application = __toESM(require("expo-application"), 1);
43
+ var import_react = require("react");
44
+ var import_react_native2 = require("react-native");
45
+ var INITIAL_OTA_ID = "00000000-0000-0000-0000-000000000000";
46
+ var BUNDLE_ID_KEY_PREFIX = "hotUpdater.bundleId";
47
+ var PRE_RELEASE_BUNDLE_ID_KEY = "hotUpdater.preReleaseBundleId";
48
+ function createHotUpdater(config) {
49
+ var {
50
+ storage,
51
+ updateStrategy = "appVersion"
52
+ } = config;
53
+ var isUpdatePending = false;
54
+ var getAppliedOta = function getAppliedOta2() {
55
+ var id = import_react_native.HotUpdater.getBundleId();
56
+ if (id === INITIAL_OTA_ID) return null;
57
+ if (id === import_react_native.HotUpdater.getMinBundleId()) return null;
58
+ return id;
59
+ };
60
+ var getShortOtaId = function getShortOtaId2() {
61
+ var fullId = getAppliedOta();
62
+ return fullId ? fullId.slice(-12) : null;
63
+ };
64
+ var getIsUpdatePending = function getIsUpdatePending2() {
65
+ return isUpdatePending;
66
+ };
67
+ var getPreReleaseBundleId = function getPreReleaseBundleId2() {
68
+ return storage.get(PRE_RELEASE_BUNDLE_ID_KEY);
69
+ };
70
+ var handleUpdateDownloaded = function handleUpdateDownloaded2(id) {
71
+ var options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
72
+ var appVersion = Application.nativeApplicationVersion;
73
+ if (appVersion) {
74
+ storage.set(`${BUNDLE_ID_KEY_PREFIX}.${appVersion}`, id);
75
+ }
76
+ if (options.isPreRelease) {
77
+ storage.set(PRE_RELEASE_BUNDLE_ID_KEY, id);
78
+ } else {
79
+ storage.delete(PRE_RELEASE_BUNDLE_ID_KEY);
80
+ }
81
+ isUpdatePending = true;
82
+ };
83
+ var useOtaUpdater = function useOtaUpdater2() {
84
+ var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
85
+ var {
86
+ enabled = true,
87
+ onUpdateDownloaded: onUpdateDownloadedCallback,
88
+ onError
89
+ } = options;
90
+ var progress = (0, import_react_native.useHotUpdaterStore)(function (state) {
91
+ return state.progress;
92
+ });
93
+ var isUpdating = progress > 0.01;
94
+ var [isUserClearedForAccess, setIsUserClearedForAccess] = (0, import_react.useState)(false);
95
+ var isUserClearedForAccessRef = (0, import_react.useRef)(isUserClearedForAccess);
96
+ isUserClearedForAccessRef.current = isUserClearedForAccess;
97
+ (0, import_react.useEffect)(function () {
98
+ if (!isUpdating) {
99
+ var timer = setTimeout(function () {
100
+ if (!isUserClearedForAccessRef.current) {
101
+ setIsUserClearedForAccess(true);
102
+ }
103
+ }, 5e3);
104
+ return function () {
105
+ return clearTimeout(timer);
106
+ };
107
+ }
108
+ return void 0;
109
+ }, [isUpdating]);
110
+ (0, import_react.useEffect)(function () {
111
+ var timer = setTimeout(function () {
112
+ if (!isUserClearedForAccessRef.current) {
113
+ setIsUserClearedForAccess(true);
114
+ }
115
+ }, 2e4);
116
+ return function () {
117
+ return clearTimeout(timer);
118
+ };
119
+ }, []);
120
+ (0, import_react.useEffect)(function () {
121
+ var shouldContinue = true;
122
+ (async function () {
123
+ try {
124
+ if (!enabled) {
125
+ setIsUserClearedForAccess(true);
126
+ return;
127
+ }
128
+ if (!shouldContinue) return;
129
+ var updateInfo = await import_react_native.HotUpdater.checkForUpdate({
130
+ updateStrategy
131
+ });
132
+ if (!updateInfo) {
133
+ setIsUserClearedForAccess(true);
134
+ return;
135
+ }
136
+ if (!shouldContinue) return;
137
+ if (updateInfo.status === "ROLLBACK") {
138
+ var preReleaseBundleId = getPreReleaseBundleId();
139
+ var currentBundleId = import_react_native.HotUpdater.getBundleId();
140
+ if (preReleaseBundleId && preReleaseBundleId === currentBundleId && currentBundleId > updateInfo.id) {
141
+ import_react_native2.Alert.alert("Update Skipped", "Skipped rollback because you are using a newer pre-release bundle.");
142
+ setIsUserClearedForAccess(true);
143
+ return;
144
+ }
145
+ }
146
+ if (!updateInfo.shouldForceUpdate) {
147
+ setIsUserClearedForAccess(true);
148
+ }
149
+ if (!shouldContinue) return;
150
+ await updateInfo.updateBundle();
151
+ handleUpdateDownloaded(updateInfo.id);
152
+ var info = {
153
+ id: updateInfo.id,
154
+ isCriticalUpdate: updateInfo.shouldForceUpdate,
155
+ fileUrl: updateInfo.fileUrl,
156
+ message: updateInfo.message
157
+ };
158
+ onUpdateDownloadedCallback === null || onUpdateDownloadedCallback === void 0 ? void 0 : onUpdateDownloadedCallback(info);
159
+ if (!shouldContinue) return;
160
+ if (updateInfo.shouldForceUpdate) {
161
+ if (!isUserClearedForAccessRef.current) {
162
+ import_react_native.HotUpdater.reload();
163
+ return;
164
+ }
165
+ import_react_native2.Alert.alert("Update Downloaded", "An important update has been downloaded. Reload now to apply it?", [{
166
+ text: "Later",
167
+ style: "cancel"
168
+ }, {
169
+ text: "Reload Now",
170
+ onPress: function onPress() {
171
+ return import_react_native.HotUpdater.reload();
172
+ }
173
+ }]);
174
+ }
175
+ } catch (error) {
176
+ onError === null || onError === void 0 ? void 0 : onError(error);
177
+ setIsUserClearedForAccess(true);
178
+ } finally {
179
+ if (!isUserClearedForAccessRef.current) {
180
+ setIsUserClearedForAccess(true);
181
+ }
182
+ }
183
+ })();
184
+ return function () {
185
+ shouldContinue = false;
186
+ };
187
+ }, [enabled, onUpdateDownloadedCallback, onError]);
188
+ return {
189
+ userClearedForAccess: isUserClearedForAccess,
190
+ progress,
191
+ isUpdatePending: getIsUpdatePending()
192
+ };
193
+ };
194
+ var checkForUpdate = async function checkForUpdate2() {
195
+ var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
196
+ var {
197
+ channel,
198
+ isPreRelease = false
199
+ } = options;
200
+ var requestHeaders = {};
201
+ if (channel) {
202
+ requestHeaders["X-Channel"] = channel;
203
+ }
204
+ var updateInfo = await import_react_native.HotUpdater.checkForUpdate({
205
+ updateStrategy,
206
+ ...(Object.keys(requestHeaders).length > 0 && {
207
+ requestHeaders
208
+ })
209
+ });
210
+ if (updateInfo) {
211
+ await updateInfo.updateBundle();
212
+ handleUpdateDownloaded(updateInfo.id, {
213
+ isPreRelease
214
+ });
215
+ return {
216
+ id: updateInfo.id,
217
+ isCriticalUpdate: updateInfo.shouldForceUpdate,
218
+ fileUrl: updateInfo.fileUrl,
219
+ message: updateInfo.message
220
+ };
221
+ }
222
+ return null;
223
+ };
224
+ return {
225
+ useOtaUpdater,
226
+ checkForUpdate,
227
+ getAppliedOta,
228
+ getShortOtaId,
229
+ getIsUpdatePending,
230
+ reload: function reload() {
231
+ return import_react_native.HotUpdater.reload();
232
+ },
233
+ getBundleId: function getBundleId() {
234
+ return import_react_native.HotUpdater.getBundleId();
235
+ },
236
+ getMinBundleId: function getMinBundleId() {
237
+ return import_react_native.HotUpdater.getMinBundleId();
238
+ },
239
+ getChannel: function getChannel() {
240
+ return import_react_native.HotUpdater.getChannel();
241
+ },
242
+ clearCrashHistory: function clearCrashHistory() {
243
+ return import_react_native.HotUpdater.clearCrashHistory();
244
+ },
245
+ getCrashHistory: function getCrashHistory() {
246
+ return import_react_native.HotUpdater.getCrashHistory();
247
+ }
248
+ };
249
+ }
250
+ //# sourceMappingURL=createHotUpdater.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["__toCommonJS","mod","__copyProps","__defProp","value","createHotUpdater_exports","__export","createHotUpdater","module","exports","import_react_native","require","Application","__toESM","import_react","import_react_native2","INITIAL_OTA_ID","BUNDLE_ID_KEY_PREFIX","PRE_RELEASE_BUNDLE_ID_KEY","config","storage","updateStrategy","isUpdatePending","getAppliedOta","getAppliedOta2","id","HotUpdater","getBundleId","getMinBundleId","getShortOtaId","getShortOtaId2","fullId","slice","getIsUpdatePending","getIsUpdatePending2","getPreReleaseBundleId","getPreReleaseBundleId2","get","handleUpdateDownloaded","handleUpdateDownloaded2","options","arguments","length","appVersion","nativeApplicationVersion","set","isPreRelease","delete","useOtaUpdater","useOtaUpdater2","enabled","onUpdateDownloaded","onUpdateDownloadedCallback","onError","progress","useHotUpdaterStore","state","isUpdating","isUserClearedForAccess","setIsUserClearedForAccess","useState","isUserClearedForAccessRef","useRef","current","useEffect","timer","setTimeout","clearTimeout","shouldContinue","updateInfo","checkForUpdate","status","preReleaseBundleId","currentBundleId","Alert","alert","shouldForceUpdate","updateBundle","info","isCriticalUpdate","fileUrl","message","reload","text","style","onPress","error","userClearedForAccess","checkForUpdate2","channel","requestHeaders","Object","keys"],"sources":["../../src/createHotUpdater.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}