@@ -14,6 +14,23 @@ const { registerIpcHandlers } = require("./ipc-handlers");
1414const { setMenuLanguage, mt } = require ( "./menu-i18n" ) ;
1515const isDev = process . env . NODE_ENV === "development" ;
1616
17+ // Global safety net: log (and, if telemetry is on, report) any promise
18+ // rejection or exception that escaped a local handler instead of letting Node
19+ // crash the process. Registered before any async startup work runs. Notably
20+ // this catches rejections from the auto-updater (Squirrel.Mac) code paths.
21+ process . on ( "unhandledRejection" , ( reason ) => {
22+ console . error ( "[Main] Unhandled promise rejection:" , reason ) ;
23+ if ( typeof Sentry !== "undefined" && isTelemetryEnabled ( ) ) {
24+ Sentry . captureException ( reason ) ;
25+ }
26+ } ) ;
27+ process . on ( "uncaughtException" , ( error ) => {
28+ console . error ( "[Main] Uncaught exception:" , error ) ;
29+ if ( typeof Sentry !== "undefined" && isTelemetryEnabled ( ) ) {
30+ Sentry . captureException ( error ) ;
31+ }
32+ } ) ;
33+
1734// Telemetry (Sentry error reporting) is OPT-IN. It is only initialized when the
1835// user turned on "Crash & error reporting" in Settings (persisted as
1936// `telemetryEnabled` in the Electron config). See initTelemetryMain().
@@ -79,6 +96,16 @@ autoUpdater.on("error", (err) => {
7996 console . error ( "[AutoUpdater] Error:" , err ) ;
8097} ) ;
8198
99+ // Trigger the installer relaunch. This is the Squirrel.Mac crash site, so guard
100+ // it: a synchronous throw here must not take down the click handler / process.
101+ const quitAndInstall = ( ) => {
102+ try {
103+ autoUpdater . quitAndInstall ( ) ;
104+ } catch ( err ) {
105+ console . error ( "[AutoUpdater] quitAndInstall failed:" , err ) ;
106+ }
107+ } ;
108+
82109let mainWindow ;
83110let splashWindow = null ;
84111let goProcess = null ;
@@ -756,7 +783,7 @@ function updateTrayMenu() {
756783 ? [
757784 {
758785 label : mt ( "restartToUpdate" ) ,
759- click : ( ) => autoUpdater . quitAndInstall ( ) ,
786+ click : ( ) => quitAndInstall ( ) ,
760787 } ,
761788 ]
762789 : [ ] ) ,
@@ -1033,7 +1060,7 @@ function createMenu() {
10331060 ? [
10341061 {
10351062 label : mt ( "restartToUpdate" ) ,
1036- click : ( ) => autoUpdater . quitAndInstall ( ) ,
1063+ click : ( ) => quitAndInstall ( ) ,
10371064 } ,
10381065 ]
10391066 : [ ] ) ,
@@ -1087,28 +1114,41 @@ app.whenReady().then(async () => {
10871114 createWindow ( ) ;
10881115
10891116 // Check for updates after launch
1090- autoUpdater . checkForUpdatesAndNotify ( ) ;
1117+ autoUpdater . checkForUpdatesAndNotify ( ) . catch ( ( err ) => {
1118+ console . error ( "[AutoUpdater] checkForUpdatesAndNotify failed:" , err ) ;
1119+ } ) ;
10911120
10921121 // Re-check for updates every hour for long-running sessions
1093- setInterval ( ( ) => autoUpdater . checkForUpdates ( ) , 60 * 60 * 1000 ) ;
1122+ setInterval ( ( ) => {
1123+ autoUpdater . checkForUpdates ( ) . catch ( ( err ) => {
1124+ console . error ( "[AutoUpdater] periodic checkForUpdates failed:" , err ) ;
1125+ } ) ;
1126+ } , 60 * 60 * 1000 ) ;
10941127
10951128 app . on ( "activate" , async ( ) => {
1096- // On macOS, re-create a window when the dock icon is clicked
1097- if ( BrowserWindow . getAllWindows ( ) . length === 0 ) {
1098- // Ensure backend is running
1099- if ( ! goProcess ) {
1100- launchGoBinary ( ) ;
1101- await waitForBackend ( ) ;
1102- } else {
1103- // Process exists but might not be listening yet
1104- await waitForBackend ( 10 , 500 ) ;
1129+ // On macOS, re-create a window when the dock icon is clicked. Electron
1130+ // discards the promise returned by this async listener, so guard it here.
1131+ try {
1132+ if ( BrowserWindow . getAllWindows ( ) . length === 0 ) {
1133+ // Ensure backend is running
1134+ if ( ! goProcess ) {
1135+ launchGoBinary ( ) ;
1136+ await waitForBackend ( ) ;
1137+ } else {
1138+ // Process exists but might not be listening yet
1139+ await waitForBackend ( 10 , 500 ) ;
1140+ }
1141+ createWindow ( ) ;
1142+ } else if ( mainWindow ) {
1143+ // If window exists but is hidden, show it
1144+ showMainWindow ( ) ;
11051145 }
1106- createWindow ( ) ;
1107- } else if ( mainWindow ) {
1108- // If window exists but is hidden, show it
1109- showMainWindow ( ) ;
1146+ } catch ( err ) {
1147+ console . error ( "[Main] activate handler failed:" , err ) ;
11101148 }
11111149 } ) ;
1150+ } ) . catch ( ( err ) => {
1151+ console . error ( "[Main] Startup (whenReady) failed:" , err ) ;
11121152} ) ;
11131153
11141154// Keep app running in menu bar even when all windows are closed
0 commit comments