refactor(main): audit warning suppression rules

This commit is contained in:
ZacharyZhang-NY committed 2026-04-22 19:16:22 -04:00
1 parent 0235bc9b0d
commit e43a89096d
5 files changed
+116 -59

No files matched your search

+1 -1
View File
@@ -1,4 +1,4 @@
import "./suppress-warnings";
import "./install-main-warning-suppressions";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { app } from "electron";
@@ -0,0 +1,18 @@
import {
classifyConsoleErrorSuppression,
classifyWarningSuppression,
} from "./main-warning-suppression-rules";
const originalEmitWarning = process.emitWarning.bind(process);
process.emitWarning = ((warning: unknown, ...rest: unknown[]) => {
if (classifyWarningSuppression(warning)) return;
return (originalEmitWarning as (...args: unknown[]) => void)(warning, ...rest);
}) as typeof process.emitWarning;
const originalConsoleError = console.error.bind(console);
console.error = ((...args: unknown[]) => {
if (classifyConsoleErrorSuppression(args)) return;
return originalConsoleError(...args);
}) as typeof console.error;
@@ -0,0 +1,53 @@
export type WarningSuppressionCategory =
| "node-sqlite-experimental-warning"
| "electron-disposed-web-frame-send";
interface SuppressionRule<TInput> {
category: WarningSuppressionCategory;
reason: string;
matches: (input: TInput) => boolean;
}
export const WARNING_SUPPRESSION_RULES: ReadonlyArray<SuppressionRule<unknown>> = [
{
category: "node-sqlite-experimental-warning",
reason: "Node emits this before the local SQLite profile store can run; the runtime version pins the API surface.",
matches: isSqliteExperimentalWarning,
},
];
export const CONSOLE_ERROR_SUPPRESSION_RULES: ReadonlyArray<SuppressionRule<unknown[]>> = [
{
category: "electron-disposed-web-frame-send",
reason: "Electron logs a send to a disposed renderer frame during close, reload, or HMR after the send has become a no-op.",
matches: isDisposedWebFrameSend,
},
];
export function classifyWarningSuppression(warning: unknown): WarningSuppressionCategory | null {
return WARNING_SUPPRESSION_RULES.find((rule) => rule.matches(warning))?.category ?? null;
}
export function classifyConsoleErrorSuppression(args: unknown[]): WarningSuppressionCategory | null {
return CONSOLE_ERROR_SUPPRESSION_RULES.find((rule) => rule.matches(args))?.category ?? null;
}
function isSqliteExperimentalWarning(warning: unknown): boolean {
if (typeof warning === "string") {
return /SQLite is an experimental feature/.test(warning);
}
if (warning instanceof Error) {
return warning.name === "ExperimentalWarning" && /SQLite/.test(warning.message);
}
return false;
}
function isDisposedWebFrameSend(args: unknown[]): boolean {
if (args.length === 0) return false;
const first = args[0];
if (typeof first !== "string") return false;
if (!first.startsWith("Error sending from webFrameMain")) return false;
const payload = args[1];
const message = payload instanceof Error ? payload.message : String(payload ?? "");
return message.includes("Render frame was disposed");
}
-58
View File
@@ -1,58 +0,0 @@
/**
* Silences two Electron/Node sources of stderr spam that are pure
* lifecycle noise, not logic bugs:
*
* 1. `node:sqlite` ExperimentalWarning on first import — emitted by the
* Node runtime itself. Must be installed before any module touches
* `node:sqlite`, or the warning has already fired.
*
* 2. `Error sending from webFrameMain:` — emitted by Electron's own
* `WebFrameMain.prototype.send` when the renderer frame was disposed
* mid-send (window close, dev HMR, reload). Electron catches the
* native exception internally and `console.error`s it; the send is
* already a no-op by the time our `webContents.send` returns, and
* nothing downstream reads the message. With every agent-event fan
* out producing two sends, a single dead renderer floods the log
* with thousands of copies and can stall the main event loop on
* synchronous stderr I/O. We filter only this specific prefix so
* real console errors still surface.
*
* Targeted: everything else passes through unchanged.
*/
const originalEmitWarning = process.emitWarning.bind(process);
function isSqliteExperimentalWarning(warning: unknown): boolean {
if (typeof warning === "string") {
return /SQLite is an experimental feature/.test(warning);
}
if (warning instanceof Error) {
return warning.name === "ExperimentalWarning" && /SQLite/.test(warning.message);
}
return false;
}
process.emitWarning = ((warning: unknown, ...rest: unknown[]) => {
if (isSqliteExperimentalWarning(warning)) return;
return (originalEmitWarning as (...args: unknown[]) => void)(warning, ...rest);
}) as typeof process.emitWarning;
const originalConsoleError = console.error.bind(console);
function isDisposedWebFrameNoise(args: unknown[]): boolean {
if (args.length === 0) return false;
const first = args[0];
if (typeof first !== "string") return false;
if (!first.startsWith("Error sending from webFrameMain")) return false;
// Only swallow when the accompanying error is the disposal signal;
// any other payload surfaces normally so genuine IPC failures still
// show up in logs.
const payload = args[1];
const message = payload instanceof Error ? payload.message : String(payload ?? "");
return message.includes("Render frame was disposed");
}
console.error = ((...args: unknown[]) => {
if (isDisposedWebFrameNoise(args)) return;
return originalConsoleError(...args);
}) as typeof console.error;