@@ -44,6 +44,7 @@ let config: Config | null = null;
4444let ipcMain : IpcMain | null = null ;
4545// eslint-disable-next-line @typescript-eslint/consistent-type-imports
4646let updaterService : typeof import ( "@/desktop/updater" ) . UpdaterService . prototype | null = null ;
47+ let updaterHandlersRegistered = false ;
4748const isE2ETest = process . env . MUX_E2E === "1" ;
4849const 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