tinyexec

repository·main·Indexed 16 days ago

https://github.com/tinylibs/tinyexec

A minimal, lightweight wrapper around Node.js child processes designed to simplify command execution. It provides asynchronous (x, exec) and synchronous (xSync, execSync) execution, support for piping commands, real-time output iteration via async loops, and automatic PATH management for node_modules/.bin. Features include AbortSignal support, timeout configuration, and a NonZeroExitError for structured error handling when throwOnError is enabled.

Tokens
3.7K
Snippets
17
Records
19
Agent score
59%

What's inside tinyexec

  1. Access Node modules/binaries automatically

    main

    By default, tinyexec prepends node_modules/.bin and the current node executable's directory to PATH, allowing you to run locally installed binaries directly (e.g., eslint). To disable this behavior, set {nodePath: false} in the options.

    // Uses local node_modules/eslint
    await x('eslint', ['.']);
    
    // Disables automatic PATH prepending
    await x('eslint', ['.'], {nodePath: false});
  2. Pipe a process to another command

    main

    Use the .pipe() method to chain commands. The pipe method accepts the same options as a regular execution.

    const proc1 = x('ls', ['-l']);
    const proc2 = proc1.pipe('grep', ['.js']);
    const result = await proc2;
    
    console.log(result.stdout);
  3. Abort a process using AbortSignal

    main

    Pass an AbortSignal via the signal option. When the controller is aborted, the process is killed, and the aborted and killed properties on the result will be set to true.

    const aborter = new AbortController();
    const proc = x('node', ['./foo.mjs'], {
      signal: aborter.signal
    });
    
    // elsewhere...
    aborter.abort();
    
    await proc;
    
    proc.aborted; // true
    proc.killed; // true
  4. Iterate over process output lines

    main

    You can iterate over the lines of output (stdout and stderr combined in the order they appear) using an async loop on the object returned by x().

    import {x} from 'tinyexec';
    
    const proc = x('ls', ['-l']);
    
    for await (const line of proc) {
      // line will be from stderr/stdout in the order you'd see it in a term
    }
  5. Pass a string to stdin

    main

    To pass data to a process's standard input (useful for secrets or whitespace-sensitive values), use the stdin option.

    const result = await x('gh', ['auth', 'login', '--with-token'], {
      stdin: process.env.GITHUB_TOKEN
    });
    
    console.log(result.exitCode);
  6. Execute commands asynchronously with x()

    main

    Use the x function to spawn and await a child process. By default, tinyexec does not throw on non-zero exit codes; you should check result.exitCode or pass {throwOnError: true} in the options. Output is returned exactly as produced, including trailing newlines.

    import {x} from 'tinyexec';
    
    const result = await x('ls', ['-l']);
    
    // result.stdout - the stdout as a string
    // result.stderr - the stderr as a string
    // result.exitCode - the process exit code as a number
  7. Execute commands synchronously with xSync()

    main

    Use xSync for blocking, synchronous execution.

    Limitations of xSync: Because it blocks the event loop, the following features are not supported in the synchronous API:

    • signal (AbortSignal)
    • persist
    • kill() method
    • stdin piping
    • pipe() method

    Other options like timeout, throwOnError, and nodeOptions work as expected.

    import {xSync} from 'tinyexec';
    
    const result = xSync('ls', ['-l']);
    
    // result.stdout - the stdout as a string
    // result.stderr - the stderr as a string
    // result.exitCode - the process exit code as a number
    
    // You can also iterate over lines synchronously
    for (const line of result) {
      // from stdout then stderr
    }
  8. Configure execution options for tinyexec

    main

    Both async (x) and sync (xSync) functions accept an options object to control execution behavior.

    Common Options (Options / SyncOptions)

    • timeout: (number) Maximum time in milliseconds to allow the process to run before it is aborted.
    • throwOnError: (boolean) If true, throws a NonZeroExitError if the process exits with a non-zero code or is killed by a signal.
    • nodePath: (boolean) If true, adjusts the environment to ensure the correct Node.js path is used.

    Async Specific Options (Options)

    • signal: AbortSignal used to manually abort the process.
    • nodeOptions: SpawnOptions passed directly to Node's child_process.spawn (e.g., env, cwd).
    • persist: (boolean) If true, the process is detached (useful for background tasks).
    • stdin: Can be a string (to write to stdin immediately), a Result (to pipe from another process), or an ExecProcess.

    Sync Specific Options (SyncOptions)

    • nodeOptions: SpawnSyncOptions passed directly to Node's child_process.spawnSync.
  9. Configure execution with options

    main

    Pass an options object to x() to control process behavior. Available options include:

    • signal: An AbortSignal to allow aborting the execution.
    • timeout: Time in milliseconds at which the process will be forcibly killed.
    • persist: If true, the process will continue after the host exits.
    • stdin: A string or another Result to be used as input.
    • nodeOptions: Any valid options to Node's underlying spawn function.
    • throwOnError: If true, non-zero exit codes will throw an error.
    • nodePath: If false, node_modules/.bin and the current node executable's directory will not be prepended to PATH (defaults to true).
    await x('ls', [], {
      timeout: 1000
    });
  10. Result object API reference

    main

    The object returned by x() (an awaitable Result) provides the following properties and methods:

    • pipe(command[, args[, options]]): Pipes the current command to another command. command is the executable name without arguments.
    • process: The underlying Node.js ChildProcess. Use this for advanced access to streams and events.
    • kill([signal]): Kills the process with the specified signal (defaults to SIGTERM).
    • pid: The current process ID (number).
    • aborted: Boolean indicating if the process was aborted via an AbortSignal.
    • killed: Boolean indicating if the process was killed via kill() or an abort signal.
    • exitCode: The exit code of the completed process (number).
    const proc = x('node', ['./foo.mjs']);
    
    // Accessing underlying Node ChildProcess
    proc.process?.stdout?.on('data', (chunk) => { /* ... */ });
    
    // Accessing properties
    const pid = proc.pid;
    const code = proc.exitCode;