UNPKG

@bazumax/capacitor-codepush

Version:
1,016 lines (1,007 loc) 85.6 kB
var capacitorPlugin = (function (exports, acquisitionSdk, filesystem, core, http, device, dialog) { 'use strict'; /** * Callback / error / logging utilities. */ class CodePushUtil { /** * Performs a copy of all members of fromParameter to toParameter, with the condition that they are unassigned or null in toParameter. */ static copyUnassignedMembers(fromParameter, toParameter) { for (let key in fromParameter) { if (toParameter[key] === undefined || toParameter[key] === null) { toParameter[key] = fromParameter[key]; } } } /** * Given two Cordova style callbacks for success and error, this function returns a node.js * style callback where the error is the first parameter and the result the second. */ static getNodeStyleCallbackFor(successCallback, errorCallback) { return (error, result) => { if (error) { errorCallback && errorCallback(error); } else { successCallback && successCallback(result); } }; } /** * Gets the message of an error, if any. Otherwise it returns the empty string. */ static getErrorMessage(e) { return e && e.message || e && e.toString() || ""; } /** * Logs a message using the CodePush tag. */ static logMessage(msg) { console.log(CodePushUtil.TAG + " " + msg); } /** * Logs an error message using the CodePush tag. */ static logError(message, error) { const errorMessage = `${message || ""} ${CodePushUtil.getErrorMessage(error)}`; const stackTrace = error && error.stack ? `. StackTrace: ${error.stack}` : ""; console.error(`${CodePushUtil.TAG} ${errorMessage}${stackTrace}`); } } /** * Tag used for logging to the console. */ CodePushUtil.TAG = "[CodePush]"; /** * Logs the error to the console and then forwards it to the provided ErrorCallback, if any. * TODO: remove me */ CodePushUtil.invokeErrorCallback = (error, errorCallback) => { CodePushUtil.logError(null, error); errorCallback && errorCallback(error); }; /** * Logs the error to the console and then throws the error. */ CodePushUtil.throwError = (error) => { CodePushUtil.logError(null, error); throw error; }; /** * Defines the available install modes for updates. */ exports.InstallMode = void 0; (function (InstallMode) { /** * The update will be applied to the running application immediately. The application will be reloaded with the new content immediately. */ InstallMode[InstallMode["IMMEDIATE"] = 0] = "IMMEDIATE"; /** * The update is downloaded but not installed immediately. The new content will be available the next time the application is started. */ InstallMode[InstallMode["ON_NEXT_RESTART"] = 1] = "ON_NEXT_RESTART"; /** * The udpate is downloaded but not installed immediately. The new content will be available the next time the application is resumed or restarted, whichever event happends first. */ InstallMode[InstallMode["ON_NEXT_RESUME"] = 2] = "ON_NEXT_RESUME"; })(exports.InstallMode || (exports.InstallMode = {})); var __awaiter$5 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; /** * File utilities for CodePush. */ class FileUtil { static directoryExists(directory, path) { return __awaiter$5(this, void 0, void 0, function* () { try { const statResult = yield filesystem.Filesystem.stat({ directory, path }); // directory for Android, NSFileTypeDirectory for iOS return statResult.type === "directory" || statResult.type === "NSFileTypeDirectory"; } catch (error) { return false; } }); } static writeStringToDataFile(content, path, createIfNotExists, callback) { FileUtil.writeStringToFile(content, filesystem.Directory.Data, path, createIfNotExists, callback); } static fileExists(directory, path) { return __awaiter$5(this, void 0, void 0, function* () { try { const statResult = yield filesystem.Filesystem.stat({ directory, path }); // file for Android, NSFileTypeRegular for iOS return statResult.type === "file" || statResult.type === "NSFileTypeRegular"; } catch (error) { return false; } }); } /** * Makes sure the given directory exists and is empty. */ static cleanDataDirectory(path) { return __awaiter$5(this, void 0, void 0, function* () { if (yield FileUtil.dataDirectoryExists(path)) { yield FileUtil.deleteDataDirectory(path); } yield filesystem.Filesystem.mkdir({ directory: filesystem.Directory.Data, path, recursive: true }); const appDir = yield filesystem.Filesystem.getUri({ directory: filesystem.Directory.Data, path }); return appDir.uri; }); } static getUri(fsDir, path) { return __awaiter$5(this, void 0, void 0, function* () { const result = yield filesystem.Filesystem.getUri({ directory: fsDir, path }); return result.uri; }); } static getDataUri(path) { return FileUtil.getUri(filesystem.Directory.Data, path); } static dataDirectoryExists(path) { return FileUtil.directoryExists(filesystem.Directory.Data, path); } static copyDirectoryEntriesTo(sourceDir, destinationDir, ignoreList = []) { return __awaiter$5(this, void 0, void 0, function* () { /* Native-side exception occurs while trying to copy “.DS_Store” and “__MACOSX” entries generated by macOS, so just skip them */ if (ignoreList.indexOf(".DS_Store") === -1) { ignoreList.push(".DS_Store"); } if (ignoreList.indexOf("__MACOSX") === -1) { ignoreList.push("__MACOSX"); } // @capacitor/filesystem plugin throw error when destination directory already exists. if (yield FileUtil.directoryExists(destinationDir.directory, destinationDir.path)) { const { files } = yield filesystem.Filesystem.readdir(sourceDir); for (let i = 0; i < files.length; i++) { // @capacitor/filesystem v4 returns object instead of string // @ts-expect-error const file = files[i].name; if (ignoreList.includes(file)) continue; const sourcePath = sourceDir.path + "/" + file; const destPath = destinationDir.path + "/" + file; const source = Object.assign(Object.assign({}, sourceDir), { path: sourcePath }); const destination = Object.assign(Object.assign({}, destinationDir), { path: destPath }); if (yield FileUtil.directoryExists(source.directory, source.path)) { // is directory yield FileUtil.copyDirectoryEntriesTo(source, destination); } else { // is file yield FileUtil.copy(source, destination); } } } else { yield FileUtil.copy(sourceDir, destinationDir); } }); } static copy(source, destination) { return __awaiter$5(this, void 0, void 0, function* () { yield filesystem.Filesystem.copy({ directory: source.directory, from: source.path, to: destination.path, toDirectory: destination.directory }); }); } /** * Recursively deletes the contents of a directory. */ static deleteDataDirectory(path) { return __awaiter$5(this, void 0, void 0, function* () { yield filesystem.Filesystem.rmdir({ directory: filesystem.Directory.Data, path, recursive: true }).then(() => null); }); } /** * Deletes a given set of files from a directory. */ static deleteEntriesFromDataDirectory(dirPath, filesToDelete) { return __awaiter$5(this, void 0, void 0, function* () { for (const file of filesToDelete) { const path = dirPath + "/" + file; const fileExists = yield FileUtil.fileExists(filesystem.Directory.Data, path); if (!fileExists) continue; try { yield filesystem.Filesystem.deleteFile({ directory: filesystem.Directory.Data, path }); } catch (error) { /* If delete fails, silently continue */ console.log("Could not delete file: " + path); } } }); } /** * Writes a string to a file. */ static writeStringToFile(data, directory, path, createIfNotExists, callback) { return __awaiter$5(this, void 0, void 0, function* () { try { yield filesystem.Filesystem.writeFile({ directory, path, data, encoding: filesystem.Encoding.UTF8 }); callback(null, null); } catch (error) { callback(new Error("Could write the current package information file. Error code: " + error.code), null); } }); } static readFile(directory, path) { return __awaiter$5(this, void 0, void 0, function* () { const result = yield filesystem.Filesystem.readFile({ directory, path, encoding: filesystem.Encoding.UTF8 }); return result.data; }); } static readDataFile(path) { return FileUtil.readFile(filesystem.Directory.Data, path); } } // Type definitions for Apache Cordova CodePush plugin. const CodePush$1 = /*#__PURE__*/ core.registerPlugin("CodePush"); var __awaiter$4 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; const DefaultServerUrl = "https://codepush.appcenter.ms/"; /** * Provides information about the native app. */ class NativeAppInfo { /** * Gets the application build timestamp. */ static getApplicationBuildTime() { return __awaiter$4(this, void 0, void 0, function* () { try { const result = yield CodePush$1.getNativeBuildTime(); return result.value; } catch (e) { throw new Error("Could not get application timestamp."); } }); } /** * Gets the application version. */ static getApplicationVersion() { return __awaiter$4(this, void 0, void 0, function* () { try { const result = yield CodePush$1.getAppVersion(); return result.value; } catch (e) { throw new Error("Could not get application version."); } }); } /** * Gets a hash of the `public` folder contents compiled in the app store binary. */ static getBinaryHash() { return __awaiter$4(this, void 0, void 0, function* () { try { const result = yield CodePush$1.getBinaryHash(); return result.value; } catch (e) { throw new Error("Could not get binary hash."); } }); } /** * Gets the server URL from config.xml by calling into the native platform. */ static getServerURL() { return __awaiter$4(this, void 0, void 0, function* () { try { const result = yield CodePush$1.getServerURL(); return result.value; } catch (e) { return DefaultServerUrl; } }); } /** * Gets the deployment key from config.xml by calling into the native platform. */ static getDeploymentKey() { return __awaiter$4(this, void 0, void 0, function* () { try { const result = yield CodePush$1.getDeploymentKey(); return result.value; } catch (e) { throw new Error("Deployment key not found."); } }); } /** * Checks if a package update was previously attempted but failed for a given package hash. * Every reverted update is stored such that the application developer has the option to ignore * updates that previously failed. This way, an infinite update loop can be prevented in case of a bad update package. */ static isFailedUpdate(packageHash) { return __awaiter$4(this, void 0, void 0, function* () { try { const result = yield CodePush$1.isFailedUpdate({ packageHash }); return result.value; } catch (e) { /* In case of an error, return false. */ return false; } }); } /** * Checks if this is the first application run of a package after it has been applied. * The didUpdateCallback callback can be used for migrating data from the old app version to the new one. * * @param packageHash The hash value of the package. * @returns Whether it is the first run after an update. */ static isFirstRun(packageHash) { return __awaiter$4(this, void 0, void 0, function* () { try { const result = yield CodePush$1.isFirstRun({ packageHash }); return result.value; } catch (e) { /* In case of an error, return false. */ return false; } }); } /** * Checks with the native side if there is a pending update. */ static isPendingUpdate() { return __awaiter$4(this, void 0, void 0, function* () { try { const result = yield CodePush$1.isPendingUpdate(); return result.value; } catch (e) { /* In case of an error, return false. */ return false; } }); } } /** * Base class for CodePush packages. */ class Package { } /** * XMLHttpRequest-based implementation of Http.Requester. */ class HttpRequester { constructor(contentType) { this.contentType = contentType; } request(verb, url, callbackOrRequestBody, callback) { var requestBody; var requestCallback = callback; // request(verb, url, callback) if (!requestCallback && typeof callbackOrRequestBody === "function") { requestCallback = callbackOrRequestBody; } // request(verb, url, requestBody, callback) if (typeof callbackOrRequestBody === "string") { requestBody = callbackOrRequestBody; } if (typeof requestBody === "string") { try { requestBody = JSON.parse(requestBody); // if it is stringify JSON string, parse } catch (e) { // do nothing } } var methodName = this.getHttpMethodName(verb); if (methodName === null) { return requestCallback(new Error("Method Not Allowed"), null); } const headers = { "X-CodePush-Plugin-Name": "cordova-plugin-code-push", "X-CodePush-Plugin-Version": "1.11.13", "X-CodePush-SDK-Version": "3.1.5" }; if (this.contentType) { headers["Content-Type"] = this.contentType; } const options = { method: methodName, url, headers }; if (methodName === "GET") { options.params = requestBody; } else { options.data = requestBody; } http.Http.request(options).then((nativeRes) => { if (typeof nativeRes.data === "object") nativeRes.data = JSON.stringify(nativeRes.data); var response = { statusCode: nativeRes.status, body: nativeRes.data }; requestCallback && requestCallback(null, response); }); } /** * Gets the HTTP method name as a string. * The reason for which this is needed is because the Http.Verb enum corresponds to integer values from native runtime. */ getHttpMethodName(verb) { switch (verb) { case 0 /* GET */: return "GET"; case 4 /* DELETE */: return "DELETE"; case 1 /* HEAD */: return "HEAD"; case 8 /* PATCH */: return "PATCH"; case 2 /* POST */: return "POST"; case 3 /* PUT */: return "PUT"; case 5 /* TRACE */: case 6 /* OPTIONS */: case 7 /* CONNECT */: default: return null; } } } var __awaiter$3 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; /** * Interacts with the CodePush Acquisition SDK. */ class Sdk { /** * Reads the CodePush configuration and creates an AcquisitionManager instance using it. */ static getAcquisitionManager(userDeploymentKey, contentType) { return __awaiter$3(this, void 0, void 0, function* () { const resolveManager = () => { if (userDeploymentKey !== Sdk.DefaultConfiguration.deploymentKey || contentType) { var customConfiguration = { deploymentKey: userDeploymentKey || Sdk.DefaultConfiguration.deploymentKey, serverUrl: Sdk.DefaultConfiguration.serverUrl, ignoreAppVersion: Sdk.DefaultConfiguration.ignoreAppVersion, appVersion: Sdk.DefaultConfiguration.appVersion, clientUniqueId: Sdk.DefaultConfiguration.clientUniqueId }; var requester = new HttpRequester(contentType); var customAcquisitionManager = new acquisitionSdk.AcquisitionManager(requester, customConfiguration); return Promise.resolve(customAcquisitionManager); } else if (Sdk.DefaultConfiguration.deploymentKey) { return Promise.resolve(Sdk.DefaultAcquisitionManager); } else { return Promise.reject(new Error("No deployment key provided, please provide a default one in your config.xml or specify one in the call to checkForUpdate() or sync().")); } }; if (Sdk.DefaultAcquisitionManager) { return resolveManager(); } else { let serverUrl = null; try { serverUrl = yield NativeAppInfo.getServerURL(); } catch (e) { throw new Error("Could not get the CodePush configuration. Please check your config.xml file."); } let appVersion = null; try { appVersion = yield NativeAppInfo.getApplicationVersion(); } catch (e) { throw new Error("Could not get the app version. Please check your config.xml file."); } let deploymentKey = null; try { deploymentKey = yield NativeAppInfo.getDeploymentKey(); } catch (e) { } const device$1 = yield device.Device.getId(); Sdk.DefaultConfiguration = { deploymentKey, serverUrl, ignoreAppVersion: false, appVersion, clientUniqueId: device$1.uuid }; if (deploymentKey) { Sdk.DefaultAcquisitionManager = new acquisitionSdk.AcquisitionManager(new HttpRequester(), Sdk.DefaultConfiguration); } return resolveManager(); } }); } /** * Reports the deployment status to the CodePush server. */ static reportStatusDeploy(pkg, status, currentDeploymentKey, previousLabelOrAppVersion, previousDeploymentKey, callback) { return __awaiter$3(this, void 0, void 0, function* () { try { const acquisitionManager = yield Sdk.getAcquisitionManager(currentDeploymentKey, "application/json"); acquisitionManager.reportStatusDeploy(pkg, status, previousLabelOrAppVersion, previousDeploymentKey, callback); } catch (e) { callback && callback(e); } }); } /** * Reports the download status to the CodePush server. */ static reportStatusDownload(pkg, deploymentKey, callback) { return __awaiter$3(this, void 0, void 0, function* () { try { const acquisitionManager = yield Sdk.getAcquisitionManager(deploymentKey, "application/json"); acquisitionManager.reportStatusDownload(pkg, callback); } catch (e) { callback && callback(new Error("An error occured while reporting the download status. " + e)); } }); } } var __awaiter$2 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; /** * Defines a local package. * * !! THIS TYPE IS READ FROM NATIVE CODE AS WELL. ANY CHANGES TO THIS INTERFACE NEEDS TO BE UPDATED IN NATIVE CODE !! */ class LocalPackage extends Package { /** * Applies this package to the application. The application will be reloaded with this package and on every application launch this package will be loaded. * On the first run after the update, the application will wait for a codePush.notifyApplicationReady() call. Once this call is made, the install operation is considered a success. * Otherwise, the install operation will be marked as failed, and the application is reverted to its previous version on the next run. * * @param installOptions Optional parameter used for customizing the installation behavior. */ install(installOptions) { return __awaiter$2(this, void 0, void 0, function* () { return new Promise((resolve, reject) => __awaiter$2(this, void 0, void 0, function* () { try { CodePushUtil.logMessage("Installing update"); if (!installOptions) { installOptions = LocalPackage.getDefaultInstallOptions(); } else { CodePushUtil.copyUnassignedMembers(LocalPackage.getDefaultInstallOptions(), installOptions); } var installError = (error) => { CodePushUtil.invokeErrorCallback(error, reject); Sdk.reportStatusDeploy(this, acquisitionSdk.AcquisitionStatus.DeploymentFailed, this.deploymentKey); }; let unzipDir; try { unzipDir = yield FileUtil.cleanDataDirectory(LocalPackage.DownloadUnzipDir); } catch (error) { installError(error); return; } try { yield CodePush$1.unzip({ zipFile: this.localPath, targetDirectory: unzipDir }); } catch (unzipError) { installError(new Error("Could not unzip package" + CodePushUtil.getErrorMessage(unzipError))); return; } try { const newPackageLocation = LocalPackage.VersionsDir + "/" + this.packageHash; const deploymentResult = yield LocalPackage.handleDeployment(newPackageLocation); yield this.verifyPackage(deploymentResult); this.localPath = deploymentResult.deployDir; this.finishInstall(deploymentResult.deployDir, installOptions, resolve, installError); } catch (error) { installError(error); } } catch (e) { installError && installError(new Error("An error occured while installing the package. " + CodePushUtil.getErrorMessage(e))); } })); }); } verifyPackage(deploymentResult) { return new Promise((resolve, reject) => { var deployDir = deploymentResult.deployDir; var verificationFail = (error) => { reject(error); }; var verify = (isSignatureVerificationEnabled, isSignatureAppearedInBundle, publicKey, signature) => { if (isSignatureVerificationEnabled) { if (isSignatureAppearedInBundle) { this.verifyHash(deployDir, this.packageHash, verificationFail, () => { this.verifySignature(deployDir, this.packageHash, publicKey, signature, verificationFail, resolve); }); } else { var errorMessage = "Error! Public key was provided but there is no JWT signature within app bundle to verify. " + "Possible reasons, why that might happen: \n" + "1. You've been released CodePush bundle update using version of CodePush CLI that is not support code signing.\n" + "2. You've been released CodePush bundle update without providing --privateKeyPath option."; reject(new Error(errorMessage)); } } else { if (isSignatureAppearedInBundle) { CodePushUtil.logMessage("Warning! JWT signature exists in codepush update but code integrity check couldn't be performed because there is no public key configured. " + "Please ensure that public key is properly configured within your application."); // verifyHash this.verifyHash(deployDir, this.packageHash, verificationFail, resolve); } else { if (deploymentResult.isDiffUpdate) { // verifyHash this.verifyHash(deployDir, this.packageHash, verificationFail, resolve); } else { resolve(); } } } }; if (deploymentResult.isDiffUpdate) { CodePushUtil.logMessage("Applying diff update"); } else { CodePushUtil.logMessage("Applying full update"); } var isSignatureVerificationEnabled, isSignatureAppearedInBundle; var publicKey; this.getPublicKey((error, publicKeyResult) => { if (error) { reject(new Error("Error reading public key. " + error)); return; } publicKey = publicKeyResult; isSignatureVerificationEnabled = !!publicKey; this.getSignatureFromUpdate(deploymentResult.deployDir, (error, signature) => { if (error) { reject(new Error("Error reading signature from update. " + error)); return; } isSignatureAppearedInBundle = !!signature; verify(isSignatureVerificationEnabled, isSignatureAppearedInBundle, publicKey, signature); }); }); }); } getPublicKey(callback) { var success = (publicKey) => { callback(null, publicKey); }; var fail = (error) => { callback(error, null); }; CodePush$1.getPublicKey().then(result => success(result.value || null), fail); } getSignatureFromUpdate(deployDir, callback) { return __awaiter$2(this, void 0, void 0, function* () { const filePath = deployDir + "/public/.codepushrelease"; if (!(yield FileUtil.fileExists(filesystem.Directory.Data, filePath))) { // signature absents in the bundle callback(null, null); return; } try { const signature = yield FileUtil.readFile(filesystem.Directory.Data, filePath); callback(null, signature); } catch (error) { // error reading signature file from bundle callback(error, null); } }); } verifyHash(deployDir, newUpdateHash, errorCallback, successCallback) { var packageHashSuccess = (computedHash) => { if (computedHash !== newUpdateHash) { errorCallback(new Error("The update contents failed the data integrity check.")); return; } CodePushUtil.logMessage("The update contents succeeded the data integrity check."); successCallback(); }; var packageHashFail = (error) => { errorCallback(new Error("Unable to compute hash for package: " + error)); }; CodePushUtil.logMessage("Verifying hash for folder path: " + deployDir); CodePush$1.getPackageHash({ path: deployDir }).then(result => packageHashSuccess(result.value), packageHashFail); } verifySignature(deployDir, newUpdateHash, publicKey, signature, errorCallback, successCallback) { var decodeSignatureSuccess = (contentHash) => { if (contentHash !== newUpdateHash) { errorCallback(new Error("The update contents failed the code signing check.")); return; } CodePushUtil.logMessage("The update contents succeeded the code signing check."); successCallback(); }; var decodeSignatureFail = (error) => { errorCallback(new Error("Unable to verify signature for package: " + error)); }; CodePushUtil.logMessage("Verifying signature for folder path: " + deployDir); CodePush$1.decodeSignature({ publicKey, signature }).then(result => decodeSignatureSuccess(result.value), decodeSignatureFail); } finishInstall(deployDir, installOptions, installSuccess, installError) { function backupPackageInformationFileIfNeeded(backupIfNeededDone) { return __awaiter$2(this, void 0, void 0, function* () { const pendingUpdate = yield NativeAppInfo.isPendingUpdate(); if (pendingUpdate) { // Don't back up the currently installed update since it hasn't been "confirmed" backupIfNeededDone(null, null); } else { try { yield LocalPackage.backupPackageInformationFile(); backupIfNeededDone(null, null); } catch (err) { backupIfNeededDone(err, null); } } }); } LocalPackage.getCurrentOrDefaultPackage().then((oldPackage) => { backupPackageInformationFileIfNeeded((backupError) => { /* continue on error, current package information is missing if this is the first update */ this.writeNewPackageMetadata().then(() => { var invokeSuccessAndInstall = () => { CodePushUtil.logMessage("Install succeeded."); var installModeToUse = this.isMandatory ? installOptions.mandatoryInstallMode : installOptions.installMode; if (installModeToUse === exports.InstallMode.IMMEDIATE) { /* invoke success before navigating */ installSuccess && installSuccess(installModeToUse); /* no need for callbacks, the javascript context will reload */ CodePush$1.install({ startLocation: deployDir, installMode: installModeToUse, minimumBackgroundDuration: installOptions.minimumBackgroundDuration }); } else { CodePush$1.install({ startLocation: deployDir, installMode: installModeToUse, minimumBackgroundDuration: installOptions.minimumBackgroundDuration }).then(() => { installSuccess && installSuccess(installModeToUse); }, () => { installError && installError(); }); } }; var preInstallSuccess = () => { /* package will be cleaned up after success, on the native side */ invokeSuccessAndInstall(); }; var preInstallFailure = (preInstallError) => { CodePushUtil.logError("Preinstall failure.", preInstallError); var error = new Error("An error has occured while installing the package. " + CodePushUtil.getErrorMessage(preInstallError)); installError && installError(error); }; CodePush$1.preInstall({ startLocation: deployDir }).then(preInstallSuccess, preInstallFailure); }, (writeMetadataError) => { installError && installError(writeMetadataError); }); }); }, installError); } static handleDeployment(newPackageLocation) { return __awaiter$2(this, void 0, void 0, function* () { const manifestFile = { directory: filesystem.Directory.Data, path: LocalPackage.DownloadUnzipDir + "/" + LocalPackage.DiffManifestFile }; const isDiffUpdate = yield FileUtil.fileExists(manifestFile.directory, manifestFile.path); if (!(yield FileUtil.directoryExists(filesystem.Directory.Data, LocalPackage.VersionsDir))) { // If directory not exists, create recursive folder yield filesystem.Filesystem.mkdir({ path: LocalPackage.VersionsDir, directory: filesystem.Directory.Data, recursive: true }); } if (isDiffUpdate) { yield LocalPackage.handleDiffDeployment(newPackageLocation, manifestFile); } else { yield LocalPackage.handleCleanDeployment(newPackageLocation); } return { deployDir: newPackageLocation, isDiffUpdate }; }); } writeNewPackageMetadata() { return __awaiter$2(this, void 0, void 0, function* () { const timestamp = yield NativeAppInfo.getApplicationBuildTime().catch(buildTimeError => { CodePushUtil.logError("Could not get application build time. " + buildTimeError); }); const appVersion = yield NativeAppInfo.getApplicationVersion().catch(appVersionError => { CodePushUtil.logError("Could not get application version." + appVersionError); }); const currentPackageMetadata = { nativeBuildTime: timestamp, localPath: this.localPath, appVersion: appVersion, deploymentKey: this.deploymentKey, description: this.description, isMandatory: this.isMandatory, packageSize: this.packageSize, label: this.label, packageHash: this.packageHash, isFirstRun: false, failedInstall: false, install: undefined }; return new Promise((resolve, reject) => { LocalPackage.writeCurrentPackageInformation(currentPackageMetadata, error => error ? reject(error) : resolve()); }); }); } static handleCleanDeployment(newPackageLocation) { return __awaiter$2(this, void 0, void 0, function* () { // no diff manifest const source = { directory: filesystem.Directory.Data, path: LocalPackage.DownloadUnzipDir }; const target = { directory: filesystem.Directory.Data, path: newPackageLocation }; // TODO: create destination directory if it doesn't exist return FileUtil.copyDirectoryEntriesTo(source, target); }); } static copyCurrentPackage(newPackageLocation, ignoreList) { return __awaiter$2(this, void 0, void 0, function* () { const currentPackagePath = yield new Promise(resolve => { LocalPackage.getPackage(LocalPackage.PackageInfoFile, (currentPackage) => resolve(currentPackage.localPath), () => resolve()); }); newPackageLocation = currentPackagePath ? newPackageLocation : newPackageLocation + "/public"; // https://github.com/ionic-team/capacitor/pull/2514 Directory.Application variable was removed. (TODO - for check) const source = currentPackagePath ? { directory: filesystem.Directory.Data, path: currentPackagePath } : { directory: filesystem.Directory.Data, path: "public" }; const target = { directory: filesystem.Directory.Data, path: newPackageLocation }; return FileUtil.copyDirectoryEntriesTo(source, target, ignoreList); }); } static handleDiffDeployment(newPackageLocation, diffManifest) { return __awaiter$2(this, void 0, void 0, function* () { let manifest; try { yield LocalPackage.copyCurrentPackage(newPackageLocation, [".codepushrelease"]); yield LocalPackage.handleCleanDeployment(newPackageLocation); /* delete files mentioned in the manifest */ const content = yield FileUtil.readFile(diffManifest.directory, diffManifest.path); manifest = JSON.parse(content); yield FileUtil.deleteEntriesFromDataDirectory(newPackageLocation, manifest.deletedFiles); } catch (error) { throw new Error("Cannot perform diff-update."); } }); } /** * Writes the given local package information to the current package information file. * @param packageInfoMetadata The object to serialize. * @param callback In case of an error, this function will be called with the error as the fist parameter. */ static writeCurrentPackageInformation(packageInfoMetadata, callback) { var content = JSON.stringify(packageInfoMetadata); FileUtil.writeStringToDataFile(content, LocalPackage.RootDir + "/" + LocalPackage.PackageInfoFile, true, callback); } /** * Backs up the current package information to the old package information file. * This file is used for recovery in case of an update going wrong. * @param callback In case of an error, this function will be called with the error as the fist parameter. */ static backupPackageInformationFile() { return __awaiter$2(this, void 0, void 0, function* () { const source = { directory: filesystem.Directory.Data, path: LocalPackage.RootDir + "/" + LocalPackage.PackageInfoFile }; const destination = { directory: filesystem.Directory.Data, path: LocalPackage.RootDir + "/" + LocalPackage.OldPackageInfoFile }; return FileUtil.copy(source, destination); }); } /** * Get the previous package information. * * @param packageSuccess Callback invoked with the old package information. * @param packageError Optional callback invoked in case of an error. */ static getOldPackage(packageSuccess, packageError) { LocalPackage.getPackage(LocalPackage.OldPackageInfoFile, packageSuccess, packageError); } /** * Reads package information from a given file. * * @param packageFile The package file name. * @param packageSuccess Callback invoked with the package information. * @param packageError Optional callback invoked in case of an error. */ static getPackage(packageFile, packageSuccess, packageError) { return __awaiter$2(this, void 0, void 0, function* () { var handleError = (e) => { packageError && packageError(new Error("Cannot read package information. " + CodePushUtil.getErrorMessage(e))); }; try { const content = yield FileUtil.readDataFile(LocalPackage.RootDir + "/" + packageFile); const packageInfo = JSON.parse(content); LocalPackage.getLocalPackageFromMetadata(packageInfo).then(packageSuccess, packageError); } catch (e) { handleError(e); } }); } static getLocalPackageFromMetadata(metadata) { return __awaiter$2(this, void 0, void 0, function* () { if (!metadata) { throw new Error("Invalid package metadata."); } const installFailed = yield NativeAppInfo.isFailedUpdate(metadata.packageHash); const isFirstRun = yield NativeAppInfo.isFirstRun(metadata.packageHash); const localPackage = new LocalPackage(); localPackage.appVersion = metadata.appVersion; localPackage.deploymentKey = metadata.deploymentKey; localPackage.description = metadata.description; localPackage.isMandatory = metadata.isMandatory; localPackage.failedInstall = installFailed; localPackage.isFirstRun = isFirstRun; localPackage.label = metadata.label; localPackage.localPath = metadata.localPath; localPackage.packageHash = metadata.packageHash; localPackage.packageSize = metadata.packageSize; return localPackage; }); } static getCurrentOrDefaultPackage() { return LocalPackage.getPackageInfoOrDefault(LocalPackage.PackageInfoFile); } static getOldOrDefaultPackage() { return __awaiter$2(this, void 0, void 0, function* () { return LocalPackage.getPackageInfoOrDefault(LocalPackage.OldPackageInfoFile); }); } static getPackageInfoOrDefault(packageFile) { return __awaiter$2(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { const packageFailure