Files
ChatApp/apps/desktop/src/lib/appUpdates.ts
T
byGalax 825160ee46 feat(desktop): port v0.11.4-v0.15.2 from Tauri to Electron + Discord-parity audio (v0.16.0)
Chronological port of every Tauri release commit (v0.11.4 -> v0.15.2)
into the Electron rebuild, plus Discord-style audio handling that goes
beyond the Tauri original.

Highlights:
  - All 17 Tauri release commits ported (audio fixes, custom notification
    sound, Discord-style chat UX, profile banner, changelog page,
    Discord-parity call UX, screen-share echo + re-watch UX, audio-loop
    fix).
  - Native napi-rs audio-loopback addon with WASAPI process-loopback:
      * EXCLUDE_TARGET_PROCESS_TREE for full-screen shares -> peers
        never hear themselves echoed back through the capture.
      * INCLUDE_TARGET_PROCESS_TREE for window shares -> only the
        picked window's audio is captured, not the whole OS mixer
        (Discord parity).
      * HWND -> PID resolution via Win32 GetWindowThreadProcessId.
  - Discord-style screen-source picker (thumbnail grid, screens vs
    apps tabs, live-refreshing thumbnails).
  - Hash routing fix for packaged builds (file:// can't resolve
    BrowserRouter paths).
  - Tauri sources removed (apps/desktop/src-tauri).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 23:35:01 +02:00

83 lines
2.3 KiB
TypeScript

import { isTauriRuntime } from './globalShortcut';
export interface UpdateState {
available: boolean;
version: string | null;
notes: string | null;
downloading: boolean;
downloaded: boolean;
error: string | null;
}
export const IDLE_UPDATE_STATE: UpdateState = {
available: false,
version: null,
notes: null,
downloading: false,
downloaded: false,
error: null,
};
// Module-local flag: main owns the real "pending update" state via
// electron-updater, but the renderer also needs to refuse installUpdate()
// calls that weren't preceded by a successful checkForUpdate().
let hasPendingUpdate = false;
export async function checkForUpdate(): Promise<UpdateState> {
if (!isTauriRuntime()) {
return { ...IDLE_UPDATE_STATE };
}
try {
const result = await window.electronAPI.checkForUpdate();
if (!result.available || !result.info) {
hasPendingUpdate = false;
return { ...IDLE_UPDATE_STATE };
}
hasPendingUpdate = true;
return {
available: true,
version: result.info.version ?? null,
notes: result.info.releaseNotes ?? null,
downloading: false,
downloaded: false,
error: null,
};
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
const benign =
/could not fetch a valid release json|network|timed? out|failed to fetch|connection|enotfound|econnreset|etimedout|404/i.test(
msg,
);
if (!benign) {
console.warn('checkForUpdate failed', err);
}
return {
...IDLE_UPDATE_STATE,
error: benign ? null : msg,
};
}
}
// Downloads + installs the previously checked update. On Windows the
// app quits during install (passive installer); electron-updater
// triggers a relaunch on macOS/Linux.
export async function installUpdate(
onProgress?: (downloaded: number, total: number | null) => void,
): Promise<void> {
if (!hasPendingUpdate) {
throw new Error('no pending update — call checkForUpdate() first');
}
let unsub: (() => void) | null = null;
if (onProgress) {
unsub = window.electronAPI.onUpdaterProgress((p) => {
onProgress(p.transferred, p.total || null);
});
}
try {
await window.electronAPI.downloadInstallUpdate();
} finally {
unsub?.();
hasPendingUpdate = false;
}
}