Skip to content
Merged
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
5 changes: 4 additions & 1 deletion desktop/src/main/__tests__/updater.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ const electronUpdaterMock = {
},
}

vi.mock("electron-updater", () => electronUpdaterMock)
vi.mock("electron-updater", () => ({
...electronUpdaterMock,
default: electronUpdaterMock,
}))
vi.mock("electron", () => ({
app: {
isPackaged: true,
Expand Down
11 changes: 11 additions & 0 deletions desktop/src/main/ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
checkForUpdatesWithChannel,
downloadUpdate,
getAutoDownloadEnabled,
getLastStatus,
getReleaseChannel,
installUpdate,
setAutoDownloadEnabled,
Expand Down Expand Up @@ -808,6 +809,16 @@ export function registerIpcHandlers(deps: IpcDependencies): { tunnelProcesses: M
await checkForUpdates()
})

// Deferred so the renderer's update-status listener (registered after this
// call resolves) is attached before the replay arrives.
ipcMain.handle("app_ready", (event) => {
setImmediate(() => {
if (!event.sender.isDestroyed()) {
event.sender.send("update-status", getLastStatus())
}
})
})

ipcMain.handle("install_update", async () => {
installUpdate()
})
Expand Down
29 changes: 22 additions & 7 deletions desktop/src/main/updater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,15 @@ export function getLastStatus(): UpdateStatus {
}

function normalizeReleaseNotes(
notes: string | { note: string }[] | null | undefined,
notes: string | { note: string | null }[] | null | undefined,
): string | undefined {
if (!notes) return undefined
if (typeof notes === "string") return notes
if (Array.isArray(notes)) return notes.map((n) => n.note).join("\n")
if (Array.isArray(notes))
return notes
.map((n) => n.note)
.filter((n): n is string => !!n)
.join("\n")
return undefined
}

Expand All @@ -119,16 +123,27 @@ export function setAutoDownloadEnabled(enabled: boolean): void {
// Update the live autoUpdater too so the change takes effect this session.
// electron-updater reads autoDownload at the moment update-available fires.
if (app.isPackaged) {
import("electron-updater")
.then(({ autoUpdater }) => {
if (autoUpdater && typeof autoUpdater === "object") {
loadAutoUpdater()
.then((autoUpdater) => {
if (autoUpdater) {
autoUpdater.autoDownload = enabled
}
})
.catch(() => {})
}
}

// electron-updater exposes `autoUpdater` via a CJS getter that Node's
// cjs-module-lexer doesn't surface as a named export under ESM. We have to
// reach it through `default` (the CJS module.exports), which invokes the
// getter and returns the platform-specific updater instance.
async function loadAutoUpdater(): Promise<
(typeof import("electron-updater"))["autoUpdater"] | null
> {
const mod = await import("electron-updater")
return mod.default?.autoUpdater ?? mod.autoUpdater ?? null
}

export function getAutoDownloadEnabled(): boolean {
return autoDownloadEnabled
}
Expand All @@ -147,7 +162,7 @@ export async function initAutoUpdater(
return
}

const { autoUpdater } = await import("electron-updater")
const autoUpdater = await loadAutoUpdater()

if (!autoUpdater || typeof autoUpdater.checkForUpdates !== "function") {
setStatus({
Expand Down Expand Up @@ -230,7 +245,7 @@ async function getUpdater() {
setStatus({ state: "not-available", code: "dev-mode" })
return null
}
const { autoUpdater } = await import("electron-updater")
const autoUpdater = await loadAutoUpdater()
if (!autoUpdater || typeof autoUpdater.checkForUpdates !== "function") {
setStatus({
state: "error",
Expand Down
Loading