UNPKG

@appzung/react-native-code-push

Version:

React Native plugin for the CodePush service

226 lines (219 loc) 11.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.sync = exports.DEFAULT_UPDATE_DIALOG = void 0; var _reactNative = require("react-native"); var _checkForUpdates = require("./checkForUpdates.js"); var _InstallModeEnum = require("./enums/InstallMode.enum.js"); var _LogLevelEnum = require("./enums/LogLevel.enum.js"); var _SyncStatusEnum = require("./enums/SyncStatus.enum.js"); var _getCurrentPackage = require("./internals/getCurrentPackage.js"); var _shouldUpdateBeIgnored = require("./internals/shouldUpdateBeIgnored.js"); var _log = require("./internals/utils/log.js"); var _notifyAppReady = require("./notifyAppReady.js"); /** * Represents the default settings that will be used by the sync method if * an update dialog is configured to be displayed. */ const DEFAULT_UPDATE_DIALOG = exports.DEFAULT_UPDATE_DIALOG = { appendReleaseDescription: false, descriptionPrefix: ' Description: ', mandatoryContinueButtonLabel: 'Continue', mandatoryUpdateMessage: 'An update is available that must be installed.', optionalIgnoreButtonLabel: 'Ignore', optionalInstallButtonLabel: 'Install', optionalUpdateMessage: 'An update is available. Would you like to install it?', title: 'Update available' }; /* * The syncInternal method provides a simple, one-line experience for * incorporating the check, download and installation of an update. * * It simply composes the existing API methods together and adds additional * support for respecting mandatory updates, ignoring previously failed * releases, and displaying a standard confirmation UI to the end-user * when an update is available. */ async function syncInternal(options, syncStatusChangeCallback, downloadProgressCallback, handleBinaryVersionMismatchCallback) { let resolvedInstallMode; const syncOptions = { releaseChannelPublicId: undefined, ignoreFailedUpdates: true, rollbackRetryOptions: undefined, installMode: _InstallModeEnum.InstallMode.ON_NEXT_RESTART, mandatoryInstallMode: _InstallModeEnum.InstallMode.IMMEDIATE, minimumBackgroundDuration: 0, updateDialog: undefined, ...options }; syncStatusChangeCallback = typeof syncStatusChangeCallback === 'function' ? syncStatusChangeCallback : syncStatus => { switch (syncStatus) { case _SyncStatusEnum.SyncStatus.CHECKING_FOR_UPDATE: (0, _log.log)(_LogLevelEnum.LogLevel.INFO, 'Checking for update.'); break; case _SyncStatusEnum.SyncStatus.AWAITING_USER_ACTION: (0, _log.log)(_LogLevelEnum.LogLevel.INFO, 'Awaiting user action.'); break; case _SyncStatusEnum.SyncStatus.DOWNLOADING_PACKAGE: (0, _log.log)(_LogLevelEnum.LogLevel.INFO, 'Downloading package.'); break; case _SyncStatusEnum.SyncStatus.INSTALLING_UPDATE: (0, _log.log)(_LogLevelEnum.LogLevel.INFO, 'Installing update.'); break; case _SyncStatusEnum.SyncStatus.UP_TO_DATE: (0, _log.log)(_LogLevelEnum.LogLevel.INFO, 'App is up to date.'); break; case _SyncStatusEnum.SyncStatus.UPDATE_IGNORED: (0, _log.log)(_LogLevelEnum.LogLevel.INFO, 'User cancelled the update.'); break; case _SyncStatusEnum.SyncStatus.UPDATE_INSTALLED: if (resolvedInstallMode === _InstallModeEnum.InstallMode.ON_NEXT_RESTART) { (0, _log.log)(_LogLevelEnum.LogLevel.INFO, 'Update is installed and will be run on the next app restart.'); } else if (resolvedInstallMode === _InstallModeEnum.InstallMode.ON_NEXT_RESUME) { if (syncOptions.minimumBackgroundDuration) { (0, _log.log)(_LogLevelEnum.LogLevel.INFO, `Update is installed and will be run after the app has been in the background for at least ${syncOptions.minimumBackgroundDuration} seconds.`); } else { (0, _log.log)(_LogLevelEnum.LogLevel.INFO, 'Update is installed and will be run when the app next resumes.'); } } break; case _SyncStatusEnum.SyncStatus.UNKNOWN_ERROR: (0, _log.log)(_LogLevelEnum.LogLevel.ERROR, 'An unknown error occurred.'); break; } }; try { await (0, _notifyAppReady.notifyAppReady)(); syncStatusChangeCallback(_SyncStatusEnum.SyncStatus.CHECKING_FOR_UPDATE); const remotePackage = await (0, _checkForUpdates.checkForUpdate)(syncOptions.releaseChannelPublicId, handleBinaryVersionMismatchCallback); const doDownloadAndInstall = async () => { if (!remotePackage) { throw new Error('remotePackage should be defined'); } syncStatusChangeCallback(_SyncStatusEnum.SyncStatus.DOWNLOADING_PACKAGE); const localPackage = await remotePackage.download(downloadProgressCallback); // Determine the correct install mode based on whether the update is mandatory or not. resolvedInstallMode = localPackage.isMandatory ? syncOptions.mandatoryInstallMode : syncOptions.installMode; syncStatusChangeCallback(_SyncStatusEnum.SyncStatus.INSTALLING_UPDATE); await localPackage.install(resolvedInstallMode, syncOptions.minimumBackgroundDuration, () => { syncStatusChangeCallback(_SyncStatusEnum.SyncStatus.UPDATE_INSTALLED); }); return _SyncStatusEnum.SyncStatus.UPDATE_INSTALLED; }; const updateShouldBeIgnored = await (0, _shouldUpdateBeIgnored.shouldUpdateBeIgnored)(remotePackage, syncOptions); if (!remotePackage || updateShouldBeIgnored) { if (updateShouldBeIgnored) { (0, _log.log)(_LogLevelEnum.LogLevel.INFO, 'An update is available, but it is being ignored due to having been previously rolled back.'); } const currentPackage = await (0, _getCurrentPackage.getCurrentPackage)(); if (currentPackage && currentPackage.isPending) { syncStatusChangeCallback(_SyncStatusEnum.SyncStatus.UPDATE_INSTALLED); return _SyncStatusEnum.SyncStatus.UPDATE_INSTALLED; } else { syncStatusChangeCallback(_SyncStatusEnum.SyncStatus.UP_TO_DATE); return _SyncStatusEnum.SyncStatus.UP_TO_DATE; } } else if (syncOptions.updateDialog) { const updateDialogConfig = typeof syncOptions.updateDialog !== 'object' ? DEFAULT_UPDATE_DIALOG : { ...DEFAULT_UPDATE_DIALOG, ...syncOptions.updateDialog }; return await new Promise((resolve, reject) => { let message; let installButtonText; const dialogButtons = []; if (remotePackage.isMandatory) { message = updateDialogConfig.mandatoryUpdateMessage; installButtonText = updateDialogConfig.mandatoryContinueButtonLabel; } else { message = updateDialogConfig.optionalUpdateMessage; installButtonText = updateDialogConfig.optionalInstallButtonLabel; // Since this is an optional update, add a button // to allow the end-user to ignore it dialogButtons.push({ text: updateDialogConfig.optionalIgnoreButtonLabel ?? '', onPress: () => { syncStatusChangeCallback(_SyncStatusEnum.SyncStatus.UPDATE_IGNORED); resolve(_SyncStatusEnum.SyncStatus.UPDATE_IGNORED); } }); } // Since the install button should be placed to the // right of any other button, add it last dialogButtons.push({ text: installButtonText ?? '', onPress: () => { doDownloadAndInstall().then(resolve, reject); } }); // If the update has a description, and the developer // explicitly chose to display it, then set that as the message if (updateDialogConfig.appendReleaseDescription && remotePackage.description) { message += `${updateDialogConfig.descriptionPrefix} ${remotePackage.description}`; } syncStatusChangeCallback(_SyncStatusEnum.SyncStatus.AWAITING_USER_ACTION); _reactNative.Alert.alert(updateDialogConfig.title || '', message || '', _reactNative.Platform.OS === 'android' ? [...dialogButtons.reverse()] : dialogButtons); }); } else { return await doDownloadAndInstall(); } } catch (error) { syncStatusChangeCallback(_SyncStatusEnum.SyncStatus.UNKNOWN_ERROR); (0, _log.log)(_LogLevelEnum.LogLevel.ERROR, error != null && typeof error === 'object' && 'message' in error && typeof error.message === 'string' ? error.message : 'Unknown'); throw error; } } /** * @function * * Allows checking for an update, downloading it and installing it, all with a single call. * * Unless you need custom UI and/or behavior, we recommend most developers to use this method when integrating CodePush into their apps, if they are not using the `withCodePush` HOC. * * @param options Options used to configure the end-user update experience (e.g. show a prompt?, install the update immediately?). * @param syncStatusChangedCallback An optional callback that allows tracking the status of the sync operation, as opposed to simply checking the resolved state via the returned Promise. * @param downloadProgressCallback An optional callback that allows tracking the progress of an update while it is being downloaded. * @param handleBinaryVersionMismatchCallback An optional callback for handling target binary version mismatch */ const sync = exports.sync = (() => { // This function allows only one syncInternal operation to proceed at any given time. // Parallel calls to sync() while one is ongoing yields CodePush.SyncStatus.SYNC_IN_PROGRESS. let syncInProgress = false; const setSyncCompleted = () => { syncInProgress = false; }; return (options, syncStatusChangedCallback, downloadProgressCallback, handleBinaryVersionMismatchCallback) => { (0, _log.log)(_LogLevelEnum.LogLevel.DEBUG, `sync start`); let syncStatusCallbackWithTryCatch = status => { (0, _log.log)(_LogLevelEnum.LogLevel.DEBUG, `sync status ${_SyncStatusEnum.SyncStatus[status]}`); if (typeof syncStatusChangedCallback !== 'function') { return; } try { syncStatusChangedCallback(status); } catch (error) { (0, _log.log)(_LogLevelEnum.LogLevel.ERROR, `An error has occurred : ${error instanceof Error ? error.stack : 'unknown'}`); } }; let downloadProgressCallbackWithTryCatch; if (typeof downloadProgressCallback === 'function') { downloadProgressCallbackWithTryCatch = (...args) => { try { downloadProgressCallback(...args); } catch (error) { (0, _log.log)(_LogLevelEnum.LogLevel.ERROR, `An error has occurred: ${error instanceof Error ? error.stack : 'unknown'}`); } }; } if (syncInProgress) { typeof syncStatusCallbackWithTryCatch === 'function' ? syncStatusCallbackWithTryCatch(_SyncStatusEnum.SyncStatus.SYNC_IN_PROGRESS) : (0, _log.log)(_LogLevelEnum.LogLevel.WARN, 'Sync already in progress.'); return Promise.resolve(_SyncStatusEnum.SyncStatus.SYNC_IN_PROGRESS); } syncInProgress = true; const syncPromise = syncInternal(options, syncStatusCallbackWithTryCatch, downloadProgressCallbackWithTryCatch, handleBinaryVersionMismatchCallback); syncPromise.then(setSyncCompleted).catch(setSyncCompleted); return syncPromise; }; })(); //# sourceMappingURL=sync.js.map