awaitly 1.34.0 → 2.0.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 (241) hide show
  1. package/dist/{duration.d.ts → di-BDlT7InM.d.cts} +15 -1
  2. package/dist/{duration.d.cts → di-BbFFfO8y.d.ts} +15 -1
  3. package/dist/errors-DtXvrCiO.d.cts +708 -0
  4. package/dist/errors-DtXvrCiO.d.ts +708 -0
  5. package/dist/index.cjs +4594 -1
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.d.cts +1970 -141
  8. package/dist/index.d.ts +1970 -141
  9. package/dist/index.js +4398 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/result.cjs +641 -1
  12. package/dist/result.cjs.map +1 -1
  13. package/dist/result.d.cts +35 -5
  14. package/dist/result.d.ts +35 -5
  15. package/dist/result.js +561 -1
  16. package/dist/result.js.map +1 -1
  17. package/dist/testing.cjs +4202 -8
  18. package/dist/testing.cjs.map +1 -1
  19. package/dist/testing.d.cts +2 -6
  20. package/dist/testing.d.ts +2 -6
  21. package/dist/testing.js +4154 -8
  22. package/dist/testing.js.map +1 -1
  23. package/dist/{run-entry-D2MmJFj9.d.cts → types-B8NfNRGX.d.ts} +1152 -1499
  24. package/dist/{run-entry-Dduz-is2.d.ts → types-BZ2f4MRR.d.cts} +1152 -1499
  25. package/dist/workflow.cjs +7096 -6
  26. package/dist/workflow.cjs.map +1 -1
  27. package/dist/workflow.d.cts +3346 -22
  28. package/dist/workflow.d.ts +3346 -22
  29. package/dist/workflow.js +6929 -6
  30. package/dist/workflow.js.map +1 -1
  31. package/package.json +13 -178
  32. package/dist/adapters.cjs +0 -7
  33. package/dist/adapters.cjs.map +0 -1
  34. package/dist/adapters.d.cts +0 -179
  35. package/dist/adapters.d.ts +0 -179
  36. package/dist/adapters.js +0 -7
  37. package/dist/adapters.js.map +0 -1
  38. package/dist/batch.cjs +0 -7
  39. package/dist/batch.cjs.map +0 -1
  40. package/dist/batch.d.cts +0 -200
  41. package/dist/batch.d.ts +0 -200
  42. package/dist/batch.js +0 -7
  43. package/dist/batch.js.map +0 -1
  44. package/dist/bind-deps.cjs +0 -2
  45. package/dist/bind-deps.cjs.map +0 -1
  46. package/dist/bind-deps.d.cts +0 -28
  47. package/dist/bind-deps.d.ts +0 -28
  48. package/dist/bind-deps.js +0 -2
  49. package/dist/bind-deps.js.map +0 -1
  50. package/dist/cache.cjs +0 -2
  51. package/dist/cache.cjs.map +0 -1
  52. package/dist/cache.d.cts +0 -269
  53. package/dist/cache.d.ts +0 -269
  54. package/dist/cache.js +0 -2
  55. package/dist/cache.js.map +0 -1
  56. package/dist/circuit-breaker.cjs +0 -7
  57. package/dist/circuit-breaker.cjs.map +0 -1
  58. package/dist/circuit-breaker.d.cts +0 -211
  59. package/dist/circuit-breaker.d.ts +0 -211
  60. package/dist/circuit-breaker.js +0 -7
  61. package/dist/circuit-breaker.js.map +0 -1
  62. package/dist/conditional.cjs +0 -2
  63. package/dist/conditional.cjs.map +0 -1
  64. package/dist/conditional.d.cts +0 -252
  65. package/dist/conditional.d.ts +0 -252
  66. package/dist/conditional.js +0 -2
  67. package/dist/conditional.js.map +0 -1
  68. package/dist/core.cjs +0 -7
  69. package/dist/core.cjs.map +0 -1
  70. package/dist/core.d.cts +0 -5
  71. package/dist/core.d.ts +0 -5
  72. package/dist/core.js +0 -7
  73. package/dist/core.js.map +0 -1
  74. package/dist/di-COl5oFnR.d.cts +0 -15
  75. package/dist/di-CyDj_JyZ.d.ts +0 -15
  76. package/dist/diagnostics.cjs +0 -8
  77. package/dist/diagnostics.cjs.map +0 -1
  78. package/dist/diagnostics.d.cts +0 -68
  79. package/dist/diagnostics.d.ts +0 -68
  80. package/dist/diagnostics.js +0 -8
  81. package/dist/diagnostics.js.map +0 -1
  82. package/dist/durable.cjs +0 -11
  83. package/dist/durable.cjs.map +0 -1
  84. package/dist/durable.d.cts +0 -9
  85. package/dist/durable.d.ts +0 -9
  86. package/dist/durable.js +0 -11
  87. package/dist/durable.js.map +0 -1
  88. package/dist/duration.cjs +0 -2
  89. package/dist/duration.cjs.map +0 -1
  90. package/dist/duration.js +0 -2
  91. package/dist/duration.js.map +0 -1
  92. package/dist/engine.cjs +0 -11
  93. package/dist/engine.cjs.map +0 -1
  94. package/dist/engine.d.cts +0 -115
  95. package/dist/engine.d.ts +0 -115
  96. package/dist/engine.js +0 -11
  97. package/dist/engine.js.map +0 -1
  98. package/dist/errors.cjs +0 -2
  99. package/dist/errors.cjs.map +0 -1
  100. package/dist/errors.d.cts +0 -361
  101. package/dist/errors.d.ts +0 -361
  102. package/dist/errors.js +0 -2
  103. package/dist/errors.js.map +0 -1
  104. package/dist/fetch.cjs +0 -7
  105. package/dist/fetch.cjs.map +0 -1
  106. package/dist/fetch.d.cts +0 -86
  107. package/dist/fetch.d.ts +0 -86
  108. package/dist/fetch.js +0 -7
  109. package/dist/fetch.js.map +0 -1
  110. package/dist/flow.cjs +0 -7
  111. package/dist/flow.cjs.map +0 -1
  112. package/dist/flow.d.cts +0 -163
  113. package/dist/flow.d.ts +0 -163
  114. package/dist/flow.js +0 -7
  115. package/dist/flow.js.map +0 -1
  116. package/dist/functional.cjs +0 -2
  117. package/dist/functional.cjs.map +0 -1
  118. package/dist/functional.d.cts +0 -444
  119. package/dist/functional.d.ts +0 -444
  120. package/dist/functional.js +0 -2
  121. package/dist/functional.js.map +0 -1
  122. package/dist/guards-BodHXLzX.d.cts +0 -72
  123. package/dist/guards-CeWoQ8fn.d.ts +0 -72
  124. package/dist/hitl-BPE_1UiM.d.cts +0 -468
  125. package/dist/hitl-byp570uC.d.ts +0 -468
  126. package/dist/hitl.cjs +0 -7
  127. package/dist/hitl.cjs.map +0 -1
  128. package/dist/hitl.d.cts +0 -442
  129. package/dist/hitl.d.ts +0 -442
  130. package/dist/hitl.js +0 -7
  131. package/dist/hitl.js.map +0 -1
  132. package/dist/index-BYT3amEz.d.ts +0 -417
  133. package/dist/index-C_ak66jy.d.cts +0 -417
  134. package/dist/match-entry-DjI2bLpD.d.cts +0 -209
  135. package/dist/match-entry-DjI2bLpD.d.ts +0 -209
  136. package/dist/match.cjs +0 -2
  137. package/dist/match.cjs.map +0 -1
  138. package/dist/match.d.cts +0 -1
  139. package/dist/match.d.ts +0 -1
  140. package/dist/match.js +0 -2
  141. package/dist/match.js.map +0 -1
  142. package/dist/otel.cjs +0 -2
  143. package/dist/otel.cjs.map +0 -1
  144. package/dist/otel.d.cts +0 -188
  145. package/dist/otel.d.ts +0 -188
  146. package/dist/otel.js +0 -2
  147. package/dist/otel.js.map +0 -1
  148. package/dist/persistence-entry-DOMx3woy.d.ts +0 -822
  149. package/dist/persistence-entry-ymCA4iDu.d.cts +0 -822
  150. package/dist/persistence.cjs +0 -2
  151. package/dist/persistence.cjs.map +0 -1
  152. package/dist/persistence.d.cts +0 -7
  153. package/dist/persistence.d.ts +0 -7
  154. package/dist/persistence.js +0 -2
  155. package/dist/persistence.js.map +0 -1
  156. package/dist/policies.cjs +0 -2
  157. package/dist/policies.cjs.map +0 -1
  158. package/dist/policies.d.cts +0 -379
  159. package/dist/policies.d.ts +0 -379
  160. package/dist/policies.js +0 -2
  161. package/dist/policies.js.map +0 -1
  162. package/dist/ratelimit.cjs +0 -7
  163. package/dist/ratelimit.cjs.map +0 -1
  164. package/dist/ratelimit.d.cts +0 -458
  165. package/dist/ratelimit.d.ts +0 -458
  166. package/dist/ratelimit.js +0 -7
  167. package/dist/ratelimit.js.map +0 -1
  168. package/dist/reliability.cjs +0 -11
  169. package/dist/reliability.cjs.map +0 -1
  170. package/dist/reliability.d.cts +0 -11
  171. package/dist/reliability.d.ts +0 -11
  172. package/dist/reliability.js +0 -11
  173. package/dist/reliability.js.map +0 -1
  174. package/dist/resolver.cjs +0 -7
  175. package/dist/resolver.cjs.map +0 -1
  176. package/dist/resolver.d.cts +0 -68
  177. package/dist/resolver.d.ts +0 -68
  178. package/dist/resolver.js +0 -7
  179. package/dist/resolver.js.map +0 -1
  180. package/dist/resource.cjs +0 -7
  181. package/dist/resource.cjs.map +0 -1
  182. package/dist/resource.d.cts +0 -174
  183. package/dist/resource.d.ts +0 -174
  184. package/dist/resource.js +0 -7
  185. package/dist/resource.js.map +0 -1
  186. package/dist/result/retry.cjs +0 -2
  187. package/dist/result/retry.cjs.map +0 -1
  188. package/dist/result/retry.d.cts +0 -70
  189. package/dist/result/retry.d.ts +0 -70
  190. package/dist/result/retry.js +0 -2
  191. package/dist/result/retry.js.map +0 -1
  192. package/dist/retry.cjs +0 -2
  193. package/dist/retry.cjs.map +0 -1
  194. package/dist/retry.d.cts +0 -388
  195. package/dist/retry.d.ts +0 -388
  196. package/dist/retry.js +0 -2
  197. package/dist/retry.js.map +0 -1
  198. package/dist/run.cjs +0 -7
  199. package/dist/run.cjs.map +0 -1
  200. package/dist/run.d.cts +0 -4
  201. package/dist/run.d.ts +0 -4
  202. package/dist/run.js +0 -7
  203. package/dist/run.js.map +0 -1
  204. package/dist/saga.cjs +0 -11
  205. package/dist/saga.cjs.map +0 -1
  206. package/dist/saga.d.cts +0 -164
  207. package/dist/saga.d.ts +0 -164
  208. package/dist/saga.js +0 -11
  209. package/dist/saga.js.map +0 -1
  210. package/dist/singleflight.cjs +0 -2
  211. package/dist/singleflight.cjs.map +0 -1
  212. package/dist/singleflight.d.cts +0 -145
  213. package/dist/singleflight.d.ts +0 -145
  214. package/dist/singleflight.js +0 -2
  215. package/dist/singleflight.js.map +0 -1
  216. package/dist/slugs.cjs +0 -2
  217. package/dist/slugs.cjs.map +0 -1
  218. package/dist/slugs.d.cts +0 -67
  219. package/dist/slugs.d.ts +0 -67
  220. package/dist/slugs.js +0 -2
  221. package/dist/slugs.js.map +0 -1
  222. package/dist/streaming.cjs +0 -9
  223. package/dist/streaming.cjs.map +0 -1
  224. package/dist/streaming.d.cts +0 -596
  225. package/dist/streaming.d.ts +0 -596
  226. package/dist/streaming.js +0 -9
  227. package/dist/streaming.js.map +0 -1
  228. package/dist/tagged-error.cjs +0 -2
  229. package/dist/tagged-error.cjs.map +0 -1
  230. package/dist/tagged-error.d.cts +0 -275
  231. package/dist/tagged-error.d.ts +0 -275
  232. package/dist/tagged-error.js +0 -2
  233. package/dist/tagged-error.js.map +0 -1
  234. package/dist/types-DQmzO9f4.d.ts +0 -323
  235. package/dist/types-qBUOYi-4.d.cts +0 -323
  236. package/dist/webhook.cjs +0 -7
  237. package/dist/webhook.cjs.map +0 -1
  238. package/dist/webhook.d.cts +0 -499
  239. package/dist/webhook.d.ts +0 -499
  240. package/dist/webhook.js +0 -7
  241. package/dist/webhook.js.map +0 -1
@@ -1,9 +1,49 @@
1
- import { UnexpectedError } from './errors.js';
1
+ import { U as UnexpectedError } from './errors-DtXvrCiO.cjs';
2
+ import { StandardSchemaV1 } from '@standard-schema/spec';
2
3
 
3
4
  /**
4
- * awaitly/core
5
+ * Bound steps for the deps-first forms: run(deps, fn) and workflow({ steps }).
5
6
  *
6
- * Core Result primitives and run() function.
7
+ * Each dep key becomes a step function with the dep's own arguments that
8
+ * unwraps the ok value and early-exits on err. Kept out of core/index.ts
9
+ * so the core stays focused on the run/step engine.
10
+ */
11
+
12
+ type AnyFunction$1 = (...args: never[]) => unknown;
13
+ /**
14
+ * Success value of a dependency's return type. Result-returning deps
15
+ * contribute their `ok` value; plain (non-Result) deps pass through as-is.
16
+ * Shared with the policy wrappers, which normalize the same way.
17
+ */
18
+ type DepValueOfReturn<R> = [Extract<Awaited<R>, {
19
+ ok: true;
20
+ }>] extends [never] ? Awaited<R> : Extract<Awaited<R>, {
21
+ ok: true;
22
+ }> extends {
23
+ value: infer V;
24
+ } ? V : never;
25
+ /**
26
+ * The steps object passed to `run(deps, fn)`: each dep key becomes a step
27
+ * function with the same arguments that resolves to the unwrapped value
28
+ * (early-exiting the run on error).
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * const result = await run({ getUser, getOrder }, async (s) => {
33
+ * const user = await s.getUser(userId); // User — unwrapped
34
+ * const order = await s.getOrder(user.id); // Order
35
+ * return { user, order };
36
+ * });
37
+ * ```
38
+ */
39
+ type BoundSteps<Deps extends Record<string, AnyFunction$1>> = {
40
+ [K in keyof Deps]: (...args: Parameters<Deps[K]>) => Promise<DepValueOfReturn<ReturnType<Deps[K]>>>;
41
+ };
42
+
43
+ /**
44
+ * Core module (internal): Result primitives and the run() function.
45
+ *
46
+ * Surfaced through the root `awaitly` entry (formerly `awaitly/core`).
7
47
  * Use this module for minimal bundle size when you don't need the full workflow capabilities
8
48
  * (like retries, timeout, or state persistence) provided by `createWorkflow`.
9
49
  *
@@ -27,7 +67,7 @@ type DurationInput = string | DurationObject;
27
67
  *
28
68
  * @example
29
69
  * ```typescript
30
- * const success = Awaitly.ok(42);
70
+ * const success = ok(42);
31
71
  * // Type shown: Ok<number>
32
72
  * ```
33
73
  */
