Add in-app updater: check Gitea releases, show changelog, download + run installer
A new Settings → "Software update" card lets users update AeroFetch from inside the app: - src/main/updater.ts — queries the configured Gitea repo's latest release over the public REST API, compares the tag to app.getVersion(), and (on request) streams the installer asset to the OS temp dir with progress events, then launches it and quits so it can replace the app. - Security: only the trusted update host over HTTPS is ever downloaded from, and only a freshly-downloaded .exe inside our temp dir is ever executed — the download URL from the release JSON can't redirect us elsewhere. No token is ever shipped; the source repo must be anonymously readable (public). - IPC: app:update-check / -download / -run + an -progress push channel, exposed via preload (checkForAppUpdate / downloadAppUpdate / runAppUpdate / onAppUpdateProgress). - UI: "Check for updates" → shows the new version and its release notes, then "Update now" (with a download progress bar) or "View release". Up-to-date and error states handled. Preview mock added so the flow is exercisable in `npm run ui`. Note: the update source repo/host are constants at the top of updater.ts (currently debont80/AeroFetch). Downloads work once the release repo is public and the Gitea instance allows anonymous API + asset access. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
import { contextBridge, ipcRenderer, type IpcRendererEvent } from 'electron'
|
||||
import {
|
||||
IpcChannels,
|
||||
type AppUpdateInfo,
|
||||
type AppUpdateDownload,
|
||||
type AppUpdateProgress,
|
||||
type YtdlpVersionResult,
|
||||
type YtdlpUpdateChannel,
|
||||
type YtdlpUpdateResult,
|
||||
@@ -31,6 +34,24 @@ const api = {
|
||||
/** AeroFetch's own version string (e.g. '0.3.1'). */
|
||||
getAppVersion: (): Promise<string> => ipcRenderer.invoke(IpcChannels.appVersion),
|
||||
|
||||
/** Check the configured Gitea repo for a newer AeroFetch release. */
|
||||
checkForAppUpdate: (): Promise<AppUpdateInfo> => ipcRenderer.invoke(IpcChannels.appUpdateCheck),
|
||||
|
||||
/** Download the latest release's installer to a temp file. */
|
||||
downloadAppUpdate: (url: string): Promise<AppUpdateDownload> =>
|
||||
ipcRenderer.invoke(IpcChannels.appUpdateDownload, url),
|
||||
|
||||
/** Launch a downloaded installer and quit so it can replace the app. */
|
||||
runAppUpdate: (filePath: string): Promise<{ ok: boolean; error?: string }> =>
|
||||
ipcRenderer.invoke(IpcChannels.appUpdateRun, filePath),
|
||||
|
||||
/** Subscribe to installer download progress. Returns an unsubscribe function. */
|
||||
onAppUpdateProgress: (cb: (p: AppUpdateProgress) => void): (() => void) => {
|
||||
const listener = (_e: IpcRendererEvent, p: AppUpdateProgress): void => cb(p)
|
||||
ipcRenderer.on(IpcChannels.appUpdateProgress, listener)
|
||||
return () => ipcRenderer.removeListener(IpcChannels.appUpdateProgress, listener)
|
||||
},
|
||||
|
||||
getYtdlpVersion: (): Promise<YtdlpVersionResult> =>
|
||||
ipcRenderer.invoke(IpcChannels.ytdlpVersion),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user