UNPKG

react-native-flix-codepush

Version:

A modern CodePush implementation for React Native applications

148 lines (124 loc) 4.25 kB
import { NativeModules } from 'react-native'; import { CodePushDeploymentStatus, CodePushInstallMode, type CodePushConfig, type CodePushLocalPackage, type CodePushRemotePackage, type DownloadProgressCallback, type FlixCodePushNativeModule, type SyncStatusChangedCallback } from '../types'; import { CodePushError } from '../utils/CodePushError'; import { handleNativeError, validateDeploymentKey } from '../utils/common'; import { ApiClient } from './ApiClient'; import { PackageManager } from './PackageManager'; let NativeFlixCodePush: FlixCodePushNativeModule; try { const NativeModule = require('../NativeFlixCodePush').default; NativeFlixCodePush = NativeModule; } catch (error) { NativeFlixCodePush = NativeModules.FlixCodePush as FlixCodePushNativeModule; } export class UpdateManager { private apiClient: ApiClient; private packageManager: PackageManager; private config: CodePushConfig | null = null; private statusChangeCallbacks: Set<SyncStatusChangedCallback> = new Set(); constructor() { this.apiClient = new ApiClient(''); this.packageManager = new PackageManager(''); } async initialize(): Promise<CodePushConfig> { if (this.config) { return this.config; } try { this.config = await handleNativeError( NativeFlixCodePush.getConfiguration() ); this.apiClient = new ApiClient(this.config.serverUrl); this.packageManager = new PackageManager(this.config.serverUrl); return this.config; } catch (error) { if (error instanceof CodePushError) { throw error; } throw new CodePushError( `Failed to initialize update manager: ${(error as Error).message}`, 'INITIALIZATION_ERROR', 'Configuration' ); } } async getConfiguration(): Promise<CodePushConfig> { return this.config || this.initialize(); } async checkForUpdate(deploymentKey?: string): Promise<CodePushRemotePackage | null> { const config = await this.getConfiguration(); const key = deploymentKey || config.deploymentKey; if (!validateDeploymentKey(key)) { throw CodePushError.invalidDeploymentKey(key); } const currentPackage = await this.packageManager.getCurrentPackage(); const appVersion = await handleNativeError(NativeFlixCodePush.getAppVersion()); return this.apiClient.checkForUpdate( key, appVersion, currentPackage?.packageHash ); } async downloadUpdate( remotePackage: CodePushRemotePackage, progressCallback?: DownloadProgressCallback ): Promise<CodePushLocalPackage> { return this.packageManager.downloadAndPreparePackage(remotePackage, progressCallback); } async installUpdate( packageHash: string, installMode: CodePushInstallMode = CodePushInstallMode.ON_NEXT_RESTART ): Promise<void> { return this.packageManager.installPackage(packageHash, installMode); } async reportStatus( status: CodePushDeploymentStatus, localPackage: CodePushLocalPackage ): Promise<void> { const deviceId = await handleNativeError(NativeFlixCodePush.getDeviceId()); return this.apiClient.reportStatus( status, localPackage.deploymentKey, localPackage.label, localPackage.appVersion, deviceId, localPackage.previousLabelOrAppVersion ); } async getCurrentPackage(): Promise<CodePushLocalPackage | null> { return this.packageManager.getCurrentPackage(); } async restartApplication(onlyIfUpdateIsPending: boolean = false): Promise<void> { return this.packageManager.restartApplication(onlyIfUpdateIsPending); } async clearUpdates(): Promise<void> { return this.packageManager.clearUpdates(); } cancelDownload(): void { this.packageManager.cancelDownload(); } addStatusChangeListener(callback: SyncStatusChangedCallback): () => void { this.statusChangeCallbacks.add(callback); return () => { this.statusChangeCallbacks.delete(callback); }; } notifyStatusChange(status: number): void { this.statusChangeCallbacks.forEach(callback => { try { callback(status); } catch (error) { console.error('Error in status change callback:', error); } }); } }