@onrails/result 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/DESIGN.md +119 -0
  2. package/LICENSE +21 -0
  3. package/README.md +323 -0
  4. package/RECIPES.md +367 -0
  5. package/dist/async-CCA1yK8q.d.cts +147 -0
  6. package/dist/async-DH_-dNIo.d.ts +147 -0
  7. package/dist/compat/neverthrow.cjs +446 -0
  8. package/dist/compat/neverthrow.cjs.map +1 -0
  9. package/dist/compat/neverthrow.d.cts +77 -0
  10. package/dist/compat/neverthrow.d.ts +77 -0
  11. package/dist/compat/neverthrow.js +435 -0
  12. package/dist/compat/neverthrow.js.map +1 -0
  13. package/dist/extra.cjs +37 -0
  14. package/dist/extra.cjs.map +1 -0
  15. package/dist/extra.d.cts +50 -0
  16. package/dist/extra.d.ts +50 -0
  17. package/dist/extra.js +31 -0
  18. package/dist/extra.js.map +1 -0
  19. package/dist/fluent.cjs +64 -0
  20. package/dist/fluent.cjs.map +1 -0
  21. package/dist/fluent.d.cts +28 -0
  22. package/dist/fluent.d.ts +28 -0
  23. package/dist/fluent.js +61 -0
  24. package/dist/fluent.js.map +1 -0
  25. package/dist/index.cjs +406 -0
  26. package/dist/index.cjs.map +1 -0
  27. package/dist/index.d.cts +227 -0
  28. package/dist/index.d.ts +227 -0
  29. package/dist/index.js +369 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/interop.cjs +248 -0
  32. package/dist/interop.cjs.map +1 -0
  33. package/dist/interop.d.cts +25 -0
  34. package/dist/interop.d.ts +25 -0
  35. package/dist/interop.js +244 -0
  36. package/dist/interop.js.map +1 -0
  37. package/dist/mcp.cjs +292 -0
  38. package/dist/mcp.cjs.map +1 -0
  39. package/dist/mcp.d.cts +62 -0
  40. package/dist/mcp.d.ts +62 -0
  41. package/dist/mcp.js +284 -0
  42. package/dist/mcp.js.map +1 -0
  43. package/dist/pipe.cjs +16 -0
  44. package/dist/pipe.cjs.map +1 -0
  45. package/dist/pipe.d.cts +26 -0
  46. package/dist/pipe.d.ts +26 -0
  47. package/dist/pipe.js +14 -0
  48. package/dist/pipe.js.map +1 -0
  49. package/dist/railway.cjs +443 -0
  50. package/dist/railway.cjs.map +1 -0
  51. package/dist/railway.d.cts +214 -0
  52. package/dist/railway.d.ts +214 -0
  53. package/dist/railway.js +431 -0
  54. package/dist/railway.js.map +1 -0
  55. package/dist/try-gen.cjs +40 -0
  56. package/dist/try-gen.cjs.map +1 -0
  57. package/dist/try-gen.d.cts +23 -0
  58. package/dist/try-gen.d.ts +23 -0
  59. package/dist/try-gen.js +36 -0
  60. package/dist/try-gen.js.map +1 -0
  61. package/dist/types-C2Dp1d5J.d.cts +21 -0
  62. package/dist/types-C2Dp1d5J.d.ts +21 -0
  63. package/dist/validation.cjs +70 -0
  64. package/dist/validation.cjs.map +1 -0
  65. package/dist/validation.d.cts +72 -0
  66. package/dist/validation.d.ts +72 -0
  67. package/dist/validation.js +65 -0
  68. package/dist/validation.js.map +1 -0
  69. package/package.json +114 -0
