All files / dingtalk-openclaw-connector/src/utils async.ts

0% Statements 0/32
100% Branches 1/1
100% Functions 1/1
0% Lines 0/32

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                                                                                       
export type RaceResult<T> =
  | { status: "success"; value: T }
  | { status: "timeout" }
  | { status: "aborted" };
 
export async function raceWithTimeoutAndAbort<T>(
  promise: Promise<T>,
  opts: { timeoutMs: number; abortSignal?: AbortSignal },
): Promise<RaceResult<T>> {
  const { timeoutMs, abortSignal } = opts;
 
  const timeoutPromise = new Promise<RaceResult<T>>((resolve) => {
    const timeoutId = setTimeout(() => resolve({ status: "timeout" }), timeoutMs);
    // Clean up timeout if promise resolves first
    promise.finally(() => clearTimeout(timeoutId));
  });
 
  const abortPromise = new Promise<RaceResult<T>>((resolve) => {
    if (!abortSignal) {
      resolve({ status: "aborted" });
      return;
    }
    if (abortSignal.aborted) {
      resolve({ status: "aborted" });
      return;
    }
    const onAbort = () => resolve({ status: "aborted" });
    abortSignal.addEventListener("abort", onAbort, { once: true });
    // Clean up listener if promise resolves first
    promise.finally(() => abortSignal.removeEventListener("abort", onAbort));
  });
 
  try {
    const value = await Promise.race([promise, timeoutPromise, abortPromise]);
    if (value === timeoutPromise || value === abortPromise) {
      return value;
    }
    return { status: "success", value };
  } catch (err) {
    // Propagate errors from the main promise
    throw err;
  }
}