Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,24 @@ A handy helper, to help with Syntax's production.
- Svelte(5) Kit
- Tauri
- FFMPEG

## Features

### Auto-Updater

The application includes an automatic update system that allows users to check for and install updates seamlessly.

**Usage:**
- Click the "Check for Updates" button in the main application interface
- If an update is available, you'll be prompted to install it
- The updater will download and install the update automatically
- Restart the application to complete the update process

**Configuration:**
The updater is configured to check GitHub releases for updates. To set up releases for automatic updates:

1. Create a GitHub release with the appropriate assets
2. Ensure the release includes a `latest.json` file with update metadata
3. The updater will automatically detect and offer to install new versions

For production use, make sure to configure a proper signing key in `src-tauri/tauri.conf.json`.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@tauri-apps/plugin-http": "2.0.0-rc.1",
"@tauri-apps/plugin-log": "2.0.0-rc.0",
"@tauri-apps/plugin-shell": ">=2.0.0-rc.0",
"@tauri-apps/plugin-updater": "2.0.0-rc.0",
"@types/markdown-it": "^14.1.2",
"dexie": "^4.0.8",
"ink-mde": "^0.33.0",
Expand Down
10 changes: 10 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@ tauri-plugin-decorum = "1.0.0"
reqwest = { version = "0.11", features = ["json"] }
tauri-plugin-devtools = "2.0.0-rc"
tauri-plugin-log = "2.0.0-rc.1"
tauri-plugin-updater = "2.0.0-rc"
log = "0.4"
which = "6.0.3"
56 changes: 56 additions & 0 deletions src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,59 @@ async fn upload_to_youtube(
Err("Upload failed".to_string())
}

#[tauri::command]
async fn check_for_updates(app: tauri::AppHandle) -> Result<String, String> {
match tauri_plugin_updater::UpdaterExt::updater(&app) {
Some(updater) => {
match updater.check().await {
Ok(Some(update)) => {
Ok(format!("Update available: {} -> {}", env!("CARGO_PKG_VERSION"), update.version))
},
Ok(None) => {
Ok(format!("You're running the latest version: {}", env!("CARGO_PKG_VERSION")))
},
Err(e) => {
Err(format!("Failed to check for updates: {}", e))
}
}
},
None => {
Err("Updater not available".to_string())
}
}
}

#[tauri::command]
async fn install_update(app: tauri::AppHandle) -> Result<String, String> {
match tauri_plugin_updater::UpdaterExt::updater(&app) {
Some(updater) => {
match updater.check().await {
Ok(Some(update)) => {
match update.download_and_install(|_chunk_length, _content_length| {
// You can use this to show progress
}).await {
Comment on lines +417 to +421
Copy link

Copilot AI Sep 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The install_update function calls updater.check().await again, which duplicates the network request that was already made in check_for_updates. Consider caching the update information or restructuring the flow to avoid redundant API calls.

Copilot uses AI. Check for mistakes.
Ok(_) => {
Ok("Update installed successfully. Please restart the application.".to_string())
},
Err(e) => {
Err(format!("Failed to install update: {}", e))
}
}
},
Ok(None) => {
Ok("No updates available to install".to_string())
},
Err(e) => {
Err(format!("Failed to check for updates: {}", e))
}
}
},
None => {
Err("Updater not available".to_string())
}
}
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
let mut builder = tauri::Builder::default();
Expand Down Expand Up @@ -415,6 +468,7 @@ pub fn run() {
builder
.plugin(tauri_plugin_http::init())
.plugin(tauri_plugin_decorum::init()) // initialize the decorum plugin
.plugin(tauri_plugin_updater::Builder::new().build()) // initialize the updater plugin
.setup(|app| {
// Create a custom titlebar for main window
// On macOS it needs hiddenTitle: true and titleBarStyle: overlay
Expand Down Expand Up @@ -461,6 +515,8 @@ pub fn run() {
hide_login_window,
login_youtube,
upload_to_youtube,
check_for_updates,
install_update,
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
Expand Down
8 changes: 8 additions & 0 deletions src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@
"scope": [
"**"
]
},
"updater": {
"active": true,
"endpoints": [
"https://github.com/syntaxfm/production-assistant/releases/latest/download/latest.json"
],
"dialog": true,
"pubkey": ""
Copy link

Copilot AI Sep 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The public key is empty, which means updates won't be cryptographically verified. This poses a security risk as malicious updates could be installed. Either add a proper signing key for production or add a comment explaining this is for development only.

Suggested change
"pubkey": ""
"pubkey": "",
"pubkeyComment": "Empty pubkey is for development only. Do not use in production."

Copilot uses AI. Check for mistakes.
}
},
"productName": "Syntax PA",
Expand Down
44 changes: 44 additions & 0 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,47 @@
import Avatar from '$lib/auth/Avatar.svelte';
import ProjectButton from '$/lib/components/ProjectButton.svelte';
app_data.sync();

let isCheckingUpdates = $state(false);
let updateMessage = $state('');

async function checkForUpdates() {
isCheckingUpdates = true;
updateMessage = '';
try {
const result = await invoke('check_for_updates');
Copy link

Copilot AI Sep 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The invoke function is not imported. You need to add import { invoke } from '@tauri-apps/api/core'; at the top of the script section.

Copilot uses AI. Check for mistakes.
updateMessage = result as string;

// If update is available, offer to install
if ((result as string).includes('Update available')) {
const shouldInstall = confirm(`${result}\n\nWould you like to install the update now?`);
if (shouldInstall) {
await installUpdate();
}
} else {
alert(result);
}
Comment on lines +20 to +27
Copy link

Copilot AI Sep 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Using confirm() and alert() dialogs creates a poor user experience. Consider implementing custom modal components or using Tauri's dialog API for more consistent, styled prompts that match the application's design.

Copilot uses AI. Check for mistakes.
} catch (error) {
const errorMsg = `Error checking for updates: ${error}`;
updateMessage = errorMsg;
alert(errorMsg);
} finally {
isCheckingUpdates = false;
}
}

async function installUpdate() {
try {
updateMessage = 'Installing update...';
const result = await invoke('install_update');
updateMessage = result as string;
alert(result);
} catch (error) {
const errorMsg = `Error installing update: ${error}`;
updateMessage = errorMsg;
alert(errorMsg);
}
}
</script>

<div class="content">
Expand All @@ -27,6 +68,9 @@
/></label
>
<button class="small ghost" onclick={app_data.export_to_json}>Export Data</button>
<button class="small ghost" onclick={checkForUpdates} disabled={isCheckingUpdates}>
{isCheckingUpdates ? 'Checking...' : 'Check for Updates'}
</button>
</div>
</div>
<div class="grid">
Expand Down