Skip to main content

@tuturuuu/utils/effect

@tuturuuu/utils/effect is the platform entrypoint for Effect. It keeps Effect adoption consistent across Tuturuuu apps and services while preserving existing React, TanStack Query, Zod, and Supabase conventions.
import {
  Effect,
  fromDataError,
  runEffectAsResult,
  TuturuuuEffectError,
} from '@tuturuuu/utils/effect';

Exports

The entrypoint re-exports the Effect modules that Tuturuuu code should use by default:
  • Effect
  • Data
  • Context
  • Layer
  • Schedule
  • Duration
  • Option
  • Either
  • Cause
It also exports Tuturuuu helpers:
  • TuturuuuEffectError
  • toTuturuuuEffectError
  • serializeTuturuuuEffectError
  • fromDataError
  • fromPromise
  • withTuturuuuRetry
  • withTuturuuuTimeout
  • forEachConcurrently
  • runEffectAsResult

Expected Errors

Use TuturuuuEffectError for expected, typed failures that can cross a server/action/API boundary in a sanitized shape.
import { Effect, TuturuuuEffectError } from '@tuturuuu/utils/effect';

const requireWorkspace = (wsId?: string) =>
  wsId
    ? Effect.succeed(wsId)
    : Effect.fail(
        new TuturuuuEffectError({
          code: 'WORKSPACE_REQUIRED',
          message: 'Workspace ID is required.',
          status: 400,
        })
      );

Supabase-Style Results

Use fromDataError for APIs that return { data, error }, including Supabase queries and RPC calls.
const program = fromDataError(
  () =>
    supabase
      .from('workspaces')
      .select('id')
      .eq('id', wsId)
      .maybeSingle(),
  {
    code: 'WORKSPACE_READ_FAILED',
    message: 'Workspace read failed.',
    context: { wsId },
  }
);
fromDataError preserves service-specific code, message, details, and hint fields when present, then falls back to the provided Tuturuuu metadata.

Promise Results

Use fromPromise for async work that can throw or reject.
const response = fromPromise(
  () => fetch(url, { cache: 'no-store' }),
  {
    code: 'UPSTREAM_REQUEST_FAILED',
    message: 'Upstream request failed.',
    context: { url },
  }
);
fromPromise receives the Effect-managed AbortSignal. Pass it into fetch, SDK calls, or other abortable APIs so timeouts and fiber interruption can cancel the underlying work.

Retry And Timeout

Use withTuturuuuRetry and withTuturuuuTimeout when a server/service workflow needs explicit resilience policy with Tuturuuu error metadata.
const resilient = withTuturuuuRetry(
  withTuturuuuTimeout(response, {
    code: 'UPSTREAM_TIMEOUT',
    duration: '10 seconds',
    message: 'Upstream timed out.',
  }),
  {
    times: 2,
    delay: '250 millis',
    while: (error) => error.code === 'UPSTREAM_REQUEST_FAILED',
  }
);
Keep retry predicates narrow. Retry transient network, timeout, and temporary upstream failures. Do not retry validation, permission, or tenant-boundary errors unless the domain package documents idempotency.

Controlled Concurrency

Use forEachConcurrently for bounded parallel work. It defaults to Tuturuuu’s shared concurrency value and can be tightened per service.
const enrichedRows = forEachConcurrently(
  rows,
  (row) => enrichRowEffect(row),
  { concurrency: 4 }
);

Boundary Conversion

Use runEffectAsResult at route, action, or helper boundaries that already return result objects.
const result = await runEffectAsResult(program);

if (!result.ok) {
  return Response.json({ error: result.error.message }, { status: 500 });
}

return Response.json(result.data);
Do not expose raw upstream diagnostics, secrets, URLs with credentials, stack traces, or filesystem paths in public responses. Add safe metadata to context, and keep detailed diagnostics in the existing server logging path.