@@ -45,7 +85,7 @@ type Ok<T> = {
45
85
  *
46
86
  * @example
47
87
  * ```typescript
48
- * const failure = Awaitly.err({ type: "NOT_FOUND", message: "User not found" });
88
+ * const failure = err({ type: "NOT_FOUND", message: "User not found" });
49
89
  * // Type shown: Err<{ type: string; message: string }>
50
90
  * ```
51
91
  */
@@ -69,191 +109,18 @@ type Result<T, E = unknown, C = unknown> = Ok<T> | Err<E, C>;
69
109
  * Use this for asynchronous operations that might fail.
70
110
  */
71
111
  type AsyncResult<T, E = unknown, C = unknown> = Promise<Result<T, E, C>>;
72
- /** Discriminant for PromiseRejectedError type - use in switch statements */
73
- declare const PROMISE_REJECTED: "PROMISE_REJECTED";
74
- /**
75
- * Named error constant for unexpected/unhandled errors.
76
- * Used by the analyzer when a step doesn't declare errors.
77
- */
78
- declare const AWAITLY_UNEXPECTED: "AWAITLY_UNEXPECTED";
79
- /**
80
- * Named error constant for cancelled operations.
81
- */
82
- declare const AWAITLY_CANCELLED: "AWAITLY_CANCELLED";
83
- /**
84
- * Named error constant for timed-out operations.
85
- */
86
- declare const AWAITLY_TIMEOUT: "AWAITLY_TIMEOUT";
87
- /**
88
- * Helper to create a tuple of string literal tags with preserved literal types.
89
- * Use this when you need to store error tags in a variable while keeping
90
- * TypeScript's literal type inference (avoiding widening to string[]).
91
- *
92
- * @param t - The string literal tags
93
- * @returns The same array with preserved literal types
94
- *
95
- * @example
96
- * ```typescript
97
- * // Without tags() - type widens to string[]
98
- * const errs = ['CART_NOT_FOUND', 'CART_EMPTY']; // string[]
99
- *
100
- * // With tags() - literal types preserved
101
- * const errs = tags('CART_NOT_FOUND', 'CART_EMPTY'); // ['CART_NOT_FOUND', 'CART_EMPTY']
102
- *
103
- * await step('getCart', () => getCart(id), {
104
- * errors: errs, // Analyzer can extract literal types
105
- * out: 'cart',
106
- * });
107
- * ```
108
- */
109
- declare const tags: <const T extends readonly string[]>(...t: T) => T;
110
-
111
- type PromiseRejectedError = {
112
- type: typeof PROMISE_REJECTED;
113
- cause: unknown;
114
- };
115
- /** Cause type for promise rejections in async batch helpers */
116
- type PromiseRejectionCause = {
117
- type: "PROMISE_REJECTION";
118
- reason: unknown;
119
- };
120
- type EmptyInputError = {
121
- type: "EMPTY_INPUT";
122
- message: string;
123
- };
124
112
  type MaybeAsyncResult<T, E, C = unknown> = Result<T, E, C> | Promise<Result<T, E, C>>;
125
- /**
126
- * Creates a successful Result.
127
- * Use this when an operation completes successfully.
128
- *
129
- * @remarks When to use: Wrap a successful value in a Result for consistent return types.
130
- *
131
- * @param value - The success value to wrap
132
- * @returns An Ok object with `{ ok: true, value }`
133
- *
134
- * @example
135
- * ```typescript
136
- * const success = Awaitly.ok(42);
137
- * // Type: Ok<number>
138
- *
139
- * function divide(a: number, b: number): Result<number, string> {
140
- * if (b === 0) return Awaitly.err("Division by zero");
141
- * return Awaitly.ok(a / b);
142
- * }
143
- * ```
144
- */
145
- declare function ok<T>(value: T): Ok<T>;
146
- /**
147
- * Creates a failed Result.
148
- * Use this when an operation fails.
149
- *
150
- * @remarks When to use: Return a typed failure without throwing so callers can handle it explicitly.
151
- *
152
- * @param error - The error value describing what went wrong (e.g., error code, object)
153
- * @returns An Err object with `{ ok: false, error }`
154
- *
155
- * @example
156
- * ```typescript
157
- * // Simple error
158
- * const r1 = Awaitly.err("NOT_FOUND");
159
- * // Type: Err<"NOT_FOUND">
160
- *
161
- * // Error with context (include in error object)
162
- * const r2 = Awaitly.err({ type: "PROCESSING_FAILED", cause: originalError });
163
- * // Type: Err<{ type: string; cause: Error }>
164
- * ```
165
- */
166
- declare function err<E, C = unknown>(error: E, options?: {
167
- cause?: C;
168
- }): Err<E, C>;
169
- /**
170
- * Checks if a Result is successful.
171
- * Use this to narrow the type of a Result to the success case.
172
- *
173
- * @remarks When to use: Prefer functional-style checks or array filtering over `result.ok`.
174
- *
175
- * @param r - The Result to check
176
- * @returns `true` if successful, allowing access to `r.value`
177
- *
178
- * @example
179
- * ```typescript
180
- * const r = someOperation();
181
- * if (isOk(r)) {
182
- * // Use r.value (Type is T)
183
- * processValue(r.value);
184
- * } else {
185
- * // Handle r.error (Type is E)
186
- * handleError(r.error);
187
- * }
188
- * ```
189
- */
190
- declare const isOk: <T, E, C>(r: Result<T, E, C>) => r is Ok<T>;
191
- /**
192
- * Checks if a Result is a failure.
193
- * Use this to narrow the type of a Result to the error case.
194
- *
195
- * @remarks When to use: Prefer functional-style checks or array filtering over `result.ok`.
196
- *
197
- * @param r - The Result to check
198
- * @returns `true` if failed, allowing access to `r.error` and `r.cause`
199
- *
200
- * @example
201
- * ```typescript
202
- * if (isErr(r)) {
203
- * // Handle error case early
204
- * return;
205
- * }
206
- * // Proceed with success case
207
- * ```
208
- */
209
- declare const isErr: <T, E, C>(r: Result<T, E, C>) => r is Err<E, C>;
210
- /**
211
- * Checks if an error is an UnexpectedError.
212
- * Used internally by the framework but exported for advanced custom handling.
213
- * Indicates an error that wasn't typed/expected in the `run` signature.
214
- *
215
- * @remarks When to use: Distinguish unexpected failures from your typed error union.
216
- */
217
- declare const isUnexpectedError: (e: unknown) => e is UnexpectedError;
218
- /**
219
- * Type for exhaustive error handlers mapping string literal errors and UnexpectedError.
220
- * Each key in E gets a handler, plus UnexpectedError is required.
221
- */
222
- type MatchErrorHandlers<E extends string, R> = {
223
- [K in Exclude<E, "UnexpectedError">]: (error: K) => R;
224
- } & {
225
- UnexpectedError: (error: UnexpectedError) => R;
226
- };
227
- /**
228
- * Exhaustive pattern matching for error types.
229
- * Handles both string literal errors and UnexpectedError, ensuring all cases are covered.
230
- *
231
- * @param error - The error to match (string literal or UnexpectedError)
232
- * @param handlers - Object with a handler for each error case plus UnexpectedError
233
- * @returns The result of the matched handler
234
- *
235
- * @example
236
- * ```typescript
237
- * type FetchError = "NOT_FOUND" | "FETCH_ERROR";
238
- * const result: Result<User, FetchError | UnexpectedError> = await fetchUser();
239
- *
240
- * if (!result.ok) {
241
- * return matchError(result.error, {
242
- * NOT_FOUND: () => 404,
243
- * FETCH_ERROR: () => 500,
244
- * UnexpectedError: (e) => { throw e.cause; }
245
- * });
246
- * }
247
- * ```
248
- */
249
- declare function matchError<E extends string, R>(handlers: MatchErrorHandlers<E, R>): (error: E | UnexpectedError) => R;
250
- declare function matchError<E extends string, R>(error: E | UnexpectedError, handlers: MatchErrorHandlers<E, R>): R;
251
113
  type AnyFunction = (...args: never[]) => unknown;
252
114
  /**
253
115
  * Helper to extract the error type from Result or AsyncResult return values.
254
116
  * Works even when a function is declared to return a union of both forms.
117
+ * Plain (non-Result) return types contribute `never` — without the [never]
118
+ * guard they would infer `unknown` and poison error unions built from
119
+ * mixed deps.
255
120
  */
256
- type ErrorOfReturn<R> = Extract<Awaited<R>, {
121
+ type ErrorOfReturn<R> = [Extract<Awaited<R>, {
122
+ ok: false;
123
+ }>] extends [never] ? never : Extract<Awaited<R>, {
257
124
  ok: false;
258
125
  }> extends {
259
126
  error: infer E;
@@ -262,12 +129,6 @@ type ErrorOfReturn<R> = Extract<Awaited<R>, {
262
129
  * Extract error type from a single function's return type
263
130
  */
264
131
  type ErrorOf<T extends AnyFunction> = ErrorOfReturn<ReturnType<T>>;
265
- /**
266
- * Extract union of error types from multiple functions (tuple form)
267
- */
268
- type Errors<T extends AnyFunction[]> = {
269
- [K in keyof T]: ErrorOf<T[K]>;
270
- }[number];
271
132
  /**
272
133
  * Extract union of error types from a deps object.
273
134
  *
@@ -281,27 +142,6 @@ type Errors<T extends AnyFunction[]> = {
281
142
  type ErrorsOf<Deps extends Record<string, AnyFunction>> = {
282
143
  [K in keyof Deps]: ErrorOf<Deps[K]>;
283
144
  }[keyof Deps];
284
- /**
285
- * Extract value type from Result
286
- */
287
- type ExtractValue<T> = T extends {
288
- ok: true;
289
- value: infer U;
290
- } ? U : never;
291
- /**
292
- * Extract error type from Result
293
- */
294
- type ExtractError<T> = T extends {
295
- ok: false;
296
- error: infer E;
297
- } ? E : never;
298
- /**
299
- * Extract cause type from Result
300
- */
301
- type ExtractCause<T> = T extends {
302
- ok: false;
303
- cause?: infer C;
304
- } ? C : never;
305
145
  /**
306
146
  * Helper to extract the cause type from Result or AsyncResult return values.
307
147
  * Works even when a function is declared to return a union of both forms.
@@ -574,14 +414,6 @@ interface StepErrorDiagnostics {
574
414
  cumulativeDurationMs?: number;
575
415
  origin: 'result' | 'throw' | 'timeout';
576
416
  }
577
- /** Extract canonical error tag. Priority: _tag > tag > code > Error.name > "unknown".
578
- * Tags are case-sensitive, whitespace-trimmed, otherwise raw.
579
- * Note: Error.name is fallback-grade (often too coarse like "Error", "TypeError"). */
580
- declare function extractErrorTag(error: unknown): string;
581
- /** Look up ErrorClassification from errorMeta for a given tag. */
582
- declare function lookupErrorClassification(tag: string, errorMeta?: Record<string, ErrorClassification>): ErrorClassification | undefined;
583
- /** Extract StepMetadata from StepOptions (returns undefined when empty). */
584
- declare function extractStepMetadata(options: StepOptions): StepMetadata | undefined;
585
417
  /**
586
418
  * Backoff strategy for retry operations.
587
419
  */
@@ -1659,6 +1491,18 @@ type WorkflowEvent<E, C = unknown> = {
1659
1491
  ts: number;
1660
1492
  metadata?: StepMetadata;
1661
1493
  context?: C;
1494
+ } | {
1495
+ type: "decision";
1496
+ workflowId: string;
1497
+ workflowName?: string;
1498
+ decisionId: string;
1499
+ label?: string;
1500
+ branch: string;
1501
+ value: unknown;
1502
+ phase?: "start" | "end";
1503
+ durationMs?: number;
1504
+ ts: number;
1505
+ context?: C;
1662
1506
  } | {
1663
1507
  type: "scope_start";
1664
1508
  workflowId: string;
@@ -1831,6 +1675,23 @@ type WorkflowEvent<E, C = unknown> = {
1831
1675
  lastStepKey?: string;
1832
1676
  context?: C;
1833
1677
  };
1678
+ /**
1679
+ * A declared workflow graph for strict runtime validation.
1680
+ *
1681
+ * Pass either a list of step/decision ids or a WorkflowDiagramDSL-shaped
1682
+ * object (`{ states: [{ id }] }`, as produced by awaitly-analyze).
1683
+ * When provided, any runtime step or decision id not present in the graph
1684
+ * fails the workflow immediately — so the static diagram is guaranteed to
1685
+ * match what actually runs. Ids containing `{...}` placeholders
1686
+ * (e.g. "item-{i}") match any value in that position.
1687
+ */
1688
+ type DeclaredGraph = readonly string[] | {
1689
+ readonly states: ReadonlyArray<{
1690
+ readonly id: string;
1691
+ /** Authored id when the unique diagram id needed a collision suffix. */
1692
+ readonly semanticId?: string;
1693
+ }>;
1694
+ };
1834
1695
  type RunOptionsWithCatch<E, C = void> = {
1835
1696
  /**
1836
1697
  * Handler for expected errors.
@@ -1866,6 +1727,11 @@ type RunOptionsWithCatch<E, C = void> = {
1866
1727
  * Useful for passing request IDs, user IDs, or loggers.
1867
1728
  */
1868
1729
  context?: C;
1730
+ /**
1731
+ * Declared workflow graph for strict runtime validation.
1732
+ * Undeclared step/decision ids fail the workflow immediately.
1733
+ */
1734
+ graph?: DeclaredGraph;
1869
1735
  /**
1870
1736
  * @internal External signal for workflow-level cancellation.
1871
1737
  * Used by createWorkflow() to pass the workflow signal to steps.
@@ -1893,6 +1759,11 @@ type RunOptionsWithoutCatch<E, C = void> = {
1893
1759
  */
1894
1760
  workflowName?: string;
1895
1761
  context?: C;
1762
+ /**
1763
+ * Declared workflow graph for strict runtime validation.
1764
+ * Undeclared step/decision ids fail the workflow immediately.
1765
+ */
1766
+ graph?: DeclaredGraph;
1896
1767
  /**
1897
1768
  * @internal External signal for workflow-level cancellation.
1898
1769
  * Used by createWorkflow() to pass the workflow signal to steps.
@@ -1967,7 +1838,7 @@ declare function isEarlyExit<E>(e: unknown): e is EarlyExit<E>;
1967
1838
  /**
1968
1839
  * run() with catchUnexpected: closed union Result<T, E>.
1969
1840
  */
1970
- declare function run<T, E, C = void>(fn: (context: {
1841
+ declare function runFn<T, E, C = void>(fn: (context: {
1971
1842
  step: RunStep<E>;
1972
1843
  }) => Promise<T> | T, options: RunOptionsWithCatch<E, C>): AsyncResult<T, E, unknown>;
1973
1844
  /**
@@ -1976,7 +1847,7 @@ declare function run<T, E, C = void>(fn: (context: {
1976
1847
  * uncaught exceptions are possible. Step errors pass through as-is.
1977
1848
  * When E is never (default), step is RunStep<unknown> so any operation is allowed.
1978
1849
  */
1979
- declare function run<T, E = never, C = void>(fn: (context: {
1850
+ declare function runFn<T, E = never, C = void>(fn: (context: {
1980
1851
  step: [E] extends [never] ? RunStep<unknown> : RunStep<E>;
1981
1852
  }) => Promise<T> | T, options?: {
1982
1853
  onError?: (error: E | UnexpectedError, stepName?: string, ctx?: C) => void;
@@ -1984,11 +1855,55 @@ declare function run<T, E = never, C = void>(fn: (context: {
1984
1855
  workflowId?: string;
1985
1856
  workflowName?: string;
1986
1857
  context?: C;
1858
+ graph?: DeclaredGraph;
1987
1859
  /** @internal External signal for workflow-level cancellation. */
1988
1860
  _workflowSignal?: AbortSignal;
1989
1861
  }): AsyncResult<T, E | UnexpectedError, unknown>;
1990
- declare namespace run {
1991
- var strict: <T, E, C = void>(fn: (context: {
1862
+ /**
1863
+ * run() with dependencies: auto-bound steps and automatic error inference.
1864
+ *
1865
+ * Pass your functions as the first argument; the callback receives a steps
1866
+ * object mirroring them. Calling `s.getUser(id)` behaves exactly like
1867
+ * `step('getUser', () => getUser(id))` — unwraps ok, early-exits on err —
1868
+ * and the result's error union is inferred from the deps. No type
1869
+ * parameters, no string IDs, no thunks.
1870
+ *
1871
+ * Plain (non-Result) functions are valid deps: their values pass through
1872
+ * and their throws become UnexpectedError, so existing code works unchanged
1873
+ * and can adopt typed errors incrementally.
1874
+ *
1875
+ * @example
1876
+ * ```typescript
1877
+ * const result = await run({ getOrder, getUser, charge }, async (s) => {
1878
+ * const order = await s.getOrder(orderId);
1879
+ * const user = await s.getUser(order.userId);
1880
+ * return s.charge(order.total);
1881
+ * });
1882
+ * // result.error: OrderNotFound | UserNotFound | ChargeDeclined | UnexpectedError
1883
+ * ```
1884
+ */
1885
+ declare function runFn<const Deps extends Record<string, AnyFunction>, T, C = void>(deps: Deps, fn: (steps: BoundSteps<Deps>, context: {
1886
+ step: [ErrorsOf<Deps>] extends [never] ? RunStep<unknown> : RunStep<ErrorsOf<Deps>>;
1887
+ }) => Promise<T> | T, options?: {
1888
+ onError?: (error: ErrorsOf<Deps> | UnexpectedError, stepName?: string, ctx?: C) => void;
1889
+ onEvent?: (event: WorkflowEvent<ErrorsOf<Deps> | UnexpectedError, C>, ctx: C) => void;
1890
+ workflowId?: string;
1891
+ workflowName?: string;
1892
+ context?: C;
1893
+ graph?: DeclaredGraph;
1894
+ /** @internal External signal for workflow-level cancellation. */
1895
+ _workflowSignal?: AbortSignal;
1896
+ }): AsyncResult<T, ErrorsOf<Deps> | UnexpectedError, unknown>;
1897
+ /**
1898
+ * The public run(): the engine with `.strict` attached.
1899
+ *
1900
+ * Assembled with a PURE-annotated Object.assign instead of a top-level
1901
+ * `run.strict = ...` mutation — a top-level property assignment is a side
1902
+ * effect that pins run (and the whole step engine) into every consumer
1903
+ * bundle even when only Result primitives are imported.
1904
+ */
1905
+ declare const run: typeof runFn & {
1906
+ strict: <T, E, C = void>(fn: (context: {
1992
1907
  step: RunStep<E>;
1993
1908
  }) => Promise<T> | T, options: {
1994
1909
  onError?: (error: E, stepName?: string, ctx?: C) => void;
@@ -2005,1427 +1920,1165 @@ declare namespace run {
2005
1920
  /** @internal External signal for workflow-level cancellation. */
2006
1921
  _workflowSignal?: AbortSignal;
2007
1922
  }) => AsyncResult<T, E, unknown>;
2008
- }
1923
+ };
1924
+
2009
1925
  /**
2010
- * Error thrown when `unwrap()` is called on an error Result.
1926
+ * awaitly/streaming - Types
2011
1927
  *
2012
- * This error is thrown to prevent silent failures when using `unwrap()`.
2013
- * Prefer using `unwrapOr`, `unwrapOrElse`, or pattern matching with `match` or `isOk`/`isErr`.
1928
+ * Core types for Result-aware streaming in workflows.
1929
+ * All stream operations return Result types, enabling typed error handling
1930
+ * throughout the streaming pipeline.
1931
+ */
1932
+
1933
+ /** Discriminant for stream write errors */
1934
+ declare const STREAM_WRITE_ERROR: "STREAM_WRITE_ERROR";
1935
+ /** Discriminant for stream read errors */
1936
+ declare const STREAM_READ_ERROR: "STREAM_READ_ERROR";
1937
+ /** Discriminant for stream close errors */
1938
+ declare const STREAM_CLOSE_ERROR: "STREAM_CLOSE_ERROR";
1939
+ /** Discriminant for stream store errors */
1940
+ declare const STREAM_STORE_ERROR: "STREAM_STORE_ERROR";
1941
+ /** Discriminant for stream ended marker */
1942
+ declare const STREAM_ENDED: "STREAM_ENDED";
1943
+ /** Discriminant for stream backpressure errors */
1944
+ declare const STREAM_BACKPRESSURE_ERROR: "STREAM_BACKPRESSURE_ERROR";
1945
+ /**
1946
+ * Error returned when a write operation fails.
1947
+ */
1948
+ type StreamWriteError = {
1949
+ type: typeof STREAM_WRITE_ERROR;
1950
+ reason: "closed" | "aborted" | "store_error";
1951
+ message: string;
1952
+ cause?: unknown;
1953
+ };
1954
+ /**
1955
+ * Error returned when a read operation fails.
1956
+ */
1957
+ type StreamReadError = {
1958
+ type: typeof STREAM_READ_ERROR;
1959
+ reason: "closed" | "store_error";
1960
+ message: string;
1961
+ cause?: unknown;
1962
+ };
1963
+ /**
1964
+ * Error returned when closing a stream fails.
1965
+ */
1966
+ type StreamCloseError = {
1967
+ type: typeof STREAM_CLOSE_ERROR;
1968
+ reason: "already_closed" | "store_error";
1969
+ message: string;
1970
+ cause?: unknown;
1971
+ };
1972
+ /**
1973
+ * Error returned from StreamStore operations.
1974
+ */
1975
+ type StreamStoreError = {
1976
+ type: typeof STREAM_STORE_ERROR;
1977
+ reason: "read_error" | "write_error" | "metadata_error" | "close_error";
1978
+ message: string;
1979
+ cause?: unknown;
1980
+ };
1981
+ /**
1982
+ * Marker indicating stream has ended (not an error, but a terminal state).
1983
+ * Used as the "error" type when stream is exhausted.
1984
+ */
1985
+ type StreamEndedMarker = {
1986
+ type: typeof STREAM_ENDED;
1987
+ finalPosition: number;
1988
+ };
1989
+ /**
1990
+ * Backpressure error when writer is paused.
1991
+ */
1992
+ type StreamBackpressureError = {
1993
+ type: typeof STREAM_BACKPRESSURE_ERROR;
1994
+ bufferedCount: number;
1995
+ highWaterMark: number;
1996
+ };
1997
+ /**
1998
+ * Union of all stream errors.
1999
+ */
2000
+ type StreamError = StreamWriteError | StreamReadError | StreamCloseError | StreamStoreError | StreamBackpressureError;
2001
+ /**
2002
+ * A single item in the stream with metadata.
2014
2003
  */
2015
- declare class UnwrapError<E = unknown, C = unknown> extends Error {
2016
- readonly error: E;
2017
- readonly cause?: C | undefined;
2018
- constructor(error: E, cause?: C | undefined);
2004
+ interface StreamItem<T> {
2005
+ /** The value stored in this stream item */
2006
+ value: T;
2007
+ /** Position in the stream (0-indexed) */
2008
+ position: number;
2009
+ /** Timestamp when item was written */
2010
+ ts: number;
2019
2011
  }
2020
2012
  /**
2021
- * Unwraps a Result, throwing an error if it's a failure.
2022
- *
2023
- * @remarks When to use: Only at boundaries or tests where a failure should be fatal.
2024
- *
2025
- * ## When to Use
2026
- *
2027
- * Use `unwrap()` when:
2028
- * - You're certain the Result is successful (e.g., after checking with `isOk`)
2029
- * - You're in a context where errors should crash (e.g., tests, initialization)
2030
- * - You need the value immediately and can't handle errors gracefully
2031
- *
2032
- * ## Why Avoid This
2033
- *
2034
- * **Prefer alternatives** in production code:
2035
- * - `unwrapOr(defaultValue)` - Provide a fallback value
2036
- * - `unwrapOrElse(fn)` - Compute fallback from error
2037
- * - `match()` - Handle both cases explicitly
2038
- * - `isOk()` / `isErr()` - Type-safe pattern matching
2039
- *
2040
- * Throwing errors makes error handling harder and can crash your application.
2041
- *
2042
- * @param r - The Result to unwrap
2043
- * @returns The success value if the Result is successful
2044
- * @throws {UnwrapError} If the Result is an error (includes the error and cause)
2045
- *
2046
- * @example
2047
- * ```typescript
2048
- * // Safe usage after checking
2049
- * const result = someOperation();
2050
- * if (isOk(result)) {
2051
- * const value = unwrap(result); // Safe - we know it's ok
2052
- * }
2053
- *
2054
- * // Unsafe usage (not recommended)
2055
- * const value = unwrap(someOperation()); // May throw!
2056
- * ```
2013
+ * Metadata about a stream.
2014
+ */
2015
+ interface StreamMetadata {
2016
+ /** Unique identifier for the stream (workflowId + namespace) */
2017
+ id: string;
2018
+ /** Namespace within the workflow */
2019
+ namespace: string;
2020
+ /** Workflow ID that owns this stream */
2021
+ workflowId: string;
2022
+ /** Number of items in the stream */
2023
+ length: number;
2024
+ /** Whether the stream has been closed */
2025
+ closed: boolean;
2026
+ /** Timestamp when stream was created */
2027
+ createdAt: number;
2028
+ /** Timestamp when stream was last written to */
2029
+ lastWriteAt?: number;
2030
+ /** Timestamp when stream was closed */
2031
+ closedAt?: number;
2032
+ }
2033
+ /**
2034
+ * Options for creating a writable stream.
2057
2035
  */
2058
- declare const unwrap: <T, E, C>(r: Result<T, E, C>) => T;
2036
+ interface StreamOptions {
2037
+ /** Named streams (default: 'default') */
2038
+ namespace?: string;
2039
+ /** Backpressure threshold (default: 16) */
2040
+ highWaterMark?: number;
2041
+ }
2059
2042
  /**
2060
- * Unwraps a Result, returning a default value if it's a failure.
2061
- *
2062
- * @remarks When to use: Provide a safe fallback without branching.
2063
- *
2064
- * ## When to Use
2065
- *
2066
- * Use `unwrapOr()` when:
2067
- * - You have a sensible default value for errors
2068
- * - You want to continue execution even on failure
2069
- * - The default value is cheap to compute (use `unwrapOrElse` if expensive)
2070
- *
2071
- * ## Why Use This
2043
+ * Options for creating a readable stream.
2044
+ */
2045
+ interface StreamReadOptions {
2046
+ /** Named streams (default: 'default') */
2047
+ namespace?: string;
2048
+ /** Resume from position (0-indexed) */
2049
+ startIndex?: number;
2050
+ }
2051
+ /**
2052
+ * Options for streamForEach operation.
2053
+ */
2054
+ interface StreamForEachOptions {
2055
+ /** Name for the operation (used in events) */
2056
+ name?: string;
2057
+ /** Checkpoint after every N items (default: 1 = checkpoint each item) */
2058
+ checkpointInterval?: number;
2059
+ /** Maximum concurrent processors (default: 1 = sequential) */
2060
+ concurrency?: number;
2061
+ }
2062
+ /**
2063
+ * Result from streamForEach operation.
2064
+ */
2065
+ interface StreamForEachResult<R> {
2066
+ /** Results from each processed item */
2067
+ results: R[];
2068
+ /** Total items processed */
2069
+ processedCount: number;
2070
+ /** Position of last processed item */
2071
+ lastPosition: number;
2072
+ }
2073
+ /**
2074
+ * Writable stream interface - never throws, returns Results.
2072
2075
  *
2073
- * - **Safe**: Never throws, always returns a value
2074
- * - **Simple**: One-liner for common error handling
2075
- * - **Type-safe**: TypeScript knows you'll always get a `T`
2076
+ * Use within a step to write values to a stream that can be consumed
2077
+ * by readers (e.g., HTTP response streaming, AI token streaming).
2076
2078
  *
2077
- * @param r - The Result to unwrap
2078
- * @param defaultValue - The value to return if the Result is an error
2079
- * @returns The success value if successful, otherwise the default value
2079
+ * @template T - Type of values written to the stream
2080
2080
  *
2081
2081
  * @example
2082
2082
  * ```typescript
2083
- * // Provide default for missing data
2084
- * const user = unwrapOr(fetchUser(id), { id: 'anonymous', name: 'Guest' });
2083
+ * const writer = step.getWritable<string>({ namespace: 'ai-response' });
2085
2084
  *
2086
- * // Provide default for numeric operations
2087
- * const count = unwrapOr(parseCount(input), 0);
2085
+ * await step(() => generateAI({
2086
+ * prompt: 'Hello',
2087
+ * onToken: async (token) => { await writer.write(token); }
2088
+ * }), { key: 'generate' });
2088
2089
  *
2089
- * // Provide default for optional features
2090
- * const config = unwrapOr(loadConfig(), getDefaultConfig());
2090
+ * await writer.close();
2091
2091
  * ```
2092
2092
  */
2093
- declare const unwrapOr: <T, E, C>(r: Result<T, E, C>, defaultValue: T) => T;
2093
+ interface StreamWriter<T> {
2094
+ /**
2095
+ * Write a value to the stream.
2096
+ * Returns an error if the stream is closed, aborted, or store fails.
2097
+ */
2098
+ write(value: T): AsyncResult<void, StreamWriteError>;
2099
+ /**
2100
+ * Close the stream normally.
2101
+ * Signals to readers that no more data will be written.
2102
+ */
2103
+ close(): AsyncResult<void, StreamCloseError>;
2104
+ /**
2105
+ * Abort the stream with a reason.
2106
+ * Use for error conditions that should terminate the stream.
2107
+ */
2108
+ abort(reason: unknown): void;
2109
+ /** Whether the stream is still writable */
2110
+ readonly writable: boolean;
2111
+ /** Current write position (number of items written) */
2112
+ readonly position: number;
2113
+ /** Stream namespace */
2114
+ readonly namespace: string;
2115
+ }
2094
2116
  /**
2095
- * Unwraps a Result, computing a default value from the error if it's a failure.
2096
- *
2097
- * @remarks When to use: Compute a fallback from the error (logging, metrics, or derived defaults).
2098
- *
2099
- * ## When to Use
2117
+ * Readable stream interface - returns STREAM_ENDED marker when complete.
2100
2118
  *
2101
- * Use `unwrapOrElse()` when:
2102
- * - The default value is expensive to compute (lazy evaluation)
2103
- * - You need to log or handle the error before providing a default
2104
- * - The default depends on the error type or cause
2105
- * - You want to transform the error into a success value
2119
+ * Use to consume values from a stream, with support for resuming from
2120
+ * a specific position.
2106
2121
  *
2107
- * ## Why Use This Instead of `unwrapOr`
2108
- *
2109
- * - **Lazy**: Default is only computed if needed (better performance)
2110
- * - **Error-aware**: You can inspect the error before providing default
2111
- * - **Flexible**: Default can depend on error type or cause
2112
- *
2113
- * @param r - The Result to unwrap
2114
- * @param fn - Function that receives the error and optional cause, returns the default value
2115
- * @returns The success value if successful, otherwise the result of calling `fn(error, cause)`
2122
+ * @template T - Type of values read from the stream
2116
2123
  *
2117
2124
  * @example
2118
2125
  * ```typescript
2119
- * // Compute default based on error type
2120
- * const port = unwrapOrElse(parsePort(env.PORT), (error) => {
2121
- * if (error === 'INVALID_FORMAT') return 3000;
2122
- * if (error === 'OUT_OF_RANGE') return 8080;
2123
- * return 4000; // default
2124
- * });
2126
+ * const reader = getStreamReader<string>(runId, { namespace: 'ai-response' });
2125
2127
  *
2126
- * // Log error before providing default
2127
- * const data = unwrapOrElse(fetchData(), (error, cause) => {
2128
- * console.error('Failed to fetch:', error, cause);
2129
- * return getCachedData();
2130
- * });
2128
+ * let result = await reader.read();
2129
+ * while (result.ok) {
2130
+ * response.write(result.value);
2131
+ * result = await reader.read();
2132
+ * }
2131
2133
  *
2132
- * // Transform error into success value
2133
- * const result = unwrapOrElse(operation(), (error) => {
2134
- * return { success: false, reason: String(error) };
2135
- * });
2134
+ * if (result.error.type === 'STREAM_ENDED') {
2135
+ * console.log('Stream complete at position', result.error.finalPosition);
2136
+ * }
2136
2137
  * ```
2137
2138
  */
2138
- declare const unwrapOrElse: <T, E, C>(r: Result<T, E, C>, fn: (error: E, cause?: C) => T) => T;
2139
+ interface StreamReader<T> {
2140
+ /**
2141
+ * Read the next value from the stream.
2142
+ * Returns StreamEndedMarker when stream is exhausted.
2143
+ */
2144
+ read(): AsyncResult<T, StreamReadError | StreamEndedMarker>;
2145
+ /**
2146
+ * Close the reader (stop consuming).
2147
+ * Does not affect the underlying stream.
2148
+ */
2149
+ close(): void;
2150
+ /** Whether there may be more data to read */
2151
+ readonly readable: boolean;
2152
+ /** Current read position */
2153
+ readonly position: number;
2154
+ /** Stream namespace */
2155
+ readonly namespace: string;
2156
+ }
2157
+ /** Unsubscribe function returned by subscribe */
2158
+ type Unsubscribe = () => void;
2139
2159
  /**
2140
- * Alias for `unwrap`. Returns the success value or throws.
2160
+ * Storage backend for stream data.
2161
+ * Follows the same patterns as persistence.ts adapters.
2141
2162
  *
2142
- * The Result is already computed; use when you want the value or throw (e.g. at boundaries or in tests).
2163
+ * @example In-memory store
2164
+ * ```typescript
2165
+ * const store = createMemoryStreamStore();
2166
+ * ```
2143
2167
  *
2144
- * @param r - The Result to unwrap
2145
- * @returns The success value if the Result is successful
2146
- * @throws {UnwrapError} If the Result is an error (includes the error and cause)
2168
+ * @example File-based store
2169
+ * ```typescript
2170
+ * const store = createFileStreamStore({ directory: './streams', fs });
2171
+ * ```
2147
2172
  */
2148
- declare const runOrThrow: <T, E, C>(r: Result<T, E, C>) => T;
2173
+ interface StreamStore {
2174
+ /**
2175
+ * Append an item to the stream.
2176
+ */
2177
+ append<T>(workflowId: string, namespace: string, item: StreamItem<T>): AsyncResult<void, StreamStoreError>;
2178
+ /**
2179
+ * Read items from the stream starting at an index.
2180
+ * @param startIndex - Position to start reading from (0-indexed)
2181
+ * @param limit - Maximum number of items to read (default: all remaining)
2182
+ */
2183
+ read<T>(workflowId: string, namespace: string, startIndex: number, limit?: number): AsyncResult<StreamItem<T>[], StreamStoreError>;
2184
+ /**
2185
+ * Get metadata about a stream.
2186
+ * Returns undefined if stream doesn't exist.
2187
+ */
2188
+ getMetadata(workflowId: string, namespace: string): AsyncResult<StreamMetadata | undefined, StreamStoreError>;
2189
+ /**
2190
+ * Mark stream as closed.
2191
+ */
2192
+ closeStream(workflowId: string, namespace: string): AsyncResult<void, StreamStoreError>;
2193
+ /**
2194
+ * Subscribe to new items in a stream.
2195
+ * Callback is invoked for each new item written.
2196
+ * Returns unsubscribe function.
2197
+ */
2198
+ subscribe<T>(workflowId: string, namespace: string, callback: (item: StreamItem<T>) => void): Unsubscribe;
2199
+ }
2149
2200
  /**
2150
- * Awaits a Promise of a Result, then returns the success value or rejects.
2151
- *
2152
- * The returned promise **resolves with T** on success and **rejects with UnwrapError** on failure.
2153
- * UnwrapError extends Error and carries the original `error` and `cause` from the Err.
2154
- *
2155
- * @param ar - A Promise or thenable that resolves to a Result
2156
- * @returns A Promise that resolves with the success value or rejects with UnwrapError
2201
+ * Check if an error is a StreamEndedMarker.
2157
2202
  */
2158
- declare const runOrThrowAsync: <T, E, C>(ar: PromiseLike<Result<T, E, C>>) => Promise<T>;
2203
+ declare function isStreamEnded(error: unknown): error is StreamEndedMarker;
2159
2204
  /**
2160
- * Convenience alias for `unwrapOr(r, null)`. Returns the success value or null.
2161
- *
2162
- * @param r - The Result to unwrap
2163
- * @returns The success value if successful, otherwise null
2205
+ * Check if an error is a StreamWriteError.
2164
2206
  */
2165
- declare const runOrNull: <T, E, C>(r: Result<T, E, C>) => T | null;
2207
+ declare function isStreamWriteError(error: unknown): error is StreamWriteError;
2166
2208
  /**
2167
- * Convenience alias for `unwrapOr(r, undefined)`. Returns the success value or undefined.
2168
- *
2169
- * @param r - The Result to unwrap
2170
- * @returns The success value if successful, otherwise undefined
2209
+ * Check if an error is a StreamReadError.
2171
2210
  */
2172
- declare const runOrUndefined: <T, E, C>(r: Result<T, E, C>) => T | undefined;
2211
+ declare function isStreamReadError(error: unknown): error is StreamReadError;
2173
2212
  /**
2174
- * Wraps a synchronous throwing function in a Result.
2175
- *
2176
- * @remarks When to use: Wrap sync code that might throw so exceptions become Err values.
2177
- *
2178
- * ## When to Use
2179
- *
2180
- * Use `from()` when:
2181
- * - You have a synchronous function that throws exceptions
2182
- * - You want to convert exceptions to typed errors
2183
- * - You're integrating with libraries that throw (e.g., JSON.parse, fs.readFileSync)
2184
- * - You need to handle errors without try/catch blocks
2185
- *
2186
- * ## Why Use This
2187
- *
2188
- * - **Type-safe errors**: Convert thrown exceptions to typed Result errors
2189
- * - **No try/catch**: Cleaner code without nested try/catch blocks
2190
- * - **Composable**: Results can be chained with `andThen`, `map`, etc.
2191
- * - **Explicit errors**: Forces you to handle errors explicitly
2192
- *
2193
- * @param fn - The synchronous function to execute (may throw)
2194
- * @returns A Result with the function's return value or the thrown error
2195
- *
2196
- * @example
2197
- * ```typescript
2198
- * // Wrap JSON.parse
2199
- * const parsed = from(() => JSON.parse('{"key": "value"}'));
2200
- * // parsed: { ok: true, value: { key: "value" } }
2201
- *
2202
- * const error = from(() => JSON.parse('invalid'));
2203
- * // error: { ok: false, error: SyntaxError }
2204
- * ```
2213
+ * Check if an error is a StreamStoreError.
2205
2214
  */
2206
- declare function from<T>(fn: () => T): Ok<T> | Err<unknown, unknown>;
2215
+ declare function isStreamStoreError(error: unknown): error is StreamStoreError;
2207
2216
  /**
2208
- * Wraps a synchronous throwing function in a Result with custom error mapping.
2209
- *
2210
- * Use this overload when you want to map thrown exceptions to your typed error union.
2211
- *
2212
- * @param fn - The synchronous function to execute (may throw)
2213
- * @param onError - Function to map the thrown exception to a typed error
2214
- * @returns A Result with the function's return value or the mapped error
2215
- *
2216
- * @example
2217
- * ```typescript
2218
- * // Map exceptions to typed errors
2219
- * const parsed = from(
2220
- * () => JSON.parse(input),
2221
- * (cause) => ({ type: 'PARSE_ERROR' as const, cause })
2222
- * );
2223
- * // parsed.error: { type: 'PARSE_ERROR', cause: SyntaxError }
2224
- *
2225
- * // Map to simple error codes
2226
- * const value = from(
2227
- * () => riskyOperation(),
2228
- * () => 'OPERATION_FAILED' as const
2229
- * );
2230
- * ```
2217
+ * Check if an error is a StreamBackpressureError.
2231
2218
  */
2232
- declare function from<T, E>(fn: () => T, onError: (cause: unknown) => E): Ok<T> | Err<E, unknown>;
2219
+ declare function isStreamBackpressureError(error: unknown): error is StreamBackpressureError;
2233
2220
  /**
2234
- * Wraps a Promise in a Result, converting rejections to errors.
2235
- *
2236
- * @remarks When to use: Wrap a Promise and keep the raw rejection as Err; use tryAsync to map errors.
2237
- *
2238
- * ## When to Use
2239
- *
2240
- * Use `fromPromise()` when:
2241
- * - You have an existing Promise that might reject
2242
- * - You want to convert Promise rejections to typed errors
2243
- * - You're working with libraries that return Promises (fetch, database clients)
2244
- * - You need to handle rejections without .catch() chains
2245
- *
2246
- * ## Why Use This
2247
- *
2248
- * - **Type-safe errors**: Convert Promise rejections to typed Result errors
2249
- * - **Composable**: Results can be chained with `andThen`, `map`, etc.
2250
- * - **Explicit handling**: Forces you to handle errors explicitly
2251
- * - **No .catch() chains**: Cleaner than Promise.catch() patterns
2252
- *
2253
- * @param promise - The Promise to await (may reject)
2254
- * @returns A Promise resolving to a Result with the resolved value or rejection reason
2255
- *
2256
- * @example
2257
- * ```typescript
2258
- * // Wrap fetch
2259
- * const result = await fromPromise(
2260
- * fetch('/api').then(r => r.json())
2261
- * );
2262
- * // result.ok: true if fetch succeeded, false if rejected
2263
- * ```
2221
+ * Create a StreamWriteError.
2264
2222
  */
2265
- declare function fromPromise<T>(promise: Promise<T>): Promise<Ok<T> | Err<unknown, unknown>>;
2223
+ declare function streamWriteError(reason: StreamWriteError["reason"], message: string, cause?: unknown): StreamWriteError;
2266
2224
  /**
2267
- * Wraps a Promise in a Result with custom error mapping.
2268
- *
2269
- * Use this overload when you want to map Promise rejections to your typed error union.
2270
- *
2271
- * @param promise - The Promise to await (may reject)
2272
- * @param onError - Function to map the rejection reason to a typed error
2273
- * @returns A Promise resolving to a Result with the resolved value or mapped error
2274
- *
2275
- * @example
2276
- * ```typescript
2277
- * // Map fetch errors to typed errors
2278
- * const result = await fromPromise(
2279
- * fetch('/api').then(r => {
2280
- * if (!r.ok) throw new Error(`HTTP ${r.status}`);
2281
- * return r.json();
2282
- * }),
2283
- * () => 'FETCH_FAILED' as const
2284
- * );
2285
- * // result.error: 'FETCH_FAILED' if fetch failed
2286
- *
2287
- * // Map with error details
2288
- * const data = await fromPromise(
2289
- * db.query(sql),
2290
- * (cause) => ({ type: 'DB_ERROR' as const, message: String(cause) })
2291
- * );
2292
- * ```
2225
+ * Create a StreamReadError.
2293
2226
  */
2294
- declare function fromPromise<T, E>(promise: Promise<T>, onError: (cause: unknown) => E): Promise<Ok<T> | Err<E, unknown>>;
2227
+ declare function streamReadError(reason: StreamReadError["reason"], message: string, cause?: unknown): StreamReadError;
2295
2228
  /**
2296
- * Wraps an async function in a Result, catching both thrown exceptions and Promise rejections.
2297
- *
2298
- * @remarks When to use: Wrap async work and map thrown/rejected values into your typed error union.
2299
- *
2300
- * ## When to Use
2301
- *
2302
- * Use `tryAsync()` when:
2303
- * - You have an async function that might throw or reject
2304
- * - You want to convert both exceptions and rejections to typed errors
2305
- * - You're creating new async functions (use `fromPromise` for existing Promises)
2306
- * - You need to handle errors without try/catch or .catch()
2307
- *
2308
- * ## Why Use This Instead of `fromPromise`
2309
- *
2310
- * - **Function form**: Takes a function, not a Promise (lazy evaluation)
2311
- * - **Catches both**: Handles both thrown exceptions and Promise rejections
2312
- * - **Cleaner syntax**: No need to wrap in Promise manually
2313
- *
2314
- * @param fn - The async function to execute (may throw or reject)
2315
- * @returns A Promise resolving to a Result with the function's return value or error
2316
- *
2317
- * @example
2318
- * ```typescript
2319
- * // Wrap async function
2320
- * const result = await tryAsync(async () => {
2321
- * const data = await fetchData();
2322
- * return processData(data);
2323
- * });
2324
- * ```
2229
+ * Create a StreamCloseError.
2325
2230
  */
2326
- declare function tryAsync<T>(fn: () => Promise<T>): AsyncResult<T, unknown>;
2231
+ declare function streamCloseError(reason: StreamCloseError["reason"], message: string, cause?: unknown): StreamCloseError;
2327
2232
  /**
2328
- * Wraps an async function in a Result with custom error mapping.
2329
- *
2330
- * Use this overload when you want to map errors to your typed error union.
2331
- *
2332
- * @param fn - The async function to execute (may throw or reject)
2333
- * @param onError - Function to map the error (exception or rejection) to a typed error
2334
- * @returns A Promise resolving to a Result with the function's return value or mapped error
2335
- *
2336
- * @example
2337
- * ```typescript
2338
- * // Map errors to typed errors
2339
- * const result = await tryAsync(
2340
- * async () => await fetchData(),
2341
- * () => 'FETCH_ERROR' as const
2342
- * );
2343
- *
2344
- * // Map with error details
2345
- * const data = await tryAsync(
2346
- * async () => await processFile(path),
2347
- * (cause) => ({ type: 'PROCESSING_ERROR' as const, cause })
2348
- * );
2349
- * ```
2233
+ * Create a StreamStoreError.
2350
2234
  */
2351
- declare function tryAsync<T, E>(fn: () => Promise<T>, onError: (cause: unknown) => E): AsyncResult<T, E>;
2235
+ declare function streamStoreError(reason: StreamStoreError["reason"], message: string, cause?: unknown): StreamStoreError;
2352
2236
  /**
2353
- * Converts a nullable value to a Result.
2354
- *
2355
- * @remarks When to use: Turn null/undefined into a typed error before continuing.
2356
- *
2357
- * ## When to Use
2358
- *
2359
- * Use `fromNullable()` when:
2360
- * - You have a value that might be `null` or `undefined`
2361
- * - You want to treat null/undefined as an error case
2362
- * - You're working with APIs that return nullable values (DOM APIs, optional properties)
2363
- * - You want to avoid null checks scattered throughout your code
2364
- *
2365
- * ## Why Use This
2366
- *
2367
- * - **Type-safe**: Converts nullable types to non-nullable Results
2368
- * - **Explicit errors**: Forces you to handle null/undefined cases
2369
- * - **Composable**: Results can be chained with `andThen`, `map`, etc.
2370
- * - **No null checks**: Eliminates need for `if (value == null)` checks
2371
- *
2372
- * @param value - The value that may be null or undefined
2373
- * @param onNull - Function that returns an error when value is null/undefined
2374
- * @returns A Result with the value if not null/undefined, otherwise the error from `onNull`
2375
- *
2376
- * @example
2377
- * ```typescript
2378
- * // Convert DOM element lookup
2379
- * const element = fromNullable(
2380
- * document.getElementById('app'),
2381
- * () => 'ELEMENT_NOT_FOUND' as const
2382
- * );
2383
- *
2384
- * // Convert optional property
2385
- * const userId = fromNullable(
2386
- * user.id,
2387
- * () => 'USER_ID_MISSING' as const
2388
- * );
2389
- *
2390
- * // Convert database query result
2391
- * const record = fromNullable(
2392
- * await db.find(id),
2393
- * () => ({ type: 'NOT_FOUND' as const, id })
2394
- * );
2395
- * ```
2237
+ * Create a StreamEndedMarker.
2396
2238
  */
2397
- declare function fromNullable<T, E>(value: T | null | undefined, onNull: () => E): Result<T, E>;
2239
+ declare function streamEnded(finalPosition: number): StreamEndedMarker;
2398
2240
  /**
2399
- * Transforms the success value of a Result.
2400
- *
2401
- * @remarks When to use: Transform only the Ok value while leaving Err untouched.
2402
- *
2403
- * ## When to Use
2404
- *
2405
- * Use `map()` when:
2406
- * - You need to transform a success value to another type
2407
- * - You want to apply a pure function to the value
2408
- * - You're building a pipeline of transformations
2409
- * - The transformation cannot fail (use `andThen` if it can fail)
2410
- *
2411
- * ## Why Use This
2412
- *
2413
- * - **Functional style**: Composable, chainable transformations
2414
- * - **Error-preserving**: Errors pass through unchanged
2415
- * - **Type-safe**: TypeScript tracks the transformation
2416
- * - **No unwrapping**: Avoids manual `if (r.ok)` checks
2417
- *
2418
- * @param r - The Result to transform
2419
- * @param fn - Pure function that transforms the success value (must not throw)
2420
- * @returns A new Result with the transformed value, or the original error if `r` was an error
2421
- *
2422
- * @example
2423
- * ```typescript
2424
- * // Transform numeric value
2425
- * const doubled = map(ok(21), n => n * 2);
2426
- * // doubled: { ok: true, value: 42 }
2427
- *
2428
- * // Transform object property
2429
- * const name = map(fetchUser(id), user => user.name);
2430
- *
2431
- * // Chain transformations
2432
- * const formatted = map(
2433
- * map(parseNumber(input), n => n * 2),
2434
- * n => `Result: ${n}`
2435
- * );
2436
- * ```
2241
+ * Create a StreamBackpressureError.
2437
2242
  */
2438
- declare function map<T, U>(r: Ok<T>, fn: (value: T) => U): Ok<U>;
2439
- declare function map<T, U, E, C>(r: Err<E, C>, fn: (value: T) => U): Err<E, C>;
2440
- declare function map<T, U, E, C>(r: Result<T, E, C>, fn: (value: T) => U): Result<U, E, C>;
2243
+ declare function streamBackpressureError(bufferedCount: number, highWaterMark: number): StreamBackpressureError;
2244
+
2441
2245
  /**
2442
- * Transforms the error value of a Result.
2443
- *
2444
- * @remarks When to use: Retype or normalize errors while leaving Ok values unchanged.
2246
+ * awaitly/persistence
2445
2247
  *
2446
- * ## When to Use
2447
- *
2448
- * Use `mapError()` when:
2449
- * - You need to normalize or transform error types
2450
- * - You want to convert errors to a different error type
2451
- * - You're building error handling pipelines
2452
- * - You need to format error messages or codes
2453
- *
2454
- * ## Why Use This
2455
- *
2456
- * - **Error normalization**: Convert errors to a common format
2457
- * - **Type transformation**: Change error type while preserving value type
2458
- * - **Composable**: Can be chained with other transformers
2459
- * - **Success-preserving**: Success values pass through unchanged
2460
- *
2461
- * @param r - The Result to transform
2462
- * @param fn - Function that transforms the error value (must not throw)
2463
- * @returns A new Result with the original value, or the transformed error if `r` was an error
2464
- *
2465
- * @example
2466
- * ```typescript
2467
- * // Normalize error codes
2468
- * const normalized = mapError(err('not_found'), e => e.toUpperCase());
2469
- * // normalized: { ok: false, error: 'NOT_FOUND' }
2470
- *
2471
- * // Convert error types
2472
- * const typed = mapError(
2473
- * err('404'),
2474
- * code => ({ type: 'HTTP_ERROR' as const, status: parseInt(code) })
2475
- * );
2476
- *
2477
- * // Format error messages
2478
- * const formatted = mapError(
2479
- * err('PARSE_ERROR'),
2480
- * code => `Failed to parse: ${code}`
2481
- * );
2482
- * ```
2248
+ * Simplified Persistence API for workflow snapshots.
2249
+ * Provides JSON-serializable snapshot format and store adapters.
2483
2250
  */
2484
- declare function mapError<T, E, F, C>(r: Result<T, E, C>, fn: (error: E) => F): Result<T, F, C>;
2251
+
2485
2252
  /**
2486
- * Pattern matches on a Result, calling the appropriate handler.
2487
- *
2488
- * @remarks When to use: Handle both Ok and Err in a single expression that returns a value.
2489
- *
2490
- * ## When to Use
2491
- *
2492
- * Use `match()` when:
2493
- * - You need to handle both success and error cases
2494
- * - You want to transform a Result to a different type
2495
- * - You need exhaustive handling (both cases must be handled)
2496
- * - You're building user-facing messages or responses
2497
- *
2498
- * ## Why Use This
2499
- *
2500
- * - **Exhaustive**: Forces you to handle both success and error cases
2501
- * - **Type-safe**: TypeScript ensures both handlers are provided
2502
- * - **Functional**: Pattern matching style, similar to Rust's `match` or Haskell's `case`
2503
- * - **Single expression**: Can be used in expressions, not just statements
2504
- *
2505
- * @param r - The Result to match
2506
- * @param handlers - Object with `ok` and `err` handler functions
2507
- * @param handlers.ok - Function called with the success value
2508
- * @param handlers.err - Function called with the error and optional cause
2509
- * @returns The return value of the appropriate handler (both must return the same type `R`)
2253
+ * Enforce JSON-safety at type level.
2254
+ * Only allows values that can be safely serialized with JSON.stringify.
2255
+ */
2256
+ type JSONValue = null | boolean | number | string | JSONValue[] | {
2257
+ [k: string]: JSONValue;
2258
+ };
2259
+ /**
2260
+ * Canonical error wire format - handles both Error instances and thrown non-Errors.
2261
+ * This is the single source of truth for serialized errors in snapshots.
2262
+ */
2263
+ type SerializedCause = {
2264
+ type: "error";
2265
+ name: string;
2266
+ message: string;
2267
+ stack?: string;
2268
+ cause?: SerializedCause;
2269
+ } | {
2270
+ type: "thrown";
2271
+ originalType?: string;
2272
+ value?: JSONValue;
2273
+ stringRepresentation: string;
2274
+ truncated?: true;
2275
+ };
2276
+ /**
2277
+ * Single source of truth for step outcome (no error/cause confusion).
2278
+ * Uses discriminated union with `ok` field.
2279
+ */
2280
+ type StepResult = {
2281
+ ok: true;
2282
+ value: JSONValue;
2283
+ } | {
2284
+ ok: false;
2285
+ error: JSONValue;
2286
+ cause: SerializedCause;
2287
+ meta?: {
2288
+ origin: "result" | "throw";
2289
+ };
2290
+ };
2291
+ /**
2292
+ * JSON-serializable workflow snapshot.
2293
+ * Designed to be passed directly to JSON.stringify without special handling.
2510
2294
  *
2511
2295
  * @example
2512
2296
  * ```typescript
2513
- * // Build user-facing messages
2514
- * const message = match(result, {
2515
- * ok: (user) => `Hello ${user.name}`,
2516
- * err: (error) => `Error: ${error}`,
2517
- * });
2518
- *
2519
- * // Transform to API response
2520
- * const response = match(operation(), {
2521
- * ok: (data) => ({ status: 200, body: data }),
2522
- * err: (error) => ({ status: 400, error: String(error) }),
2523
- * });
2297
+ * // Persist
2298
+ * localStorage.setItem('wf-123', JSON.stringify(wf.getSnapshot()));
2524
2299
  *
2525
- * // Handle with cause
2526
- * const response = match(result, {
2527
- * ok: (value) => ({ status: 'success', data: value }),
2528
- * err: (error, cause) => ({ status: 'error', error, cause }),
2529
- * });
2300
+ * // Restore (safe pattern - storage can be empty/corrupt)
2301
+ * const raw = localStorage.getItem('wf-123');
2302
+ * const snapshot = raw ? JSON.parse(raw) : null;
2303
+ * createWorkflow(deps, { snapshot }); // null = fresh start
2530
2304
  * ```
2531
2305
  */
2532
- declare function match<T, E, C, R>(handlers: {
2533
- ok: (value: T) => R;
2534
- err: (error: E, cause?: C) => R;
2535
- }): (r: Result<T, E, C>) => R;
2536
- declare function match<T, E, C, R>(r: Ok<T>, handlers: {
2537
- ok: (value: T) => R;
2538
- err: (error: E, cause?: C) => R;
2539
- }): R;
2540
- declare function match<T, E, C, R>(r: Err<E, C>, handlers: {
2541
- ok: (value: T) => R;
2542
- err: (error: E, cause?: C) => R;
2543
- }): R;
2544
- declare function match<T, E, C, R>(r: Result<T, E, C>, handlers: {
2545
- ok: (value: T) => R;
2546
- err: (error: E, cause?: C) => R;
2547
- }): R;
2548
- /**
2549
- * Chains Results together (flatMap/monadic bind).
2550
- *
2551
- * @remarks When to use: Chain dependent operations that return Result without nested branching.
2552
- *
2553
- * ## When to Use
2554
- *
2555
- * Use `andThen()` when:
2556
- * - You need to chain operations that can fail
2557
- * - The next operation depends on the previous success value
2558
- * - You're building a pipeline of dependent operations
2559
- * - You want to avoid nested `if (r.ok)` checks
2560
- *
2561
- * ## Why Use This Instead of `map`
2562
- *
2563
- * - **Can fail**: The chained function returns a Result (can fail)
2564
- * - **Short-circuits**: If first Result fails, second operation never runs
2565
- * - **Error accumulation**: Errors from both operations are in the union
2566
- * - **Composable**: Can chain multiple operations together
2567
- *
2568
- * ## Common Pattern
2569
- *
2570
- * This is the fundamental building block for Result pipelines:
2571
- * ```typescript
2572
- * andThen(operation1(), value1 =>
2573
- * andThen(operation2(value1), value2 =>
2574
- * ok({ value1, value2 })
2575
- * )
2576
- * )
2577
- * ```
2578
- *
2579
- * @param r - The first Result
2580
- * @param fn - Function that takes the success value and returns a new Result (may fail)
2581
- * @returns The Result from `fn` if `r` was successful, otherwise the original error
2582
- *
2583
- * @example
2584
- * ```typescript
2585
- * // Chain dependent operations
2586
- * const userPosts = andThen(
2587
- * fetchUser('1'),
2588
- * user => fetchPosts(user.id)
2589
- * );
2590
- *
2591
- * // Build complex pipelines
2592
- * const result = andThen(parseInput(input), parsed =>
2593
- * andThen(validate(parsed), validated =>
2594
- * process(validated)
2595
- * )
2596
- * );
2597
- *
2598
- * // Chain with different error types
2599
- * const data = andThen(
2600
- * fetchUser(id), // Returns Result<User, 'FETCH_ERROR'>
2601
- * user => fetchPosts(user.id) // Returns Result<Post[], 'NOT_FOUND'>
2602
- * );
2603
- * // data.error: 'FETCH_ERROR' | 'NOT_FOUND'
2604
- * ```
2306
+ interface WorkflowSnapshot {
2307
+ /** Snapshot format version (literal type - bump when shape changes) */
2308
+ formatVersion: 1;
2309
+ /** Workflow name (from createWorkflow first argument). */
2310
+ workflowName?: string;
2311
+ /** Step results keyed by step ID. Uses Object.create(null) internally. */
2312
+ steps: Record<string, StepResult>;
2313
+ /** Execution state metadata */
2314
+ execution: {
2315
+ status: "running" | "completed" | "failed";
2316
+ /** ISO timestamp (UTC toISOString()) */
2317
+ lastUpdated: string;
2318
+ /** ISO timestamp if finished */
2319
+ completedAt?: string;
2320
+ /**
2321
+ * For paused/running workflows: the step key of the current step.
2322
+ * Aligns with Workflow Diagram DSL step state ids (see awaitly/workflow diagram-dsl)
2323
+ * so visualizers can highlight the current node.
2324
+ */
2325
+ currentStepId?: string;
2326
+ };
2327
+ /** Optional metadata for workflow identification and replay */
2328
+ metadata?: {
2329
+ /** Detect wrong snapshot for wrong workflow */
2330
+ workflowId?: string;
2331
+ /** Optional: detect definition changes (user-supplied, advisory only) */
2332
+ definitionHash?: string;
2333
+ /** Original input for replay */
2334
+ input?: JSONValue;
2335
+ [key: string]: JSONValue | undefined;
2336
+ };
2337
+ /** Warnings for lossy serialization (keeps step results pure) */
2338
+ warnings?: Array<{
2339
+ type: "lossy_value";
2340
+ stepId: string;
2341
+ path: string;
2342
+ reason: "non-json" | "circular" | "encode-failed";
2343
+ }>;
2344
+ }
2345
+ /**
2346
+ * Warning entry for lossy value serialization.
2605
2347
  */
2606
- declare function andThen<T, U>(r: Ok<T>, fn: (value: T) => Ok<U>): Ok<U>;
2607
- declare function andThen<T, F, C2>(r: Ok<T>, fn: (value: T) => Err<F, C2>): Err<F, C2>;
2608
- declare function andThen<T, U, F, C2>(r: Ok<T>, fn: (value: T) => Result<U, F, C2>): Result<U, F, C2>;
2609
- declare function andThen<T, U, E, F, C1, C2>(r: Err<E, C1>, fn: (value: T) => Result<U, F, C2>): Err<E, C1>;
2610
- declare function andThen<T, U, E, F, C1, C2>(r: Result<T, E, C1>, fn: (value: T) => Result<U, F, C2>): Result<U, E | F, C1 | C2>;
2348
+ type SnapshotWarning = NonNullable<WorkflowSnapshot["warnings"]>[number];
2611
2349
  /**
2612
- * Executes a side effect on a successful Result without changing it.
2613
- *
2614
- * @remarks When to use: Add side effects (logging, metrics) on Ok without changing the Result.
2615
- *
2616
- * ## When to Use
2617
- *
2618
- * Use `tap()` when:
2619
- * - You need to log, debug, or observe success values
2620
- * - You want to perform side effects in a pipeline
2621
- * - You need to mutate external state based on success
2622
- * - You're debugging and want to inspect values without breaking the chain
2623
- *
2624
- * ## Why Use This
2625
- *
2626
- * - **Non-breaking**: Doesn't change the Result, just performs side effect
2627
- * - **Composable**: Can be inserted anywhere in a pipeline
2628
- * - **Type-preserving**: Returns the same Result type
2629
- * - **Lazy**: Side effect only runs if Result is successful
2630
- *
2631
- * @param r - The Result to tap
2632
- * @param fn - Side effect function called with the success value (return value ignored)
2633
- * @returns The original Result unchanged (for chaining)
2350
+ * Error thrown when snapshot structure is invalid.
2351
+ */
2352
+ declare class SnapshotFormatError extends Error {
2353
+ readonly errors: string[];
2354
+ constructor(message: string, errors?: string[]);
2355
+ }
2356
+ /**
2357
+ * Error thrown when snapshot doesn't match workflow (unknown steps, workflowId mismatch).
2358
+ */
2359
+ declare class SnapshotMismatchError extends Error {
2360
+ readonly mismatchType: "unknown_steps" | "workflow_id" | "definition_hash";
2361
+ readonly details?: {
2362
+ unknownSteps?: string[];
2363
+ snapshotWorkflowId?: string;
2364
+ expectedWorkflowId?: string;
2365
+ snapshotHash?: string;
2366
+ expectedHash?: string;
2367
+ } | undefined;
2368
+ constructor(message: string, mismatchType: "unknown_steps" | "workflow_id" | "definition_hash", details?: {
2369
+ unknownSteps?: string[];
2370
+ snapshotWorkflowId?: string;
2371
+ expectedWorkflowId?: string;
2372
+ snapshotHash?: string;
2373
+ expectedHash?: string;
2374
+ } | undefined);
2375
+ }
2376
+ /**
2377
+ * Error thrown when decode fails during restore.
2378
+ */
2379
+ declare class SnapshotDecodeError extends Error {
2380
+ readonly stepId: string;
2381
+ readonly originalError?: unknown | undefined;
2382
+ constructor(message: string, stepId: string, originalError?: unknown | undefined);
2383
+ }
2384
+ /**
2385
+ * Light check to see if an object looks like a WorkflowSnapshot.
2386
+ * Cheap check for basic structure - use validateSnapshot() for full validation.
2634
2387
  *
2635
2388
  * @example
2636
2389
  * ```typescript
2637
- * // Log success values
2638
- * const logged = tap(result, user => console.log('Got user:', user.name));
2639
- * // logged === result, but console.log was called
2640
- *
2641
- * // Debug in pipeline
2642
- * const debugged = pipe(
2643
- * fetchUser(id),
2644
- * r => tap(r, user => console.log('Fetched:', user)),
2645
- * r => map(r, user => user.name)
2646
- * );
2647
- *
2648
- * // Mutate external state
2649
- * const tracked = tap(result, data => {
2650
- * analytics.track('operation_success', data);
2651
- * });
2390
+ * const raw = JSON.parse(localStorage.getItem('wf-123') || 'null');
2391
+ * if (looksLikeWorkflowSnapshot(raw)) {
2392
+ * createWorkflow(deps, { snapshot: raw });
2393
+ * }
2652
2394
  * ```
2653
2395
  */
2654
- declare function tap<T, E, C>(r: Result<T, E, C>, fn: (value: T) => void): Result<T, E, C>;
2396
+ declare function looksLikeWorkflowSnapshot(obj: unknown): obj is WorkflowSnapshot;
2655
2397
  /**
2656
- * Executes a side effect on an error Result without changing it.
2657
- *
2658
- * @remarks When to use: Add side effects (logging, metrics) on Err without changing the Result.
2659
- *
2660
- * ## When to Use
2661
- *
2662
- * Use `tapError()` when:
2663
- * - You need to log, debug, or observe error values
2664
- * - You want to perform side effects on errors in a pipeline
2665
- * - You need to report errors to external systems (logging, monitoring)
2666
- * - You're debugging and want to inspect errors without breaking the chain
2667
- *
2668
- * ## Why Use This
2398
+ * Type guard for WorkflowSnapshot. Same as looksLikeWorkflowSnapshot; use for consistent naming with isResumeState / isSerializedResumeState.
2399
+ */
2400
+ declare const isWorkflowSnapshot: typeof looksLikeWorkflowSnapshot;
2401
+ /**
2402
+ * Full validation with detailed errors.
2403
+ * Returns either a validated snapshot or an array of validation errors.
2404
+ */
2405
+ declare function validateSnapshot(obj: unknown): {
2406
+ valid: true;
2407
+ snapshot: WorkflowSnapshot;
2408
+ } | {
2409
+ valid: false;
2410
+ errors: string[];
2411
+ };
2412
+ /**
2413
+ * Throwing helper for cleaner code.
2414
+ * Validates a snapshot and throws SnapshotFormatError if invalid.
2669
2415
  *
2670
- * - **Non-breaking**: Doesn't change the Result, just performs side effect
2671
- * - **Composable**: Can be inserted anywhere in a pipeline
2672
- * - **Type-preserving**: Returns the same Result type
2673
- * - **Lazy**: Side effect only runs if Result is an error
2416
+ * @throws {SnapshotFormatError} If snapshot is invalid
2417
+ */
2418
+ declare function assertValidSnapshot(obj: unknown): WorkflowSnapshot;
2419
+ /**
2420
+ * Merge two snapshots (for incremental updates).
2421
+ * Delta steps overwrite base steps; execution from delta; metadata shallow merge.
2422
+ */
2423
+ declare function mergeSnapshots(base: WorkflowSnapshot, delta: WorkflowSnapshot): WorkflowSnapshot;
2424
+ /**
2425
+ * Serialize an Error object to SerializedCause format.
2426
+ * Preserves Error.cause recursively.
2427
+ */
2428
+ declare function serializeError(error: Error): SerializedCause;
2429
+ /**
2430
+ * Serialize a non-Error thrown value to SerializedCause format.
2431
+ */
2432
+ declare function serializeThrown(value: unknown): SerializedCause;
2433
+ /**
2434
+ * Deserialize a SerializedCause back to its original form.
2435
+ */
2436
+ declare function deserializeCauseNew(serialized: SerializedCause): unknown;
2437
+ /**
2438
+ * Simplified store interface for workflow snapshot persistence.
2439
+ * Works directly with WorkflowSnapshot objects.
2674
2440
  *
2675
- * @param r - The Result to tap
2676
- * @param fn - Side effect function called with the error and optional cause (return value ignored)
2677
- * @returns The original Result unchanged (for chaining)
2441
+ * Adapters may implement an extended contract (see awaitly/workflow): save can accept
2442
+ * WorkflowSnapshot | ResumeState; load can return WorkflowSnapshot | ResumeState | null.
2443
+ * Use isWorkflowSnapshot / isSerializedResumeState and serializeResumeState / deserializeResumeState
2444
+ * when branching. For type-safe restore, use store.loadResumeState(id) or toResumeState(await store.load(id)).
2678
2445
  *
2679
2446
  * @example
2680
2447
  * ```typescript
2681
- * // Log errors
2682
- * const logged = tapError(result, (error, cause) => {
2683
- * console.error('Error:', error, cause);
2684
- * });
2448
+ * import { postgres } from 'awaitly-postgres';
2449
+ * import { createWorkflow } from 'awaitly/workflow';
2685
2450
  *
2686
- * // Report to error tracking
2687
- * const tracked = tapError(result, (error, cause) => {
2688
- * errorTracker.report(error, cause);
2689
- * });
2451
+ * const store = postgres('postgresql://localhost/mydb');
2452
+ * const workflow = createWorkflow(deps);
2453
+ *
2454
+ * // Run and persist resume state
2455
+ * const { result, resumeState } = await workflow.runWithState(fn);
2456
+ * await store.save('wf-123', resumeState);
2690
2457
  *
2691
- * // Debug in pipeline
2692
- * const debugged = pipe(
2693
- * operation(),
2694
- * r => tapError(r, (err, cause) => console.error('Failed:', err)),
2695
- * r => mapError(r, err => 'FORMATTED_ERROR')
2696
- * );
2458
+ * // Restore
2459
+ * const loaded = await store.load('wf-123');
2460
+ * const resumeState = toResumeState(loaded);
2461
+ * if (resumeState) await workflow.run(fn, { resumeState });
2697
2462
  * ```
2698
2463
  */
2699
- declare function tapError<T, E, C>(r: Result<T, E, C>, fn: (error: E, cause?: C) => void): Result<T, E, C>;
2464
+ interface SnapshotStore {
2465
+ /** Save a workflow snapshot (upsert - insert or update). Adapters may also accept ResumeState. */
2466
+ save(id: string, snapshot: WorkflowSnapshot): Promise<void>;
2467
+ /** Load a workflow snapshot. Returns null if not found. Adapters may return ResumeState when stored as such. */
2468
+ load(id: string): Promise<WorkflowSnapshot | null>;
2469
+ /** Delete a workflow snapshot. */
2470
+ delete(id: string): Promise<void>;
2471
+ /** List workflow IDs with their last update time. */
2472
+ list(options?: {
2473
+ prefix?: string;
2474
+ limit?: number;
2475
+ }): Promise<Array<{
2476
+ id: string;
2477
+ updatedAt: string;
2478
+ }>>;
2479
+ /** Clean shutdown for tests/graceful exit. */
2480
+ close(): Promise<void>;
2481
+ }
2700
2482
  /**
2701
- * Transforms the success value of a Result, catching any errors thrown by the transform.
2702
- *
2703
- * @remarks When to use: Transform Ok values with a function that might throw and capture the failure.
2704
- *
2705
- * ## When to Use
2706
- *
2707
- * Use `mapTry()` when:
2708
- * - Your transform function might throw exceptions
2709
- * - You want to convert transform errors to typed errors
2710
- * - You're working with libraries that throw (e.g., JSON.parse, Date parsing)
2711
- * - You need to handle both Result errors and transform exceptions
2712
- *
2713
- * ## Why Use This Instead of `map`
2714
- *
2715
- * - **Exception-safe**: Catches exceptions from the transform function
2716
- * - **Error mapping**: Converts thrown exceptions to typed errors
2717
- * - **Dual error handling**: Handles both Result errors and transform exceptions
2718
- *
2719
- * @param result - The Result to transform
2720
- * @param transform - Function to transform the success value (may throw exceptions)
2721
- * @param onError - Function to map thrown exceptions to a typed error
2722
- * @returns A Result with:
2723
- * - Transformed value if both Result and transform succeed
2724
- * - Original error if Result was an error
2725
- * - Transform error if transform threw an exception
2726
- *
2727
- * @example
2728
- * ```typescript
2729
- * // Safe JSON parsing
2730
- * const parsed = mapTry(
2731
- * ok('{"key": "value"}'),
2732
- * JSON.parse,
2733
- * () => 'PARSE_ERROR' as const
2734
- * );
2735
- *
2736
- * // Safe date parsing
2737
- * const date = mapTry(
2738
- * ok('2024-01-01'),
2739
- * str => new Date(str),
2740
- * () => 'INVALID_DATE' as const
2741
- * );
2742
- *
2743
- * // Transform with error details
2744
- * const processed = mapTry(
2745
- * result,
2746
- * value => riskyTransform(value),
2747
- * (cause) => ({ type: 'TRANSFORM_ERROR' as const, cause })
2748
- * );
2749
- * ```
2483
+ * Options for the in-memory cache adapter.
2750
2484
  */
2751
- declare function mapTry<T, U, E, F, C>(result: Result<T, E, C>, transform: (value: T) => U, onError: (cause: unknown) => F): Result<U, E | F, C | unknown>;
2485
+ interface MemoryCacheOptions {
2486
+ /**
2487
+ * Maximum number of entries to store.
2488
+ * Oldest entries are evicted when limit is reached.
2489
+ */
2490
+ maxSize?: number;
2491
+ /**
2492
+ * Time-to-live in milliseconds.
2493
+ * Entries are automatically removed after this duration.
2494
+ */
2495
+ ttl?: number;
2496
+ }
2752
2497
  /**
2753
- * Transforms the error value of a Result, catching any errors thrown by the transform.
2754
- *
2755
- * @remarks When to use: Transform errors when the mapping might throw and you want that captured.
2498
+ * Create an in-memory StepCache with optional LRU eviction and TTL.
2756
2499
  *
2757
- * ## When to Use
2758
- *
2759
- * Use `mapErrorTry()` when:
2760
- * - Your error transform function might throw exceptions
2761
- * - You're doing complex error transformations (e.g., string formatting, object construction)
2762
- * - You want to handle both Result errors and transform exceptions
2763
- * - You need to safely normalize error types
2764
- *
2765
- * ## Why Use This Instead of `mapError`
2766
- *
2767
- * - **Exception-safe**: Catches exceptions from the error transform function
2768
- * - **Error mapping**: Converts thrown exceptions to typed errors
2769
- * - **Dual error handling**: Handles both Result errors and transform exceptions
2770
- *
2771
- * @param result - The Result to transform
2772
- * @param transform - Function to transform the error value (may throw exceptions)
2773
- * @param onError - Function to map thrown exceptions to a typed error
2774
- * @returns A Result with:
2775
- * - Original value if Result was successful
2776
- * - Transformed error if both Result was error and transform succeeded
2777
- * - Transform error if transform threw an exception
2500
+ * @param options - Cache options
2501
+ * @returns StepCache implementation
2778
2502
  *
2779
2503
  * @example
2780
2504
  * ```typescript
2781
- * // Safe error formatting
2782
- * const formatted = mapErrorTry(
2783
- * err('not_found'),
2784
- * e => e.toUpperCase(), // Might throw if e is not a string
2785
- * () => 'FORMAT_ERROR' as const
2786
- * );
2787
- *
2788
- * // Complex error transformation
2789
- * const normalized = mapErrorTry(
2790
- * result,
2791
- * error => ({ type: 'NORMALIZED', message: String(error) }),
2792
- * () => 'TRANSFORM_ERROR' as const
2793
- * );
2505
+ * const cache = createMemoryCache({ maxSize: 1000, ttl: 60000 });
2506
+ * const workflow = createWorkflow(deps, { cache });
2794
2507
  * ```
2795
2508
  */
2796
- declare function mapErrorTry<T, E, F, G, C>(result: Result<T, E, C>, transform: (error: E) => F, onError: (cause: unknown) => G): Result<T, F | G, C | unknown>;
2509
+ declare function createMemoryCache(options?: MemoryCacheOptions): StepCache;
2510
+
2511
+ /**
2512
+ * Workflow type definitions.
2513
+ * Pure types and interfaces; no runtime code.
2514
+ */
2515
+
2797
2516
  /**
2798
- * Transforms both the success value and error value of a Result simultaneously.
2517
+ * Interface for step result caching.
2518
+ * Implement this interface to provide custom caching strategies.
2519
+ * A simple Map<string, Result> works for in-memory caching.
2799
2520
  *
2800
- * ## When to Use
2521
+ * ## When Cache is Populated
2801
2522
  *
2802
- * Use `bimap()` when:
2803
- * - You need to transform both success and error in one operation
2804
- * - You're normalizing Results to a common format
2805
- * - You want symmetric transformation of both cases
2806
- * - You're building adapters between different Result types
2523
+ * The cache `set()` method is called after each step completes (success or error)
2524
+ * when the step has a `key` option. Both calling patterns work identically:
2807
2525
  *
2808
- * ## Why Use This Instead of `map` + `mapError`
2526
+ * ```typescript
2527
+ * // Function-wrapped pattern - cache is populated
2528
+ * await step(() => fetchUser("1"), { key: "user:1" });
2809
2529
  *
2810
- * - **Single operation**: Transforms both cases in one call
2811
- * - **Clearer intent**: Shows you're handling both cases symmetrically
2812
- * - **Less code**: Avoids chaining map and mapError
2530
+ * // Direct AsyncResult pattern - cache is also populated
2531
+ * await step(fetchUser("1"), { key: "user:1" });
2532
+ * ```
2813
2533
  *
2814
- * @param r - The Result to transform
2815
- * @param onOk - Function that transforms the success value
2816
- * @param onErr - Function that transforms the error value
2817
- * @returns A new Result with transformed value or transformed error
2534
+ * Note: Cache stores Result<unknown, unknown, unknown> because different steps
2535
+ * have different value/error/cause types. The actual runtime values are preserved;
2536
+ * only the static types are widened. For error results, the cause value is encoded
2537
+ * in CachedErrorCause to preserve metadata for proper replay.
2818
2538
  *
2819
2539
  * @example
2820
- * ```typescript
2821
- * // Normalize to API response format
2822
- * const response = bimap(
2823
- * fetchUser(id),
2824
- * user => ({ status: 'success', data: user }),
2825
- * error => ({ status: 'error', code: error })
2826
- * );
2827
- *
2828
- * // Transform types
2829
- * const stringified = bimap(
2830
- * parseNumber(input),
2831
- * n => `Value: ${n}`,
2832
- * e => `Error: ${e}`
2833
- * );
2834
- *
2835
- * // Adapt between error types
2836
- * const adapted = bimap(
2837
- * externalResult,
2838
- * value => internalValue(value),
2839
- * error => internalError(error)
2840
- * );
2841
- * ```
2540
+ * // Simple in-memory cache
2541
+ * const cache = new Map<string, Result<unknown, unknown, unknown>>();
2542
+ *
2543
+ * // Or implement custom cache with TTL, LRU, etc.
2544
+ * const cache: StepCache = {
2545
+ * get: (key) => myCache.get(key),
2546
+ * set: (key, result) => myCache.set(key, result, { ttl: 60000 }),
2547
+ * has: (key) => myCache.has(key),
2548
+ * delete: (key) => myCache.delete(key),
2549
+ * clear: () => myCache.clear(),
2550
+ * };
2551
+ */
2552
+ interface StepCache {
2553
+ get(key: string): Result<unknown, unknown, unknown> | undefined;
2554
+ set(key: string, result: Result<unknown, unknown, unknown>, options?: {
2555
+ ttl?: number;
2556
+ }): void;
2557
+ has(key: string): boolean;
2558
+ delete(key: string): boolean;
2559
+ clear(): void;
2560
+ }
2561
+ /**
2562
+ * Entry for a saved step result with optional metadata.
2563
+ * The meta field preserves origin information for proper replay.
2842
2564
  */
2843
- declare function bimap<T, U, E, F, C>(r: Result<T, E, C>, onOk: (value: T) => U, onErr: (error: E) => F): Result<U, F, C>;
2565
+ interface ResumeStateEntry {
2566
+ result: Result<unknown, unknown, unknown>;
2567
+ /** Optional metadata for error origin (from step_complete event) */
2568
+ meta?: StepFailureMeta;
2569
+ }
2844
2570
  /**
2845
- * Recovers from an error by returning a new Result.
2846
- * Similar to neverthrow's `.orElse()`.
2847
- *
2848
- * @remarks When to use: Recover from Err by returning a fallback Result or retyping the error.
2571
+ * Resume state for workflow replay.
2572
+ * Pre-populate step results to skip execution on resume.
2849
2573
  *
2850
- * ## When to Use
2574
+ * Note: When saving to persistent storage, you may need custom serialization
2575
+ * for complex cause types. JSON.stringify works for simple values, but Error
2576
+ * objects and other non-plain types require special handling.
2851
2577
  *
2852
- * Use `orElse()` when:
2853
- * - You want to recover from errors with fallback operations
2854
- * - The recovery might also fail (returns a Result)
2855
- * - You need to chain fallback strategies
2856
- * - You're implementing retry or fallback patterns
2857
- *
2858
- * ## Why Use This
2859
- *
2860
- * - **Fallback chains**: Try alternative operations on failure
2861
- * - **Error recovery**: Convert errors to success with fallback values
2862
- * - **Composable**: Can chain multiple orElse calls for cascading fallbacks
2863
- * - **Type-safe**: TypeScript tracks the error union through recovery
2864
- *
2865
- * @param r - The Result to potentially recover from
2866
- * @param fn - Function that takes the error and returns a new Result (may succeed or fail)
2867
- * @returns The original Result if successful, or the result of the recovery function
2578
+ * @example
2579
+ * // Collect from step_complete events using the helper
2580
+ * const collector = createResumeStateCollector();
2581
+ * const workflow = createWorkflow({ fetchUser }, {
2582
+ * onEvent: collector.handleEvent,
2583
+ * });
2584
+ * // Later: collector.getResumeState() returns ResumeState
2868
2585
  *
2869
2586
  * @example
2870
- * ```typescript
2871
- * // Fallback to default user
2872
- * const user = orElse(
2873
- * fetchUser(id),
2874
- * error => error === 'NOT_FOUND' ? ok(defaultUser) : err(error)
2875
- * );
2876
- *
2877
- * // Try cache, then database, then fail
2878
- * const data = orElse(
2879
- * orElse(
2880
- * fetchFromCache(key),
2881
- * () => fetchFromDatabase(key)
2882
- * ),
2883
- * () => err('DATA_UNAVAILABLE' as const)
2884
- * );
2885
- *
2886
- * // Convert specific errors to success
2887
- * const result = orElse(
2888
- * riskyOperation(),
2889
- * error => error.code === 'RETRY' ? ok(defaultValue) : err(error)
2890
- * );
2891
- * ```
2587
+ * // Resume with saved state
2588
+ * const workflow = createWorkflow({ fetchUser }, {
2589
+ * resumeState: { steps: savedSteps }
2590
+ * });
2892
2591
  */
2893
- declare function orElse<T, E, E2, C, C2>(r: Result<T, E, C>, fn: (error: E, cause?: C) => Result<T, E2, C2>): Result<T, E2, C2>;
2592
+ interface ResumeState {
2593
+ /** Map of step keys to their cached results with optional metadata */
2594
+ steps: Map<string, ResumeStateEntry>;
2595
+ }
2894
2596
  /**
2895
- * Async version of orElse for recovering from errors with async operations.
2896
- *
2897
- * @param r - The Result or AsyncResult to potentially recover from
2898
- * @param fn - Async function that takes the error and returns a new Result
2899
- * @returns Promise of the original Result if successful, or the result of the recovery function
2900
- *
2901
- * @example
2902
- * ```typescript
2903
- * // Try primary API, fall back to secondary
2904
- * const data = await orElseAsync(
2905
- * await fetchFromPrimaryApi(),
2906
- * async (error) => {
2907
- * if (error === 'UNAVAILABLE') {
2908
- * return await fetchFromSecondaryApi();
2909
- * }
2910
- * return err(error);
2911
- * }
2912
- * );
2913
- * ```
2597
+ * Constraint for Result-returning functions
2598
+ * Used by createWorkflow to ensure only valid functions are passed
2914
2599
  */
2915
- declare function orElseAsync<T, E, E2, C, C2>(r: Result<T, E, C> | Promise<Result<T, E, C>>, fn: (error: E, cause?: C) => Result<T, E2, C2> | Promise<Result<T, E2, C2>>): Promise<Result<T, E2, C2>>;
2600
+ type AnyResultFn = (...args: any[]) => Result<any, any, any> | Promise<Result<any, any, any>>;
2916
2601
  /**
2917
- * Recovers from an error by returning a plain value (not a Result).
2918
- * Useful when you want to provide a default value on error.
2919
- *
2920
- * ## When to Use
2921
- *
2922
- * Use `recover()` when:
2923
- * - You want to provide a fallback value on error
2924
- * - Recovery cannot fail (unlike orElse which returns a Result)
2925
- * - You're implementing default value patterns
2926
- * - You want to guarantee a successful Result
2927
- *
2928
- * ## Why Use This Instead of `orElse`
2929
- *
2930
- * - **Simpler**: Recovery function returns plain value, not Result
2931
- * - **Guaranteed success**: Always returns ok() after recovery
2932
- * - **Clearer intent**: Shows recovery cannot fail
2933
- *
2934
- * @param r - The Result to potentially recover from
2935
- * @param fn - Function that takes the error and returns a recovery value
2936
- * @returns The original Result if successful, or ok(recoveryValue) if error
2937
- *
2938
- * @example
2939
- * ```typescript
2940
- * // Provide default user on NOT_FOUND
2941
- * const user = recover(
2942
- * fetchUser(id),
2943
- * error => error === 'NOT_FOUND' ? defaultUser : guestUser
2944
- * );
2945
- *
2946
- * // Convert all errors to default
2947
- * const config = recover(
2948
- * loadConfig(),
2949
- * () => defaultConfig
2950
- * );
2951
- *
2952
- * // Recover with error-based defaults
2953
- * const value = recover(
2954
- * parseNumber(input),
2955
- * error => error === 'EMPTY' ? 0 : -1
2956
- * );
2957
- * ```
2602
+ * Extract union of error types from a deps object
2603
+ * Example: ErrorsOfDeps<{ fetchUser: typeof fetchUser, fetchPosts: typeof fetchPosts }>
2604
+ * yields: 'NOT_FOUND' | 'FETCH_ERROR'
2958
2605
  */
2959
- declare function recover<T, E, C>(r: Result<T, E, C>, fn: (error: E, cause?: C) => T): Ok<T>;
2606
+ type ErrorsOfDeps<Deps extends Record<string, AnyResultFn>> = {
2607
+ [K in keyof Deps]: ErrorOf<Deps[K]>;
2608
+ }[keyof Deps];
2960
2609
  /**
2961
- * Async version of recover for recovering with async operations.
2610
+ * Extract union of cause types from a deps object.
2611
+ * Example: CausesOfDeps<{ fetchUser: typeof fetchUser }> where fetchUser returns Result<User, "NOT_FOUND", Error>
2612
+ * yields: Error
2962
2613
  *
2963
- * @param r - The Result or AsyncResult to potentially recover from
2964
- * @param fn - Async function that takes the error and returns a recovery value
2965
- * @returns Promise of ok(value) - either original or recovered
2966
- *
2967
- * @example
2968
- * ```typescript
2969
- * // Recover by fetching default from API
2970
- * const user = await recoverAsync(
2971
- * await fetchUser(id),
2972
- * async (error) => await fetchDefaultUser()
2973
- * );
2974
- * ```
2614
+ * Note: This represents the domain cause types from declared functions.
2615
+ * However, workflow results may also have unknown causes from step.try failures
2616
+ * or uncaught exceptions, so the actual Result cause type is `unknown`.
2975
2617
  */
2976
- declare function recoverAsync<T, E, C>(r: Result<T, E, C> | Promise<Result<T, E, C>>, fn: (error: E, cause?: C) => T | Promise<T>): Promise<Ok<T>>;
2618
+ type CausesOfDeps<Deps extends Record<string, AnyResultFn>> = CauseOf<Deps[keyof Deps]>;
2977
2619
  /**
2978
- * Validates and type-narrows a value to a Result.
2620
+ * Execution-time options that can override creation-time options.
2621
+ * Pass these to `workflow.run(fn, execOptions)` for per-run configuration.
2979
2622
  *
2980
- * Since this library uses plain objects for Results, serialization is trivial -
2981
- * the serialized form IS the Result. This function validates the structure and
2982
- * provides type-safe narrowing.
2983
- *
2984
- * ## When to Use
2985
- *
2986
- * Use `hydrate()` when:
2987
- * - Receiving Results over RPC/network
2988
- * - Deserializing Results from storage
2989
- * - Validating untrusted data as Results
2990
- *
2991
- * @param value - The unknown value to validate as a Result
2992
- * @returns The value as a typed Result, or null if invalid
2623
+ * Rule: Use `workflow(...)` for normal runs. Use `workflow.run(...)` when you need per-run hooks/options.
2993
2624
  *
2994
2625
  * @example
2995
2626
  * ```typescript
2996
- * // Deserialize from JSON
2997
- * const parsed = JSON.parse(jsonString);
2998
- * const result = hydrate<User, ApiError>(parsed);
2999
- * if (result) {
3000
- * // result is Result<User, ApiError>
3001
- * }
2627
+ * const workflow = createWorkflow(deps, { cache, onEvent: defaultHandler });
3002
2628
  *
3003
- * // Validate RPC response
3004
- * const rpcResponse = await fetchFromService();
3005
- * const result = hydrate<Data, ServiceError>(rpcResponse);
3006
- * ```
3007
- */
3008
- declare function hydrate<T, E, C = unknown>(value: unknown): Result<T, E, C> | null;
3009
- /**
3010
- * Type guard to check if a value is a valid serialized Result.
2629
+ * // Normal run uses creation-time options
2630
+ * await workflow(async ({ step }) => { ... });
3011
2631
  *
3012
- * @param value - The value to check
3013
- * @returns True if the value is a valid Result structure
2632
+ * // Per-run options override creation-time options
2633
+ * await workflow.run(async ({ step }) => { ... }, { onEvent: viz.handleEvent });
3014
2634
  *
3015
- * @example
3016
- * ```typescript
3017
- * if (isSerializedResult(data)) {
3018
- * // data is Result<unknown, unknown, unknown>
3019
- * if (data.ok) {
3020
- * console.log(data.value);
3021
- * }
3022
- * }
2635
+ * // Pre-bind defaults with .with() (overridable by .run())
2636
+ * const visualized = workflow.with({ onEvent: viz.handleEvent });
2637
+ * await visualized(async ({ step }) => { ... });
3023
2638
  * ```
3024
2639
  */
3025
- declare function isSerializedResult(value: unknown): value is Result<unknown, unknown, unknown>;
3026
- type AllValues<T extends readonly Result<unknown, unknown, unknown>[]> = {
3027
- [K in keyof T]: T[K] extends Ok<infer V> ? V : T[K] extends Err<unknown, unknown> ? never : T[K] extends Result<infer V, unknown, unknown> ? V : never;
2640
+ type ExecutionOptions<E, U = UnexpectedError, C = void> = {
2641
+ /**
2642
+ * Event handler for workflow and step lifecycle events.
2643
+ * Overrides `onEvent` from creation-time options.
2644
+ */
2645
+ onEvent?: (event: WorkflowEvent<E | U, C>, ctx: C) => void;
2646
+ /**
2647
+ * Error handler called when a step fails.
2648
+ * Overrides `onError` from creation-time options.
2649
+ */
2650
+ onError?: (error: E | U, stepName?: string, ctx?: C) => void;
2651
+ /**
2652
+ * AbortSignal for workflow-level cancellation.
2653
+ * Overrides `signal` from creation-time options.
2654
+ */
2655
+ signal?: AbortSignal;
2656
+ /**
2657
+ * Factory to create per-run context. Can be async.
2658
+ * Overrides `createContext` from creation-time options.
2659
+ */
2660
+ createContext?: () => C | Promise<C>;
2661
+ /**
2662
+ * Resume state for workflow replay. Can be a factory function (sync or async).
2663
+ * Overrides `resumeState` from creation-time options.
2664
+ */
2665
+ resumeState?: ResumeState | (() => ResumeState | Promise<ResumeState>);
2666
+ /**
2667
+ * Hook to check if workflow should run (concurrency control).
2668
+ * Overrides `shouldRun` from creation-time options.
2669
+ */
2670
+ shouldRun?: (workflowId: string, context: C) => boolean | Promise<boolean>;
2671
+ /**
2672
+ * Hook called before workflow execution starts.
2673
+ * Overrides `onBeforeStart` from creation-time options.
2674
+ */
2675
+ onBeforeStart?: (workflowId: string, context: C) => boolean | Promise<boolean>;
2676
+ /**
2677
+ * Hook called after each step completes (only for steps with a `key`).
2678
+ * Overrides `onAfterStep` from creation-time options.
2679
+ */
2680
+ onAfterStep?: (stepKey: string, result: Result<unknown, unknown, unknown>, workflowId: string, context: C) => void | Promise<void>;
2681
+ /**
2682
+ * Enable strict mode for this specific run (analyzer validation only).
2683
+ */
2684
+ strict?: boolean;
2685
+ /**
2686
+ * Declared workflow graph for strict runtime validation.
2687
+ * Undeclared step/decision ids fail the run immediately.
2688
+ * Overrides `graph` from creation-time options.
2689
+ */
2690
+ graph?: DeclaredGraph;
2691
+ /**
2692
+ * Enable development warnings for this run.
2693
+ * Only active when NODE_ENV !== 'production'.
2694
+ */
2695
+ devWarnings?: boolean;
3028
2696
  };
3029
- type AllErrors<T extends readonly Result<unknown, unknown, unknown>[]> = {
3030
- [K in keyof T]: T[K] extends Ok<unknown> ? never : T[K] extends Err<infer E, unknown> ? E : T[K] extends Result<unknown, infer E, unknown> ? E : never;
3031
- }[number];
3032
- type AllCauses<T extends readonly Result<unknown, unknown, unknown>[]> = {
3033
- [K in keyof T]: T[K] extends Ok<unknown> ? never : T[K] extends Err<unknown, infer C> ? C : T[K] extends Result<unknown, unknown, infer C> ? C : never;
3034
- }[number];
3035
- type AllResult<T extends readonly Result<unknown, unknown, unknown>[]> = [
3036
- AllErrors<T>
3037
- ] extends [never] ? Ok<AllValues<T>> : Result<AllValues<T>, AllErrors<T>, AllCauses<T>>;
3038
2697
  /**
3039
- * Combines multiple Results into one, requiring all to succeed.
3040
- *
3041
- * ## When to Use
3042
- *
3043
- * Use `all()` when:
3044
- * - You have multiple independent operations that all must succeed
3045
- * - You want to short-circuit on the first error (fail-fast)
3046
- * - You need all values together (e.g., combining API responses)
3047
- * - Performance matters (stops on first error, doesn't wait for all)
3048
- *
3049
- * ## Why Use This
3050
- *
3051
- * - **Fail-fast**: Stops immediately on first error (better performance)
3052
- * - **Type-safe**: TypeScript infers the array type from input
3053
- * - **Short-circuit**: Doesn't evaluate remaining Results after error
3054
- * - **Composable**: Can be chained with other operations
3055
- *
3056
- * ## Important
3057
- *
3058
- * - **Short-circuits**: Returns first error immediately, doesn't wait for all Results
3059
- * - **All must succeed**: If any Result fails, the entire operation fails
3060
- * - **Use `allSettled`**: If you need to collect all errors (e.g., form validation)
3061
- *
3062
- * @param results - Array of Results to combine (all must succeed)
3063
- * @returns A Result with an array of all success values, or the first error encountered
3064
- *
3065
- * @example
3066
- * ```typescript
3067
- * // Combine multiple successful Results
3068
- * const combined = all([Awaitly.ok(1), Awaitly.ok(2), Awaitly.ok(3)]);
3069
- * // combined: { ok: true, value: [1, 2, 3] }
3070
- *
3071
- * // Short-circuits on first error
3072
- * const error = all([Awaitly.ok(1), Awaitly.err('ERROR'), Awaitly.ok(3)]);
3073
- * // error: { ok: false, error: 'ERROR' }
3074
- * // Note: Awaitly.ok(3) is never evaluated
3075
- *
3076
- * // Combine API responses
3077
- * const data = all([
3078
- * fetchUser(id),
3079
- * fetchPosts(id),
3080
- * fetchComments(id)
3081
- * ]);
3082
- * // data.value: [user, posts, comments] if all succeed
3083
- * ```
2698
+ * Per-run configuration. Extends ExecutionOptions with dep overrides.
2699
+ * Pass to `workflow.run(fn, config)` or `workflow.run(name, fn, config)`.
2700
+ */
2701
+ type RunConfig<E, U = UnexpectedError, C = void, Deps = unknown> = ExecutionOptions<E, U, C> & {
2702
+ /** Override creation-time deps (partial merge). */
2703
+ deps?: Partial<Deps>;
2704
+ /** Step result cache for this run. */
2705
+ cache?: StepCache;
2706
+ /** Restore workflow from a previously saved snapshot. */
2707
+ snapshot?: WorkflowSnapshot | null;
2708
+ /** Stream store for this run. */
2709
+ streamStore?: StreamStore;
2710
+ };
2711
+ /**
2712
+ * Workflow options. Error union is always closed: E | U.
2713
+ * When catchUnexpected is omitted, U defaults to UnexpectedError.
3084
2714
  */
3085
- declare function all<const T extends readonly Result<unknown, unknown, unknown>[]>(results: T): AllResult<T>;
2715
+ type WorkflowOptions<E, U = UnexpectedError, C = void, Errs extends readonly string[] = readonly string[]> = {
2716
+ /** Standard Schema for input validation. Works with Zod, Valibot, ArkType, etc. */
2717
+ inputSchema?: StandardSchemaV1;
2718
+ /** Input data to validate against inputSchema and pass to workflow context. */
2719
+ input?: unknown;
2720
+ /** Short description for labels/tooltips (static analysis) */
2721
+ description?: string;
2722
+ /** Full markdown documentation (static analysis) */
2723
+ markdown?: string;
2724
+ /**
2725
+ * Map uncaught exceptions (and cancellation) to your error type U.
2726
+ * When omitted, U = UnexpectedError and the default mapper returns an UnexpectedError instance.
2727
+ */
2728
+ catchUnexpected?: (cause: unknown) => U;
2729
+ /**
2730
+ * Declared errors for the workflow (strict validation).
2731
+ * When provided, the analyzer validates that computed errors match declared errors.
2732
+ */
2733
+ errors?: Errs;
2734
+ onError?: (error: E | U, stepName?: string, ctx?: C) => void;
2735
+ /**
2736
+ * Unified event stream for workflow and step lifecycle.
2737
+ *
2738
+ * Context is automatically included in `event.context` when provided via `createContext`.
2739
+ * The separate `ctx` parameter is provided for convenience.
2740
+ */
2741
+ onEvent?: (event: WorkflowEvent<E | U, C>, ctx: C) => void;
2742
+ /** Create per-run context for event correlation */
2743
+ createContext?: () => C;
2744
+ /** Step result cache - only steps with a `key` option are cached */
2745
+ cache?: StepCache;
2746
+ /** Pre-populate cache from saved state for workflow resume. Prefer `snapshot` option. */
2747
+ resumeState?: ResumeState | (() => ResumeState | Promise<ResumeState>);
2748
+ /**
2749
+ * Restore workflow from a previously saved snapshot.
2750
+ * Pass `null` for fresh start (e.g., when store.load() returns nothing).
2751
+ */
2752
+ snapshot?: WorkflowSnapshot | null;
2753
+ /**
2754
+ * Custom serialization for encoding/decoding values during snapshot operations.
2755
+ */
2756
+ serialization?: {
2757
+ encode?: (value: unknown) => JSONValue;
2758
+ decode?: (value: JSONValue) => unknown;
2759
+ };
2760
+ snapshotSerialization?: {
2761
+ strict?: boolean;
2762
+ };
2763
+ onUnknownSteps?: "warn" | "error" | "ignore";
2764
+ onDefinitionChange?: "warn" | "error" | "ignore";
2765
+ /**
2766
+ * External AbortSignal for workflow-level cancellation.
2767
+ * Cancellation is mapped through catchUnexpected (default: UnexpectedError with cause.thrown = WorkflowCancelledError).
2768
+ */
2769
+ signal?: AbortSignal;
2770
+ onBeforeStart?: (workflowId: string, context: C) => boolean | Promise<boolean>;
2771
+ onAfterStep?: (stepKey: string, result: Result<unknown, unknown, unknown>, workflowId: string, context: C) => void | Promise<void>;
2772
+ shouldRun?: (workflowId: string, context: C) => boolean | Promise<boolean>;
2773
+ streamStore?: StreamStore;
2774
+ /**
2775
+ * Declared workflow graph for strict runtime validation.
2776
+ * When provided, any runtime step/decision id not present in the graph
2777
+ * fails the workflow immediately, guaranteeing the static diagram matches
2778
+ * what actually runs. Produce it with awaitly-analyze's renderWorkflowDSL,
2779
+ * or pass a plain list of ids.
2780
+ */
2781
+ graph?: DeclaredGraph;
2782
+ /**
2783
+ * Enable development warnings.
2784
+ * Only active when NODE_ENV !== 'production'.
2785
+ */
2786
+ devWarnings?: boolean;
2787
+ };
3086
2788
  /**
3087
- * Combines multiple Results or Promises of Results into one (async version of `all`).
3088
- *
3089
- * ## When to Use
3090
- *
3091
- * Use `allAsync()` when:
3092
- * - You have multiple async operations that all must succeed
3093
- * - You want to run operations in parallel (better performance)
3094
- * - You want to short-circuit on the first error (fail-fast)
3095
- * - You need all values together from parallel operations
3096
- *
3097
- * ## Why Use This Instead of `all`
3098
- *
3099
- * - **Parallel execution**: All Promises start immediately (faster)
3100
- * - **Async support**: Works with Promises and AsyncResults
3101
- * - **Promise rejection handling**: Converts Promise rejections to `PromiseRejectedError`
3102
- *
3103
- * ## Important
3104
- *
3105
- * - **Short-circuits**: Returns first error immediately, cancels remaining operations
3106
- * - **Parallel**: All operations start simultaneously (unlike sequential `andThen`)
3107
- * - **Use `allSettledAsync`**: If you need to collect all errors
3108
- *
3109
- * @param results - Array of Results or Promises of Results to combine (all must succeed)
3110
- * @returns A Promise resolving to a Result with an array of all success values, or the first error
3111
- *
3112
- * @example
3113
- * ```typescript
3114
- * // Parallel API calls
3115
- * const combined = await allAsync([
3116
- * fetchUser('1'),
3117
- * fetchPosts('1'),
3118
- * fetchComments('1')
3119
- * ]);
3120
- * // All three calls start simultaneously
3121
- * // combined: { ok: true, value: [user, posts, comments] } if all succeed
3122
- *
3123
- * // Mix Results and Promises
3124
- * const data = await allAsync([
3125
- * ok(cachedUser), // Already resolved
3126
- * fetchPosts(userId), // Promise
3127
- * ]);
3128
- * ```
2789
+ * Workflow context provided to callbacks, containing workflow metadata
2790
+ * and data store for step outputs.
2791
+ * This allows conditional helpers and other utilities to access workflowId, onEvent, and context.
3129
2792
  */
3130
- declare function allAsync<const T extends readonly (Result<unknown, unknown, unknown> | Promise<Result<unknown, unknown, unknown>>)[]>(results: T): Promise<Result<{
3131
- [K in keyof T]: T[K] extends Result<infer V, unknown, unknown> | Promise<Result<infer V, unknown, unknown>> ? V : never;
3132
- }, {
3133
- [K in keyof T]: T[K] extends Result<unknown, infer E, unknown> | Promise<Result<unknown, infer E, unknown>> ? E : never;
3134
- }[number] | PromiseRejectedError, {
3135
- [K in keyof T]: T[K] extends Result<unknown, unknown, infer C> | Promise<Result<unknown, unknown, infer C>> ? C : never;
3136
- }[number] | PromiseRejectionCause>>;
3137
- type SettledError<E, C = unknown> = {
3138
- error: E;
3139
- cause?: C;
2793
+ type WorkflowContext<C = void, Input = Record<string, unknown>, Data = Record<string, unknown>> = {
2794
+ /**
2795
+ * Unique ID for this workflow run.
2796
+ */
2797
+ workflowId: string;
2798
+ /**
2799
+ * Event emitter function for workflow events.
2800
+ * Can be used with conditional helpers to emit step_skipped events.
2801
+ */
2802
+ onEvent?: (event: WorkflowEvent<unknown, C>) => void;
2803
+ /**
2804
+ * Per-run context created by createContext (or undefined if not provided).
2805
+ * Automatically included in all workflow events.
2806
+ */
2807
+ context?: C;
2808
+ /**
2809
+ * Workflow-level AbortSignal (if provided in workflow options).
2810
+ * Use this to check cancellation or pass to operations that support AbortSignal.
2811
+ *
2812
+ * @example
2813
+ * ```typescript
2814
+ * const result = await workflow(async ({ step, deps, ctx }) => {
2815
+ * // Pass signal to fetch
2816
+ * const response = await fetch(url, { signal: ctx.signal });
2817
+ * // Or check manually
2818
+ * if (ctx.signal?.aborted) return early();
2819
+ * });
2820
+ * ```
2821
+ */
2822
+ signal?: AbortSignal;
2823
+ /**
2824
+ * Input data passed to the workflow.
2825
+ * Access via `ctx.input.key` for static analysis tracking.
2826
+ *
2827
+ * @example
2828
+ * ```typescript
2829
+ * await step('getCart', () => getCart(ctx.input.cartId), {
2830
+ * errors: ['CART_NOT_FOUND'],
2831
+ * });
2832
+ * ```
2833
+ */
2834
+ input: Input;
2835
+ /**
2836
+ * Get a value from the workflow data store by key.
2837
+ * Preferred over `ctx.get()` for static analysis as it's easier to trace.
2838
+ *
2839
+ * @param key - The key to retrieve
2840
+ * @returns The value at that key
2841
+ *
2842
+ * @example
2843
+ * ```typescript
2844
+ * // Use ctx.ref() inside step callbacks for tracked dependencies
2845
+ * await step('charge', () => chargeCard(ctx.ref('cart').total), {
2846
+ * errors: ['CARD_DECLINED'],
2847
+ * });
2848
+ * ```
2849
+ */
2850
+ ref: <K extends keyof Data>(key: K) => Data[K];
2851
+ /**
2852
+ * Set a value in the workflow data store.
2853
+ * Prefer using `out` option on steps instead for better static analysis.
2854
+ *
2855
+ * @param key - The key to set
2856
+ * @param value - The value to store
2857
+ *
2858
+ * @example
2859
+ * ```typescript
2860
+ * // Prefer out option:
2861
+ * await step('getCart', () => getCart(id), { out: 'cart' });
2862
+ *
2863
+ * // Escape hatch (less analyzable):
2864
+ * const cart = await step('getCart', () => getCart(id));
2865
+ * ctx.set('cart', cart);
2866
+ * ```
2867
+ */
2868
+ set: <K extends string>(key: K, value: unknown) => void;
2869
+ /**
2870
+ * Get a value from the workflow data store.
2871
+ * Prefer `ctx.ref()` for better static analysis.
2872
+ *
2873
+ * @param key - The key to retrieve
2874
+ * @returns The value at that key (or undefined)
2875
+ */
2876
+ get: <K extends keyof Data>(key: K) => Data[K] | undefined;
3140
2877
  };
3141
- type AllSettledResult<T extends readonly Result<unknown, unknown, unknown>[]> = [
3142
- AllErrors<T>
3143
- ] extends [never] ? Ok<AllValues<T>> : Result<AllValues<T>, SettledError<AllErrors<T>, AllCauses<T>>[]>;
3144
2878
  /**
3145
- * Combines multiple Results, collecting all errors instead of short-circuiting.
3146
- *
3147
- * ## When to Use
3148
- *
3149
- * Use `allSettled()` when:
3150
- * - You need to see ALL errors, not just the first one
3151
- * - You're doing form validation (show all field errors)
3152
- * - You want to collect partial results (some succeed, some fail)
3153
- * - You need to process all Results regardless of failures
3154
- *
3155
- * ## Why Use This Instead of `all`
3156
- *
3157
- * - **Collects all errors**: Returns array of all errors, not just first
3158
- * - **No short-circuit**: Evaluates all Results even if some fail
3159
- * - **Partial success**: Can see which operations succeeded and which failed
3160
- * - **Better UX**: Show users all validation errors at once
3161
- *
3162
- * ## Important
3163
- *
3164
- * - **No short-circuit**: All Results are evaluated (slower if many fail early)
3165
- * - **Error array**: Returns array of `{ error, cause }` objects, not single error
3166
- * - **Use `all`**: If you want fail-fast behavior (better performance)
3167
- *
3168
- * @param results - Array of Results to combine (all are evaluated)
3169
- * @returns A Result with:
3170
- * - Array of all success values if all succeed
3171
- * - Array of `{ error, cause }` objects if any fail
3172
- *
3173
- * @example
3174
- * ```typescript
3175
- * // Form validation - show all errors
3176
- * const validated = allSettled([
3177
- * validateEmail(email),
3178
- * validatePassword(password),
3179
- * validateAge(age),
3180
- * ]);
3181
- * // If email and password fail:
3182
- * // { ok: false, error: [
3183
- * // { error: 'INVALID_EMAIL' },
3184
- * // { error: 'WEAK_PASSWORD' }
3185
- * // ]}
3186
- *
3187
- * // Collect partial results
3188
- * const results = allSettled([
3189
- * fetchUser('1'), // succeeds
3190
- * fetchUser('2'), // fails
3191
- * fetchUser('3'), // succeeds
3192
- * ]);
3193
- * // Can see which succeeded and which failed
3194
- * ```
2879
+ * Bound steps for a workflow's deps: each dep key becomes a step function
2880
+ * with the dep's arguments that unwraps ok / early-exits on err — same as
2881
+ * the deps-first run(deps, fn) form. `never` deps (no deps) yield no steps.
3195
2882
  */
3196
- declare function allSettled<const T extends readonly Result<unknown, unknown, unknown>[]>(results: T): AllSettledResult<T>;
2883
+ type WorkflowSteps<Deps> = [Deps] extends [
2884
+ Record<string, (...args: never[]) => unknown>
2885
+ ] ? BoundSteps<Deps> : Record<string, never>;
2886
+ /** Workflow function type (no args). E is the full step error union (deps errors + any ExtraE from step.workflow/withFallback). */
2887
+ type WorkflowFn<T, E, Deps, C = void> = (context: {
2888
+ step: RunStep<E>;
2889
+ steps: WorkflowSteps<Deps>;
2890
+ deps: Deps;
2891
+ ctx: WorkflowContext<C>;
2892
+ }) => T | Promise<T>;
3197
2893
  /**
3198
- * Splits an array of Results into separate arrays of success values and errors.
3199
- *
3200
- * ## When to Use
3201
- *
3202
- * Use `partition()` when:
3203
- * - You have an array of Results and need to separate successes from failures
3204
- * - You want to process successes and errors separately
3205
- * - You're collecting results from multiple operations (some may fail)
3206
- * - You need to handle partial success scenarios
3207
- *
3208
- * ## Why Use This
3209
- *
3210
- * - **Simple separation**: One call splits successes and errors
3211
- * - **Type-safe**: TypeScript knows `values` is `T[]` and `errors` is `E[]`
3212
- * - **No unwrapping**: Doesn't require manual `if (r.ok)` checks
3213
- * - **Preserves order**: Maintains original array order in both arrays
3214
- *
3215
- * ## Common Pattern
3216
- *
3217
- * Often used after `Promise.all()` with Results:
3218
- * ```typescript
3219
- * const results = await Promise.all(ids.map(id => fetchUser(id)));
3220
- * const { values: users, errors } = partition(results);
3221
- * // Process successful users, handle errors separately
3222
- * ```
2894
+ * Return type of runWithState: result plus resume state for persistence.
2895
+ * resumeState is always present, even when the run fails or returns an error Result.
2896
+ */
2897
+ type RunWithStateResult<T, E, U> = {
2898
+ result: Result<T, E | U, unknown>;
2899
+ resumeState: ResumeState;
2900
+ };
2901
+ /**
2902
+ * Workflow return type. Error union is always closed: E | ExtraE | U (default U = UnexpectedError).
2903
+ * ExtraE is inferred from the callback when using step.workflow or step.withFallback with errors not in deps.
2904
+ * Methods: .run() (4 overloads) and .runWithState() (4 overloads) for run-and-persist flows.
3223
2905
  *
3224
- * @param results - Array of Results to partition
3225
- * @returns An object with:
3226
- * - `values`: Array of all success values (type `T[]`)
3227
- * - `errors`: Array of all error values (type `E[]`)
2906
+ * Cause type is `unknown` because step.try/catchUnexpected receive thrown values.
2907
+ */
2908
+ interface Workflow<E, U = UnexpectedError, Deps = unknown, C = void> {
2909
+ /**
2910
+ * Pre-bind dependency overrides and return another `Workflow`.
2911
+ * Chain `.withDeps()` and call `.run()` / `.runWithState()` as normal.
2912
+ * Precedence: createWorkflow deps < withDeps deps < run config deps.
2913
+ */
2914
+ withDeps(overrides: Partial<Deps>): Workflow<E, U, Deps, C>;
2915
+ /**
2916
+ * Execute workflow (anonymous run).
2917
+ * ExtraE is inferred from the callback (e.g. from step.workflow / step.withFallback); result is Result<T, E | ExtraE | U>.
2918
+ * T is inferred from the callback return type. For nested workflows (calling another workflow.run() inside the callback),
2919
+ * inference can sometimes fall back to `any`; adding an explicit return type to the callback (e.g.
2920
+ * `async (ctx): Promise<{ user: User; enriched: Enriched }> => { ... }`) gives the compiler a target and preserves types.
2921
+ */
2922
+ run<T, ExtraE = never>(fn: WorkflowFn<T, E | ExtraE, Deps, C>): AsyncResult<T, E | ExtraE | U, unknown>;
2923
+ /**
2924
+ * Execute workflow with config overrides.
2925
+ */
2926
+ run<T, ExtraE = never>(fn: WorkflowFn<T, E | ExtraE, Deps, C>, config: RunConfig<E, U, C, Deps>): AsyncResult<T, E | ExtraE | U, unknown>;
2927
+ /**
2928
+ * Execute named workflow run (for logging, tracing, resume).
2929
+ */
2930
+ run<T, ExtraE = never>(name: string, fn: WorkflowFn<T, E | ExtraE, Deps, C>): AsyncResult<T, E | ExtraE | U, unknown>;
2931
+ /**
2932
+ * Execute named workflow run with config overrides.
2933
+ */
2934
+ run<T, ExtraE = never>(name: string, fn: WorkflowFn<T, E | ExtraE, Deps, C>, config: RunConfig<E, U, C, Deps>): AsyncResult<T, E | ExtraE | U, unknown>;
2935
+ /**
2936
+ * Execute workflow and return result plus resume state for persistence.
2937
+ * resumeState is always present (even on failure) so callers can persist partial state.
2938
+ * Same overloads as run(); does not throw — follows the same "never throw, always Result" contract as run().
2939
+ *
2940
+ * @example
2941
+ * const { result, resumeState } = await workflow.runWithState(fn);
2942
+ * await store.save(id, resumeState);
2943
+ */
2944
+ runWithState<T, ExtraE = never>(fn: WorkflowFn<T, E | ExtraE, Deps, C>): Promise<RunWithStateResult<T, E | ExtraE, U>>;
2945
+ /**
2946
+ * Execute workflow with config overrides and return result plus resume state.
2947
+ */
2948
+ runWithState<T, ExtraE = never>(fn: WorkflowFn<T, E | ExtraE, Deps, C>, config: RunConfig<E, U, C, Deps>): Promise<RunWithStateResult<T, E | ExtraE, U>>;
2949
+ /**
2950
+ * Execute named workflow run and return result plus resume state.
2951
+ */
2952
+ runWithState<T, ExtraE = never>(name: string, fn: WorkflowFn<T, E | ExtraE, Deps, C>): Promise<RunWithStateResult<T, E | ExtraE, U>>;
2953
+ /**
2954
+ * Execute named workflow run with config overrides and return result plus resume state.
2955
+ */
2956
+ runWithState<T, ExtraE = never>(name: string, fn: WorkflowFn<T, E | ExtraE, Deps, C>, config: RunConfig<E, U, C, Deps>): Promise<RunWithStateResult<T, E | ExtraE, U>>;
2957
+ }
2958
+ /**
2959
+ * Error returned when a workflow is cancelled via AbortSignal.
3228
2960
  *
3229
2961
  * @example
3230
2962
  * ```typescript
3231
- * // Split successes and errors
3232
- * const results = [ok(1), err('ERROR_1'), ok(3), err('ERROR_2')];
3233
- * const { values, errors } = partition(results);
3234
- * // values: [1, 3]
3235
- * // errors: ['ERROR_1', 'ERROR_2']
3236
- *
3237
- * // Process batch operations
3238
- * const userResults = await Promise.all(userIds.map(id => fetchUser(id)));
3239
- * const { values: users, errors: fetchErrors } = partition(userResults);
2963
+ * const controller = new AbortController();
2964
+ * const workflow = createWorkflow(deps, { signal: controller.signal });
3240
2965
  *
3241
- * // Process successful users
3242
- * users.forEach(user => processUser(user));
2966
+ * // Later:
2967
+ * controller.abort('User navigated away');
3243
2968
  *
3244
- * // Handle errors
3245
- * fetchErrors.forEach(error => logError(error));
2969
+ * const result = await workflowPromise;
2970
+ * if (!result.ok && isWorkflowCancelled(result.error)) {
2971
+ * console.log('Cancelled:', result.error.reason);
2972
+ * }
3246
2973
  * ```
3247
2974
  */
3248
- declare function partition<T, E, C>(results: readonly Result<T, E, C>[]): {
3249
- values: T[];
3250
- errors: E[];
2975
+ type WorkflowCancelledError = {
2976
+ type: "WORKFLOW_CANCELLED";
2977
+ /** Reason from AbortSignal.reason (if provided) */
2978
+ reason?: string;
2979
+ /** Last successfully completed keyed step (for resume purposes) */
2980
+ lastStepKey?: string;
3251
2981
  };
3252
- type AnyValue<T extends readonly Result<unknown, unknown, unknown>[]> = T[number] extends Result<infer U, unknown, unknown> ? U : never;
3253
- type AnyErrors<T extends readonly Result<unknown, unknown, unknown>[]> = {
3254
- -readonly [K in keyof T]: T[K] extends Result<unknown, infer E, unknown> ? E : never;
3255
- }[number];
3256
- type AnyCauses<T extends readonly Result<unknown, unknown, unknown>[]> = {
3257
- -readonly [K in keyof T]: T[K] extends Result<unknown, unknown, infer C> ? C : never;
3258
- }[number];
3259
2982
  /**
3260
- * Returns the first successful Result from an array (succeeds fast).
3261
- *
3262
- * ## When to Use
3263
- *
3264
- * Use `any()` when:
3265
- * - You have multiple fallback options and need the first that succeeds
3266
- * - You're trying multiple strategies (e.g., cache → DB → API)
3267
- * - You want fail-fast success (stops on first success)
3268
- * - You have redundant data sources and any one will do
3269
- *
3270
- * ## Why Use This
3271
- *
3272
- * - **Succeeds fast**: Returns immediately on first success (better performance)
3273
- * - **Fallback pattern**: Perfect for trying multiple options
3274
- * - **Short-circuits**: Stops evaluating after first success
3275
- * - **Type-safe**: TypeScript infers the success type
3276
- *
3277
- * ## Important
3278
- *
3279
- * - **First success wins**: Returns first successful Result, ignores rest
3280
- * - **All errors**: If all fail, returns first error (not all errors)
3281
- * - **Empty array**: Returns `EmptyInputError` if array is empty
3282
- * - **Use `all`**: If you need ALL to succeed
3283
- *
3284
- * @param results - Array of Results to check (evaluated in order)
3285
- * @returns The first successful Result, or first error if all fail, or `EmptyInputError` if empty
2983
+ * Standard error type for steps awaiting human approval.
2984
+ * Use this as the error type for approval-gated steps.
3286
2985
  *
3287
2986
  * @example
3288
- * ```typescript
3289
- * // Try multiple fallback strategies
3290
- * const data = any([
3291
- * fetchFromCache(id),
3292
- * fetchFromDB(id),
3293
- * fetchFromAPI(id)
3294
- * ]);
3295
- * // Returns first that succeeds
3296
- *
3297
- * // Try multiple formats
3298
- * const parsed = any([
3299
- * parseJSON(input),
3300
- * parseXML(input),
3301
- * parseYAML(input)
3302
- * ]);
3303
- *
3304
- * // All errors case
3305
- * const allErrors = any([err('A'), err('B'), err('C')]);
3306
- * // allErrors: { ok: false, error: 'A' } (first error)
3307
- * ```
2987
+ * const requireApproval = async (userId: string): AsyncResult<Approval, PendingApproval> => {
2988
+ * const status = await checkApprovalStatus(userId);
2989
+ * if (status === 'pending') {
2990
+ * return err({ type: 'PENDING_APPROVAL', stepKey: `approval:${userId}` });
2991
+ * }
2992
+ * return ok(status.approval);
2993
+ * };
3308
2994
  */
3309
- declare function any<const T extends readonly Result<unknown, unknown, unknown>[]>(results: T): Result<AnyValue<T>, AnyErrors<T> | EmptyInputError, AnyCauses<T>>;
3310
- type AnyAsyncValue<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = Awaited<T[number]> extends Result<infer U, unknown, unknown> ? U : never;
3311
- type AnyAsyncErrors<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = {
3312
- -readonly [K in keyof T]: Awaited<T[K]> extends Result<unknown, infer E, unknown> ? E : never;
3313
- }[number];
3314
- type AnyAsyncCauses<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = {
3315
- -readonly [K in keyof T]: Awaited<T[K]> extends Result<unknown, unknown, infer C> ? C : never;
3316
- }[number];
2995
+ type PendingApproval = {
2996
+ type: "PENDING_APPROVAL";
2997
+ /** Step key for correlation when resuming */
2998
+ stepKey: string;
2999
+ /** Optional reason for the pending state */
3000
+ reason?: string;
3001
+ /** Optional metadata for the approval request */
3002
+ metadata?: Record<string, unknown>;
3003
+ };
3317
3004
  /**
3318
- * Returns the first successful Result from an array of Results or Promises (async version of `any`).
3319
- *
3320
- * ## When to Use
3321
- *
3322
- * Use `anyAsync()` when:
3323
- * - You have multiple async fallback options and need the first that succeeds
3324
- * - You're trying multiple async strategies in parallel (cache → DB → API)
3325
- * - You want fail-fast success from parallel operations
3326
- * - You have redundant async data sources and any one will do
3327
- *
3328
- * ## Why Use This Instead of `any`
3329
- *
3330
- * - **Parallel execution**: All Promises start immediately (faster)
3331
- * - **Async support**: Works with Promises and AsyncResults
3332
- * - **Promise rejection handling**: Converts Promise rejections to `PromiseRejectedError`
3333
- *
3334
- * ## Important
3335
- *
3336
- * - **First success wins**: Returns first successful Result (from any Promise)
3337
- * - **Parallel**: All operations run simultaneously
3338
- * - **All errors**: If all fail, returns first error encountered
3339
- *
3340
- * @param results - Array of Results or Promises of Results to check (all start in parallel)
3341
- * @returns A Promise resolving to the first successful Result, or first error if all fail
3342
- *
3343
- * @example
3344
- * ```typescript
3345
- * // Try multiple async fallbacks in parallel
3346
- * const data = await anyAsync([
3347
- * fetchFromCache(id), // Fastest wins
3348
- * fetchFromDB(id),
3349
- * fetchFromAPI(id)
3350
- * ]);
3351
- *
3352
- * // Try multiple API endpoints
3353
- * const response = await anyAsync([
3354
- * fetch('/api/v1/data'),
3355
- * fetch('/api/v2/data'),
3356
- * fetch('/backup-api/data')
3357
- * ]);
3358
- * ```
3005
+ * Standard error type for steps awaiting an HTTP callback (webhook).
3006
+ * Use with injectHook() to resume when the app receives the callback.
3007
+ * stepKey is always "hook:" + hookId for resume state.
3359
3008
  */
3360
- declare function anyAsync<const T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]>(results: T): Promise<Result<AnyAsyncValue<T>, AnyAsyncErrors<T> | EmptyInputError | PromiseRejectedError, AnyAsyncCauses<T> | PromiseRejectionCause>>;
3361
- type AllAsyncValues<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = {
3362
- [K in keyof T]: Awaited<T[K]> extends Result<infer V, unknown, unknown> ? V : never;
3009
+ type PendingHook = {
3010
+ type: "PENDING_HOOK";
3011
+ hookId: string;
3012
+ /** Step key used in resume state; always "hook:" + hookId */
3013
+ stepKey: string;
3014
+ metadata?: Record<string, unknown>;
3363
3015
  };
3364
- type AllAsyncErrors<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = {
3365
- [K in keyof T]: Awaited<T[K]> extends Result<unknown, infer E, unknown> ? E : never;
3366
- }[number];
3367
- type AllAsyncCauses<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = {
3368
- [K in keyof T]: Awaited<T[K]> extends Result<unknown, unknown, infer C> ? C : never;
3369
- }[number];
3370
3016
  /**
3371
- * Combines multiple Results or Promises of Results, collecting all errors (async version of `allSettled`).
3372
- *
3373
- * ## When to Use
3374
- *
3375
- * Use `allSettledAsync()` when:
3376
- * - You have multiple async operations and need ALL errors reported
3377
- * - You're doing async form validation (show all field errors at once)
3378
- * - You want to run operations in parallel and collect all results
3379
- *
3380
- * ## Behavior
3381
- *
3382
- * **Note:** Unlike `Promise.allSettled()`, this returns a Result:
3383
- * - `ok(values[])` if ALL succeed
3384
- * - `err(SettledError[])` if ANY fail (with all collected errors)
3385
- *
3386
- * This is consistent with awaitly's philosophy - all functions return Results.
3387
- * `Promise.allSettled()` always succeeds with per-item status objects; this function
3388
- * returns a single Result indicating overall success or failure.
3389
- *
3390
- * ## Why Use This Instead of `allSettled`
3391
- *
3392
- * - **Parallel execution**: All Promises start immediately (faster)
3393
- * - **Async support**: Works with Promises and AsyncResults
3394
- * - **Promise rejection handling**: Converts Promise rejections to `PromiseRejectedError`
3395
- *
3396
- * ## Important
3397
- *
3398
- * - **No short-circuit**: All operations complete (even if some fail)
3399
- * - **Parallel**: All operations run simultaneously
3400
- * - **Error array**: Returns array of `SettledError` objects (`{ error, cause? }`)
3401
- *
3402
- * @param results - Array of Results or Promises of Results to combine (all are evaluated)
3403
- * @returns A Promise resolving to a Result with:
3404
- * - `ok(values[])` - Array of all success values if ALL succeed
3405
- * - `err(errors[])` - Array of `SettledError` objects if ANY fail
3406
- *
3407
- * @example
3408
- * ```typescript
3409
- * // Async form validation - see all errors at once
3410
- * const validated = await allSettledAsync([
3411
- * validateEmailAsync(email),
3412
- * validatePasswordAsync(password),
3413
- * checkUsernameAvailableAsync(username),
3414
- * ]);
3415
- *
3416
- * if (!validated.ok) {
3417
- * // validated.error is array of all validation failures
3418
- * console.log('Errors:', validated.error.map(e => e.error));
3419
- * }
3420
- *
3421
- * // Parallel API calls with error collection
3422
- * const results = await allSettledAsync([
3423
- * fetchUser('1'),
3424
- * fetchUser('2'),
3425
- * fetchUser('3'),
3426
- * ]);
3427
- * ```
3017
+ * Error returned when approval is rejected.
3018
+ */
3019
+ type ApprovalRejected = {
3020
+ type: "APPROVAL_REJECTED";
3021
+ /** Step key for correlation */
3022
+ stepKey: string;
3023
+ /** Reason the approval was rejected */
3024
+ reason: string;
3025
+ };
3026
+ /**
3027
+ * Options for creating an approval-gated step.
3028
+ */
3029
+ interface ApprovalStepOptions<T> {
3030
+ /** Stable key for this approval step (used for resume) */
3031
+ key: string;
3032
+ /** Function to check current approval status from external source */
3033
+ checkApproval: () => Promise<{
3034
+ status: "pending";
3035
+ } | {
3036
+ status: "approved";
3037
+ value: T;
3038
+ } | {
3039
+ status: "rejected";
3040
+ reason: string;
3041
+ }>;
3042
+ /** Optional reason shown when pending */
3043
+ pendingReason?: string;
3044
+ /** Optional metadata for the approval request */
3045
+ metadata?: Record<string, unknown>;
3046
+ }
3047
+ /**
3048
+ * Options for creating a gated (pre-approval) step.
3428
3049
  */
3429
- declare function allSettledAsync<const T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]>(results: T): Promise<Result<AllAsyncValues<T>, SettledError<AllAsyncErrors<T> | PromiseRejectedError, AllAsyncCauses<T> | PromiseRejectionCause>[]>>;
3050
+ interface GatedStepOptions<TArgs, T> {
3051
+ /** Stable key for this gated step (used for approval tracking) */
3052
+ key: string;
3053
+ /**
3054
+ * Condition to check if approval is required.
3055
+ * If returns true, execution pauses for approval.
3056
+ * If returns false, operation executes immediately.
3057
+ */
3058
+ requiresApproval: boolean | ((args: TArgs) => boolean | Promise<boolean>);
3059
+ /**
3060
+ * Human-readable description of what this operation does.
3061
+ * Shown in the approval UI so humans understand what they're approving.
3062
+ */
3063
+ description: string | ((args: TArgs) => string);
3064
+ /**
3065
+ * Check if approval has been granted externally.
3066
+ * If not provided, the step always returns PendingApproval when gated.
3067
+ */
3068
+ checkApproval?: () => Promise<{
3069
+ status: "pending";
3070
+ } | {
3071
+ status: "approved";
3072
+ value?: T;
3073
+ } | {
3074
+ status: "rejected";
3075
+ reason: string;
3076
+ }>;
3077
+ /**
3078
+ * Optional metadata to include in the approval request.
3079
+ * The args are automatically included as `pendingArgs`.
3080
+ */
3081
+ metadata?: Record<string, unknown>;
3082
+ }
3430
3083
 
3431
- export { orElseAsync as $, AWAITLY_CANCELLED as A, extractStepMetadata as B, type CauseOf as C, from as D, type EmptyInputError as E, fromNullable as F, fromPromise as G, hydrate as H, isErr as I, isOk as J, isSerializedResult as K, isUnexpectedError as L, type MatchErrorHandlers as M, lookupErrorClassification as N, type Ok as O, PROMISE_REJECTED as P, map as Q, type Result as R, type SettledError as S, mapError as T, UnwrapError as U, mapErrorTry as V, mapTry as W, match as X, matchError as Y, ok as Z, orElse as _, AWAITLY_TIMEOUT as a, partition as a0, recover as a1, recoverAsync as a2, runOrNull as a3, runOrThrow as a4, runOrThrowAsync as a5, runOrUndefined as a6, tags as a7, tap as a8, tapError as a9, tryAsync as aa, unwrap as ab, unwrapOr as ac, unwrapOrElse as ad, type BackoffStrategy as ae, type RetryOptions as af, type WorkflowEvent as ag, type RunStep as ah, type StepOptions as ai, type RunOptions as aj, type RunOptionsWithCatch as ak, type RunOptionsWithoutCatch as al, STEP_TIMEOUT_MARKER as am, type ScopeType as an, type StepTimeoutError as ao, type StepTimeoutMarkerMeta as ap, type TimeoutOptions as aq, getStepTimeoutMeta as ar, isStepTimeoutError as as, run as at, type StepFailureMeta as au, EARLY_EXIT_SYMBOL as av, type EarlyExit as aw, createEarlyExit as ax, isEarlyExit as ay, AWAITLY_UNEXPECTED as b, type AsyncResult as c, type Err as d, type ErrorClassification as e, type ErrorOf as f, type Errors as g, type ErrorsOf as h, type ExtractCause as i, type ExtractError as j, type ExtractValue as k, type MaybeAsyncResult as l, type PromiseRejectedError as m, type PromiseRejectionCause as n, type StepErrorDiagnostics as o, type StepMetadata as p, all as q, allAsync as r, allSettled as s, allSettledAsync as t, andThen as u, any as v, anyAsync as w, bimap as x, err as y, extractErrorTag as z };
3084
+ export { STREAM_ENDED as $, type AsyncResult as A, type BackoffStrategy as B, type WorkflowSnapshot as C, type DepValueOfReturn as D, EARLY_EXIT_SYMBOL as E, type ApprovalStepOptions as F, type GatedStepOptions as G, type Workflow as H, type WorkflowOptions as I, type SnapshotStore as J, type ResumeStateEntry as K, type StreamStore as L, type StreamReader as M, type CausesOfDeps as N, type Ok as O, type PendingApproval as P, type ExecutionOptions as Q, type Result as R, type StepOptions as S, type TimeoutOptions as T, type JSONValue as U, type MemoryCacheOptions as V, type WorkflowEvent as W, type RunConfig as X, type RunWithStateResult as Y, STREAM_BACKPRESSURE_ERROR as Z, STREAM_CLOSE_ERROR as _, type RetryOptions as a, STREAM_READ_ERROR as a0, STREAM_STORE_ERROR as a1, STREAM_WRITE_ERROR as a2, type SerializedCause as a3, SnapshotDecodeError as a4, SnapshotFormatError as a5, SnapshotMismatchError as a6, type SnapshotWarning as a7, type StepCache as a8, type StepErrorDiagnostics as a9, isWorkflowSnapshot as aA, looksLikeWorkflowSnapshot as aB, mergeSnapshots as aC, serializeError as aD, serializeThrown as aE, streamBackpressureError as aF, streamCloseError as aG, streamEnded as aH, streamReadError as aI, streamStoreError as aJ, streamWriteError as aK, validateSnapshot as aL, type StepMetadata as aa, type StreamBackpressureError as ab, type StreamCloseError as ac, type StreamEndedMarker as ad, type StreamError as ae, type StreamForEachOptions as af, type StreamForEachResult as ag, type StreamItem as ah, type StreamMetadata as ai, type StreamOptions as aj, type StreamReadError as ak, type StreamReadOptions as al, type StreamStoreError as am, type StreamWriteError as an, type StreamWriter as ao, type Unsubscribe as ap, type WorkflowFn as aq, type WorkflowSteps as ar, assertValidSnapshot as as, createMemoryCache as at, deserializeCauseNew as au, isStreamBackpressureError as av, isStreamEnded as aw, isStreamReadError as ax, isStreamStoreError as ay, isStreamWriteError as az, type BoundSteps as b, type EarlyExit as c, type RunOptions as d, type RunOptionsWithCatch as e, type RunOptionsWithoutCatch as f, type RunStep as g, STEP_TIMEOUT_MARKER as h, type ScopeType as i, type StepFailureMeta as j, type StepTimeoutError as k, type StepTimeoutMarkerMeta as l, createEarlyExit as m, getStepTimeoutMeta as n, isEarlyExit as o, isStepTimeoutError as p, type AnyResultFn as q, run as r, type ErrorsOfDeps as s, type WorkflowContext as t, type Err as u, type ApprovalRejected as v, type PendingHook as w, type ResumeState as x, type WorkflowCancelledError as y, type StepResult as z };