diff --git a/main.js b/main.js index 16327985..00f2b0fd 100644 --- a/main.js +++ b/main.js @@ -23,6 +23,35 @@ const webapps = require("./webapps"); // them, so a write that cannot land is not an error worth stopping for. for (const stream of [process.stdout, process.stderr]) stream.on("error", () => {}); +// Node's ws turns "closed while still connecting" into a crash: close() on a +// CONNECTING socket aborts the handshake and emits an error on the next tick, +// and an error event with no listener is an uncaught exception. Browser +// WebSockets shrug the same thing off, so libraries written for both do it — +// nostr-tools drops its onerror handler and then closes the socket, which is +// what the WizardConnect relay teardown in Aegis runs on every wallet +// disconnect. Seen 2026-09-27 as the "JavaScript error occurred in the main +// process" dialog. Every consumer in this process (messenger, add-ons, +// WizardConnect via isomorphic-ws) shares this one ws module, so guard it here. +{ + const close = WebSocket.prototype.close; + WebSocket.prototype.close = function (...args) { + if (this.readyState === WebSocket.CONNECTING && this.listenerCount("error") === 0) this.once("error", () => {}); + return close.apply(this, args); + }; +} +// Anything else that escapes to the top of the main process: Electron would +// show a modal "JavaScript error occurred in the main process" and carry on. +// Carry on without the modal, and keep the report where it can be found. +process.on("uncaughtException", (err) => { + const line = `[${new Date().toISOString()}] uncaught: ${(err && err.stack) || err}\n`; + try { console.error(line); } catch {} + try { + const f = path.join(app.getPath("userData"), "main-errors.log"); + try { if (fs.statSync(f).size > 512 * 1024) fs.truncateSync(f, 0); } catch {} + fs.appendFileSync(f, line); + } catch {} +}); + // Packaged builds ship the resolver and tor/ as unpacked resources (they can't // run from inside app.asar); dev runs read them from the repo. const RES_DIR = app.isPackaged ? process.resourcesPath : __dirname;