Files
2026-07-13 13:08:41 +08:00

101 lines
2.4 KiB
TypeScript

import { format } from "util";
type WritableStream = NodeJS.WriteStream & {
closed?: boolean;
destroyed?: boolean;
writable?: boolean;
writableEnded?: boolean;
writableFinished?: boolean;
};
let installed = false;
const originalConsoleError = console.error.bind(console);
export function isIgnorablePipeError(error: unknown): boolean {
const err = error as NodeJS.ErrnoException | undefined;
const code = typeof err?.code === "string" ? err.code : "";
const message = error instanceof Error ? error.message : String(error ?? "");
return (
code === "EPIPE" ||
code === "ERR_STREAM_DESTROYED" ||
code === "ERR_STREAM_WRITE_AFTER_END" ||
/broken pipe/i.test(message) ||
/write after end/i.test(message) ||
/stream has been destroyed/i.test(message)
);
}
function isWritable(stream: WritableStream): boolean {
return (
stream.writable !== false &&
!stream.closed &&
!stream.destroyed &&
!stream.writableEnded &&
!stream.writableFinished
);
}
function reportUnexpectedStreamError(error: unknown): void {
if (isIgnorablePipeError(error)) {
return;
}
try {
originalConsoleError("[SafeConsole] stdout/stderr stream error:", error);
} catch {
/* If the console itself is unavailable, there is nowhere useful to report this. */
}
}
function writeToStream(stream: WritableStream, text: string): boolean {
if (!isWritable(stream)) {
return false;
}
try {
return stream.write(text, (error?: Error | null) => {
if (error) {
reportUnexpectedStreamError(error);
}
});
} catch (error) {
reportUnexpectedStreamError(error);
return false;
}
}
export function safeStdoutWrite(text: string): boolean {
return writeToStream(process.stdout, text);
}
export function safeStderrWrite(text: string): boolean {
return writeToStream(process.stderr, text);
}
export function safeLog(...args: unknown[]): void {
safeStdoutWrite(`${format(...args)}\n`);
}
export function safeWarn(...args: unknown[]): void {
safeStderrWrite(`${format(...args)}\n`);
}
export function safeError(...args: unknown[]): void {
safeStderrWrite(`${format(...args)}\n`);
}
export function installSafeConsole(): void {
if (installed) {
return;
}
installed = true;
process.stdout.on("error", reportUnexpectedStreamError);
process.stderr.on("error", reportUnexpectedStreamError);
console.log = safeLog;
console.warn = safeWarn;
console.error = safeError;
}