1import { CodedError, NativeModulesProxy, UnavailabilityError } from 'expo-modules-core'; 2import ExpoUpdates from './ExpoUpdates'; 3/** 4 * The UUID that uniquely identifies the currently running update. The 5 * UUID is represented in its canonical string form (`xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`) and 6 * will always use lowercase letters. This value is `null` when running in a local development environment or any other environment where `expo-updates` is disabled. 7 */ 8export const updateId = ExpoUpdates.updateId && typeof ExpoUpdates.updateId === 'string' 9 ? ExpoUpdates.updateId.toLowerCase() 10 : null; 11/** 12 * The name of the release channel currently configured in this standalone or bare app when using 13 * classic updates. When using Expo Updates, the value of this field is always `"default"`. 14 */ 15export const releaseChannel = ExpoUpdates.releaseChannel ?? 'default'; 16/** 17 * The channel name of the current build, if configured for use with EAS Update. `null` otherwise. 18 * 19 * Expo Go and development builds are not set to a specific channel and can run any updates compatible with their native runtime. Therefore, this value will always be `null` when running an update on Expo Go or a development build. 20 */ 21export const channel = ExpoUpdates.channel ?? null; 22/** 23 * The runtime version of the current build. 24 */ 25export const runtimeVersion = ExpoUpdates.runtimeVersion ?? null; 26const _checkAutomaticallyMapNativeToJS = { 27 ALWAYS: 'ON_LOAD', 28 ERROR_RECOVERY_ONLY: 'ON_ERROR_RECOVERY', 29 NEVER: 'NEVER', 30 WIFI_ONLY: 'WIFI_ONLY', 31}; 32/** 33 * Determines if and when expo-updates checks for and downloads updates automatically on startup. 34 */ 35export const checkAutomatically = _checkAutomaticallyMapNativeToJS[ExpoUpdates.checkAutomatically] ?? null; 36// @docsMissing 37/** 38 * @hidden 39 */ 40export const localAssets = ExpoUpdates.localAssets ?? {}; 41/** 42 * `expo-updates` does its very best to always launch monotonically newer versions of your app so 43 * you don't need to worry about backwards compatibility when you put out an update. In very rare 44 * cases, it's possible that `expo-updates` may need to fall back to the update that's embedded in 45 * the app binary, even after newer updates have been downloaded and run (an "emergency launch"). 46 * This boolean will be `true` if the app is launching under this fallback mechanism and `false` 47 * otherwise. If you are concerned about backwards compatibility of future updates to your app, you 48 * can use this constant to provide special behavior for this rare case. 49 */ 50export const isEmergencyLaunch = ExpoUpdates.isEmergencyLaunch || false; 51/** 52 * This will be true if the currently running update is the one embedded in the build, 53 * and not one downloaded from the updates server. 54 */ 55export const isEmbeddedLaunch = ExpoUpdates.isEmbeddedLaunch || false; 56// @docsMissing 57/** 58 * @hidden 59 */ 60export const isUsingEmbeddedAssets = ExpoUpdates.isUsingEmbeddedAssets || false; 61/** 62 * If `expo-updates` is enabled, this is the 63 * [manifest](/versions/latest/sdk/constants/#manifest) (or 64 * [classic manifest](/versions/latest/sdk/constants/#appmanifest)) 65 * object for the update that's currently running. 66 * 67 * In development mode, or any other environment in which `expo-updates` is disabled, this object is 68 * empty. 69 */ 70export const manifest = (ExpoUpdates.manifestString ? JSON.parse(ExpoUpdates.manifestString) : ExpoUpdates.manifest) ?? 71 {}; 72/** 73 * If `expo-updates` is enabled, this is a `Date` object representing the creation time of the update that's currently running (whether it was embedded or downloaded at runtime). 74 * 75 * In development mode, or any other environment in which `expo-updates` is disabled, this value is 76 * null. 77 */ 78export const createdAt = ExpoUpdates.commitTime 79 ? new Date(ExpoUpdates.commitTime) 80 : null; 81const isUsingDeveloperTool = !!manifest.developer?.tool; 82const isUsingExpoDevelopmentClient = NativeModulesProxy.ExponentConstants?.appOwnership === 'expo'; 83const manualUpdatesInstructions = isUsingExpoDevelopmentClient 84 ? 'To test manual updates, publish your project using `expo publish` and open the published ' + 85 'version in this development client.' 86 : 'To test manual updates, make a release build with `npm run ios --configuration Release` or ' + 87 '`npm run android --variant Release`.'; 88/** 89 * Instructs the app to reload using the most recently downloaded version. This is useful for 90 * triggering a newly downloaded update to launch without the user needing to manually restart the 91 * app. 92 * 93 * It is not recommended to place any meaningful logic after a call to `await 94 * Updates.reloadAsync()`. This is because the promise is resolved after verifying that the app can 95 * be reloaded, and immediately before posting an asynchronous task to the main thread to actually 96 * reload the app. It is unsafe to make any assumptions about whether any more JS code will be 97 * executed after the `Updates.reloadAsync` method call resolves, since that depends on the OS and 98 * the state of the native module and main threads. 99 * 100 * This method cannot be used in development mode, and the returned promise will be rejected if you 101 * try to do so. 102 * 103 * @return A promise that fulfills right before the reload instruction is sent to the JS runtime, or 104 * rejects if it cannot find a reference to the JS runtime. If the promise is rejected in production 105 * mode, it most likely means you have installed the module incorrectly. Double check you've 106 * followed the installation instructions. In particular, on iOS ensure that you set the `bridge` 107 * property on `EXUpdatesAppController` with a pointer to the `RCTBridge` you want to reload, and on 108 * Android ensure you either call `UpdatesController.initialize` with the instance of 109 * `ReactApplication` you want to reload, or call `UpdatesController.setReactNativeHost` with the 110 * proper instance of `ReactNativeHost`. 111 */ 112export async function reloadAsync() { 113 if (!ExpoUpdates.reload) { 114 throw new UnavailabilityError('Updates', 'reloadAsync'); 115 } 116 if (!ExpoUpdates?.nativeDebug && __DEV__ && !isUsingExpoDevelopmentClient) { 117 throw new CodedError('ERR_UPDATES_DISABLED', `You cannot use the Updates module in development mode in a production app. ${manualUpdatesInstructions}`); 118 } 119 await ExpoUpdates.reload(); 120} 121/** 122 * Checks the server to see if a newly deployed update to your project is available. Does not 123 * actually download the update. This method cannot be used in development mode, and the returned 124 * promise will be rejected if you try to do so. 125 * 126 * Checking for an update uses a device's bandwidth and battery life like any network call. 127 * Additionally, updates served by Expo may be rate limited. A good rule of thumb to check for 128 * updates judiciously is to check when the user launches or foregrounds the app. Avoid polling for 129 * updates in a frequent loop. 130 * 131 * @return A promise that fulfills with an [`UpdateCheckResult`](#updatecheckresult) object. 132 * 133 * The promise rejects if the app is in development mode, or if there is an unexpected error or 134 * timeout communicating with the server. 135 */ 136export async function checkForUpdateAsync() { 137 if (!ExpoUpdates.checkForUpdateAsync) { 138 throw new UnavailabilityError('Updates', 'checkForUpdateAsync'); 139 } 140 if (!ExpoUpdates?.nativeDebug && (__DEV__ || isUsingDeveloperTool)) { 141 throw new CodedError('ERR_UPDATES_DISABLED', `You cannot check for updates in development mode. ${manualUpdatesInstructions}`); 142 } 143 const result = await ExpoUpdates.checkForUpdateAsync(); 144 if (result.manifestString) { 145 result.manifest = JSON.parse(result.manifestString); 146 delete result.manifestString; 147 } 148 return result; 149} 150/** 151 * Retrieves the current extra params. 152 */ 153export async function getExtraParamsAsync() { 154 if (!ExpoUpdates.getExtraParamsAsync) { 155 throw new UnavailabilityError('Updates', 'getExtraParamsAsync'); 156 } 157 return await ExpoUpdates.getExtraParamsAsync(); 158} 159/** 160 * Sets an extra param if value is non-null, otherwise unsets the param. 161 * Extra params are sent as an [Expo Structured Field Value Dictionary](https://docs.expo.dev/technical-specs/expo-sfv-0/) 162 * in the `Expo-Extra-Params` header of update requests. A compliant update server may use these params when selecting an update to serve. 163 */ 164export async function setExtraParamAsync(key, value) { 165 if (!ExpoUpdates.setExtraParamAsync) { 166 throw new UnavailabilityError('Updates', 'setExtraParamAsync'); 167 } 168 return await ExpoUpdates.setExtraParamAsync(key, value ?? null); 169} 170/** 171 * Retrieves the most recent expo-updates log entries. 172 * 173 * @param maxAge Sets the max age of retrieved log entries in milliseconds. Default to 3600000 ms (1 hour). 174 * 175 * @return A promise that fulfills with an array of [`UpdatesLogEntry`](#updateslogentry) objects; 176 * 177 * The promise rejects if there is an unexpected error in retrieving the logs. 178 */ 179export async function readLogEntriesAsync(maxAge = 3600000) { 180 if (!ExpoUpdates.readLogEntriesAsync) { 181 throw new UnavailabilityError('Updates', 'readLogEntriesAsync'); 182 } 183 return await ExpoUpdates.readLogEntriesAsync(maxAge); 184} 185/** 186 * Clears existing expo-updates log entries. 187 * 188 * > For now, this operation does nothing on the client. Once log persistence has been 189 * > implemented, this operation will actually remove existing logs. 190 * 191 * @return A promise that fulfills if the clear operation was successful. 192 * 193 * The promise rejects if there is an unexpected error in clearing the logs. 194 * 195 */ 196export async function clearLogEntriesAsync() { 197 if (!ExpoUpdates.clearLogEntriesAsync) { 198 throw new UnavailabilityError('Updates', 'clearLogEntriesAsync'); 199 } 200 await ExpoUpdates.clearLogEntriesAsync(); 201} 202/** 203 * Downloads the most recently deployed update to your project from server to the device's local 204 * storage. This method cannot be used in development mode, and the returned promise will be 205 * rejected if you try to do so. 206 * 207 > **Note:** [`reloadAsync()`](#updatesreloadasync) can be called after promise resolution to 208 * reload the app using the most recently downloaded version. Otherwise, the update will be applied 209 * on the next app cold start. 210 * 211 * @return A promise that fulfills with an [`UpdateFetchResult`](#updatefetchresult) object. 212 * 213 * The promise rejects if the app is in development mode, or if there is an unexpected error or 214 * timeout communicating with the server. 215 */ 216export async function fetchUpdateAsync() { 217 if (!ExpoUpdates.fetchUpdateAsync) { 218 throw new UnavailabilityError('Updates', 'fetchUpdateAsync'); 219 } 220 if (!ExpoUpdates?.nativeDebug && (__DEV__ || isUsingDeveloperTool)) { 221 throw new CodedError('ERR_UPDATES_DISABLED', `You cannot fetch updates in development mode. ${manualUpdatesInstructions}`); 222 } 223 const result = await ExpoUpdates.fetchUpdateAsync(); 224 if (result.manifestString) { 225 result.manifest = JSON.parse(result.manifestString); 226 delete result.manifestString; 227 } 228 return result; 229} 230/** 231 * @hidden 232 */ 233export function clearUpdateCacheExperimentalAsync(_sdkVersion) { 234 console.warn("This method is no longer necessary. `expo-updates` now automatically deletes your app's old bundle files!"); 235} 236/** 237 * @hidden 238 */ 239export function transformNativeStateMachineContext(originalNativeContext) { 240 const nativeContext = { ...originalNativeContext }; 241 if (nativeContext.latestManifestString) { 242 nativeContext.latestManifest = JSON.parse(nativeContext.latestManifestString); 243 delete nativeContext.latestManifestString; 244 } 245 if (nativeContext.downloadedManifestString) { 246 nativeContext.downloadedManifest = JSON.parse(nativeContext.downloadedManifestString); 247 delete nativeContext.downloadedManifestString; 248 } 249 if (nativeContext.lastCheckForUpdateTimeString) { 250 nativeContext.lastCheckForUpdateTime = new Date(nativeContext.lastCheckForUpdateTimeString); 251 delete nativeContext.lastCheckForUpdateTimeString; 252 } 253 if (nativeContext.rollbackString) { 254 nativeContext.rollback = JSON.parse(nativeContext.rollbackString); 255 delete nativeContext.rollbackString; 256 } 257 return nativeContext; 258} 259/** 260 * @hidden 261 */ 262export async function getNativeStateMachineContextAsync() { 263 // Return the current state machine context 264 if (!ExpoUpdates.getNativeStateMachineContextAsync) { 265 throw new UnavailabilityError('Updates', 'getNativeStateMachineContextAsync'); 266 } 267 const nativeContext = await ExpoUpdates.getNativeStateMachineContextAsync(); 268 return transformNativeStateMachineContext(nativeContext); 269} 270//# sourceMappingURL=Updates.js.map