# All files / src/utils fetch.ts

70% Statements 14/20
65% Branches 13/20
50% Functions 1/2
72.22% Lines 13/18

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

    97x

    97x
    17x

    80x
    23x

    57x
    57x
    57x

    57x

    57x

    97x

    57x
    57x

     /**
     * Fetch with timeout support.
     * Wraps the standard fetch API with an AbortController to enforce request timeouts.
     *
     * @param url - The URL to fetch
     * @param options - Standard fetch options
     * @param timeoutMs - Timeout in milliseconds (optional)
     * @returns Promise<Response>
     * @throws Error if the request times out
     */
    export async function fetchWithTimeout(
      url: string,
      options: RequestInit = {},
      timeoutMs?: number
    ): Promise<Response> {
      const userSignal = options.signal;

      // If no timeout is specified and no user signal, use standard fetch
      if ((!timeoutMs || timeoutMs <= 0) && !userSignal) {
        return fetch(url, options);
      }

      // If only user signal (no timeout), use it directly
      if (!timeoutMs || timeoutMs <= 0) {
        return fetch(url, options);
      }

      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
      Eif (timeoutId.unref) timeoutId.unref();

      try {
        // Merge user signal with timeout signal
        const mergedSignal = userSignal
          ? AbortSignal.any([userSignal, controller.signal])
          : controller.signal;

        const response = await fetch(url, {
          ...options,
          signal: mergedSignal
        });
        clearTimeout(timeoutId);
        return response;
      } catch (error: unknown) {
        clearTimeout(timeoutId);

        // Check if the error was due to timeout abort
        const isAbortError = error instanceof Error && error.name === "AbortError";
        if (isAbortError && controller.signal.aborted) {
          throw new Error(`Request timeout after ${timeoutMs}ms`);
        }

        throw error;
      }
    }