@@ -0,0 +1,214 @@
1
+ import { R as ResultAsync } from './async-CCA1yK8q.cjs';
2
+ import { R as Result } from './types-C2Dp1d5J.cjs';
3
+
4
+ /**
5
+ * Tracks whether a {@link Railway} workflow has crossed an async boundary.
6
+ * Sync workflows return {@link Result}; async workflows return {@link ResultAsync}.
7
+ */
8
+ type RailwayMode = "sync" | "async";
9
+ /**
10
+ * Mode-aware output type for a {@link Railway} workflow: sync mode →
11
+ * `Result<T, E>`, async mode → `ResultAsync<T, E>`.
12
+ */
13
+ type RailwayOutput<T, E, M extends RailwayMode> = M extends "async" ? ResultAsync<T, E> : Result<T, E>;
14
+ /**
15
+ * Initial context shape for a {@link railway} functional pipeline.
16
+ * Wraps the raw input under the `input` key so subsequent named steps
17
+ * can reference it via `ctx.input`.
18
+ */
19
+ type RailwayInput<I> = {
20
+ readonly input: I;
21
+ };
22
+ type BranchFn<C extends object> = (ctx: C) => ResultAsync<unknown, unknown>;
23
+ type BranchRecord = Record<string, (ctx: never) => ResultAsync<unknown, unknown>>;
24
+ type BranchOk<R> = R extends (ctx: never) => ResultAsync<infer T, infer _E> ? T : never;
25
+ type BranchErr<R> = R extends (ctx: never) => ResultAsync<infer _T, infer E> ? E : never;
26
+ type BranchInput<R> = R extends (ctx: infer C) => ResultAsync<unknown, unknown> ? C : never;
27
+ type ParallelInput<R extends BranchRecord> = BranchInput<R[keyof R]> & object;
28
+ type ParallelOutput<R extends BranchRecord> = {
29
+ [K in keyof R]: BranchOk<R[K]>;
30
+ };
31
+ type ParallelError<R extends BranchRecord> = BranchErr<R[keyof R]>;
32
+ type ParserLike<I, T> = {
33
+ readonly parse: (input: I) => T;
34
+ } | ((input: I) => T);
35
+ type UnaryStep<I, O> = (input: I) => O;
36
+ /**
37
+ * Named-context workflow builder. Each step appends a typed field to the
38
+ * accumulating context object; the workflow tracks sync/async mode so the
39
+ * final output type ({@link RailwayOutput}) is correct.
40
+ *
41
+ * Use `Railway` when a service workflow has 4+ named steps, mixed sync and
42
+ * async boundaries, or independent async branches that should run in
43
+ * parallel. For 1–2 step flows, prefer `flatMap` / `asyncAfter` directly.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * const summary = Railway
48
+ * .fromSync("id", () => IdSchema.parse(raw), toError)
49
+ * .fromPromise("row", ({ id }) => db.profiles.findFirst({ where: eq(profiles.id, id) }), toError)
50
+ * .require("profile", "row", ({ id }) => ({ kind: "not_found" as const, id }))
51
+ * .derive("normalized", ({ profile }) => normalizeProfile(profile))
52
+ * .parallel({
53
+ * artifacts: ({ normalized }) => loadArtifacts(normalized.id),
54
+ * metrics: ({ normalized }) => loadMetrics(normalized.id),
55
+ * })
56
+ * .select(({ normalized, artifacts, metrics }) =>
57
+ * toProfileSummary({ profile: normalized, artifacts, metrics }),
58
+ * );
59
+ * // ResultAsync<ProfileSummary, ParseError | DbError | NotFound>
60
+ * ```
61
+ */
62
+ declare class Railway<C extends object, E, M extends RailwayMode> {
63
+ private readonly state;
64
+ private constructor();
65
+ /** Start an empty sync workflow with no fields in context. */
66
+ static empty(): Railway<Record<never, never>, never, "sync">;
67
+ /** Start a sync workflow with the given context as the initial state. */
68
+ static context<C extends object>(context: C): Railway<C, never, "sync">;
69
+ /**
70
+ * Start a sync workflow with a throwing function — `onThrow` maps any
71
+ * exception to a typed error.
72
+ */
73
+ static fromSync<K extends string, T, E>(key: K, fn: () => T, onThrow: (error: unknown) => E): Railway<Record<K, T>, E, "sync">;
74
+ /** Start a sync workflow with a `Result`-returning function. */
75
+ static fromResult<K extends string, T, E>(key: K, fn: () => Result<T, E>): Railway<Record<K, T>, E, "sync">;
76
+ /** Start an async workflow with a `PromiseLike`-returning function. */
77
+ static fromPromise<K extends string, T, E>(key: K, fn: () => PromiseLike<T>, onReject: (error: unknown) => E): Railway<Record<K, T>, E, "async">;
78
+ /** Start an async workflow with a `ResultAsync`-returning function. */
79
+ static fromAsync<K extends string, T, E>(key: K, fn: () => ResultAsync<T, E>): Railway<Record<K, T>, E, "async">;
80
+ /**
81
+ * Pure sync derivation — `fn` must not throw. Use {@link fromSync} for
82
+ * throwing transforms.
83
+ */
84
+ derive<K extends string, T>(key: K, fn: (ctx: C) => T): Railway<C & Record<K, T>, E, M>;
85
+ /**
86
+ * Throwing sync transform. Adds `{ [key]: T }` to context; converts any
87
+ * exception to `Err<F>` via `onThrow`.
88
+ */
89
+ fromSync<K extends string, T, F>(key: K, fn: (ctx: C) => T, onThrow: (error: unknown) => F): Railway<C & Record<K, T>, E | F, M>;
90
+ /**
91
+ * Sync `Result`-returning step. Adds `{ [key]: T }` to context on `Ok`;
92
+ * short-circuits the workflow on `Err`. Error union widens to `E | F`.
93
+ */
94
+ fromResult<K extends string, T, F>(key: K, fn: (ctx: C) => Result<T, F>): Railway<C & Record<K, T>, E | F, M>;
95
+ /**
96
+ * Promise-returning step — upgrades the workflow to async mode. Reject
97
+ * reasons go through `onReject` to become typed `Err<F>`.
98
+ */
99
+ fromPromise<K extends string, T, F>(key: K, fn: (ctx: C) => PromiseLike<T>, onReject: (error: unknown) => F): Railway<C & Record<K, T>, E | F, "async">;
100
+ /**
101
+ * `ResultAsync`-returning step — upgrades the workflow to async mode.
102
+ * Already-typed error: no mapper needed.
103
+ */
104
+ fromAsync<K extends string, T, F>(key: K, fn: (ctx: C) => ResultAsync<T, F>): Railway<C & Record<K, T>, E | F, "async">;
105
+ /**
106
+ * Narrow a nullable context field into a required non-null field. If the
107
+ * source field is `null` / `undefined`, the workflow short-circuits with
108
+ * `onMissing(ctx)`.
109
+ *
110
+ * @example
111
+ * ```ts
112
+ * .fromPromise("row", ({ id }) => db.users.findFirst({ where: eq(users.id, id) }))
113
+ * .require("user", "row", ({ id }) => ({ kind: "not_found" as const, id }))
114
+ * // user is now User (non-null), not User | null
115
+ * ```
116
+ */
117
+ require<K extends string, S extends keyof C, F>(key: K, source: S, onMissing: (ctx: C) => F): Railway<C & Record<K, NonNullable<C[S]>>, E | F, M>;
118
+ /**
119
+ * Run independent `ResultAsync` branches concurrently and merge their
120
+ * named outputs back into context. Upgrades the workflow to async mode.
121
+ * On multiple failures, the first `Err` in record-iteration order wins.
122
+ *
123
+ * @example
124
+ * ```ts
125
+ * .parallel({
126
+ * recent: ({ userId }) => loadRecent(userId),
127
+ * metrics: ({ userId }) => loadMetrics(userId),
128
+ * })
129
+ * // ctx now has { ..., recent, metrics }
130
+ * ```
131
+ */
132
+ parallel<R extends Record<string, BranchFn<C>>>(branches: R): Railway<C & ParallelOutput<R>, E | ParallelError<R>, "async">;
133
+ /**
134
+ * Project the final context into the workflow's output type. Hides the
135
+ * internal context shape from callers.
136
+ */
137
+ select<T>(fn: (ctx: C) => T): RailwayOutput<T, E, M>;
138
+ /**
139
+ * Return the accumulated context as-is. Use when downstream code needs
140
+ * every named field; prefer {@link select} when you can project to a DTO.
141
+ */
142
+ done(): RailwayOutput<C, E, M>;
143
+ }
144
+ /**
145
+ * Functional companion to {@link Railway} — point-free composition of
146
+ * reusable workflow steps. Starts from `Railway.context({ input })` and
147
+ * applies each step in order. Step factories live below: {@link parseWith},
148
+ * {@link fromSyncNamed}, {@link fromResultNamed}, {@link fromPromiseNamed},
149
+ * {@link fromAsyncNamed}, {@link deriveNamed}, {@link requireNamed},
150
+ * {@link parallelNamed}, {@link select}.
151
+ *
152
+ * @example
153
+ * ```ts
154
+ * const summary = railway(
155
+ * rawId,
156
+ * parseWith(IdSchema, toError).as("id"),
157
+ * fromPromiseNamed("row", ({ id }) => db.profiles.findFirst({ where: eq(profiles.id, id) }), toError),
158
+ * requireNamed("profile", "row", ({ id }) => ({ kind: "not_found" as const, id })),
159
+ * deriveNamed("normalized", ({ profile }) => normalizeProfile(profile)),
160
+ * select(({ normalized }) => toProfileSummary(normalized)),
161
+ * );
162
+ * ```
163
+ */
164
+ declare function railway<I, A>(input: I, step1: UnaryStep<Railway<RailwayInput<I>, never, "sync">, A>): A;
165
+ declare function railway<I, A, B>(input: I, step1: UnaryStep<Railway<RailwayInput<I>, never, "sync">, A>, step2: UnaryStep<A, B>): B;
166
+ declare function railway<I, A, B, C>(input: I, step1: UnaryStep<Railway<RailwayInput<I>, never, "sync">, A>, step2: UnaryStep<A, B>, step3: UnaryStep<B, C>): C;
167
+ declare function railway<I, A, B, C, D>(input: I, step1: UnaryStep<Railway<RailwayInput<I>, never, "sync">, A>, step2: UnaryStep<A, B>, step3: UnaryStep<B, C>, step4: UnaryStep<C, D>): D;
168
+ declare function railway<I, A, B, C, D, E>(input: I, step1: UnaryStep<Railway<RailwayInput<I>, never, "sync">, A>, step2: UnaryStep<A, B>, step3: UnaryStep<B, C>, step4: UnaryStep<C, D>, step5: UnaryStep<D, E>): E;
169
+ declare function railway<I, A, B, C, D, E, F>(input: I, step1: UnaryStep<Railway<RailwayInput<I>, never, "sync">, A>, step2: UnaryStep<A, B>, step3: UnaryStep<B, C>, step4: UnaryStep<C, D>, step5: UnaryStep<D, E>, step6: UnaryStep<E, F>): F;
170
+ declare function railway<I, A, B, C, D, E, F, G>(input: I, step1: UnaryStep<Railway<RailwayInput<I>, never, "sync">, A>, step2: UnaryStep<A, B>, step3: UnaryStep<B, C>, step4: UnaryStep<C, D>, step5: UnaryStep<D, E>, step6: UnaryStep<E, F>, step7: UnaryStep<F, G>): G;
171
+ declare function railway<I, A, B, C, D, E, F, G, H>(input: I, step1: UnaryStep<Railway<RailwayInput<I>, never, "sync">, A>, step2: UnaryStep<A, B>, step3: UnaryStep<B, C>, step4: UnaryStep<C, D>, step5: UnaryStep<D, E>, step6: UnaryStep<E, F>, step7: UnaryStep<F, G>, step8: UnaryStep<G, H>): H;
172
+ /**
173
+ * Step factory: parse the workflow input with a Zod-like schema (or a
174
+ * unary parse function). Call `.as(key)` to name the output field.
175
+ *
176
+ * @example
177
+ * ```ts
178
+ * parseWith(IdSchema, toError).as("id");
179
+ * // Used as the first step in `railway(rawId, parseId, ...)`
180
+ * ```
181
+ */
182
+ declare const parseWith: <I, T, E>(parser: ParserLike<I, T>, onThrow: (error: unknown) => E) => {
183
+ as: <K extends string>(key: K) => <F, M extends RailwayMode>(workflow: Railway<RailwayInput<I>, F, M>) => Railway<RailwayInput<I> & Record<K, T>, F | E, M>;
184
+ };
185
+ /**
186
+ * Reusable wrapper around {@link Railway.fromSync}. Captures key + fn +
187
+ * onThrow once; applies to any compatible workflow.
188
+ */
189
+ declare const fromSyncNamed: <K extends string, C extends object, T, E>(key: K, fn: (ctx: C) => T, onThrow: (error: unknown) => E) => <I extends C, F, M extends RailwayMode>(workflow: Railway<I, F, M>) => Railway<I & Record<K, T>, F | E, M>;
190
+ /** Reusable wrapper around {@link Railway.fromResult}. */
191
+ declare const fromResultNamed: <K extends string, C extends object, T, E>(key: K, fn: (ctx: C) => Result<T, E>) => <I extends C, F, M extends RailwayMode>(workflow: Railway<I, F, M>) => Railway<I & Record<K, T>, F | E, M>;
192
+ /**
193
+ * Reusable wrapper around {@link Railway.fromPromise}. Upgrades the
194
+ * workflow to async mode when applied.
195
+ */
196
+ declare const fromPromiseNamed: <K extends string, C extends object, T, E>(key: K, fn: (ctx: C) => PromiseLike<T>, onReject: (error: unknown) => E) => <I extends C, F, M extends RailwayMode>(workflow: Railway<I, F, M>) => Railway<I & Record<K, T>, F | E, "async">;
197
+ /** Reusable wrapper around {@link Railway.fromAsync}. */
198
+ declare const fromAsyncNamed: <K extends string, C extends object, T, E>(key: K, fn: (ctx: C) => ResultAsync<T, E>) => <I extends C, F, M extends RailwayMode>(workflow: Railway<I, F, M>) => Railway<I & Record<K, T>, F | E, "async">;
199
+ /** Reusable wrapper around {@link Railway.derive} — pure sync derivation. */
200
+ declare const deriveNamed: <K extends string, C extends object, T>(key: K, fn: (ctx: C) => T) => <I extends C, E, M extends RailwayMode>(workflow: Railway<I, E, M>) => Railway<I & Record<K, T>, E, M>;
201
+ /** Reusable wrapper around {@link Railway.require} — narrows a nullable field. */
202
+ declare const requireNamed: <K extends string, S extends string, C extends object, E>(key: K, source: S, onMissing: (ctx: C & Record<S, unknown>) => E) => <I extends C & Record<S, unknown>, F, M extends RailwayMode>(workflow: Railway<I, F, M>) => Railway<I & Record<K, NonNullable<I[S]>>, F | E, M>;
203
+ /**
204
+ * Reusable wrapper around {@link Railway.parallel}. Branches run
205
+ * concurrently and merge their named outputs back into context.
206
+ */
207
+ declare const parallelNamed: <R extends BranchRecord>(branches: R) => <I extends ParallelInput<R>, E, M extends RailwayMode>(workflow: Railway<I, E, M>) => Railway<I & ParallelOutput<R>, E | ParallelError<R>, "async">;
208
+ /**
209
+ * Reusable wrapper around {@link Railway.select} — projects the final
210
+ * context into the workflow's output type.
211
+ */
212
+ declare const select: <C extends object, T>(fn: (ctx: C) => T) => <E, M extends RailwayMode>(workflow: Railway<C, E, M>) => RailwayOutput<T, E, M>;
213
+
214
+ export { Railway, type RailwayInput, type RailwayMode, type RailwayOutput, deriveNamed, fromAsyncNamed, fromPromiseNamed, fromResultNamed, fromSyncNamed, parallelNamed, parseWith, railway, requireNamed, select };
@@ -0,0 +1,214 @@
1
+ import { R as ResultAsync } from './async-DH_-dNIo.js';
2
+ import { R as Result } from './types-C2Dp1d5J.js';
3
+
4
+ /**
5
+ * Tracks whether a {@link Railway} workflow has crossed an async boundary.
6
+ * Sync workflows return {@link Result}; async workflows return {@link ResultAsync}.
7
+ */
8
+ type RailwayMode = "sync" | "async";
9
+ /**
10
+ * Mode-aware output type for a {@link Railway} workflow: sync mode →
11
+ * `Result<T, E>`, async mode → `ResultAsync<T, E>`.
12
+ */
13
+ type RailwayOutput<T, E, M extends RailwayMode> = M extends "async" ? ResultAsync<T, E> : Result<T, E>;
14
+ /**
15
+ * Initial context shape for a {@link railway} functional pipeline.
16
+ * Wraps the raw input under the `input` key so subsequent named steps
17
+ * can reference it via `ctx.input`.
18
+ */
19
+ type RailwayInput<I> = {
20
+ readonly input: I;
21
+ };
22
+ type BranchFn<C extends object> = (ctx: C) => ResultAsync<unknown, unknown>;
23
+ type BranchRecord = Record<string, (ctx: never) => ResultAsync<unknown, unknown>>;
24
+ type BranchOk<R> = R extends (ctx: never) => ResultAsync<infer T, infer _E> ? T : never;
25
+ type BranchErr<R> = R extends (ctx: never) => ResultAsync<infer _T, infer E> ? E : never;
26
+ type BranchInput<R> = R extends (ctx: infer C) => ResultAsync<unknown, unknown> ? C : never;
27
+ type ParallelInput<R extends BranchRecord> = BranchInput<R[keyof R]> & object;
28
+ type ParallelOutput<R extends BranchRecord> = {
29
+ [K in keyof R]: BranchOk<R[K]>;
30
+ };
31
+ type ParallelError<R extends BranchRecord> = BranchErr<R[keyof R]>;
32
+ type ParserLike<I, T> = {
33
+ readonly parse: (input: I) => T;
34
+ } | ((input: I) => T);
35
+ type UnaryStep<I, O> = (input: I) => O;
36
+ /**
37
+ * Named-context workflow builder. Each step appends a typed field to the
38
+ * accumulating context object; the workflow tracks sync/async mode so the
39
+ * final output type ({@link RailwayOutput}) is correct.
40
+ *
41
+ * Use `Railway` when a service workflow has 4+ named steps, mixed sync and
42
+ * async boundaries, or independent async branches that should run in
43
+ * parallel. For 1–2 step flows, prefer `flatMap` / `asyncAfter` directly.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * const summary = Railway
48
+ * .fromSync("id", () => IdSchema.parse(raw), toError)
49
+ * .fromPromise("row", ({ id }) => db.profiles.findFirst({ where: eq(profiles.id, id) }), toError)
50
+ * .require("profile", "row", ({ id }) => ({ kind: "not_found" as const, id }))
51
+ * .derive("normalized", ({ profile }) => normalizeProfile(profile))
52
+ * .parallel({
53
+ * artifacts: ({ normalized }) => loadArtifacts(normalized.id),
54
+ * metrics: ({ normalized }) => loadMetrics(normalized.id),
55
+ * })
56
+ * .select(({ normalized, artifacts, metrics }) =>
57
+ * toProfileSummary({ profile: normalized, artifacts, metrics }),
58
+ * );
59
+ * // ResultAsync<ProfileSummary, ParseError | DbError | NotFound>
60
+ * ```
61
+ */
62
+ declare class Railway<C extends object, E, M extends RailwayMode> {
63
+ private readonly state;
64
+ private constructor();
65
+ /** Start an empty sync workflow with no fields in context. */
66
+ static empty(): Railway<Record<never, never>, never, "sync">;
67
+ /** Start a sync workflow with the given context as the initial state. */
68
+ static context<C extends object>(context: C): Railway<C, never, "sync">;
69
+ /**
70
+ * Start a sync workflow with a throwing function — `onThrow` maps any
71
+ * exception to a typed error.
72
+ */
73
+ static fromSync<K extends string, T, E>(key: K, fn: () => T, onThrow: (error: unknown) => E): Railway<Record<K, T>, E, "sync">;
74
+ /** Start a sync workflow with a `Result`-returning function. */
75
+ static fromResult<K extends string, T, E>(key: K, fn: () => Result<T, E>): Railway<Record<K, T>, E, "sync">;
76
+ /** Start an async workflow with a `PromiseLike`-returning function. */
77
+ static fromPromise<K extends string, T, E>(key: K, fn: () => PromiseLike<T>, onReject: (error: unknown) => E): Railway<Record<K, T>, E, "async">;
78
+ /** Start an async workflow with a `ResultAsync`-returning function. */
79
+ static fromAsync<K extends string, T, E>(key: K, fn: () => ResultAsync<T, E>): Railway<Record<K, T>, E, "async">;
80
+ /**
81
+ * Pure sync derivation — `fn` must not throw. Use {@link fromSync} for
82
+ * throwing transforms.
83
+ */
84
+ derive<K extends string, T>(key: K, fn: (ctx: C) => T): Railway<C & Record<K, T>, E, M>;
85
+ /**
86
+ * Throwing sync transform. Adds `{ [key]: T }` to context; converts any
87
+ * exception to `Err<F>` via `onThrow`.
88
+ */
89
+ fromSync<K extends string, T, F>(key: K, fn: (ctx: C) => T, onThrow: (error: unknown) => F): Railway<C & Record<K, T>, E | F, M>;
90
+ /**
91
+ * Sync `Result`-returning step. Adds `{ [key]: T }` to context on `Ok`;
92
+ * short-circuits the workflow on `Err`. Error union widens to `E | F`.
93
+ */
94
+ fromResult<K extends string, T, F>(key: K, fn: (ctx: C) => Result<T, F>): Railway<C & Record<K, T>, E | F, M>;
95
+ /**
96
+ * Promise-returning step — upgrades the workflow to async mode. Reject
97
+ * reasons go through `onReject` to become typed `Err<F>`.
98
+ */
99
+ fromPromise<K extends string, T, F>(key: K, fn: (ctx: C) => PromiseLike<T>, onReject: (error: unknown) => F): Railway<C & Record<K, T>, E | F, "async">;
100
+ /**
101
+ * `ResultAsync`-returning step — upgrades the workflow to async mode.
102
+ * Already-typed error: no mapper needed.
103
+ */
104
+ fromAsync<K extends string, T, F>(key: K, fn: (ctx: C) => ResultAsync<T, F>): Railway<C & Record<K, T>, E | F, "async">;
105
+ /**
106
+ * Narrow a nullable context field into a required non-null field. If the
107
+ * source field is `null` / `undefined`, the workflow short-circuits with
108
+ * `onMissing(ctx)`.
109
+ *
110
+ * @example
111
+ * ```ts
112
+ * .fromPromise("row", ({ id }) => db.users.findFirst({ where: eq(users.id, id) }))
113
+ * .require("user", "row", ({ id }) => ({ kind: "not_found" as const, id }))
114
+ * // user is now User (non-null), not User | null
115
+ * ```
116
+ */
117
+ require<K extends string, S extends keyof C, F>(key: K, source: S, onMissing: (ctx: C) => F): Railway<C & Record<K, NonNullable<C[S]>>, E | F, M>;
118
+ /**
119
+ * Run independent `ResultAsync` branches concurrently and merge their
120
+ * named outputs back into context. Upgrades the workflow to async mode.
121
+ * On multiple failures, the first `Err` in record-iteration order wins.
122
+ *
123
+ * @example
124
+ * ```ts
125
+ * .parallel({
126
+ * recent: ({ userId }) => loadRecent(userId),
127
+ * metrics: ({ userId }) => loadMetrics(userId),
128
+ * })
129
+ * // ctx now has { ..., recent, metrics }
130
+ * ```
131
+ */
132
+ parallel<R extends Record<string, BranchFn<C>>>(branches: R): Railway<C & ParallelOutput<R>, E | ParallelError<R>, "async">;
133
+ /**
134
+ * Project the final context into the workflow's output type. Hides the
135
+ * internal context shape from callers.
136
+ */
137
+ select<T>(fn: (ctx: C) => T): RailwayOutput<T, E, M>;
138
+ /**
139
+ * Return the accumulated context as-is. Use when downstream code needs
140
+ * every named field; prefer {@link select} when you can project to a DTO.
141
+ */
142
+ done(): RailwayOutput<C, E, M>;
143
+ }
144
+ /**
145
+ * Functional companion to {@link Railway} — point-free composition of
146
+ * reusable workflow steps. Starts from `Railway.context({ input })` and
147
+ * applies each step in order. Step factories live below: {@link parseWith},
148
+ * {@link fromSyncNamed}, {@link fromResultNamed}, {@link fromPromiseNamed},
149
+ * {@link fromAsyncNamed}, {@link deriveNamed}, {@link requireNamed},
150
+ * {@link parallelNamed}, {@link select}.
151
+ *
152
+ * @example
153
+ * ```ts
154
+ * const summary = railway(
155
+ * rawId,
156
+ * parseWith(IdSchema, toError).as("id"),
157
+ * fromPromiseNamed("row", ({ id }) => db.profiles.findFirst({ where: eq(profiles.id, id) }), toError),
158
+ * requireNamed("profile", "row", ({ id }) => ({ kind: "not_found" as const, id })),
159
+ * deriveNamed("normalized", ({ profile }) => normalizeProfile(profile)),
160
+ * select(({ normalized }) => toProfileSummary(normalized)),
161
+ * );
162
+ * ```
163
+ */
164
+ declare function railway<I, A>(input: I, step1: UnaryStep<Railway<RailwayInput<I>, never, "sync">, A>): A;
165
+ declare function railway<I, A, B>(input: I, step1: UnaryStep<Railway<RailwayInput<I>, never, "sync">, A>, step2: UnaryStep<A, B>): B;
166
+ declare function railway<I, A, B, C>(input: I, step1: UnaryStep<Railway<RailwayInput<I>, never, "sync">, A>, step2: UnaryStep<A, B>, step3: UnaryStep<B, C>): C;
167
+ declare function railway<I, A, B, C, D>(input: I, step1: UnaryStep<Railway<RailwayInput<I>, never, "sync">, A>, step2: UnaryStep<A, B>, step3: UnaryStep<B, C>, step4: UnaryStep<C, D>): D;
168
+ declare function railway<I, A, B, C, D, E>(input: I, step1: UnaryStep<Railway<RailwayInput<I>, never, "sync">, A>, step2: UnaryStep<A, B>, step3: UnaryStep<B, C>, step4: UnaryStep<C, D>, step5: UnaryStep<D, E>): E;
169
+ declare function railway<I, A, B, C, D, E, F>(input: I, step1: UnaryStep<Railway<RailwayInput<I>, never, "sync">, A>, step2: UnaryStep<A, B>, step3: UnaryStep<B, C>, step4: UnaryStep<C, D>, step5: UnaryStep<D, E>, step6: UnaryStep<E, F>): F;
170
+ declare function railway<I, A, B, C, D, E, F, G>(input: I, step1: UnaryStep<Railway<RailwayInput<I>, never, "sync">, A>, step2: UnaryStep<A, B>, step3: UnaryStep<B, C>, step4: UnaryStep<C, D>, step5: UnaryStep<D, E>, step6: UnaryStep<E, F>, step7: UnaryStep<F, G>): G;
171
+ declare function railway<I, A, B, C, D, E, F, G, H>(input: I, step1: UnaryStep<Railway<RailwayInput<I>, never, "sync">, A>, step2: UnaryStep<A, B>, step3: UnaryStep<B, C>, step4: UnaryStep<C, D>, step5: UnaryStep<D, E>, step6: UnaryStep<E, F>, step7: UnaryStep<F, G>, step8: UnaryStep<G, H>): H;
172
+ /**
173
+ * Step factory: parse the workflow input with a Zod-like schema (or a
174
+ * unary parse function). Call `.as(key)` to name the output field.
175
+ *
176
+ * @example
177
+ * ```ts
178
+ * parseWith(IdSchema, toError).as("id");
179
+ * // Used as the first step in `railway(rawId, parseId, ...)`
180
+ * ```
181
+ */
182
+ declare const parseWith: <I, T, E>(parser: ParserLike<I, T>, onThrow: (error: unknown) => E) => {
183
+ as: <K extends string>(key: K) => <F, M extends RailwayMode>(workflow: Railway<RailwayInput<I>, F, M>) => Railway<RailwayInput<I> & Record<K, T>, F | E, M>;
184
+ };
185
+ /**
186
+ * Reusable wrapper around {@link Railway.fromSync}. Captures key + fn +
187
+ * onThrow once; applies to any compatible workflow.
188
+ */
189
+ declare const fromSyncNamed: <K extends string, C extends object, T, E>(key: K, fn: (ctx: C) => T, onThrow: (error: unknown) => E) => <I extends C, F, M extends RailwayMode>(workflow: Railway<I, F, M>) => Railway<I & Record<K, T>, F | E, M>;
190
+ /** Reusable wrapper around {@link Railway.fromResult}. */
191
+ declare const fromResultNamed: <K extends string, C extends object, T, E>(key: K, fn: (ctx: C) => Result<T, E>) => <I extends C, F, M extends RailwayMode>(workflow: Railway<I, F, M>) => Railway<I & Record<K, T>, F | E, M>;
192
+ /**
193
+ * Reusable wrapper around {@link Railway.fromPromise}. Upgrades the
194
+ * workflow to async mode when applied.
195
+ */
196
+ declare const fromPromiseNamed: <K extends string, C extends object, T, E>(key: K, fn: (ctx: C) => PromiseLike<T>, onReject: (error: unknown) => E) => <I extends C, F, M extends RailwayMode>(workflow: Railway<I, F, M>) => Railway<I & Record<K, T>, F | E, "async">;
197
+ /** Reusable wrapper around {@link Railway.fromAsync}. */
198
+ declare const fromAsyncNamed: <K extends string, C extends object, T, E>(key: K, fn: (ctx: C) => ResultAsync<T, E>) => <I extends C, F, M extends RailwayMode>(workflow: Railway<I, F, M>) => Railway<I & Record<K, T>, F | E, "async">;
199
+ /** Reusable wrapper around {@link Railway.derive} — pure sync derivation. */
200
+ declare const deriveNamed: <K extends string, C extends object, T>(key: K, fn: (ctx: C) => T) => <I extends C, E, M extends RailwayMode>(workflow: Railway<I, E, M>) => Railway<I & Record<K, T>, E, M>;
201
+ /** Reusable wrapper around {@link Railway.require} — narrows a nullable field. */
202
+ declare const requireNamed: <K extends string, S extends string, C extends object, E>(key: K, source: S, onMissing: (ctx: C & Record<S, unknown>) => E) => <I extends C & Record<S, unknown>, F, M extends RailwayMode>(workflow: Railway<I, F, M>) => Railway<I & Record<K, NonNullable<I[S]>>, F | E, M>;
203
+ /**
204
+ * Reusable wrapper around {@link Railway.parallel}. Branches run
205
+ * concurrently and merge their named outputs back into context.
206
+ */
207
+ declare const parallelNamed: <R extends BranchRecord>(branches: R) => <I extends ParallelInput<R>, E, M extends RailwayMode>(workflow: Railway<I, E, M>) => Railway<I & ParallelOutput<R>, E | ParallelError<R>, "async">;
208
+ /**
209
+ * Reusable wrapper around {@link Railway.select} — projects the final
210
+ * context into the workflow's output type.
211
+ */
212
+ declare const select: <C extends object, T>(fn: (ctx: C) => T) => <E, M extends RailwayMode>(workflow: Railway<C, E, M>) => RailwayOutput<T, E, M>;
213
+
214
+ export { Railway, type RailwayInput, type RailwayMode, type RailwayOutput, deriveNamed, fromAsyncNamed, fromPromiseNamed, fromResultNamed, fromSyncNamed, parallelNamed, parseWith, railway, requireNamed, select };