From 8b5d92f4666aea143def4667df40c7039a4c4d56 Mon Sep 17 00:00:00 2001 From: Jake Date: Sat, 18 Apr 2026 09:41:42 +0100 Subject: [PATCH] feat(updater): wire tauri-plugin-updater with GitHub releases endpoint + update toast --- src-tauri/Cargo.toml | 1 + src-tauri/src/commands/mod.rs | 1 + src-tauri/src/commands/update.rs | 38 ++++++++++++++++++++++++++++++++ src-tauri/src/lib.rs | 4 ++++ src-tauri/tauri.conf.json | 9 ++++++++ src/routes/+layout.svelte | 10 +++++++++ 6 files changed, 63 insertions(+) create mode 100644 src-tauri/src/commands/update.rs diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 135642c..31857a5 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -27,6 +27,7 @@ tauri = { version = "2", features = ["tray-icon"] } tauri-plugin-opener = "2" tauri-plugin-dialog = "2" tauri-plugin-global-shortcut = "2" +tauri-plugin-updater = "2" # Serialisation serde = { version = "1", features = ["derive"] } diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs index 9f6a180..fde1399 100644 --- a/src-tauri/src/commands/mod.rs +++ b/src-tauri/src/commands/mod.rs @@ -7,4 +7,5 @@ pub mod live; pub mod models; pub mod transcription; pub mod transcripts; +pub mod update; pub mod windows; diff --git a/src-tauri/src/commands/update.rs b/src-tauri/src/commands/update.rs new file mode 100644 index 0000000..911740e --- /dev/null +++ b/src-tauri/src/commands/update.rs @@ -0,0 +1,38 @@ +use tauri::AppHandle; +use tauri_plugin_updater::UpdaterExt; + +/// Check for an available update. Returns Some(version_string) if one is +/// available, None if already up to date, and Err if the check fails. +#[tauri::command] +pub async fn check_for_update(app: AppHandle) -> Result, String> { + let update = app + .updater() + .map_err(|e| format!("Updater not available: {e}"))? + .check() + .await + .map_err(|e| format!("Update check failed: {e}"))?; + + match update { + Some(u) => Ok(Some(u.version.to_string())), + None => Ok(None), + } +} + +/// Download and stage the update. The app will install it on next launch. +#[tauri::command] +pub async fn install_update(app: AppHandle) -> Result<(), String> { + let update = app + .updater() + .map_err(|e| format!("Updater not available: {e}"))? + .check() + .await + .map_err(|e| format!("Update check failed: {e}"))? + .ok_or_else(|| "No update available".to_string())?; + + update + .download_and_install(|_, _| {}, || {}) + .await + .map_err(|e| format!("Install failed: {e}"))?; + + Ok(()) +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index b9349c1..feed2b6 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -123,6 +123,7 @@ pub fn run() { .plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_global_shortcut::Builder::new().build()) + .plugin(tauri_plugin_updater::Builder::new().build()) .setup(|app| { // Initialise database (blocking in setup — runs once at startup) let db_path = database_path(); @@ -285,6 +286,9 @@ pub fn run() { commands::hotkey::start_evdev_hotkey, commands::hotkey::update_evdev_hotkey, commands::hotkey::stop_evdev_hotkey, + // Updater + commands::update::check_for_update, + commands::update::install_update, ]) .run(tauri::generate_context!()) .expect("error while running Kon"); diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index fff89c3..c25ab71 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -26,6 +26,15 @@ "csp": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' asset: https://asset.localhost; connect-src ipc: http://ipc.localhost asset: https://asset.localhost http://localhost:* ws://localhost:*; media-src 'self' asset: https://asset.localhost" } }, + "plugins": { + "updater": { + "endpoints": [ + "https://github.com/jakejars/kon/releases/latest/download/latest.json" + ], + "dialog": false, + "pubkey": "" + } + }, "bundle": { "active": true, "targets": "all", diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index e5dd84a..5b4b1b1 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -10,6 +10,7 @@ import { loadOsInfo } from "$lib/utils/osInfo.js"; import { page, settings, saveSettings } from "$lib/stores/page.svelte.js"; import { getPreferences, updatePreferences } from "$lib/stores/preferences.svelte.js"; + import { toasts } from "$lib/stores/toasts.svelte.js"; import { page as sveltePage } from "$app/stores"; @@ -230,6 +231,15 @@ } catch { // If commands fail, skip first-run check } + + // Background update check — non-blocking, silent on failure + invoke("check_for_update") + .then((version) => { + if (version) { + toasts.info(`Kon ${version} is available. Restart to install.`); + } + }) + .catch(() => { /* update check failure must not affect the app */ }); }); onDestroy(() => {