Documentation for Simbo's Packages
    Preparing search index...

    Module @simbo/graceful-exit - v1.1.0

    Graceful Exit

    📦 @simbo/graceful-exit

    Gracefully terminate a Node.js process with predictable exit codes, clear console output, and optional teardown steps.

    It distinguishes between numeric exit codes, user‑initiated cancellations (e.g., Inquirer’s ExitPromptError), user‑facing errors with hints, and unknown errors.

    • âś… Simple API: gracefulExit(error?, exitCode?) returns Promise<never> and exits the process.

    • đź§ą Teardown support: Run any number of sync/async cleanup steps before exiting.

    • đź§­ Smart exit codes:

      • Uses the explicit exitCode argument if provided.
      • Else, if error is a non‑zero number, uses that.
      • Else, 1 when exiting due to an error, 0 when clean.
    • 🗣️ User‑friendly output: Pretty console messages via @simbo/cli-output helpers.

    • 🙋 Special cases handled:

      • Inquirer's ExitPromptError → prints a "Prompt Cancelled" message.
      • UserFacingError → prints message and an optional hint (custom or default).
      • Unknown values → passed through stringifyError().

    Install @simbo/graceful-exit from the npm registry:

    npm i [-D] @simbo/graceful-exit
    

    For a complete API reference, see the documentation.

    import { gracefulExit } from '@simbo/graceful-exit';

    try {
    // Your code …
    if (shouldExitEarly) {
    await gracefulExit(); // exits with code 0
    }

    // … more work

    await gracefulExit(); // exits with code 0
    } catch (error) {
    await gracefulExit(error); // exits with code 1
    }
    await gracefulExit(new Error('Fatal'), 2); // prints error, exits with code 2
    await gracefulExit(undefined, 2); // no output, exits with code 2

    Register cleanup steps that run before the process exits.

    import { gracefulExit } from '@simbo/graceful-exit';
    import {
    onTeardown,
    offTeardown,
    type TeardownStep,
    } from '@simbo/graceful-exit/teardown';

    // Teardown may be sync or async:
    const closeDatabase: TeardownStep = async () => database.close();

    const trackExit: TeardownStep = async (error?: unknown, code?: number) =>
    (error || code) && (await metrics.trackExit(error, code));

    const sayGoodbye: TeardownStep = () => console.log('Goodbye!');

    // Register the teardown steps:
    onTeardown(closeDatabase);
    onTeardown(trackExit);
    onTeardown(sayGoodbye);

    // Now steps will be called on any graceful exit.

    try {
    // …work
    // Optionally remove a teardown step:
    if (condition) {
    offTeardown(trackExit);
    }
    await gracefulExit();
    } catch (error) {
    await gracefulExit(error);
    }

    Steps are stored in a Set and executed in registration order.

    Note


    If any teardown step fails during an otherwise successful exit (code 0), the exit code is switched to 1 and the error is logged.

    await gracefulExit(2);
    // → prints "Exiting. (Error #2)" and exits with 2

    await gracefulExit(new Error('Oops'));
    // → pretty‑printed via stringifyError

    import { UserFacingError } from '@simbo/user-facing-error';
    await gracefulExit(
    new UserFacingError('Invalid input', 'Use --help for usage'),
    );
    // → prints message + hint

    // Inquirer cancellation (ExitPromptError)
    import { ExitPromptError } from '@inquirer/core';
    const e = new ExitPromptError();
    await gracefulExit(e);
    // → prints "Prompt Cancelled" and exits with 1

    MIT © Simon Lepel

    Modules

    teardown