@capgo/capacitor-updater
Version:
Live update for capacitor apps
1,084 lines • 79.3 kB
TypeScript
import type { PluginListenerHandle } from '@capacitor/core';
declare module '@capacitor/cli' {
interface PluginsConfig {
/**
* CapacitorUpdater can be configured with these options:
*/
CapacitorUpdater?: {
/**
* Configure the number of milliseconds the native plugin should wait before considering an update 'failed'.
*
* Only available for Android and iOS.
*
* @default 10000 // (10 seconds)
* @example 1000 // (1 second, minimum 1000)
*/
appReadyTimeout?: number;
/**
* Configure the number of seconds the native plugin should wait before considering API timeout.
*
* Only available for Android and iOS.
*
* @default 20 // (20 second)
* @example 10 // (10 second)
*/
responseTimeout?: number;
/**
* Configure whether the plugin should use automatically delete failed bundles.
*
* Only available for Android and iOS.
*
* @default true
* @example false
*/
autoDeleteFailed?: boolean;
/**
* Configure whether the plugin should use automatically delete previous bundles after a successful update.
*
* Only available for Android and iOS.
*
* @default true
* @example false
*/
autoDeletePrevious?: boolean;
/**
* Configure whether the plugin should use Auto Update via an update server.
*
* Only available for Android and iOS.
*
* @default true
* @example false
*/
autoUpdate?: boolean;
/**
* Automatically delete previous downloaded bundles when a newer native app bundle is installed to the device.
* Setting this to false can broke the auto update flow if the user download from the store a native app bundle that is older than the current downloaded bundle. Upload will be prevented by channel setting downgrade_under_native.
* Only available for Android and iOS.
*
* @default true
* @example false
*/
resetWhenUpdate?: boolean;
/**
* Configure the URL / endpoint to which update checks are sent.
*
* Only available for Android and iOS.
*
* @default https://plugin.capgo.app/updates
* @example https://example.com/api/auto_update
*/
updateUrl?: string;
/**
* Configure the URL / endpoint for channel operations.
*
* Only available for Android and iOS.
*
* @default https://plugin.capgo.app/channel_self
* @example https://example.com/api/channel
*/
channelUrl?: string;
/**
* Configure the URL / endpoint to which update statistics are sent.
*
* Only available for Android and iOS. Set to "" to disable stats reporting.
*
* @default https://plugin.capgo.app/stats
* @example https://example.com/api/stats
*/
statsUrl?: string;
/**
* Configure the public key for end to end live update encryption Version 2
*
* Only available for Android and iOS.
*
* @default undefined
* @since 6.2.0
*/
publicKey?: string;
/**
* Configure the current version of the app. This will be used for the first update request.
* If not set, the plugin will get the version from the native code.
*
* Only available for Android and iOS.
*
* @default undefined
* @since 4.17.48
*/
version?: string;
/**
* Configure when the plugin should direct install updates. Only for autoUpdate mode.
* Works well for apps less than 10MB and with uploads done using --delta flag.
* Zip or apps more than 10MB will be relatively slow for users to update.
* - false: Never do direct updates (use default behavior: download at start, set when backgrounded)
* - atInstall: Direct update only when app is installed, updated from store, otherwise act as directUpdate = false
* - onLaunch: Direct update only on app installed, updated from store or after app kill, otherwise act as directUpdate = false
* - always: Direct update in all previous cases (app installed, updated from store, after app kill or app resume), never act as directUpdate = false
* - true: (deprecated) Same as "always" for backward compatibility
*
* Activate this flag will automatically make the CLI upload delta in CICD envs and will ask for confirmation in local uploads.
* Only available for Android and iOS.
*
* @default false
* @since 5.1.0
*/
directUpdate?: boolean | 'atInstall' | 'always' | 'onLaunch';
/**
* Automatically handle splashscreen hiding when using directUpdate. When enabled, the plugin will automatically hide the splashscreen after updates are applied or when no update is needed.
* This removes the need to manually listen for appReady events and call SplashScreen.hide().
* Only works when directUpdate is set to "atInstall", "always", "onLaunch", or true.
* Requires the @capacitor/splash-screen plugin to be installed and configured with launchAutoHide: false.
* Requires autoUpdate and directUpdate to be enabled.
*
* Only available for Android and iOS.
*
* @default false
* @since 7.6.0
*/
autoSplashscreen?: boolean;
/**
* Display a native loading indicator on top of the splashscreen while automatic direct updates are running.
* Only takes effect when {@link autoSplashscreen} is enabled.
* Requires the @capacitor/splash-screen plugin to be installed and configured with launchAutoHide: false.
*
* Only available for Android and iOS.
*
* @default false
* @since 7.19.0
*/
autoSplashscreenLoader?: boolean;
/**
* Automatically hide the splashscreen after the specified number of milliseconds when using automatic direct updates.
* If the timeout elapses, the update continues to download in the background while the splashscreen is dismissed.
* Set to `0` (zero) to disable the timeout.
* When the timeout fires, the direct update flow is skipped and the downloaded bundle is installed on the next background/launch.
* Requires {@link autoSplashscreen} to be enabled.
*
* Only available for Android and iOS.
*
* @default 10000 // (10 seconds)
* @since 7.19.0
*/
autoSplashscreenTimeout?: number;
/**
* Configure the delay period for period update check. the unit is in seconds.
*
* Only available for Android and iOS.
* Cannot be less than 600 seconds (10 minutes).
*
* @default 0 (disabled)
* @example 3600 (1 hour)
* @example 86400 (24 hours)
*/
periodCheckDelay?: number;
/**
* Configure the CLI to use a local server for testing or self-hosted update server.
*
*
* @default undefined
* @since 4.17.48
*/
localS3?: boolean;
/**
* Configure the CLI to use a local server for testing or self-hosted update server.
*
*
* @default undefined
* @since 4.17.48
*/
localHost?: string;
/**
* Configure the CLI to use a local server for testing or self-hosted update server.
*
*
* @default undefined
* @since 4.17.48
*/
localWebHost?: string;
/**
* Configure the CLI to use a local server for testing or self-hosted update server.
*
*
* @default undefined
* @since 4.17.48
*/
localSupa?: string;
/**
* Configure the CLI to use a local server for testing.
*
*
* @default undefined
* @since 4.17.48
*/
localSupaAnon?: string;
/**
* Configure the CLI to use a local api for testing.
*
*
* @default undefined
* @since 6.3.3
*/
localApi?: string;
/**
* Configure the CLI to use a local file api for testing.
*
*
* @default undefined
* @since 6.3.3
*/
localApiFiles?: string;
/**
* Allow the plugin to modify the updateUrl, statsUrl and channelUrl dynamically from the JavaScript side.
*
*
* @default false
* @since 5.4.0
*/
allowModifyUrl?: boolean;
/**
* Allow the plugin to modify the appId dynamically from the JavaScript side.
*
*
* @default false
* @since 7.14.0
*/
allowModifyAppId?: boolean;
/**
* Allow marking bundles as errored from JavaScript while using manual update flows.
* When enabled, {@link CapacitorUpdaterPlugin.setBundleError} can change a bundle status to `error`.
*
* @default false
* @since 7.20.0
*/
allowManualBundleError?: boolean;
/**
* Persist the customId set through {@link CapacitorUpdaterPlugin.setCustomId} across app restarts.
*
* Only available for Android and iOS.
*
* @default false (will be true by default in a future major release v8.x.x)
* @since 7.17.3
*/
persistCustomId?: boolean;
/**
* Persist the updateUrl, statsUrl and channelUrl set through {@link CapacitorUpdaterPlugin.setUpdateUrl},
* {@link CapacitorUpdaterPlugin.setStatsUrl} and {@link CapacitorUpdaterPlugin.setChannelUrl} across app restarts.
*
* Only available for Android and iOS.
*
* @default false
* @since 7.20.0
*/
persistModifyUrl?: boolean;
/**
* Allow or disallow the {@link CapacitorUpdaterPlugin.setChannel} method to modify the defaultChannel.
* When set to `false`, calling `setChannel()` will return an error with code `disabled_by_config`.
*
* @default true
* @since 7.34.0
*/
allowSetDefaultChannel?: boolean;
/**
* Set the default channel for the app in the config. Case sensitive.
* This will setting will override the default channel set in the cloud, but will still respect overrides made in the cloud.
* This requires the channel to allow devices to self dissociate/associate in the channel settings. https://capgo.app/docs/public-api/channels/#channel-configuration-options
*
*
* @default undefined
* @since 5.5.0
*/
defaultChannel?: string;
/**
* Configure the app id for the app in the config.
*
* @default undefined
* @since 6.0.0
*/
appId?: string;
/**
* Configure the plugin to keep the URL path after a reload.
* WARNING: When a reload is triggered, 'window.history' will be cleared.
*
* @default false
* @since 6.8.0
*/
keepUrlPathAfterReload?: boolean;
/**
* Disable the JavaScript logging of the plugin. if true, the plugin will not log to the JavaScript console. only the native log will be done
*
* @default false
* @since 7.3.0
*/
disableJSLogging?: boolean;
/**
* Enable OS-level logging. When enabled, logs are written to the system log which can be inspected in production builds.
*
* - **iOS**: Uses os_log instead of Swift.print, logs accessible via Console.app or Instruments
* - **Android**: Logs to Logcat (android.util.Log)
*
* When set to false, system logging is disabled on both platforms (only JavaScript console logging will occur if enabled).
*
* This is useful for debugging production apps (App Store/TestFlight builds on iOS, or production APKs on Android).
*
* @default true
* @since 8.42.0
*/
osLogging?: boolean;
/**
* Enable shake gesture to show update menu for debugging/testing purposes
*
* @default false
* @since 7.5.0
*/
shakeMenu?: boolean;
/**
* Enable the shake gesture to show a channel selector menu for switching between update channels.
* When enabled AND `shakeMenu` is true, the shake gesture shows a channel selector
* instead of the default debug menu (Go Home/Reload/Close).
*
* After selecting a channel, the app automatically checks for updates and downloads if available.
* Only works if channels have `allow_self_set` enabled on the backend.
*
* Only available for Android and iOS.
*
* @default false
* @since 8.43.0
*/
allowShakeChannelSelector?: boolean;
};
}
}
export interface CapacitorUpdaterPlugin {
/**
* Notify the native layer that JavaScript initialized successfully.
*
* **CRITICAL: You must call this method on every app launch to prevent automatic rollback.**
*
* This is a simple notification to confirm that your bundle's JavaScript loaded and executed.
* The native web server successfully served the bundle files and your JS runtime started.
* That's all it checks - nothing more complex.
*
* **What triggers rollback:**
* - NOT calling this method within the timeout (default: 10 seconds)
* - Complete JavaScript failure (bundle won't load at all)
*
* **What does NOT trigger rollback:**
* - Runtime errors after initialization (API failures, crashes, etc.)
* - Network request failures
* - Application logic errors
*
* **IMPORTANT: Call this BEFORE any network requests.**
* Don't wait for APIs, data loading, or async operations. Call it as soon as your
* JavaScript bundle starts executing to confirm the bundle itself is valid.
*
* Best practices:
* - Call immediately in your app entry point (main.js, app component mount, etc.)
* - Don't put it after network calls or heavy initialization
* - Don't wrap it in try/catch with conditions
* - Adjust {@link PluginsConfig.CapacitorUpdater.appReadyTimeout} if you need more time
*
* @returns {Promise<AppReadyResult>} Always resolves successfully with current bundle info. This method never fails.
*/
notifyAppReady(): Promise<AppReadyResult>;
/**
* Set the update URL for the app dynamically at runtime.
*
* This overrides the {@link PluginsConfig.CapacitorUpdater.updateUrl} config value.
* Requires {@link PluginsConfig.CapacitorUpdater.allowModifyUrl} to be set to `true`.
*
* Use {@link PluginsConfig.CapacitorUpdater.persistModifyUrl} to persist this value across app restarts.
* Otherwise, the URL will reset to the config value on next app launch.
*
* @param options Contains the URL to use for checking for updates.
* @returns {Promise<void>} Resolves when the URL is successfully updated.
* @throws {Error} If `allowModifyUrl` is false or if the operation fails.
* @since 5.4.0
*/
setUpdateUrl(options: UpdateUrl): Promise<void>;
/**
* Set the statistics URL for the app dynamically at runtime.
*
* This overrides the {@link PluginsConfig.CapacitorUpdater.statsUrl} config value.
* Requires {@link PluginsConfig.CapacitorUpdater.allowModifyUrl} to be set to `true`.
*
* Pass an empty string to disable statistics gathering entirely.
* Use {@link PluginsConfig.CapacitorUpdater.persistModifyUrl} to persist this value across app restarts.
*
* @param options Contains the URL to use for sending statistics, or an empty string to disable.
* @returns {Promise<void>} Resolves when the URL is successfully updated.
* @throws {Error} If `allowModifyUrl` is false or if the operation fails.
* @since 5.4.0
*/
setStatsUrl(options: StatsUrl): Promise<void>;
/**
* Set the channel URL for the app dynamically at runtime.
*
* This overrides the {@link PluginsConfig.CapacitorUpdater.channelUrl} config value.
* Requires {@link PluginsConfig.CapacitorUpdater.allowModifyUrl} to be set to `true`.
*
* Use {@link PluginsConfig.CapacitorUpdater.persistModifyUrl} to persist this value across app restarts.
* Otherwise, the URL will reset to the config value on next app launch.
*
* @param options Contains the URL to use for channel operations.
* @returns {Promise<void>} Resolves when the URL is successfully updated.
* @throws {Error} If `allowModifyUrl` is false or if the operation fails.
* @since 5.4.0
*/
setChannelUrl(options: ChannelUrl): Promise<void>;
/**
* Download a new bundle from the provided URL for later installation.
*
* The downloaded bundle is stored locally but not activated. To use it:
* - Call {@link next} to set it for installation on next app backgrounding/restart
* - Call {@link set} to activate it immediately (destroys current JavaScript context)
*
* The URL should point to a zip file containing either:
* - Your app files directly in the zip root, or
* - A single folder containing all your app files
*
* The bundle must include an `index.html` file at the root level.
*
* For encrypted bundles, provide the `sessionKey` and `checksum` parameters.
* For multi-file delta updates, provide the `manifest` array.
*
* @example
* const bundle = await CapacitorUpdater.download({
* url: `https://example.com/versions/${version}/dist.zip`,
* version: version
* });
* // Bundle is downloaded but not active yet
* await CapacitorUpdater.next({ id: bundle.id }); // Will activate on next background
*
* @param options The {@link DownloadOptions} for downloading a new bundle zip.
* @returns {Promise<BundleInfo>} The {@link BundleInfo} for the downloaded bundle.
* @throws {Error} If the download fails or the bundle is invalid.
*/
download(options: DownloadOptions): Promise<BundleInfo>;
/**
* Set the next bundle to be activated when the app backgrounds or restarts.
*
* This is the recommended way to apply updates as it doesn't interrupt the user's current session.
* The bundle will be activated when:
* - The app is backgrounded (user switches away), or
* - The app is killed and relaunched, or
* - {@link reload} is called manually
*
* Unlike {@link set}, this method does NOT destroy the current JavaScript context immediately.
* Your app continues running normally until one of the above events occurs.
*
* Use {@link setMultiDelay} to add additional conditions before the update is applied.
*
* @param options Contains the ID of the bundle to set as next. Use {@link BundleInfo.id} from a downloaded bundle.
* @returns {Promise<BundleInfo>} The {@link BundleInfo} for the specified bundle.
* @throws {Error} When there is no index.html file inside the bundle folder or the bundle doesn't exist.
*/
next(options: BundleId): Promise<BundleInfo>;
/**
* Set the current bundle and immediately reloads the app.
*
* **IMPORTANT: This is a terminal operation that destroys the current JavaScript context.**
*
* When you call this method:
* - The entire JavaScript context is immediately destroyed
* - The app reloads from a different folder with different files
* - NO code after this call will execute
* - NO promises will resolve
* - NO callbacks will fire
* - Event listeners registered after this call are unreliable and may never fire
*
* The reload happens automatically - you don't need to do anything else.
* If you need to preserve state like the current URL path, use the {@link PluginsConfig.CapacitorUpdater.keepUrlPathAfterReload} config option.
* For other state preservation needs, save your data before calling this method (e.g., to localStorage).
*
* **Do not** try to execute additional logic after calling `set()` - it won't work as expected.
*
* @param options A {@link BundleId} object containing the new bundle id to set as current.
* @returns {Promise<void>} A promise that will never resolve because the JavaScript context is destroyed.
* @throws {Error} When there is no index.html file inside the bundle folder.
*/
set(options: BundleId): Promise<void>;
/**
* Delete a bundle from local storage to free up disk space.
*
* You cannot delete:
* - The currently active bundle
* - The `builtin` bundle (the version shipped with your app)
* - The bundle set as `next` (call {@link next} with a different bundle first)
*
* Use {@link list} to get all available bundle IDs.
*
* **Note:** The bundle ID is NOT the same as the version name.
* Use the `id` field from {@link BundleInfo}, not the `version` field.
*
* @param options A {@link BundleId} object containing the bundle ID to delete.
* @returns {Promise<void>} Resolves when the bundle is successfully deleted.
* @throws {Error} If the bundle is currently in use or doesn't exist.
*/
delete(options: BundleId): Promise<void>;
/**
* Manually mark a bundle as failed/errored in manual update mode.
*
* This is useful when you detect that a bundle has critical issues and want to prevent
* it from being used again. The bundle status will be changed to `error` and the plugin
* will avoid using this bundle in the future.
*
* **Requirements:**
* - {@link PluginsConfig.CapacitorUpdater.allowManualBundleError} must be set to `true`
* - Only works in manual update mode (when autoUpdate is disabled)
*
* Common use case: After downloading and testing a bundle, you discover it has critical
* bugs and want to mark it as failed so it won't be retried.
*
* @param options A {@link BundleId} object containing the bundle ID to mark as errored.
* @returns {Promise<BundleInfo>} The updated {@link BundleInfo} with status set to `error`.
* @throws {Error} When the bundle does not exist or `allowManualBundleError` is false.
* @since 7.20.0
*/
setBundleError(options: BundleId): Promise<BundleInfo>;
/**
* Get all locally downloaded bundles stored in your app.
*
* This returns all bundles that have been downloaded and are available locally, including:
* - The currently active bundle
* - The `builtin` bundle (shipped with your app)
* - Any downloaded bundles waiting to be activated
* - Failed bundles (with `error` status)
*
* Use this to:
* - Check available disk space by counting bundles
* - Delete old bundles with {@link delete}
* - Monitor bundle download status
*
* @param options The {@link ListOptions} for customizing the bundle list output.
* @returns {Promise<BundleListResult>} A promise containing the array of {@link BundleInfo} objects.
* @throws {Error} If the operation fails.
*/
list(options?: ListOptions): Promise<BundleListResult>;
/**
* Reset the app to a known good bundle.
*
* This method helps recover from problematic updates by reverting to either:
* - The `builtin` bundle (the original version shipped with your app to App Store/Play Store)
* - The last successfully loaded bundle (most recent bundle that worked correctly)
*
* **IMPORTANT: This triggers an immediate app reload, destroying the current JavaScript context.**
* See {@link set} for details on the implications of this operation.
*
* Use cases:
* - Emergency recovery when an update causes critical issues
* - Testing rollback functionality
* - Providing users a "reset to factory" option
*
* @param options {@link ResetOptions} to control reset behavior.
* If `toLastSuccessful` is `false` (or omitted), resets to builtin.
* If `true`, resets to last successful bundle.
* If `usePendingBundle` is `true`, applies the pending bundle set via {@link next} and clears it.
* @returns {Promise<void>} A promise that may never resolve because the app will be reloaded.
* @throws {Error} If the reset operation fails.
*/
reset(options?: ResetOptions): Promise<void>;
/**
* Get information about the currently active bundle.
*
* Returns:
* - `bundle`: The currently active bundle information
* - `native`: The version of the builtin bundle (the original app version from App/Play Store)
*
* If no updates have been applied, `bundle.id` will be `"builtin"`, indicating the app
* is running the original version shipped with the native app.
*
* Use this to:
* - Display the current version to users
* - Check if an update is currently active
* - Compare against available updates
* - Log the active bundle for debugging
*
* @returns {Promise<CurrentBundleResult>} A promise with the current bundle and native version info.
* @throws {Error} If the operation fails.
*/
current(): Promise<CurrentBundleResult>;
/**
* Manually reload the app to apply a pending update.
*
* This triggers the same reload behavior that happens automatically when the app backgrounds.
* If you've called {@link next} to queue an update, calling `reload()` will apply it immediately.
*
* **IMPORTANT: This destroys the current JavaScript context immediately.**
* See {@link set} for details on the implications of this operation.
*
* Common use cases:
* - Applying an update immediately after download instead of waiting for backgrounding
* - Providing a "Restart now" button to users after an update is ready
* - Testing update flows during development
*
* If no update is pending (no call to {@link next}), this simply reloads the current bundle.
*
* @returns {Promise<void>} A promise that may never resolve because the app will be reloaded.
* @throws {Error} If the reload operation fails.
*/
reload(): Promise<void>;
/**
* Configure conditions that must be met before a pending update is applied.
*
* After calling {@link next} to queue an update, use this method to control when it gets applied.
* The update will only be installed after ALL specified conditions are satisfied.
*
* Available condition types:
* - `background`: Wait for the app to be backgrounded. Optionally specify duration in milliseconds.
* - `kill`: Wait for the app to be killed and relaunched (**Note:** Current behavior triggers update immediately on kill, not on next background. This will be fixed in v8.)
* - `date`: Wait until a specific date/time (ISO 8601 format)
* - `nativeVersion`: Wait until the native app is updated to a specific version
*
* Condition value formats:
* - `background`: Number in milliseconds (e.g., `"300000"` for 5 minutes), or omit for immediate
* - `kill`: No value needed
* - `date`: ISO 8601 date string (e.g., `"2025-12-31T23:59:59Z"`)
* - `nativeVersion`: Version string (e.g., `"2.0.0"`)
*
* @example
* // Update after user kills app OR after 5 minutes in background
* await CapacitorUpdater.setMultiDelay({
* delayConditions: [
* { kind: 'kill' },
* { kind: 'background', value: '300000' }
* ]
* });
*
* @example
* // Update after a specific date
* await CapacitorUpdater.setMultiDelay({
* delayConditions: [{ kind: 'date', value: '2025-12-31T23:59:59Z' }]
* });
*
* @example
* // Default behavior: update on next background
* await CapacitorUpdater.setMultiDelay({
* delayConditions: [{ kind: 'background' }]
* });
*
* @param options Contains the {@link MultiDelayConditions} array of conditions.
* @returns {Promise<void>} Resolves when the delay conditions are set.
* @throws {Error} If the operation fails or conditions are invalid.
* @since 4.3.0
*/
setMultiDelay(options: MultiDelayConditions): Promise<void>;
/**
* Cancel all delay conditions and apply the pending update immediately.
*
* If you've set delay conditions with {@link setMultiDelay}, this method clears them
* and triggers the pending update to be applied on the next app background or restart.
*
* This is useful when:
* - User manually requests to update now (e.g., clicks "Update now" button)
* - Your app detects it's a good time to update (e.g., user finished critical task)
* - You want to override a time-based delay early
*
* @returns {Promise<void>} Resolves when the delay conditions are cleared.
* @throws {Error} If the operation fails.
* @since 4.0.0
*/
cancelDelay(): Promise<void>;
/**
* Check the update server for the latest available bundle version.
*
* This queries your configured update URL (or Capgo backend) to see if a newer bundle
* is available for download. It does NOT download the bundle automatically.
*
* The response includes:
* - `version`: The latest available version identifier
* - `url`: Download URL for the bundle (if available)
* - `breaking`: Whether this update is marked as incompatible (requires native app update)
* - `message`: Optional message from the server
* - `manifest`: File list for delta updates (if using multi-file downloads)
*
* After receiving the latest version info, you can:
* 1. Compare it with your current version
* 2. Download it using {@link download}
* 3. Apply it using {@link next} or {@link set}
*
* **Important: Error handling for "no new version available"**
*
* When the device's current version matches the latest version on the server (i.e., the device is already
* up-to-date), the server returns a 200 response with `error: "no_new_version_available"` and
* `message: "No new version available"`. **This causes `getLatest()` to throw an error**, even though
* this is a normal, expected condition.
*
* You should catch this specific error to handle it gracefully:
*
* ```typescript
* try {
* const latest = await CapacitorUpdater.getLatest();
* // New version is available, proceed with download
* } catch (error) {
* if (error.message === 'No new version available') {
* // Device is already on the latest version - this is normal
* console.log('Already up to date');
* } else {
* // Actual error occurred
* console.error('Failed to check for updates:', error);
* }
* }
* ```
*
* In this scenario, the server:
* - Logs the request with a "No new version available" message
* - Sends a "noNew" stat action to track that the device checked for updates but was already current (done on the backend)
*
* @param options Optional {@link GetLatestOptions} to specify which channel to check.
* @returns {Promise<LatestVersion>} Information about the latest available bundle version.
* @throws {Error} Always throws when no new version is available (`error: "no_new_version_available"`), or when the request fails.
* @since 4.0.0
*/
getLatest(options?: GetLatestOptions): Promise<LatestVersion>;
/**
* Assign this device to a specific update channel at runtime.
*
* Channels allow you to distribute different bundle versions to different groups of users
* (e.g., "production", "beta", "staging"). This method switches the device to a new channel.
*
* **Requirements:**
* - The target channel must allow self-assignment (configured in your Capgo dashboard or backend)
* - The backend may accept or reject the request based on channel settings
*
* **When to use:**
* - After the app is ready and the user has interacted (e.g., opted into beta program)
* - To implement in-app channel switching (beta toggle, tester access, etc.)
* - For user-driven channel changes
*
* **When NOT to use:**
* - At app boot/initialization - use {@link PluginsConfig.CapacitorUpdater.defaultChannel} config instead
* - Before user interaction
*
* **Important: Listen for the `channelPrivate` event**
*
* When a user attempts to set a channel that doesn't allow device self-assignment, the method will
* throw an error AND fire a {@link addListener}('channelPrivate') event. You should listen to this event
* to provide appropriate feedback to users:
*
* ```typescript
* CapacitorUpdater.addListener('channelPrivate', (data) => {
* console.warn(`Cannot access channel "${data.channel}": ${data.message}`);
* // Show user-friendly message
* });
* ```
*
* This sends a request to the Capgo backend linking your device ID to the specified channel.
*
* @param options The {@link SetChannelOptions} containing the channel name and optional auto-update trigger.
* @returns {Promise<ChannelRes>} Channel operation result with status and optional error/message.
* @throws {Error} If the channel doesn't exist or doesn't allow self-assignment.
* @since 4.7.0
*/
setChannel(options: SetChannelOptions): Promise<ChannelRes>;
/**
* Remove the device's channel assignment and return to the default channel.
*
* This unlinks the device from any specifically assigned channel, causing it to fall back to:
* - The {@link PluginsConfig.CapacitorUpdater.defaultChannel} if configured, or
* - Your backend's default channel for this app
*
* Use this when:
* - Users opt out of beta/testing programs
* - You want to reset a device to standard update distribution
* - Testing channel switching behavior
*
* @param options {@link UnsetChannelOptions} containing optional auto-update trigger.
* @returns {Promise<void>} Resolves when the channel is successfully unset.
* @throws {Error} If the operation fails.
* @since 4.7.0
*/
unsetChannel(options: UnsetChannelOptions): Promise<void>;
/**
* Get the current channel assigned to this device.
*
* Returns information about:
* - `channel`: The currently assigned channel name (if any)
* - `allowSet`: Whether the channel allows self-assignment
* - `status`: Operation status
* - `error`/`message`: Additional information (if applicable)
*
* Use this to:
* - Display current channel to users (e.g., "You're on the Beta channel")
* - Check if a device is on a specific channel before showing features
* - Verify channel assignment after calling {@link setChannel}
*
* @returns {Promise<GetChannelRes>} The current channel information.
* @throws {Error} If the operation fails.
* @since 4.8.0
*/
getChannel(): Promise<GetChannelRes>;
/**
* Get a list of all channels available for this device to self-assign to.
*
* Only returns channels where `allow_self_set` is `true`. These are channels that
* users can switch to using {@link setChannel} without backend administrator intervention.
*
* Each channel includes:
* - `id`: Unique channel identifier
* - `name`: Human-readable channel name
* - `public`: Whether the channel is publicly visible
* - `allow_self_set`: Always `true` in results (filtered to only self-assignable channels)
*
* Use this to:
* - Build a channel selector UI for users (e.g., "Join Beta" button)
* - Show available testing/preview channels
* - Implement channel discovery features
*
* @returns {Promise<ListChannelsResult>} List of channels the device can self-assign to.
* @throws {Error} If the operation fails or the request to the backend fails.
* @since 7.5.0
*/
listChannels(): Promise<ListChannelsResult>;
/**
* Set a custom identifier for this device.
*
* This allows you to identify devices by your own custom ID (user ID, account ID, etc.)
* instead of or in addition to the device's unique hardware ID. The custom ID is sent
* to your update server and can be used for:
* - Targeting specific users for updates
* - Analytics and user tracking
* - Debugging and support (correlating devices with users)
* - A/B testing or feature flagging
*
* **Persistence:**
* - When {@link PluginsConfig.CapacitorUpdater.persistCustomId} is `true`, the ID persists across app restarts
* - When `false`, the ID is only kept for the current session
*
* **Clearing the custom ID:**
* - Pass an empty string `""` to remove any stored custom ID
*
* @param options The {@link SetCustomIdOptions} containing the custom identifier string.
* @returns {Promise<void>} Resolves immediately (synchronous operation).
* @throws {Error} If the operation fails.
* @since 4.9.0
*/
setCustomId(options: SetCustomIdOptions): Promise<void>;
/**
* Get the builtin bundle version (the original version shipped with your native app).
*
* This returns the version of the bundle that was included when the app was installed
* from the App Store or Play Store. This is NOT the currently active bundle version -
* use {@link current} for that.
*
* Returns:
* - The {@link PluginsConfig.CapacitorUpdater.version} config value if set, or
* - The native app version from platform configs (package.json, Info.plist, build.gradle)
*
* Use this to:
* - Display the "factory" version to users
* - Compare against downloaded bundle versions
* - Determine if any updates have been applied
* - Debugging version mismatches
*
* @returns {Promise<BuiltinVersion>} The builtin bundle version string.
* @since 5.2.0
*/
getBuiltinVersion(): Promise<BuiltinVersion>;
/**
* Get the unique, privacy-friendly identifier for this device.
*
* This ID is used to identify the device when communicating with update servers.
* It's automatically generated and stored securely by the plugin.
*
* **Privacy & Security characteristics:**
* - Generated as a UUID (not based on hardware identifiers)
* - Stored securely in platform-specific secure storage
* - Android: Android Keystore (persists across app reinstalls on API 23+)
* - iOS: Keychain with `kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly`
* - Not synced to cloud (iOS)
* - Follows Apple and Google privacy best practices
* - Users can clear it via system settings (Android) or keychain access (iOS)
*
* **Persistence:**
* The device ID persists across app reinstalls to maintain consistent device identity
* for update tracking and analytics.
*
* Use this to:
* - Debug update delivery issues (check what ID the server sees)
* - Implement device-specific features
* - Correlate server logs with specific devices
*
* @returns {Promise<DeviceId>} The unique device identifier string.
* @throws {Error} If the operation fails.
*/
getDeviceId(): Promise<DeviceId>;
/**
* Get the version of the Capacitor Updater plugin installed in your app.
*
* This returns the version of the native plugin code (Android/iOS), which is sent
* to the update server with each request. This is NOT your app version or bundle version.
*
* Use this to:
* - Debug plugin-specific issues (when reporting bugs)
* - Verify plugin installation and version
* - Check compatibility with backend features
* - Display in debug/about screens
*
* @returns {Promise<PluginVersion>} The Capacitor Updater plugin version string.
* @throws {Error} If the operation fails.
*/
getPluginVersion(): Promise<PluginVersion>;
/**
* Check if automatic updates are currently enabled.
*
* Returns `true` if {@link PluginsConfig.CapacitorUpdater.autoUpdate} is enabled,
* meaning the plugin will automatically check for, download, and apply updates.
*
* Returns `false` if in manual mode, where you control the update flow using
* {@link getLatest}, {@link download}, {@link next}, and {@link set}.
*
* Use this to:
* - Determine which update flow your app is using
* - Show/hide manual update UI based on mode
* - Debug update behavior
*
* @returns {Promise<AutoUpdateEnabled>} `true` if auto-update is enabled, `false` if in manual mode.
* @throws {Error} If the operation fails.
*/
isAutoUpdateEnabled(): Promise<AutoUpdateEnabled>;
/**
* Remove all event listeners registered for this plugin.
*
* This unregisters all listeners added via {@link addListener} for all event types:
* - `download`
* - `noNeedUpdate`
* - `updateAvailable`
* - `downloadComplete`
* - `downloadFailed`
* - `breakingAvailable` / `majorAvailable`
* - `updateFailed`
* - `appReloaded`
* - `appReady`
*
* Use this during cleanup (e.g., when unmounting components or closing screens)
* to prevent memory leaks from lingering event listeners.
*
* @returns {Promise<void>} Resolves when all listeners are removed.
* @since 1.0.0
*/
removeAllListeners(): Promise<void>;
/**
* Listen for bundle download event in the App. Fires once a download has started, during downloading and when finished.
* This will return you all download percent during the download
*
* @since 2.0.11
*/
addListener(eventName: 'download', listenerFunc: (state: DownloadEvent) => void): Promise<PluginListenerHandle>;
/**
* Listen for no need to update event, useful when you want force check every time the app is launched
*
* @since 4.0.0
*/
addListener(eventName: 'noNeedUpdate', listenerFunc: (state: NoNeedEvent) => void): Promise<PluginListenerHandle>;
/**
* Listen for available update event, useful when you want to force check every time the app is launched
*
* @since 4.0.0
*/
addListener(eventName: 'updateAvailable', listenerFunc: (state: UpdateAvailableEvent) => void): Promise<PluginListenerHandle>;
/**
* Listen for downloadComplete events.
*
* @since 4.0.0
*/
addListener(eventName: 'downloadComplete', listenerFunc: (state: DownloadCompleteEvent) => void): Promise<PluginListenerHandle>;
/**
* Listen for breaking update events when the backend flags an update as incompatible with the current app.
* Emits the same payload as the legacy `majorAvailable` listener.
*
* @since 7.22.0
*/
addListener(eventName: 'breakingAvailable', listenerFunc: (state: BreakingAvailableEvent) => void): Promise<PluginListenerHandle>;
/**
* Listen for Major update event in the App, let you know when major update is blocked by setting disableAutoUpdateBreaking
*
* @deprecated Deprecated alias for {@link addListener} with `breakingAvailable`. Emits the same payload. will be removed in v8
* @since 2.3.0
*/
addListener(eventName: 'majorAvailable', listenerFunc: (state: MajorAvailableEvent) => void): Promise<PluginListenerHandle>;
/**
* Listen for update fail event in the App, let you know when update has fail to install at next app start
*
* @since 2.3.0
*/
addListener(eventName: 'updateFailed', listenerFunc: (state: UpdateFailedEvent) => void): Promise<PluginListenerHandle>;
/**
* Listen for set event in the App, let you know when a bundle has been applied successfully.
* This event is retained natively until JavaScript consumes it, so if the app reloads before your
* listener is attached, the last pending `set` event is delivered once the listener subscribes.
*
* @since 8.43.12
*/
addListener(eventName: 'set', listenerFunc: (state: SetEvent) => void): Promise<PluginListenerHandle>;
/**
* Listen for set next event in the App, let you know when a bundle is queued as the next bundle to install.
*
* @since 6.14.0
*/
addListener(eventName: 'setNext', listenerFunc: (state: SetNextEvent) => void): Promise<PluginListenerHandle>;
/**
* Listen for download fail event in the App, let you know when a bundle download has failed
*
* @since 4.0.0
*/
addListener(eventName: 'downloadFailed', listenerFunc: (state: DownloadFailedEvent) => void): Promise<PluginListenerHandle>;
/**
* Listen for reload event in the App, let you know when reload has happened
*
* @since 4.3.0
*/
addListener(eventName: 'appReloaded', listenerFunc: () => void): Promise<PluginListenerHandle>;
/**
* Listen for app ready event in the App, let you know when app is ready to use.
* This event is retained natively until JavaScript consumes it, so it can still be delivered after
* a reload even if the listener is attached later in app startup.
*
* @since 5.1.0
*/
addListener(eventName: 'appReady', listenerFunc: (state: AppReadyEvent) => void): Promise<PluginListenerHandle>;
/**
* Listen for channel private event, fired when attempting to set a channel that doesn't allow device self-assignment.
*
* This event is useful for:
* - Informing users they don't have permission to switch to a specific channel
* - Implementing custom error handling for channel restrictions
* - Logging unauthorized channel access attempts
*
* @since 7.34.0
*/
addListener(eventName: 'channelPrivate', listenerFunc: (state: ChannelPrivateEvent) => void): Promise<PluginListenerHandle>;
/**
* Listen for flexible update state changes on Android.
*
* This event fires during the flexible update download process, providing:
* - Download progress (bytes downloaded / total bytes)
* - Installation status changes
*
* **Install status values:**
* - `UNKNOWN` (0): Unknown status
* - `PENDING` (1): Download pending
* - `DOWNLOADING` (2): Download in progress
* - `INSTALLING` (3): Installing the update
* - `INSTALLED` (4): Update installed (app restart needed)
* - `FAILED` (5): Update failed
* - `CANCELED` (6): Update was canceled
* - `DOWNLOADED` (11): Download complete, ready to install
*
* When status is `DOWNLOADED`, you should prompt the user and call
* {@link completeFlexibleUpdate} to finish the installation.
*
* @since 8.0.0
*/
addListener(eventName: 'onFlexibleUpdateStateChange', listenerFunc: (state: FlexibleUpdateState) => void): Promise<PluginListenerHandle>;
/**
* Check if the auto-update feature is available (not disabled by custom server configuration).
*
* Returns `false` when a custom `updateUrl` is configured, as this typically indicates
* you're using a self-hosted update server that may not support all auto-update features.
*
* Returns `true` when using the default Capgo backend or when the feature is available.
*
* This is different from {@link isAutoUpdateEnabled}:
* - `isAutoUpdateEnabled()`: Checks if auto-update MODE is turned on/off
* - `isAutoUpdateAvailable()`: Checks if auto-update is SUPPORTED with your current configuration
*
* @returns {Promise<AutoUpdateAvailable>} `false` when custom updateUrl