Fix WebSocket crash + heartbeat default 10min + docs refresh
- Wrap Baileys connection.update listeners in try-catch to prevent unhandled exceptions from crashing the relay process - Add WebSocket-level error handlers in session.ts - Add global unhandledRejection/uncaughtException handlers in index.ts - Make listener.onClose error-safe with .catch() in auto-reply.ts - Change default heartbeat from 30min to 10min - Rewrite claude-config.md with personality, better explain personal assistant features, add recommended MCPs section
This commit is contained in:
18
src/index.ts
18
src/index.ts
@@ -117,5 +117,23 @@ const isMain =
|
||||
process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1];
|
||||
|
||||
if (isMain) {
|
||||
// Global error handlers to prevent silent crashes from unhandled rejections/exceptions.
|
||||
// These log the error and exit gracefully instead of crashing without trace.
|
||||
process.on("unhandledRejection", (reason, promise) => {
|
||||
console.error(
|
||||
"[warelay] Unhandled promise rejection:",
|
||||
reason instanceof Error ? reason.stack ?? reason.message : reason,
|
||||
);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
process.on("uncaughtException", (error) => {
|
||||
console.error(
|
||||
"[warelay] Uncaught exception:",
|
||||
error.stack ?? error.message,
|
||||
);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
program.parseAsync(process.argv);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ export type WebMonitorTuning = {
|
||||
const formatDuration = (ms: number) =>
|
||||
ms >= 1000 ? `${(ms / 1000).toFixed(2)}s` : `${ms}ms`;
|
||||
|
||||
const DEFAULT_REPLY_HEARTBEAT_MINUTES = 30;
|
||||
const DEFAULT_REPLY_HEARTBEAT_MINUTES = 10;
|
||||
export const HEARTBEAT_TOKEN = "HEARTBEAT_OK";
|
||||
export const HEARTBEAT_PROMPT = "HEARTBEAT ultrathink";
|
||||
|
||||
@@ -758,7 +758,13 @@ export async function monitorWebProvider(
|
||||
}
|
||||
|
||||
const reason = await Promise.race([
|
||||
listener.onClose ?? waitForever(),
|
||||
listener.onClose?.catch((err) => {
|
||||
reconnectLogger.error(
|
||||
{ error: String(err) },
|
||||
"listener.onClose rejected",
|
||||
);
|
||||
return { status: 500, isLoggedOut: false, error: err };
|
||||
}) ?? waitForever(),
|
||||
abortPromise ?? waitForever(),
|
||||
]);
|
||||
|
||||
|
||||
@@ -165,12 +165,24 @@ export async function monitorWebInbox(options: {
|
||||
sock.ev.on(
|
||||
"connection.update",
|
||||
(update: Partial<import("@whiskeysockets/baileys").ConnectionState>) => {
|
||||
if (update.connection === "close") {
|
||||
const status = getStatusCode(update.lastDisconnect?.error);
|
||||
try {
|
||||
if (update.connection === "close") {
|
||||
const status = getStatusCode(update.lastDisconnect?.error);
|
||||
onCloseResolve?.({
|
||||
status,
|
||||
isLoggedOut: status === DisconnectReason.loggedOut,
|
||||
error: update.lastDisconnect?.error,
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
inboundLogger.error(
|
||||
{ error: String(err) },
|
||||
"connection.update handler error",
|
||||
);
|
||||
onCloseResolve?.({
|
||||
status,
|
||||
isLoggedOut: status === DisconnectReason.loggedOut,
|
||||
error: update.lastDisconnect?.error,
|
||||
status: undefined,
|
||||
isLoggedOut: false,
|
||||
error: err,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -57,29 +57,45 @@ export async function createWaSocket(printQr: boolean, verbose: boolean) {
|
||||
markOnlineOnConnect: false,
|
||||
});
|
||||
|
||||
const sessionLogger = getChildLogger({ module: "web-session" });
|
||||
|
||||
sock.ev.on("creds.update", saveCreds);
|
||||
sock.ev.on(
|
||||
"connection.update",
|
||||
(update: Partial<import("@whiskeysockets/baileys").ConnectionState>) => {
|
||||
const { connection, lastDisconnect, qr } = update;
|
||||
if (qr && printQr) {
|
||||
console.log("Scan this QR in WhatsApp (Linked Devices):");
|
||||
qrcode.generate(qr, { small: true });
|
||||
}
|
||||
if (connection === "close") {
|
||||
const status = getStatusCode(lastDisconnect?.error);
|
||||
if (status === DisconnectReason.loggedOut) {
|
||||
console.error(
|
||||
danger("WhatsApp session logged out. Run: warelay login"),
|
||||
);
|
||||
try {
|
||||
const { connection, lastDisconnect, qr } = update;
|
||||
if (qr && printQr) {
|
||||
console.log("Scan this QR in WhatsApp (Linked Devices):");
|
||||
qrcode.generate(qr, { small: true });
|
||||
}
|
||||
}
|
||||
if (connection === "open" && verbose) {
|
||||
console.log(success("WhatsApp Web connected."));
|
||||
if (connection === "close") {
|
||||
const status = getStatusCode(lastDisconnect?.error);
|
||||
if (status === DisconnectReason.loggedOut) {
|
||||
console.error(
|
||||
danger("WhatsApp session logged out. Run: warelay login"),
|
||||
);
|
||||
}
|
||||
}
|
||||
if (connection === "open" && verbose) {
|
||||
console.log(success("WhatsApp Web connected."));
|
||||
}
|
||||
} catch (err) {
|
||||
sessionLogger.error(
|
||||
{ error: String(err) },
|
||||
"connection.update handler error",
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Handle WebSocket-level errors to prevent unhandled exceptions from crashing the process
|
||||
if (sock.ws) {
|
||||
sock.ws.on("error", (err: Error) => {
|
||||
sessionLogger.error({ error: String(err) }, "WebSocket error");
|
||||
});
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user