All files catch.ts

100% Statements 92/92
83.33% Branches 10/12
100% Functions 9/9
100% Lines 92/92

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 921x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 2x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 2x 2x 2x 2x 1x
import { Rowan, Next, Processor } from "./rowan.js";
 
/**
 * A middleware container that wraps its child middleware execution in error handling.
 * If any error occurs during the processing of child middleware or the next() call,
 * it will be caught and passed to the provided error handler function.
 * 
 * This is useful for implementing centralized error handling, logging errors,
 * transforming errors, or providing fallback behavior when middleware fails.
 * 
 * @template Ctx - The type of the context object
 * 
 * @example
 * ```typescript
 * const errorHandler = new Catch(
 *   async (error, ctx) => {
 *     console.error('Error occurred:', error.message);
 *     ctx.error = error;
 *     ctx.response = { error: 'Internal server error' };
 *   },
 *   async (ctx) => {
 *     // This middleware might throw an error
 *     if (ctx.shouldFail) {
 *       throw new Error('Something went wrong');
 *     }
 *     ctx.success = true;
 *   }
 * );
 * 
 * await errorHandler.process(context, next);
 * ```
 */
export class Catch<Ctx = any> extends Rowan<Ctx>{
  /**
   * Creates a new Catch middleware container.
   * 
   * @param onError - Async function called when an error is caught.
   *                 Receives the error and context as parameters.
   * @param middleware - Variable number of processors to wrap with error handling
   * 
   * @example
   * ```typescript
   * const catchMiddleware = new Catch(
   *   async (err, ctx) => {
   *     // Log the error
   *     console.error('Caught error:', err);
   *     
   *     // Set error response
   *     ctx.statusCode = 500;
   *     ctx.body = { error: 'Internal Server Error' };
   *     
   *     // Optionally re-throw to propagate
   *     // throw err;
   *   },
   *   middleware1,
   *   middleware2,
   *   middleware3
   * );
   * ```
   */
  constructor(private onError: (err: Error, ctx: Ctx) => Promise<void>, ...middleware: Processor<Ctx>[]) {
    super(middleware);
  }
  
  /**
   * Processes the context through child middleware with error handling.
   * 
   * The processing follows this flow:
   * 1. Executes child middleware via super.process()
   * 2. Calls the provided next() function
   * 3. If any error occurs in steps 1-2, calls the onError handler
   * 4. The onError handler can handle, transform, or re-throw the error
   * 
   * @param ctx - The context object to process
   * @param next - Function to call the next middleware in the chain
   * @returns A Promise that resolves when processing completes or error handling finishes
   * 
   * @example
   * ```typescript
   * await catchMiddleware.process(context, async () => {
   *   // This next function might also throw errors that will be caught
   *   await riskyOperation();
   * });
   * ```
   */
  process(ctx: Ctx, next: Next) {
    const self = this;
    return super.process(ctx, next).catch(function(err) { 
      return self.onError(err, ctx as Ctx); 
    });
  }
}