All files / lib/api run.ts

87.5% Statements 7/8
75% Branches 3/4
100% Functions 1/1
83.33% Lines 5/6

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                              1x       9x   9x 8x   8x        
import { Cause, type Effect, Exit, Option } from 'effect';
 
import { type AppServices, runtime } from '@/lib/runtime';
 
import type { ApiError } from './errors';
 
/**
 * Runs an effect and returns a Promise for TanStack Query (`queryFn`, `mutationFn`).
 *
 * - Rejects with the effect's own typed error (an `ApiError` instance), so code branches on
 *   `query.error` with the error classes (`instanceof`) or `Match` instead of a squashed, untyped
 *   value.
 * - Pass the query's `signal`: when TanStack Query cancels, the fiber is interrupted and the
 *   in-flight fetch is aborted.
 */
export const runEffect = async <A, E extends ApiError>(
  effect: Effect.Effect<A, E, AppServices>,
  signal?: AbortSignal,
): Promise<A> => {
  const exit = await runtime.runPromiseExit(effect, { signal });
 
  if (Exit.isSuccess(exit)) return exit.value;
  const failure = Cause.findErrorOption(exit.cause);
 
  Eif (Option.isSome(failure)) throw failure.value;
  // Defects (bugs) and interruptions: rethrow as-is so they surface instead of hiding.
  throw Cause.squash(exit.cause);
};