Skip to content

Instantly share code, notes, and snippets.

@AceCodePt
Created September 18, 2025 12:37
Show Gist options
  • Select an option

  • Save AceCodePt/0e6beea05f1e1b5b62c1d9a835a3bb19 to your computer and use it in GitHub Desktop.

Select an option

Save AceCodePt/0e6beea05f1e1b5b62c1d9a835a3bb19 to your computer and use it in GitHub Desktop.
This is a prexit typescript implementation
declare global {
namespace NodeJS {
interface Process {
emit(event: "prexit", error?: Error): boolean;
}
}
}
export type PrexitSignal =
| "exit"
| "beforeExit"
| "uncaughtException"
| "unhandledRejection"
| "SIGTSTP"
| "SIGQUIT"
| "SIGHUP"
| "SIGTERM"
| "SIGINT";
export type PrexitCallback = (
signal: string,
error?: Error,
) => unknown | Promise<unknown>;
export type LastCallback = (signal: string) => void;
export interface Prexit {
(callback: PrexitCallback): void;
(signals: PrexitSignal | PrexitSignal[], callback: PrexitCallback): void;
signals: PrexitSignal[];
logExceptions: boolean;
exiting: boolean;
last(fn: LastCallback): void;
exit(code: number, error?: Error): void;
exit(signal?: string, code?: number, error?: Error): void;
ondone(signal: string, error?: Error): void;
}
const handlers: Record<string, PrexitCallback[]> = {};
const last: LastCallback[] = [];
let finished = false;
const prexit: Prexit = (
signalsOrFn: PrexitSignal | PrexitSignal[] | PrexitCallback,
fn?: PrexitCallback,
) => {
let signals: string | string[] = prexit.signals;
let callback: PrexitCallback;
if (typeof signalsOrFn === "function") {
callback = signalsOrFn;
} else {
if (!fn) {
throw new Error(
"A callback function must be provided when specifying signals.",
);
}
callback = fn;
signals = signalsOrFn;
}
let called = false;
const signalList: string[] = ["prexit"].concat(signals);
signalList.forEach((signal) =>
handle(signal, (signal, error) => {
if (called) return;
called = true;
return callback(signal, error);
}),
);
};
prexit.signals = [
"exit",
"beforeExit",
"uncaughtException",
"unhandledRejection",
"SIGTSTP",
"SIGQUIT",
"SIGHUP",
"SIGTERM",
"SIGINT",
];
prexit.logExceptions = true;
prexit.exiting = false;
prexit.last = function addLast(fn: LastCallback): void {
if (last.length === 0) {
prexit(() => {});
}
last.push(fn);
};
function exit(signal?: PrexitSignal, code?: number): void;
function exit(code: number): void;
function exit(
signalOrCode?: PrexitSignal | number,
codeOrError?: number | Error,
error?: Error,
): void {
let code: number | undefined;
let finalError: Error | undefined;
if (typeof signalOrCode === "number") {
finalError = codeOrError as Error | undefined;
code = signalOrCode;
} else {
code = codeOrError as number | undefined;
finalError = error;
}
if (code !== undefined) {
process.exitCode = code;
}
if (Object.keys(handlers).length > 0) {
process.emit("prexit", finalError);
} else {
process.exit();
}
}
prexit.exit = exit;
prexit.ondone = function ondone(_signal: string, _error?: Error): void {
process.exit();
};
function handle(signal: string, fn: PrexitCallback): void {
const existingFns = handlers[signal];
if (existingFns) {
existingFns.push(fn);
return;
}
const fns = (handlers[signal] = [fn]);
process.on(signal, async (errorOrSignalValue: Error | any) => {
prexit.exiting = true;
if (errorOrSignalValue === signal) {
errorOrSignalValue = null;
}
const error =
errorOrSignalValue instanceof Error ? errorOrSignalValue : undefined;
if (
(signal === "uncaughtException" || signal === "unhandledRejection") &&
prexit.logExceptions
) {
console.error(errorOrSignalValue);
}
try {
const promises = fns
.map((fn) => fn(signal, error))
.filter((p): p is Promise<unknown> => p instanceof Promise);
if (promises.length > 0) {
await Promise.all(promises);
}
} catch (err: any) {
if (process.exitCode === undefined) {
process.exitCode = 1;
}
if (prexit.logExceptions) {
console.error(err);
}
}
done(signal, error);
});
}
function done(signal: string, error?: Error): void {
if (finished) return;
finished = true;
let finalError = error;
try {
last.forEach((fn) => fn(signal));
} catch (err: any) {
if (finalError) {
console.error(err);
} else {
finalError = err;
}
}
prexit.ondone(signal, finalError);
}
export default prexit;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment