Source: utils/abortHelper.js

/**
 * @module utils/abortHelper
 * @description Shared abort-signal utilities for the pipeline and runner.
 *
 * Centralises the abort-check pattern so every call-site doesn't repeat
 * the `DOMException` construction.
 *
 * ### Exports
 * - {@link throwIfAborted} — Throw if signal is already aborted.
 * - {@link isRunAborted} — Check if a run has been aborted.
 * - {@link finalizeRunIfNotAborted} — Mark run as completed (unless aborted).
 */

/**
 * Throws an AbortError if the signal has already been aborted.
 * No-op when signal is null/undefined or not yet aborted.
 *
 * @param {AbortSignal | undefined | null} signal
 */
export function throwIfAborted(signal) {
  if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
}

/**
 * Returns true if the run has been aborted (either via run.status or signal).
 * Centralises the duplicated `run.status !== "aborted" && !signal?.aborted`
 * guard used across pipeline functions.
 *
 * @param {object}                       run
 * @param {AbortSignal | undefined | null} [signal]
 */
export function isRunAborted(run, signal) {
  return run.status === "aborted" || !!signal?.aborted;
}

/**
 * Guard that marks a run as "completed" only if it wasn't already aborted,
 * then calls `onComplete` for site-specific logging / SSE emission.
 *
 * Extracts the duplicated pattern:
 *   if (run.status !== "aborted") {
 *     run.status = "completed";
 *     // …log summary, emit SSE done…
 *   }
 *
 * @param {object}   run         — mutable run record
 * @param {function} [onComplete] — called (with no args) only when the run
 *                                   is actually completed (not aborted)
 */
export function finalizeRunIfNotAborted(run, onComplete) {
  if (run.status !== "aborted") {
    // Set default "completed" before the callback so that any SSE snapshots
    // emitted inside onComplete already carry a terminal status.
    // The callback may override this to a more specific value (e.g.
    // "completed_empty") — that override is preserved because we don't
    // reassign after the callback returns.
    run.status = "completed";
    onComplete?.();
  }
}