chore: update documentation

This commit is contained in:
Lucas Nogueira
2026-09-22 11:30:47 -03:00
parent d869c162a7
commit a87a3c7d44
104 changed files with 4875 additions and 222 deletions
+135 -5
View File
@@ -2,12 +2,19 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* In-app updates for Tauri applications: check the configured endpoints for a new release,
* download it and install it.
*
* @module
*/
import { invoke, Channel, Resource } from '@tauri-apps/api/core'
/** Options used when checking for updates */
interface CheckOptions {
/**
* Request headers
* The headers to send along with the update check request.
*/
headers?: HeadersInit
/**
@@ -27,7 +34,7 @@ interface CheckOptions {
/** Options used when downloading an update */
interface DownloadOptions {
/**
* Request headers
* The headers to send along with the update download request.
*/
headers?: HeadersInit
/**
@@ -59,17 +66,58 @@ type DownloadEvent =
| { event: 'Progress'; data: { chunkLength: number } }
| { event: 'Finished' }
/**
* An update announced by the update server, as returned by {@linkcode check}.
*
* It holds a resource on the Rust side, so call {@linkcode Update.close} when you are done with it
* without installing it.
*
* @since 2.0.0
*/
class Update extends Resource {
// TODO: remove this field in v3
/** @deprecated This is always true, check if the return value is `null` instead when using {@linkcode check} */
/**
* Whether an update is available.
*
* @deprecated This is always true, check if the return value is `null` instead when using {@linkcode check}
*/
available: boolean
/**
* The version of the application that is currently running.
*/
currentVersion: string
/**
* The version announced by the update server.
*/
version: string
/**
* The publish date of the update as an RFC 3339 string, when the server provided one.
*/
date?: string
/**
* The release notes of the update, when the server provided them.
*/
body?: string
/**
* The raw update manifest returned by the server, useful when it contains
* additional fields that the updater itself does not handle.
*/
rawJson: Record<string, unknown>
private downloadedBytes?: Resource
/**
* Creates an update from the metadata returned by the backend.
* You should not need to call this yourself, use {@linkcode check} instead.
*
* @param metadata The update information returned by the backend, including the resource identifier of the update.
*
* @example
* ```typescript
* import { check } from '@tauri-apps/plugin-updater';
* // the update instance is created for you by `check`
* const update = await check();
* ```
*/
constructor(metadata: UpdateMetadata) {
super(metadata.rid)
this.available = true
@@ -80,7 +128,29 @@ class Update extends Resource {
this.rawJson = metadata.rawJson
}
/** Download the updater package. Call {@linkcode install} later to install it */
/**
* Downloads the updater package. Call {@linkcode install} later to install it.
*
* @example
* ```typescript
* import { check } from '@tauri-apps/plugin-updater';
*
* const update = await check();
* if (update) {
* let downloaded = 0;
* await update.download((event) => {
* if (event.event === 'Progress') {
* downloaded += event.data.chunkLength;
* console.log(`downloaded ${downloaded} bytes`);
* }
* });
* await update.install();
* }
* ```
*
* @param onEvent Callback invoked with a `Started` event when the first chunk is received, a `Progress` event for every downloaded chunk and a `Finished` event when the download completes.
* @param options The headers and the timeout to use for the download request.
*/
async download(
onEvent?: (progress: DownloadEvent) => void,
options?: DownloadOptions
@@ -105,6 +175,19 @@ class Update extends Resource {
*
* - **Windows:** This function exits the app after launching the updater installer successfully
* - **macOS / Linux:** You need to relaunch the app to run the newly install version
*
* @example
* ```typescript
* import { check } from '@tauri-apps/plugin-updater';
*
* const update = await check();
* if (update) {
* await update.download();
* await update.install();
* }
* ```
*
* @param options Options for the installation, such as whether the Windows installer should restart the app afterwards.
*/
async install(options?: InstallOptions): Promise<void> {
if (!this.downloadedBytes) {
@@ -128,6 +211,21 @@ class Update extends Resource {
*
* - **Windows:** This function exits the app after launching the updater installer successfully
* - **macOS / Linux:** You need to relaunch the app to run the newly install version
*
* @example
* ```typescript
* import { check } from '@tauri-apps/plugin-updater';
*
* const update = await check();
* if (update) {
* await update.downloadAndInstall((event) => {
* console.log(event.event);
* });
* }
* ```
*
* @param onEvent Callback invoked with a `Started` event when the first chunk is received, a `Progress` event for every downloaded chunk and a `Finished` event when the download completes.
* @param options The headers and the timeout to use for the download request, and the installation options.
*/
async downloadAndInstall(
onEvent?: (progress: DownloadEvent) => void,
@@ -145,13 +243,45 @@ class Update extends Resource {
})
}
/**
* Releases the update resource and the downloaded bytes held by the backend.
*
* @example
* ```typescript
* import { check } from '@tauri-apps/plugin-updater';
*
* const update = await check();
* if (update) {
* await update.close();
* }
* ```
*/
async close(): Promise<void> {
await this.downloadedBytes?.close()
await super.close()
}
}
/** Check for updates, resolves to `null` if no updates are available */
/**
* Checks the configured endpoints for an available update.
*
* @example
* ```typescript
* import { check } from '@tauri-apps/plugin-updater';
*
* const update = await check();
* if (update) {
* console.log(`update ${update.version} is available`);
* await update.downloadAndInstall();
* }
* ```
*
* @param options The headers, timeout, proxy and target to use for the update check request.
*
* @returns A promise resolving to the available {@linkcode Update}, or `null` when no update is available.
*
* @since 2.0.0
*/
async function check(options?: CheckOptions): Promise<Update | null> {
convertToRustHeaders(options)
+13
View File
@@ -66,24 +66,35 @@ pub enum Error {
/// Temp dir is not on same mount mount. This prevents our updater to rename the AppImage to a temp file.
#[error("temp directory is not on the same mount point as the AppImage")]
TempDirNotOnSameMountPoint,
/// The downloaded archive does not contain a binary for the current target.
#[error("binary for the current target not found in the archive")]
BinaryNotFoundInArchive,
/// Could not create a temporary directory to store the downloaded update.
#[error("failed to create temporary directory")]
TempDirNotFound,
/// The privilege escalation prompt shown before installing a Linux package
/// failed or was dismissed by the user.
#[error("Authentication failed or was cancelled")]
AuthenticationFailed,
/// Installing the downloaded `.deb` package failed.
#[error("Failed to install .deb package")]
DebInstallFailed,
/// The package manager could not install the downloaded Linux package.
#[error("Failed to install package")]
PackageInstallFailed,
/// The downloaded update is not in a format the updater can install on the current platform.
#[error("invalid updater binary format")]
InvalidUpdaterFormat,
/// `http` crate errors.
#[error(transparent)]
Http(#[from] http::Error),
/// A request header value is not valid.
#[error(transparent)]
InvalidHeaderValue(#[from] http::header::InvalidHeaderValue),
/// A request header name is not valid.
#[error(transparent)]
InvalidHeaderName(#[from] http::header::InvalidHeaderName),
/// The release publish date could not be formatted as an RFC 3339 string.
#[error("Failed to format date")]
FormatDate,
/// The configured updater endpoint must use a secure protocol like `https`
@@ -105,6 +116,7 @@ pub enum Error {
"The update signature does not specify the version it was signed for, which `requireSignedVersion` requires. Re-sign and re-publish this release, or disable `requireSignedVersion`."
)]
MissingSignedVersion,
/// Tauri errors.
#[error(transparent)]
Tauri(#[from] tauri::Error),
}
@@ -118,4 +130,5 @@ impl Serialize for Error {
}
}
/// A [`Result`](std::result::Result) alias whose error type is the updater [`Error`](enum@Error).
pub type Result<T> = std::result::Result<T, Error>;
+46
View File
@@ -137,6 +137,21 @@ struct UpdaterState {
headers: HeaderMap,
}
/// Builder for the updater plugin.
///
/// The values set here are the defaults used by every [`Updater`] created through
/// [`UpdaterExt::updater`] and [`UpdaterExt::updater_builder`]; they can still be overridden
/// per updater instance on the [`UpdaterBuilder`].
///
/// # Examples
///
/// ```no_run
/// use tauri::Runtime;
///
/// fn register_updater<R: Runtime>(builder: tauri::Builder<R>) -> tauri::Builder<R> {
/// builder.plugin(tauri_plugin_updater::Builder::new().build())
/// }
/// ```
#[derive(Default)]
pub struct Builder {
target: Option<String>,
@@ -147,15 +162,26 @@ pub struct Builder {
}
impl Builder {
/// Creates a new builder with the default configuration.
pub fn new() -> Self {
Self::default()
}
/// Sets the target name used when checking for updates.
///
/// It replaces the `{{target}}` variable in the endpoint URLs and is used as the key to look
/// up the release in the `platforms` object of a static update manifest.
///
/// When it is not set, the updater uses the current operating system name (`linux`, `darwin`
/// or `windows`) in the endpoint URLs and looks for `{os}-{arch}-{bundle_type}` then
/// `{os}-{arch}` in the manifest.
pub fn target(mut self, target: impl Into<String>) -> Self {
self.target.replace(target.into());
self
}
/// Sets the public key used to verify the update signature,
/// overriding the `pubkey` value of the plugin configuration.
pub fn pubkey<S: Into<String>>(mut self, pubkey: S) -> Self {
self.pubkey.replace(pubkey.into());
self
@@ -189,6 +215,11 @@ impl Builder {
self
}
/// Adds a header to be sent on every updater request.
///
/// # Errors
///
/// Returns an error if the header name or the header value is not valid.
pub fn header<K, V>(mut self, key: K, value: V) -> Result<Self>
where
HeaderName: TryFrom<K>,
@@ -204,11 +235,22 @@ impl Builder {
Ok(self)
}
/// Replaces all the headers sent on updater requests with the given map,
/// discarding the ones previously added with [`Self::header`].
pub fn headers(mut self, headers: HeaderMap) -> Self {
self.headers = headers;
self
}
/// Sets the default function used to decide whether a remote release should be installed.
///
/// The closure receives the current application version and the remote release,
/// and must return `true` when the release should be treated as an update.
///
/// It applies to every updater created through [`UpdaterExt`] and takes precedence over the
/// `allowDowngrades` configuration value; it can still be overridden per updater instance with
/// [`UpdaterBuilder::version_comparator`]. When no comparator is set at all, a release is
/// installed only if its version is greater than the current one.
pub fn default_version_comparator<
F: Fn(Version, RemoteRelease) -> bool + Send + Sync + 'static,
>(
@@ -219,6 +261,10 @@ impl Builder {
self
}
/// Builds the updater plugin, registering the `check`, `download`, `install`
/// and `download_and_install` commands used by the JavaScript API.
///
/// Pass the returned plugin to [`tauri::Builder::plugin`].
pub fn build<R: Runtime>(self) -> TauriPlugin<R, Config> {
let pubkey = self.pubkey;
let target = self.target;
+115
View File
@@ -43,15 +43,26 @@ use crate::{
const UPDATER_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),);
/// The kind of bundle the running application was installed from.
///
/// Its name is appended to the updater target string (`{os}-{arch}-{bundle_type}`) when looking
/// up the release in the update manifest and replaces the `{{bundle_type}}` variable in the
/// endpoint URLs.
#[derive(Copy, Clone)]
pub enum Installer {
/// Linux AppImage bundle, named `appimage`.
AppImage,
/// Debian package, named `deb`.
Deb,
/// RPM package, named `rpm`.
Rpm,
/// macOS application bundle, named `app`. Also used for applications distributed as DMG.
App,
/// Windows WiX (MSI) installer, named `msi`.
Msi,
/// Windows NSIS installer, named `nsis`.
Nsis,
}
@@ -68,6 +79,7 @@ impl Installer {
}
}
/// The update information of a single platform in the update manifest.
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ReleaseManifestPlatform {
/// Download URL for the platform
@@ -76,11 +88,18 @@ pub struct ReleaseManifestPlatform {
pub signature: String,
}
/// The platform specific data of a [`RemoteRelease`], in either of the two supported shapes.
#[derive(Debug, Deserialize, Serialize, Clone)]
#[serde(untagged)]
pub enum RemoteReleaseInner {
/// Server Format: the endpoint resolved the platform itself and returned a single
/// download URL and signature.
Dynamic(ReleaseManifestPlatform),
/// Static Format: the manifest describes every platform it supports and the updater
/// picks the entry matching the current target.
Static {
/// Update information for each platform, keyed by the updater target string
/// (e.g. `darwin-aarch64`).
platforms: HashMap<String, ReleaseManifestPlatform>,
},
}
@@ -126,8 +145,16 @@ impl RemoteRelease {
}
}
/// Function executed right before the Windows installer is spawned and the app exits.
/// See [`UpdaterBuilder::on_before_exit`].
pub type OnBeforeExit = Arc<dyn Fn() + Send + Sync + 'static>;
/// Function that customizes the `reqwest` client builder used for the updater requests.
/// See [`UpdaterBuilder::configure_client`].
pub type OnBeforeRequest = Arc<dyn Fn(ClientBuilder) -> ClientBuilder + Send + Sync + 'static>;
/// Function that decides whether a remote release must be installed.
///
/// It receives the current application version and the remote release,
/// and returns `true` when the release should be treated as an update.
pub type VersionComparator = Arc<dyn Fn(Version, RemoteRelease) -> bool + Send + Sync>;
#[cfg(target_os = "macos")]
type MainThreadClosure = Box<dyn FnOnce() + Send + Sync + 'static>;
@@ -155,6 +182,10 @@ struct UpdaterContext {
restart_after_install: bool,
}
/// Builder for an [`Updater`] instance.
///
/// Get one from [`crate::UpdaterExt::updater_builder`], which pre-fills it with the plugin
/// configuration, then call [`UpdaterBuilder::build`].
pub struct UpdaterBuilder {
current_version: Version,
pub(crate) version_comparator: Option<VersionComparator>,
@@ -208,6 +239,12 @@ impl UpdaterBuilder {
}
}
/// Sets the function used to decide whether the remote release must be installed,
/// replacing the comparator set with [`crate::Builder::default_version_comparator`]
/// and the behavior of the `allowDowngrades` configuration value.
///
/// When no comparator is set, a release is only installed if its version is greater
/// than the current application version.
pub fn version_comparator<F: Fn(Version, RemoteRelease) -> bool + Send + Sync + 'static>(
mut self,
f: F,
@@ -216,11 +253,29 @@ impl UpdaterBuilder {
self
}
/// Sets the target name used when checking for updates.
///
/// It replaces the `{{target}}` variable in the endpoint URLs and is used as the key to look
/// up the release in the `platforms` object of a static update manifest.
///
/// When it is not set, the updater uses the current operating system name (`linux`, `darwin`
/// or `windows`) in the endpoint URLs and looks for `{os}-{arch}-{bundle_type}` then
/// `{os}-{arch}` in the manifest.
pub fn target(mut self, target: impl Into<String>) -> Self {
self.target.replace(target.into());
self
}
/// Sets the endpoints to fetch the update manifest from,
/// overriding the `endpoints` configuration value.
///
/// They are checked in order and the first one that returns a valid release wins.
///
/// # Errors
///
/// Returns [`Error::InsecureTransportProtocol`] on release builds if an endpoint does not use
/// the `https` protocol and the `dangerousInsecureTransportProtocol` configuration value is
/// not enabled. On debug builds a warning is printed instead.
pub fn endpoints(mut self, endpoints: Vec<Url>) -> Result<Self> {
crate::config::validate_endpoints(
&endpoints,
@@ -231,11 +286,19 @@ impl UpdaterBuilder {
Ok(self)
}
/// Sets the path of the application executable, which is used to determine where the update
/// must be installed. Defaults to the path of the current executable, or to the AppImage path
/// when the application runs as an AppImage.
pub fn executable_path<P: AsRef<Path>>(mut self, p: P) -> Self {
self.executable_path.replace(p.as_ref().into());
self
}
/// Adds a header to be sent on the update check and download requests.
///
/// # Errors
///
/// Returns an error if the header name or the header value is not valid.
pub fn header<K, V>(mut self, key: K, value: V) -> Result<Self>
where
HeaderName: TryFrom<K>,
@@ -251,21 +314,28 @@ impl UpdaterBuilder {
Ok(self)
}
/// Replaces all the headers sent on the update check and download requests with the given map,
/// discarding the ones previously added with [`Self::header`].
pub fn headers(mut self, headers: HeaderMap) -> Self {
self.headers = headers;
self
}
/// Removes all the headers previously set on this builder.
pub fn clear_headers(mut self) -> Self {
self.headers.clear();
self
}
/// Sets the timeout of the update check and download requests.
/// When it is not set, the requests do not time out.
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
/// Sets the proxy used for the update check and download requests.
/// It is ignored when [`Self::no_proxy`] was called.
pub fn proxy(mut self, proxy: Url) -> Self {
self.proxy.replace(proxy);
self
@@ -277,6 +347,8 @@ impl UpdaterBuilder {
self
}
/// Sets the public key used to verify the update signature,
/// overriding the `pubkey` value of the plugin configuration.
pub fn pubkey<S: Into<String>>(mut self, pubkey: S) -> Self {
self.context.config.pubkey = pubkey.into();
self
@@ -362,6 +434,15 @@ impl UpdaterBuilder {
self
}
/// Builds the [`Updater`].
///
/// # Errors
///
/// - [`Error::EmptyEndpoints`]: neither [`Self::endpoints`] nor the `endpoints`
/// configuration value provided an endpoint to check.
/// - [`Error::UnsupportedArch`]: the updater does not support the current architecture.
/// - [`Error::FailedToDetermineExtractPath`]: the install directory could not be resolved
/// from the executable path.
pub fn build(self) -> Result<Updater> {
let endpoints = self
.endpoints
@@ -412,6 +493,9 @@ impl UpdaterBuilder {
}
}
/// Checks the configured endpoints for an application update.
///
/// Get one from [`crate::UpdaterExt::updater`] or by calling [`UpdaterBuilder::build`].
pub struct Updater {
current_version: Version,
version_comparator: Option<VersionComparator>,
@@ -429,6 +513,25 @@ pub struct Updater {
}
impl Updater {
/// Checks the endpoints for an update, returning the first release that the version
/// comparator accepts.
///
/// Each endpoint is requested in order, with the `{{current_version}}`, `{{target}}`,
/// `{{arch}}` and `{{bundle_type}}` variables replaced in its URL, until one of them
/// answers with a release manifest the updater can parse.
///
/// Resolves to `None` when an endpoint replies with `204 No Content` or when the release it
/// announced is not considered an update - by default when its version is not greater than the
/// current application version.
///
/// # Errors
///
/// - [`Error::UnsupportedOs`]: no target was set and the updater does not support the
/// current operating system.
/// - [`Error::ReleaseNotFound`]: no endpoint returned a release manifest.
/// - The last request or deserialization error when every endpoint failed.
/// - [`Error::TargetNotFound`] or [`Error::TargetsNotFound`]: the manifest has no entry
/// for the current target.
pub async fn check(&self) -> Result<Option<Update>> {
// we want JSON only
let mut headers = self.headers.clone();
@@ -638,6 +741,10 @@ impl Updater {
}
}
/// An update announced by the remote server, returned by [`Updater::check`].
///
/// Use [`Update::download`] followed by [`Update::install`], or [`Update::download_and_install`],
/// to apply it.
#[derive(Clone)]
pub struct Update {
/// Update description
@@ -1427,6 +1534,14 @@ fn updater_arch() -> Option<&'static str> {
}
}
/// Resolves the path the update must be installed to from the path of the application executable.
///
/// This is the directory holding the executable, except on macOS where the `.app` bundle path is
/// returned for executables living in `Contents/MacOS`.
///
/// # Errors
///
/// Returns [`Error::FailedToDetermineExtractPath`] when the path has no parent directory.
pub fn extract_path_from_executable(executable_path: &Path) -> Result<PathBuf> {
// Return the path of the current executable by default
// Example C:\Program Files\My App\