refactor(app-updater): split AppUpdater.tsx into focused modules (#681)

Extract the GitHub release probe, download/relaunch state and the markdown
changelog renderer out of AppUpdater.tsx:

- utils/appUpdaterHelpers.ts   isNewer, fmtBytes, pickAsset, types
- hooks/useAppUpdater.ts        release probe + download/relaunch handlers
- components/appUpdater/Changelog.tsx

Pure code-move, no behaviour change. The AppShell call site is unchanged.
This commit is contained in:
Frank Stellmacher
2026-05-14 12:12:16 +02:00
committed by GitHub
parent cca000d3af
commit b89b5d7c94
4 changed files with 312 additions and 278 deletions
+53
View File
@@ -0,0 +1,53 @@
import { IS_LINUX, IS_MACOS, IS_WINDOWS } from './platform';
export const SKIP_KEY = 'psysonic_skipped_update_version';
// Semver comparison: returns true if `a` is newer than `b`
export function isNewer(a: string, b: string): boolean {
const pa = a.replace(/^[^0-9]*/, '').split('.').map(Number);
const pb = b.replace(/^[^0-9]*/, '').split('.').map(Number);
for (let i = 0; i < 3; i++) {
if ((pa[i] ?? 0) > (pb[i] ?? 0)) return true;
if ((pa[i] ?? 0) < (pb[i] ?? 0)) return false;
}
return false;
}
export function fmtBytes(n: number): string {
if (n < 1024 * 1024) return `${(n / 1024).toFixed(0)} KB`;
return `${(n / 1024 / 1024).toFixed(1)} MB`;
}
export interface GithubAsset {
name: string;
browser_download_url: string;
size: number;
}
export interface ReleaseData {
version: string;
tag: string;
body: string;
assets: GithubAsset[];
}
export type DlState = 'idle' | 'downloading' | 'done' | 'error';
export function pickAsset(assets: GithubAsset[]): GithubAsset | undefined {
if (IS_WINDOWS) {
return assets.find(a => a.name.endsWith('-setup.exe'))
?? assets.find(a => a.name.endsWith('.exe'));
}
if (IS_MACOS) {
// Prefer Apple Silicon, fall back to Intel
return assets.find(a => a.name.endsWith('.dmg') && a.name.includes('aarch64'))
?? assets.find(a => a.name.endsWith('.dmg'));
}
if (IS_LINUX) {
// AppImage > deb > rpm
return assets.find(a => a.name.endsWith('.AppImage'))
?? assets.find(a => a.name.endsWith('.deb'))
?? assets.find(a => a.name.endsWith('.rpm'));
}
return undefined;
}