Skip to content

Commit 5494456

Browse files
committed
🤖 fix: prevent duplicate updater IPC handler registration
When window is recreated (e.g., clicking dock icon on macOS after closing all windows), createWindow() was trying to register the same IPC handlers again, causing 'Attempted to register a second handler' error. Added guard flag matching the pattern used by ipcMain.register(). _Generated with mux_
1 parent 5874155 commit 5494456

File tree

1 file changed

+38
-32
lines changed

1 file changed

+38
-32
lines changed

src/desktop/main.ts

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ let config: Config | null = null;
4444
let ipcMain: IpcMain | null = null;
4545
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
4646
let updaterService: typeof import("@/desktop/updater").UpdaterService.prototype | null = null;
47+
let updaterHandlersRegistered = false;
4748
const isE2ETest = process.env.MUX_E2E === "1";
4849
const forceDistLoad = process.env.MUX_E2E_LOAD_DIST === "1";
4950

@@ -377,42 +378,47 @@ function createWindow() {
377378
console.log(`[${timestamp()}] [window] Registering IPC handlers...`);
378379
ipcMain.register(electronIpcMain, mainWindow);
379380

380-
// Register updater IPC handlers (available in both dev and prod)
381-
electronIpcMain.handle(IPC_CHANNELS.UPDATE_CHECK, () => {
382-
// Note: log interface already includes timestamp and file location
383-
log.debug(`UPDATE_CHECK called (updaterService: ${updaterService ? "available" : "null"})`);
384-
if (!updaterService) {
385-
// Send "idle" status if updater not initialized (dev mode without DEBUG_UPDATER)
386-
if (mainWindow) {
387-
mainWindow.webContents.send(IPC_CHANNELS.UPDATE_STATUS, {
388-
type: "idle" as const,
389-
});
381+
// Register updater IPC handlers once (available in both dev and prod)
382+
// Guard prevents "Attempted to register a second handler" error when window is recreated
383+
if (!updaterHandlersRegistered) {
384+
updaterHandlersRegistered = true;
385+
386+
electronIpcMain.handle(IPC_CHANNELS.UPDATE_CHECK, () => {
387+
// Note: log interface already includes timestamp and file location
388+
log.debug(`UPDATE_CHECK called (updaterService: ${updaterService ? "available" : "null"})`);
389+
if (!updaterService) {
390+
// Send "idle" status if updater not initialized (dev mode without DEBUG_UPDATER)
391+
if (mainWindow) {
392+
mainWindow.webContents.send(IPC_CHANNELS.UPDATE_STATUS, {
393+
type: "idle" as const,
394+
});
395+
}
396+
return;
390397
}
391-
return;
392-
}
393-
log.debug("Calling updaterService.checkForUpdates()");
394-
updaterService.checkForUpdates();
395-
});
398+
log.debug("Calling updaterService.checkForUpdates()");
399+
updaterService.checkForUpdates();
400+
});
396401

397-
electronIpcMain.handle(IPC_CHANNELS.UPDATE_DOWNLOAD, async () => {
398-
if (!updaterService) throw new Error("Updater not available in development");
399-
await updaterService.downloadUpdate();
400-
});
402+
electronIpcMain.handle(IPC_CHANNELS.UPDATE_DOWNLOAD, async () => {
403+
if (!updaterService) throw new Error("Updater not available in development");
404+
await updaterService.downloadUpdate();
405+
});
401406

402-
electronIpcMain.handle(IPC_CHANNELS.UPDATE_INSTALL, () => {
403-
if (!updaterService) throw new Error("Updater not available in development");
404-
updaterService.installUpdate();
405-
});
407+
electronIpcMain.handle(IPC_CHANNELS.UPDATE_INSTALL, () => {
408+
if (!updaterService) throw new Error("Updater not available in development");
409+
updaterService.installUpdate();
410+
});
406411

407-
// Handle status subscription requests
408-
// Note: React StrictMode in dev causes components to mount twice, resulting in duplicate calls
409-
electronIpcMain.on(IPC_CHANNELS.UPDATE_STATUS_SUBSCRIBE, () => {
410-
log.debug("UPDATE_STATUS_SUBSCRIBE called");
411-
if (!mainWindow) return;
412-
const status = updaterService ? updaterService.getStatus() : { type: "idle" };
413-
log.debug("Sending current status to renderer:", status);
414-
mainWindow.webContents.send(IPC_CHANNELS.UPDATE_STATUS, status);
415-
});
412+
// Handle status subscription requests
413+
// Note: React StrictMode in dev causes components to mount twice, resulting in duplicate calls
414+
electronIpcMain.on(IPC_CHANNELS.UPDATE_STATUS_SUBSCRIBE, () => {
415+
log.debug("UPDATE_STATUS_SUBSCRIBE called");
416+
if (!mainWindow) return;
417+
const status = updaterService ? updaterService.getStatus() : { type: "idle" };
418+
log.debug("Sending current status to renderer:", status);
419+
mainWindow.webContents.send(IPC_CHANNELS.UPDATE_STATUS, status);
420+
});
421+
}
416422

417423
// Set up updater service with the main window (only in production)
418424
if (updaterService) {

0 commit comments

Comments
 (0)