onrails
    Preparing search index...

    Class Railway<C, E, M>

    Named-context workflow builder. Each step appends a typed field to the accumulating context object; the workflow tracks sync/async mode so the final output type (RailwayOutput) is correct.

    Use Railway when a service workflow has 4+ named steps, mixed sync and async boundaries, or independent async branches that should run in parallel. For 1–2 step flows, prefer flatMap / asyncAfter directly.

    const summary = Railway
    .fromSync("id", () => IdSchema.parse(raw), toError)
    .fromPromise("row", ({ id }) => db.profiles.findFirst({ where: eq(profiles.id, id) }), toError)
    .require("profile", "row", ({ id }) => ({ kind: "not_found" as const, id }))
    .derive("normalized", ({ profile }) => normalizeProfile(profile))
    .parallel({
    artifacts: ({ normalized }) => loadArtifacts(normalized.id),
    metrics: ({ normalized }) => loadMetrics(normalized.id),
    })
    .select(({ normalized, artifacts, metrics }) =>
    toProfileSummary({ profile: normalized, artifacts, metrics }),
    );
    // ResultAsync<ProfileSummary, ParseError | DbError | NotFound>

    Type Parameters

    Index

    Methods

    • Promise-returning step — upgrades the workflow to async mode. Reject reasons go through onReject to become typed Err<F>.

      Type Parameters

      • K extends string
      • T
      • F

      Parameters

      • key: K
      • fn: (ctx: C) => PromiseLike<T>
      • onReject: (error: unknown) => F

      Returns Railway<C & Record<K, T>, E | F, "async">

    • Sync Result-returning step. Adds { [key]: T } to context on Ok; short-circuits the workflow on Err. Error union widens to E | F.

      Type Parameters

      • K extends string
      • T
      • F

      Parameters

      Returns Railway<C & Record<K, T>, E | F, M>

    • Throwing sync transform. Adds { [key]: T } to context; converts any exception to Err<F> via onThrow.

      Type Parameters

      • K extends string
      • T
      • F

      Parameters

      • key: K
      • fn: (ctx: C) => T
      • onThrow: (error: unknown) => F

      Returns Railway<C & Record<K, T>, E | F, M>

    • Run independent ResultAsync branches concurrently and merge their named outputs back into context. Upgrades the workflow to async mode. On multiple failures, the first Err in record-iteration order wins.

      Type Parameters

      • R extends Record<string, BranchFn<C>>

      Parameters

      • branches: R

      Returns Railway<C & ParallelOutput<R>, E | BranchErr<R[keyof R]>, "async">

      .parallel({
      recent: ({ userId }) => loadRecent(userId),
      metrics: ({ userId }) => loadMetrics(userId),
      })
      // ctx now has { ..., recent, metrics }
    • Narrow a nullable context field into a required non-null field. If the source field is null / undefined, the workflow short-circuits with onMissing(ctx).

      Type Parameters

      • K extends string
      • S extends string | number | symbol
      • F

      Parameters

      • key: K
      • source: S
      • onMissing: (ctx: C) => F

      Returns Railway<C & Record<K, NonNullable<C[S]>>, E | F, M>

      .fromPromise("row", ({ id }) => db.users.findFirst({ where: eq(users.id, id) }))
      .require("user", "row", ({ id }) => ({ kind: "not_found" as const, id }))
      // user is now User (non-null), not User | null
    • Start an async workflow with a PromiseLike-returning function.

      Type Parameters

      • K extends string
      • T
      • E

      Parameters

      • key: K
      • fn: () => PromiseLike<T>
      • onReject: (error: unknown) => E

      Returns Railway<Record<K, T>, E, "async">

    • Start a sync workflow with a throwing function — onThrow maps any exception to a typed error.

      Type Parameters

      • K extends string
      • T
      • E

      Parameters

      • key: K
      • fn: () => T
      • onThrow: (error: unknown) => E

      Returns Railway<Record<K, T>, E, "sync">