awaitly 1.35.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 +29 -4
  14. package/dist/result.d.ts +29 -4
  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-DGs0tySr.d.cts → types-B8NfNRGX.d.ts} +1078 -1502
  24. package/dist/{run-entry-BOuNyVoO.d.ts → types-BZ2f4MRR.d.cts} +1078 -1502
  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 +3 -168
  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-By77n4Fa.d.ts +0 -15
  75. package/dist/di-OJfsohf-.d.cts +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-4sV7mTqj.d.cts +0 -72
  123. package/dist/guards-BIX05ALH.d.ts +0 -72
  124. package/dist/hitl-DFn4Xa_l.d.cts +0 -468
  125. package/dist/hitl-DU5VpKq7.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-CnvBryQB.d.ts +0 -417
  133. package/dist/index-DEZEf8Fs.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-B-8PjnSR.d.cts +0 -831
  149. package/dist/persistence-entry-D8zRkLiT.d.ts +0 -831
  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-BziYHFkD.d.ts +0 -323
  235. package/dist/types-C5jLEUqY.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,4 +1,5 @@
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
5
  * Bound steps for the deps-first forms: run(deps, fn) and workflow({ steps }).
@@ -12,6 +13,7 @@ type AnyFunction$1 = (...args: never[]) => unknown;
12
13
  /**
13
14
  * Success value of a dependency's return type. Result-returning deps
14
15
  * contribute their `ok` value; plain (non-Result) deps pass through as-is.
16
+ * Shared with the policy wrappers, which normalize the same way.
15
17
  */
16
18
  type DepValueOfReturn<R> = [Extract<Awaited<R>, {
17
19
  ok: true;
@@ -39,9 +41,9 @@ type BoundSteps<Deps extends Record<string, AnyFunction$1>> = {
39
41
  };
40
42
 
41
43
  /**
42
- * awaitly/core
44
+ * Core module (internal): Result primitives and the run() function.
43
45
  *
44
- * Core Result primitives and run() function.
46
+ * Surfaced through the root `awaitly` entry (formerly `awaitly/core`).
45
47
  * Use this module for minimal bundle size when you don't need the full workflow capabilities
46
48
  * (like retries, timeout, or state persistence) provided by `createWorkflow`.
47
49
  *
@@ -65,7 +67,7 @@ type DurationInput = string | DurationObject;
65
67
  *
66
68
  * @example
67
69
  * ```typescript
68
- * const success = Awaitly.ok(42);
70
+ * const success = ok(42);
69
71
  * // Type shown: Ok<number>
70
72
  * ```
71
73
  */
@@ -83,7 +85,7 @@ type Ok<T> = {
83
85
  *
84
86
  * @example
85
87
  * ```typescript
86
- * const failure = Awaitly.err({ type: "NOT_FOUND", message: "User not found" });
88
+ * const failure = err({ type: "NOT_FOUND", message: "User not found" });
87
89
  * // Type shown: Err<{ type: string; message: string }>
88
90
  * ```
89
91
  */
@@ -107,185 +109,7 @@ type Result<T, E = unknown, C = unknown> = Ok<T> | Err<E, C>;
107
109
  * Use this for asynchronous operations that might fail.
108
110
  */
109
111
  type AsyncResult<T, E = unknown, C = unknown> = Promise<Result<T, E, C>>;
110
- /** Discriminant for PromiseRejectedError type - use in switch statements */
111
- declare const PROMISE_REJECTED: "PROMISE_REJECTED";
112
- /**
113
- * Named error constant for unexpected/unhandled errors.
114
- * Used by the analyzer when a step doesn't declare errors.
115
- */
116
- declare const AWAITLY_UNEXPECTED: "AWAITLY_UNEXPECTED";
117
- /**
118
- * Named error constant for cancelled operations.
119
- */
120
- declare const AWAITLY_CANCELLED: "AWAITLY_CANCELLED";
121
- /**
122
- * Named error constant for timed-out operations.
123
- */
124
- declare const AWAITLY_TIMEOUT: "AWAITLY_TIMEOUT";
125
- /**
126
- * Helper to create a tuple of string literal tags with preserved literal types.
127
- * Use this when you need to store error tags in a variable while keeping
128
- * TypeScript's literal type inference (avoiding widening to string[]).
129
- *
130
- * @param t - The string literal tags
131
- * @returns The same array with preserved literal types
132
- *
133
- * @example
134
- * ```typescript
135
- * // Without tags() - type widens to string[]
136
- * const errs = ['CART_NOT_FOUND', 'CART_EMPTY']; // string[]
137
- *
138
- * // With tags() - literal types preserved
139
- * const errs = tags('CART_NOT_FOUND', 'CART_EMPTY'); // ['CART_NOT_FOUND', 'CART_EMPTY']
140
- *
141
- * await step('getCart', () => getCart(id), {
142
- * errors: errs, // Analyzer can extract literal types
143
- * out: 'cart',
144
- * });
145
- * ```
146
- */
147
- declare const tags: <const T extends readonly string[]>(...t: T) => T;
148
-
149
- type PromiseRejectedError = {
150
- type: typeof PROMISE_REJECTED;
151
- cause: unknown;
152
- };
153
- /** Cause type for promise rejections in async batch helpers */
154
- type PromiseRejectionCause = {
155
- type: "PROMISE_REJECTION";
156
- reason: unknown;
157
- };
158
- type EmptyInputError = {
159
- type: "EMPTY_INPUT";
160
- message: string;
161
- };
162
112
  type MaybeAsyncResult<T, E, C = unknown> = Result<T, E, C> | Promise<Result<T, E, C>>;
163
- /**
164
- * Creates a successful Result.
165
- * Use this when an operation completes successfully.
166
- *
167
- * @remarks When to use: Wrap a successful value in a Result for consistent return types.
168
- *
169
- * @param value - The success value to wrap
170
- * @returns An Ok object with `{ ok: true, value }`
171
- *
172
- * @example
173
- * ```typescript
174
- * const success = Awaitly.ok(42);
175
- * // Type: Ok<number>
176
- *
177
- * function divide(a: number, b: number): Result<number, string> {
178
- * if (b === 0) return Awaitly.err("Division by zero");
179
- * return Awaitly.ok(a / b);
180
- * }
181
- * ```
182
- */
183
- declare function ok<T>(value: T): Ok<T>;
184
- /**
185
- * Creates a failed Result.
186
- * Use this when an operation fails.
187
- *
188
- * @remarks When to use: Return a typed failure without throwing so callers can handle it explicitly.
189
- *
190
- * @param error - The error value describing what went wrong (e.g., error code, object)
191
- * @returns An Err object with `{ ok: false, error }`
192
- *
193
- * @example
194
- * ```typescript
195
- * // Simple error
196
- * const r1 = Awaitly.err("NOT_FOUND");
197
- * // Type: Err<"NOT_FOUND">
198
- *
199
- * // Error with context (include in error object)
200
- * const r2 = Awaitly.err({ type: "PROCESSING_FAILED", cause: originalError });
201
- * // Type: Err<{ type: string; cause: Error }>
202
- * ```
203
- */
204
- declare function err<E, C = unknown>(error: E, options?: {
205
- cause?: C;
206
- }): Err<E, C>;
207
- /**
208
- * Checks if a Result is successful.
209
- * Use this to narrow the type of a Result to the success case.
210
- *
211
- * @remarks When to use: Prefer functional-style checks or array filtering over `result.ok`.
212
- *
213
- * @param r - The Result to check
214
- * @returns `true` if successful, allowing access to `r.value`
215
- *
216
- * @example
217
- * ```typescript
218
- * const r = someOperation();
219
- * if (isOk(r)) {
220
- * // Use r.value (Type is T)
221
- * processValue(r.value);
222
- * } else {
223
- * // Handle r.error (Type is E)
224
- * handleError(r.error);
225
- * }
226
- * ```
227
- */
228
- declare const isOk: <T, E, C>(r: Result<T, E, C>) => r is Ok<T>;
229
- /**
230
- * Checks if a Result is a failure.
231
- * Use this to narrow the type of a Result to the error case.
232
- *
233
- * @remarks When to use: Prefer functional-style checks or array filtering over `result.ok`.
234
- *
235
- * @param r - The Result to check
236
- * @returns `true` if failed, allowing access to `r.error` and `r.cause`
237
- *
238
- * @example
239
- * ```typescript
240
- * if (isErr(r)) {
241
- * // Handle error case early
242
- * return;
243
- * }
244
- * // Proceed with success case
245
- * ```
246
- */
247
- declare const isErr: <T, E, C>(r: Result<T, E, C>) => r is Err<E, C>;
248
- /**
249
- * Checks if an error is an UnexpectedError.
250
- * Used internally by the framework but exported for advanced custom handling.
251
- * Indicates an error that wasn't typed/expected in the `run` signature.
252
- *
253
- * @remarks When to use: Distinguish unexpected failures from your typed error union.
254
- */
255
- declare const isUnexpectedError: (e: unknown) => e is UnexpectedError;
256
- /**
257
- * Type for exhaustive error handlers mapping string literal errors and UnexpectedError.
258
- * Each key in E gets a handler, plus UnexpectedError is required.
259
- */
260
- type MatchErrorHandlers<E extends string, R> = {
261
- [K in Exclude<E, "UnexpectedError">]: (error: K) => R;
262
- } & {
263
- UnexpectedError: (error: UnexpectedError) => R;
264
- };
265
- /**
266
- * Exhaustive pattern matching for error types.
267
- * Handles both string literal errors and UnexpectedError, ensuring all cases are covered.
268
- *
269
- * @param error - The error to match (string literal or UnexpectedError)
270
- * @param handlers - Object with a handler for each error case plus UnexpectedError
271
- * @returns The result of the matched handler
272
- *
273
- * @example
274
- * ```typescript
275
- * type FetchError = "NOT_FOUND" | "FETCH_ERROR";
276
- * const result: Result<User, FetchError | UnexpectedError> = await fetchUser();
277
- *
278
- * if (!result.ok) {
279
- * return matchError(result.error, {
280
- * NOT_FOUND: () => 404,
281
- * FETCH_ERROR: () => 500,
282
- * UnexpectedError: (e) => { throw e.cause; }
283
- * });
284
- * }
285
- * ```
286
- */
287
- declare function matchError<E extends string, R>(handlers: MatchErrorHandlers<E, R>): (error: E | UnexpectedError) => R;
288
- declare function matchError<E extends string, R>(error: E | UnexpectedError, handlers: MatchErrorHandlers<E, R>): R;
289
113
  type AnyFunction = (...args: never[]) => unknown;
290
114
  /**
291
115
  * Helper to extract the error type from Result or AsyncResult return values.
@@ -305,12 +129,6 @@ type ErrorOfReturn<R> = [Extract<Awaited<R>, {
305
129
  * Extract error type from a single function's return type
306
130
  */
307
131
  type ErrorOf<T extends AnyFunction> = ErrorOfReturn<ReturnType<T>>;
308
- /**
309
- * Extract union of error types from multiple functions (tuple form)
310
- */
311
- type Errors<T extends AnyFunction[]> = {
312
- [K in keyof T]: ErrorOf<T[K]>;
313
- }[number];
314
132
  /**
315
133
  * Extract union of error types from a deps object.
316
134
  *
@@ -324,27 +142,6 @@ type Errors<T extends AnyFunction[]> = {
324
142
  type ErrorsOf<Deps extends Record<string, AnyFunction>> = {
325
143
  [K in keyof Deps]: ErrorOf<Deps[K]>;
326
144
  }[keyof Deps];
327
- /**
328
- * Extract value type from Result
329
- */
330
- type ExtractValue<T> = T extends {
331
- ok: true;
332
- value: infer U;
333
- } ? U : never;
334
- /**
335
- * Extract error type from Result
336
- */
337
- type ExtractError<T> = T extends {
338
- ok: false;
339
- error: infer E;
340
- } ? E : never;
341
- /**
342
- * Extract cause type from Result
343
- */
344
- type ExtractCause<T> = T extends {
345
- ok: false;
346
- cause?: infer C;
347
- } ? C : never;
348
145
  /**
349
146
  * Helper to extract the cause type from Result or AsyncResult return values.
350
147
  * Works even when a function is declared to return a union of both forms.
@@ -617,14 +414,6 @@ interface StepErrorDiagnostics {
617
414
  cumulativeDurationMs?: number;
618
415
  origin: 'result' | 'throw' | 'timeout';
619
416
  }
620
- /** Extract canonical error tag. Priority: _tag > tag > code > Error.name > "unknown".
621
- * Tags are case-sensitive, whitespace-trimmed, otherwise raw.
622
- * Note: Error.name is fallback-grade (often too coarse like "Error", "TypeError"). */
623
- declare function extractErrorTag(error: unknown): string;
624
- /** Look up ErrorClassification from errorMeta for a given tag. */
625
- declare function lookupErrorClassification(tag: string, errorMeta?: Record<string, ErrorClassification>): ErrorClassification | undefined;
626
- /** Extract StepMetadata from StepOptions (returns undefined when empty). */
627
- declare function extractStepMetadata(options: StepOptions): StepMetadata | undefined;
628
417
  /**
629
418
  * Backoff strategy for retry operations.
630
419
  */
@@ -1702,6 +1491,18 @@ type WorkflowEvent<E, C = unknown> = {
1702
1491
  ts: number;
1703
1492
  metadata?: StepMetadata;
1704
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;
1705
1506
  } | {
1706
1507
  type: "scope_start";
1707
1508
  workflowId: string;
@@ -1874,6 +1675,23 @@ type WorkflowEvent<E, C = unknown> = {
1874
1675
  lastStepKey?: string;
1875
1676
  context?: C;
1876
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
+ };
1877
1695
  type RunOptionsWithCatch<E, C = void> = {
1878
1696
  /**
1879
1697
  * Handler for expected errors.
@@ -1909,6 +1727,11 @@ type RunOptionsWithCatch<E, C = void> = {
1909
1727
  * Useful for passing request IDs, user IDs, or loggers.
1910
1728
  */
1911
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;
1912
1735
  /**
1913
1736
  * @internal External signal for workflow-level cancellation.
1914
1737
  * Used by createWorkflow() to pass the workflow signal to steps.
@@ -1936,6 +1759,11 @@ type RunOptionsWithoutCatch<E, C = void> = {
1936
1759
  */
1937
1760
  workflowName?: string;
1938
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;
1939
1767
  /**
1940
1768
  * @internal External signal for workflow-level cancellation.
1941
1769
  * Used by createWorkflow() to pass the workflow signal to steps.
@@ -2010,7 +1838,7 @@ declare function isEarlyExit<E>(e: unknown): e is EarlyExit<E>;
2010
1838
  /**
2011
1839
  * run() with catchUnexpected: closed union Result<T, E>.
2012
1840
  */
2013
- declare function run<T, E, C = void>(fn: (context: {
1841
+ declare function runFn<T, E, C = void>(fn: (context: {
2014
1842
  step: RunStep<E>;
2015
1843
  }) => Promise<T> | T, options: RunOptionsWithCatch<E, C>): AsyncResult<T, E, unknown>;
2016
1844
  /**
@@ -2019,7 +1847,7 @@ declare function run<T, E, C = void>(fn: (context: {
2019
1847
  * uncaught exceptions are possible. Step errors pass through as-is.
2020
1848
  * When E is never (default), step is RunStep<unknown> so any operation is allowed.
2021
1849
  */
2022
- declare function run<T, E = never, C = void>(fn: (context: {
1850
+ declare function runFn<T, E = never, C = void>(fn: (context: {
2023
1851
  step: [E] extends [never] ? RunStep<unknown> : RunStep<E>;
2024
1852
  }) => Promise<T> | T, options?: {
2025
1853
  onError?: (error: E | UnexpectedError, stepName?: string, ctx?: C) => void;
@@ -2027,6 +1855,7 @@ declare function run<T, E = never, C = void>(fn: (context: {
2027
1855
  workflowId?: string;
2028
1856
  workflowName?: string;
2029
1857
  context?: C;
1858
+ graph?: DeclaredGraph;
2030
1859
  /** @internal External signal for workflow-level cancellation. */
2031
1860
  _workflowSignal?: AbortSignal;
2032
1861
  }): AsyncResult<T, E | UnexpectedError, unknown>;
@@ -2053,7 +1882,7 @@ declare function run<T, E = never, C = void>(fn: (context: {
2053
1882
  * // result.error: OrderNotFound | UserNotFound | ChargeDeclined | UnexpectedError
2054
1883
  * ```
2055
1884
  */
2056
- declare function run<const Deps extends Record<string, AnyFunction>, T, C = void>(deps: Deps, fn: (steps: BoundSteps<Deps>, context: {
1885
+ declare function runFn<const Deps extends Record<string, AnyFunction>, T, C = void>(deps: Deps, fn: (steps: BoundSteps<Deps>, context: {
2057
1886
  step: [ErrorsOf<Deps>] extends [never] ? RunStep<unknown> : RunStep<ErrorsOf<Deps>>;
2058
1887
  }) => Promise<T> | T, options?: {
2059
1888
  onError?: (error: ErrorsOf<Deps> | UnexpectedError, stepName?: string, ctx?: C) => void;
@@ -2061,11 +1890,20 @@ declare function run<const Deps extends Record<string, AnyFunction>, T, C = void
2061
1890
  workflowId?: string;
2062
1891
  workflowName?: string;
2063
1892
  context?: C;
1893
+ graph?: DeclaredGraph;
2064
1894
  /** @internal External signal for workflow-level cancellation. */
2065
1895
  _workflowSignal?: AbortSignal;
2066
1896
  }): AsyncResult<T, ErrorsOf<Deps> | UnexpectedError, unknown>;
2067
- declare namespace run {
2068
- var strict: <T, E, C = void>(fn: (context: {
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: {
2069
1907
  step: RunStep<E>;
2070
1908
  }) => Promise<T> | T, options: {
2071
1909
  onError?: (error: E, stepName?: string, ctx?: C) => void;
@@ -2082,1427 +1920,1165 @@ declare namespace run {
2082
1920
  /** @internal External signal for workflow-level cancellation. */
2083
1921
  _workflowSignal?: AbortSignal;
2084
1922
  }) => AsyncResult<T, E, unknown>;
2085
- }
1923
+ };
1924
+
2086
1925
  /**
2087
- * Error thrown when `unwrap()` is called on an error Result.
1926
+ * awaitly/streaming - Types
2088
1927
  *
2089
- * This error is thrown to prevent silent failures when using `unwrap()`.
2090
- * 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.
2091
1931
  */
2092
- declare class UnwrapError<E = unknown, C = unknown> extends Error {
2093
- readonly error: E;
2094
- readonly cause?: C | undefined;
2095
- constructor(error: E, cause?: C | undefined);
2096
- }
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
+ };
2097
1954
  /**
2098
- * Unwraps a Result, throwing an error if it's a failure.
2099
- *
2100
- * @remarks When to use: Only at boundaries or tests where a failure should be fatal.
2101
- *
2102
- * ## When to Use
2103
- *
2104
- * Use `unwrap()` when:
2105
- * - You're certain the Result is successful (e.g., after checking with `isOk`)
2106
- * - You're in a context where errors should crash (e.g., tests, initialization)
2107
- * - You need the value immediately and can't handle errors gracefully
2108
- *
2109
- * ## Why Avoid This
2110
- *
2111
- * **Prefer alternatives** in production code:
2112
- * - `unwrapOr(defaultValue)` - Provide a fallback value
2113
- * - `unwrapOrElse(fn)` - Compute fallback from error
2114
- * - `match()` - Handle both cases explicitly
2115
- * - `isOk()` / `isErr()` - Type-safe pattern matching
2116
- *
2117
- * Throwing errors makes error handling harder and can crash your application.
2118
- *
2119
- * @param r - The Result to unwrap
2120
- * @returns The success value if the Result is successful
2121
- * @throws {UnwrapError} If the Result is an error (includes the error and cause)
2122
- *
2123
- * @example
2124
- * ```typescript
2125
- * // Safe usage after checking
2126
- * const result = someOperation();
2127
- * if (isOk(result)) {
2128
- * const value = unwrap(result); // Safe - we know it's ok
2129
- * }
2130
- *
2131
- * // Unsafe usage (not recommended)
2132
- * const value = unwrap(someOperation()); // May throw!
2133
- * ```
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.
2134
1965
  */
2135
- declare const unwrap: <T, E, C>(r: Result<T, E, C>) => T;
1966
+ type StreamCloseError = {
1967
+ type: typeof STREAM_CLOSE_ERROR;
1968
+ reason: "already_closed" | "store_error";
1969
+ message: string;
1970
+ cause?: unknown;
1971
+ };
2136
1972
  /**
2137
- * Unwraps a Result, returning a default value if it's a failure.
2138
- *
2139
- * @remarks When to use: Provide a safe fallback without branching.
2140
- *
2141
- * ## When to Use
2142
- *
2143
- * Use `unwrapOr()` when:
2144
- * - You have a sensible default value for errors
2145
- * - You want to continue execution even on failure
2146
- * - The default value is cheap to compute (use `unwrapOrElse` if expensive)
2147
- *
2148
- * ## Why Use This
2149
- *
2150
- * - **Safe**: Never throws, always returns a value
2151
- * - **Simple**: One-liner for common error handling
2152
- * - **Type-safe**: TypeScript knows you'll always get a `T`
2153
- *
2154
- * @param r - The Result to unwrap
2155
- * @param defaultValue - The value to return if the Result is an error
2156
- * @returns The success value if successful, otherwise the default value
2157
- *
2158
- * @example
2159
- * ```typescript
2160
- * // Provide default for missing data
2161
- * const user = unwrapOr(fetchUser(id), { id: 'anonymous', name: 'Guest' });
2162
- *
2163
- * // Provide default for numeric operations
2164
- * const count = unwrapOr(parseCount(input), 0);
2165
- *
2166
- * // Provide default for optional features
2167
- * const config = unwrapOr(loadConfig(), getDefaultConfig());
2168
- * ```
1973
+ * Error returned from StreamStore operations.
2169
1974
  */
2170
- declare const unwrapOr: <T, E, C>(r: Result<T, E, C>, defaultValue: T) => T;
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
+ };
2171
1981
  /**
2172
- * Unwraps a Result, computing a default value from the error if it's a failure.
2173
- *
2174
- * @remarks When to use: Compute a fallback from the error (logging, metrics, or derived defaults).
2175
- *
2176
- * ## When to Use
2177
- *
2178
- * Use `unwrapOrElse()` when:
2179
- * - The default value is expensive to compute (lazy evaluation)
2180
- * - You need to log or handle the error before providing a default
2181
- * - The default depends on the error type or cause
2182
- * - You want to transform the error into a success value
2183
- *
2184
- * ## Why Use This Instead of `unwrapOr`
2185
- *
2186
- * - **Lazy**: Default is only computed if needed (better performance)
2187
- * - **Error-aware**: You can inspect the error before providing default
2188
- * - **Flexible**: Default can depend on error type or cause
2189
- *
2190
- * @param r - The Result to unwrap
2191
- * @param fn - Function that receives the error and optional cause, returns the default value
2192
- * @returns The success value if successful, otherwise the result of calling `fn(error, cause)`
2193
- *
2194
- * @example
2195
- * ```typescript
2196
- * // Compute default based on error type
2197
- * const port = unwrapOrElse(parsePort(env.PORT), (error) => {
2198
- * if (error === 'INVALID_FORMAT') return 3000;
2199
- * if (error === 'OUT_OF_RANGE') return 8080;
2200
- * return 4000; // default
2201
- * });
2202
- *
2203
- * // Log error before providing default
2204
- * const data = unwrapOrElse(fetchData(), (error, cause) => {
2205
- * console.error('Failed to fetch:', error, cause);
2206
- * return getCachedData();
2207
- * });
2208
- *
2209
- * // Transform error into success value
2210
- * const result = unwrapOrElse(operation(), (error) => {
2211
- * return { success: false, reason: String(error) };
2212
- * });
2213
- * ```
1982
+ * Marker indicating stream has ended (not an error, but a terminal state).
1983
+ * Used as the "error" type when stream is exhausted.
2214
1984
  */
2215
- declare const unwrapOrElse: <T, E, C>(r: Result<T, E, C>, fn: (error: E, cause?: C) => T) => T;
1985
+ type StreamEndedMarker = {
1986
+ type: typeof STREAM_ENDED;
1987
+ finalPosition: number;
1988
+ };
2216
1989
  /**
2217
- * Alias for `unwrap`. Returns the success value or throws.
2218
- *
2219
- * The Result is already computed; use when you want the value or throw (e.g. at boundaries or in tests).
2220
- *
2221
- * @param r - The Result to unwrap
2222
- * @returns The success value if the Result is successful
2223
- * @throws {UnwrapError} If the Result is an error (includes the error and cause)
1990
+ * Backpressure error when writer is paused.
2224
1991
  */
2225
- declare const runOrThrow: <T, E, C>(r: Result<T, E, C>) => T;
1992
+ type StreamBackpressureError = {
1993
+ type: typeof STREAM_BACKPRESSURE_ERROR;
1994
+ bufferedCount: number;
1995
+ highWaterMark: number;
1996
+ };
2226
1997
  /**
2227
- * Awaits a Promise of a Result, then returns the success value or rejects.
2228
- *
2229
- * The returned promise **resolves with T** on success and **rejects with UnwrapError** on failure.
2230
- * UnwrapError extends Error and carries the original `error` and `cause` from the Err.
2231
- *
2232
- * @param ar - A Promise or thenable that resolves to a Result
2233
- * @returns A Promise that resolves with the success value or rejects with UnwrapError
1998
+ * Union of all stream errors.
2234
1999
  */
2235
- declare const runOrThrowAsync: <T, E, C>(ar: PromiseLike<Result<T, E, C>>) => Promise<T>;
2000
+ type StreamError = StreamWriteError | StreamReadError | StreamCloseError | StreamStoreError | StreamBackpressureError;
2236
2001
  /**
2237
- * Convenience alias for `unwrapOr(r, null)`. Returns the success value or null.
2238
- *
2239
- * @param r - The Result to unwrap
2240
- * @returns The success value if successful, otherwise null
2002
+ * A single item in the stream with metadata.
2003
+ */
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;
2011
+ }
2012
+ /**
2013
+ * Metadata about a stream.
2241
2014
  */
2242
- declare const runOrNull: <T, E, C>(r: Result<T, E, C>) => T | null;
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
+ }
2243
2033
  /**
2244
- * Convenience alias for `unwrapOr(r, undefined)`. Returns the success value or undefined.
2245
- *
2246
- * @param r - The Result to unwrap
2247
- * @returns The success value if successful, otherwise undefined
2034
+ * Options for creating a writable stream.
2248
2035
  */
2249
- declare const runOrUndefined: <T, E, C>(r: Result<T, E, C>) => T | undefined;
2036
+ interface StreamOptions {
2037
+ /** Named streams (default: 'default') */
2038
+ namespace?: string;
2039
+ /** Backpressure threshold (default: 16) */
2040
+ highWaterMark?: number;
2041
+ }
2250
2042
  /**
2251
- * Wraps a synchronous throwing function in a Result.
2252
- *
2253
- * @remarks When to use: Wrap sync code that might throw so exceptions become Err values.
2254
- *
2255
- * ## When to Use
2256
- *
2257
- * Use `from()` when:
2258
- * - You have a synchronous function that throws exceptions
2259
- * - You want to convert exceptions to typed errors
2260
- * - You're integrating with libraries that throw (e.g., JSON.parse, fs.readFileSync)
2261
- * - You need to handle errors without try/catch blocks
2262
- *
2263
- * ## 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.
2264
2075
  *
2265
- * - **Type-safe errors**: Convert thrown exceptions to typed Result errors
2266
- * - **No try/catch**: Cleaner code without nested try/catch blocks
2267
- * - **Composable**: Results can be chained with `andThen`, `map`, etc.
2268
- * - **Explicit errors**: Forces you to handle errors explicitly
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).
2269
2078
  *
2270
- * @param fn - The synchronous function to execute (may throw)
2271
- * @returns A Result with the function's return value or the thrown error
2079
+ * @template T - Type of values written to the stream
2272
2080
  *
2273
2081
  * @example
2274
2082
  * ```typescript
2275
- * // Wrap JSON.parse
2276
- * const parsed = from(() => JSON.parse('{"key": "value"}'));
2277
- * // parsed: { ok: true, value: { key: "value" } }
2083
+ * const writer = step.getWritable<string>({ namespace: 'ai-response' });
2278
2084
  *
2279
- * const error = from(() => JSON.parse('invalid'));
2280
- * // error: { ok: false, error: SyntaxError }
2085
+ * await step(() => generateAI({
2086
+ * prompt: 'Hello',
2087
+ * onToken: async (token) => { await writer.write(token); }
2088
+ * }), { key: 'generate' });
2089
+ *
2090
+ * await writer.close();
2281
2091
  * ```
2282
2092
  */
2283
- declare function from<T>(fn: () => T): Ok<T> | Err<unknown, unknown>;
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
+ }
2284
2116
  /**
2285
- * Wraps a synchronous throwing function in a Result with custom error mapping.
2117
+ * Readable stream interface - returns STREAM_ENDED marker when complete.
2286
2118
  *
2287
- * Use this overload when you want to map thrown exceptions to your typed error union.
2119
+ * Use to consume values from a stream, with support for resuming from
2120
+ * a specific position.
2288
2121
  *
2289
- * @param fn - The synchronous function to execute (may throw)
2290
- * @param onError - Function to map the thrown exception to a typed error
2291
- * @returns A Result with the function's return value or the mapped error
2122
+ * @template T - Type of values read from the stream
2292
2123
  *
2293
2124
  * @example
2294
2125
  * ```typescript
2295
- * // Map exceptions to typed errors
2296
- * const parsed = from(
2297
- * () => JSON.parse(input),
2298
- * (cause) => ({ type: 'PARSE_ERROR' as const, cause })
2299
- * );
2300
- * // parsed.error: { type: 'PARSE_ERROR', cause: SyntaxError }
2301
- *
2302
- * // Map to simple error codes
2303
- * const value = from(
2304
- * () => riskyOperation(),
2305
- * () => 'OPERATION_FAILED' as const
2306
- * );
2307
- * ```
2308
- */
2309
- declare function from<T, E>(fn: () => T, onError: (cause: unknown) => E): Ok<T> | Err<E, unknown>;
2310
- /**
2311
- * Wraps a Promise in a Result, converting rejections to errors.
2312
- *
2313
- * @remarks When to use: Wrap a Promise and keep the raw rejection as Err; use tryAsync to map errors.
2126
+ * const reader = getStreamReader<string>(runId, { namespace: 'ai-response' });
2314
2127
  *
2315
- * ## When to Use
2316
- *
2317
- * Use `fromPromise()` when:
2318
- * - You have an existing Promise that might reject
2319
- * - You want to convert Promise rejections to typed errors
2320
- * - You're working with libraries that return Promises (fetch, database clients)
2321
- * - You need to handle rejections without .catch() chains
2322
- *
2323
- * ## Why Use This
2324
- *
2325
- * - **Type-safe errors**: Convert Promise rejections to typed Result errors
2326
- * - **Composable**: Results can be chained with `andThen`, `map`, etc.
2327
- * - **Explicit handling**: Forces you to handle errors explicitly
2328
- * - **No .catch() chains**: Cleaner than Promise.catch() patterns
2329
- *
2330
- * @param promise - The Promise to await (may reject)
2331
- * @returns A Promise resolving to a Result with the resolved value or rejection reason
2128
+ * let result = await reader.read();
2129
+ * while (result.ok) {
2130
+ * response.write(result.value);
2131
+ * result = await reader.read();
2132
+ * }
2332
2133
  *
2333
- * @example
2334
- * ```typescript
2335
- * // Wrap fetch
2336
- * const result = await fromPromise(
2337
- * fetch('/api').then(r => r.json())
2338
- * );
2339
- * // result.ok: true if fetch succeeded, false if rejected
2134
+ * if (result.error.type === 'STREAM_ENDED') {
2135
+ * console.log('Stream complete at position', result.error.finalPosition);
2136
+ * }
2340
2137
  * ```
2341
2138
  */
2342
- declare function fromPromise<T>(promise: Promise<T>): Promise<Ok<T> | Err<unknown, unknown>>;
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;
2343
2159
  /**
2344
- * Wraps a Promise in a Result with custom error mapping.
2345
- *
2346
- * Use this overload when you want to map Promise rejections to your typed error union.
2160
+ * Storage backend for stream data.
2161
+ * Follows the same patterns as persistence.ts adapters.
2347
2162
  *
2348
- * @param promise - The Promise to await (may reject)
2349
- * @param onError - Function to map the rejection reason to a typed error
2350
- * @returns A Promise resolving to a Result with the resolved value or mapped error
2163
+ * @example In-memory store
2164
+ * ```typescript
2165
+ * const store = createMemoryStreamStore();
2166
+ * ```
2351
2167
  *
2352
- * @example
2168
+ * @example File-based store
2353
2169
  * ```typescript
2354
- * // Map fetch errors to typed errors
2355
- * const result = await fromPromise(
2356
- * fetch('/api').then(r => {
2357
- * if (!r.ok) throw new Error(`HTTP ${r.status}`);
2358
- * return r.json();
2359
- * }),
2360
- * () => 'FETCH_FAILED' as const
2361
- * );
2362
- * // result.error: 'FETCH_FAILED' if fetch failed
2363
- *
2364
- * // Map with error details
2365
- * const data = await fromPromise(
2366
- * db.query(sql),
2367
- * (cause) => ({ type: 'DB_ERROR' as const, message: String(cause) })
2368
- * );
2170
+ * const store = createFileStreamStore({ directory: './streams', fs });
2369
2171
  * ```
2370
2172
  */
2371
- declare function fromPromise<T, E>(promise: Promise<T>, onError: (cause: unknown) => E): Promise<Ok<T> | Err<E, unknown>>;
2372
- /**
2373
- * Wraps an async function in a Result, catching both thrown exceptions and Promise rejections.
2374
- *
2375
- * @remarks When to use: Wrap async work and map thrown/rejected values into your typed error union.
2376
- *
2377
- * ## When to Use
2378
- *
2379
- * Use `tryAsync()` when:
2380
- * - You have an async function that might throw or reject
2381
- * - You want to convert both exceptions and rejections to typed errors
2382
- * - You're creating new async functions (use `fromPromise` for existing Promises)
2383
- * - You need to handle errors without try/catch or .catch()
2384
- *
2385
- * ## Why Use This Instead of `fromPromise`
2386
- *
2387
- * - **Function form**: Takes a function, not a Promise (lazy evaluation)
2388
- * - **Catches both**: Handles both thrown exceptions and Promise rejections
2389
- * - **Cleaner syntax**: No need to wrap in Promise manually
2390
- *
2391
- * @param fn - The async function to execute (may throw or reject)
2392
- * @returns A Promise resolving to a Result with the function's return value or error
2393
- *
2394
- * @example
2395
- * ```typescript
2396
- * // Wrap async function
2397
- * const result = await tryAsync(async () => {
2398
- * const data = await fetchData();
2399
- * return processData(data);
2400
- * });
2401
- * ```
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
+ }
2200
+ /**
2201
+ * Check if an error is a StreamEndedMarker.
2402
2202
  */
2403
- declare function tryAsync<T>(fn: () => Promise<T>): AsyncResult<T, unknown>;
2203
+ declare function isStreamEnded(error: unknown): error is StreamEndedMarker;
2404
2204
  /**
2405
- * Wraps an async function in a Result with custom error mapping.
2406
- *
2407
- * Use this overload when you want to map errors to your typed error union.
2408
- *
2409
- * @param fn - The async function to execute (may throw or reject)
2410
- * @param onError - Function to map the error (exception or rejection) to a typed error
2411
- * @returns A Promise resolving to a Result with the function's return value or mapped error
2412
- *
2413
- * @example
2414
- * ```typescript
2415
- * // Map errors to typed errors
2416
- * const result = await tryAsync(
2417
- * async () => await fetchData(),
2418
- * () => 'FETCH_ERROR' as const
2419
- * );
2420
- *
2421
- * // Map with error details
2422
- * const data = await tryAsync(
2423
- * async () => await processFile(path),
2424
- * (cause) => ({ type: 'PROCESSING_ERROR' as const, cause })
2425
- * );
2426
- * ```
2205
+ * Check if an error is a StreamWriteError.
2427
2206
  */
2428
- declare function tryAsync<T, E>(fn: () => Promise<T>, onError: (cause: unknown) => E): AsyncResult<T, E>;
2207
+ declare function isStreamWriteError(error: unknown): error is StreamWriteError;
2429
2208
  /**
2430
- * Converts a nullable value to a Result.
2431
- *
2432
- * @remarks When to use: Turn null/undefined into a typed error before continuing.
2433
- *
2434
- * ## When to Use
2435
- *
2436
- * Use `fromNullable()` when:
2437
- * - You have a value that might be `null` or `undefined`
2438
- * - You want to treat null/undefined as an error case
2439
- * - You're working with APIs that return nullable values (DOM APIs, optional properties)
2440
- * - You want to avoid null checks scattered throughout your code
2441
- *
2442
- * ## Why Use This
2443
- *
2444
- * - **Type-safe**: Converts nullable types to non-nullable Results
2445
- * - **Explicit errors**: Forces you to handle null/undefined cases
2446
- * - **Composable**: Results can be chained with `andThen`, `map`, etc.
2447
- * - **No null checks**: Eliminates need for `if (value == null)` checks
2448
- *
2449
- * @param value - The value that may be null or undefined
2450
- * @param onNull - Function that returns an error when value is null/undefined
2451
- * @returns A Result with the value if not null/undefined, otherwise the error from `onNull`
2452
- *
2453
- * @example
2454
- * ```typescript
2455
- * // Convert DOM element lookup
2456
- * const element = fromNullable(
2457
- * document.getElementById('app'),
2458
- * () => 'ELEMENT_NOT_FOUND' as const
2459
- * );
2460
- *
2461
- * // Convert optional property
2462
- * const userId = fromNullable(
2463
- * user.id,
2464
- * () => 'USER_ID_MISSING' as const
2465
- * );
2466
- *
2467
- * // Convert database query result
2468
- * const record = fromNullable(
2469
- * await db.find(id),
2470
- * () => ({ type: 'NOT_FOUND' as const, id })
2471
- * );
2472
- * ```
2209
+ * Check if an error is a StreamReadError.
2473
2210
  */
2474
- declare function fromNullable<T, E>(value: T | null | undefined, onNull: () => E): Result<T, E>;
2211
+ declare function isStreamReadError(error: unknown): error is StreamReadError;
2475
2212
  /**
2476
- * Transforms the success value of a Result.
2477
- *
2478
- * @remarks When to use: Transform only the Ok value while leaving Err untouched.
2479
- *
2480
- * ## When to Use
2481
- *
2482
- * Use `map()` when:
2483
- * - You need to transform a success value to another type
2484
- * - You want to apply a pure function to the value
2485
- * - You're building a pipeline of transformations
2486
- * - The transformation cannot fail (use `andThen` if it can fail)
2487
- *
2488
- * ## Why Use This
2489
- *
2490
- * - **Functional style**: Composable, chainable transformations
2491
- * - **Error-preserving**: Errors pass through unchanged
2492
- * - **Type-safe**: TypeScript tracks the transformation
2493
- * - **No unwrapping**: Avoids manual `if (r.ok)` checks
2494
- *
2495
- * @param r - The Result to transform
2496
- * @param fn - Pure function that transforms the success value (must not throw)
2497
- * @returns A new Result with the transformed value, or the original error if `r` was an error
2498
- *
2499
- * @example
2500
- * ```typescript
2501
- * // Transform numeric value
2502
- * const doubled = map(ok(21), n => n * 2);
2503
- * // doubled: { ok: true, value: 42 }
2504
- *
2505
- * // Transform object property
2506
- * const name = map(fetchUser(id), user => user.name);
2507
- *
2508
- * // Chain transformations
2509
- * const formatted = map(
2510
- * map(parseNumber(input), n => n * 2),
2511
- * n => `Result: ${n}`
2512
- * );
2513
- * ```
2213
+ * Check if an error is a StreamStoreError.
2514
2214
  */
2515
- declare function map<T, U>(r: Ok<T>, fn: (value: T) => U): Ok<U>;
2516
- declare function map<T, U, E, C>(r: Err<E, C>, fn: (value: T) => U): Err<E, C>;
2517
- declare function map<T, U, E, C>(r: Result<T, E, C>, fn: (value: T) => U): Result<U, E, C>;
2215
+ declare function isStreamStoreError(error: unknown): error is StreamStoreError;
2518
2216
  /**
2519
- * Transforms the error value of a Result.
2520
- *
2521
- * @remarks When to use: Retype or normalize errors while leaving Ok values unchanged.
2522
- *
2523
- * ## When to Use
2524
- *
2525
- * Use `mapError()` when:
2526
- * - You need to normalize or transform error types
2527
- * - You want to convert errors to a different error type
2528
- * - You're building error handling pipelines
2529
- * - You need to format error messages or codes
2530
- *
2531
- * ## Why Use This
2532
- *
2533
- * - **Error normalization**: Convert errors to a common format
2534
- * - **Type transformation**: Change error type while preserving value type
2535
- * - **Composable**: Can be chained with other transformers
2536
- * - **Success-preserving**: Success values pass through unchanged
2537
- *
2538
- * @param r - The Result to transform
2539
- * @param fn - Function that transforms the error value (must not throw)
2540
- * @returns A new Result with the original value, or the transformed error if `r` was an error
2541
- *
2542
- * @example
2543
- * ```typescript
2544
- * // Normalize error codes
2545
- * const normalized = mapError(err('not_found'), e => e.toUpperCase());
2546
- * // normalized: { ok: false, error: 'NOT_FOUND' }
2547
- *
2548
- * // Convert error types
2549
- * const typed = mapError(
2550
- * err('404'),
2551
- * code => ({ type: 'HTTP_ERROR' as const, status: parseInt(code) })
2552
- * );
2553
- *
2554
- * // Format error messages
2555
- * const formatted = mapError(
2556
- * err('PARSE_ERROR'),
2557
- * code => `Failed to parse: ${code}`
2558
- * );
2559
- * ```
2217
+ * Check if an error is a StreamBackpressureError.
2560
2218
  */
2561
- declare function mapError<T, E, F, C>(r: Result<T, E, C>, fn: (error: E) => F): Result<T, F, C>;
2219
+ declare function isStreamBackpressureError(error: unknown): error is StreamBackpressureError;
2562
2220
  /**
2563
- * Pattern matches on a Result, calling the appropriate handler.
2564
- *
2565
- * @remarks When to use: Handle both Ok and Err in a single expression that returns a value.
2566
- *
2567
- * ## When to Use
2568
- *
2569
- * Use `match()` when:
2570
- * - You need to handle both success and error cases
2571
- * - You want to transform a Result to a different type
2572
- * - You need exhaustive handling (both cases must be handled)
2573
- * - You're building user-facing messages or responses
2574
- *
2575
- * ## Why Use This
2576
- *
2577
- * - **Exhaustive**: Forces you to handle both success and error cases
2578
- * - **Type-safe**: TypeScript ensures both handlers are provided
2579
- * - **Functional**: Pattern matching style, similar to Rust's `match` or Haskell's `case`
2580
- * - **Single expression**: Can be used in expressions, not just statements
2221
+ * Create a StreamWriteError.
2222
+ */
2223
+ declare function streamWriteError(reason: StreamWriteError["reason"], message: string, cause?: unknown): StreamWriteError;
2224
+ /**
2225
+ * Create a StreamReadError.
2226
+ */
2227
+ declare function streamReadError(reason: StreamReadError["reason"], message: string, cause?: unknown): StreamReadError;
2228
+ /**
2229
+ * Create a StreamCloseError.
2230
+ */
2231
+ declare function streamCloseError(reason: StreamCloseError["reason"], message: string, cause?: unknown): StreamCloseError;
2232
+ /**
2233
+ * Create a StreamStoreError.
2234
+ */
2235
+ declare function streamStoreError(reason: StreamStoreError["reason"], message: string, cause?: unknown): StreamStoreError;
2236
+ /**
2237
+ * Create a StreamEndedMarker.
2238
+ */
2239
+ declare function streamEnded(finalPosition: number): StreamEndedMarker;
2240
+ /**
2241
+ * Create a StreamBackpressureError.
2242
+ */
2243
+ declare function streamBackpressureError(bufferedCount: number, highWaterMark: number): StreamBackpressureError;
2244
+
2245
+ /**
2246
+ * awaitly/persistence
2581
2247
  *
2582
- * @param r - The Result to match
2583
- * @param handlers - Object with `ok` and `err` handler functions
2584
- * @param handlers.ok - Function called with the success value
2585
- * @param handlers.err - Function called with the error and optional cause
2586
- * @returns The return value of the appropriate handler (both must return the same type `R`)
2248
+ * Simplified Persistence API for workflow snapshots.
2249
+ * Provides JSON-serializable snapshot format and store adapters.
2250
+ */
2251
+
2252
+ /**
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.
2587
2294
  *
2588
2295
  * @example
2589
2296
  * ```typescript
2590
- * // Build user-facing messages
2591
- * const message = match(result, {
2592
- * ok: (user) => `Hello ${user.name}`,
2593
- * err: (error) => `Error: ${error}`,
2594
- * });
2595
- *
2596
- * // Transform to API response
2597
- * const response = match(operation(), {
2598
- * ok: (data) => ({ status: 200, body: data }),
2599
- * err: (error) => ({ status: 400, error: String(error) }),
2600
- * });
2297
+ * // Persist
2298
+ * localStorage.setItem('wf-123', JSON.stringify(wf.getSnapshot()));
2601
2299
  *
2602
- * // Handle with cause
2603
- * const response = match(result, {
2604
- * ok: (value) => ({ status: 'success', data: value }),
2605
- * err: (error, cause) => ({ status: 'error', error, cause }),
2606
- * });
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
2607
2304
  * ```
2608
2305
  */
2609
- declare function match<T, E, C, R>(handlers: {
2610
- ok: (value: T) => R;
2611
- err: (error: E, cause?: C) => R;
2612
- }): (r: Result<T, E, C>) => R;
2613
- declare function match<T, E, C, R>(r: Ok<T>, handlers: {
2614
- ok: (value: T) => R;
2615
- err: (error: E, cause?: C) => R;
2616
- }): R;
2617
- declare function match<T, E, C, R>(r: Err<E, C>, handlers: {
2618
- ok: (value: T) => R;
2619
- err: (error: E, cause?: C) => R;
2620
- }): R;
2621
- declare function match<T, E, C, R>(r: Result<T, E, C>, handlers: {
2622
- ok: (value: T) => R;
2623
- err: (error: E, cause?: C) => R;
2624
- }): R;
2625
- /**
2626
- * Chains Results together (flatMap/monadic bind).
2627
- *
2628
- * @remarks When to use: Chain dependent operations that return Result without nested branching.
2629
- *
2630
- * ## When to Use
2631
- *
2632
- * Use `andThen()` when:
2633
- * - You need to chain operations that can fail
2634
- * - The next operation depends on the previous success value
2635
- * - You're building a pipeline of dependent operations
2636
- * - You want to avoid nested `if (r.ok)` checks
2637
- *
2638
- * ## Why Use This Instead of `map`
2639
- *
2640
- * - **Can fail**: The chained function returns a Result (can fail)
2641
- * - **Short-circuits**: If first Result fails, second operation never runs
2642
- * - **Error accumulation**: Errors from both operations are in the union
2643
- * - **Composable**: Can chain multiple operations together
2644
- *
2645
- * ## Common Pattern
2646
- *
2647
- * This is the fundamental building block for Result pipelines:
2648
- * ```typescript
2649
- * andThen(operation1(), value1 =>
2650
- * andThen(operation2(value1), value2 =>
2651
- * ok({ value1, value2 })
2652
- * )
2653
- * )
2654
- * ```
2655
- *
2656
- * @param r - The first Result
2657
- * @param fn - Function that takes the success value and returns a new Result (may fail)
2658
- * @returns The Result from `fn` if `r` was successful, otherwise the original error
2659
- *
2660
- * @example
2661
- * ```typescript
2662
- * // Chain dependent operations
2663
- * const userPosts = andThen(
2664
- * fetchUser('1'),
2665
- * user => fetchPosts(user.id)
2666
- * );
2667
- *
2668
- * // Build complex pipelines
2669
- * const result = andThen(parseInput(input), parsed =>
2670
- * andThen(validate(parsed), validated =>
2671
- * process(validated)
2672
- * )
2673
- * );
2674
- *
2675
- * // Chain with different error types
2676
- * const data = andThen(
2677
- * fetchUser(id), // Returns Result<User, 'FETCH_ERROR'>
2678
- * user => fetchPosts(user.id) // Returns Result<Post[], 'NOT_FOUND'>
2679
- * );
2680
- * // data.error: 'FETCH_ERROR' | 'NOT_FOUND'
2681
- * ```
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.
2682
2347
  */
2683
- declare function andThen<T, U>(r: Ok<T>, fn: (value: T) => Ok<U>): Ok<U>;
2684
- declare function andThen<T, F, C2>(r: Ok<T>, fn: (value: T) => Err<F, C2>): Err<F, C2>;
2685
- declare function andThen<T, U, F, C2>(r: Ok<T>, fn: (value: T) => Result<U, F, C2>): Result<U, F, C2>;
2686
- declare function andThen<T, U, E, F, C1, C2>(r: Err<E, C1>, fn: (value: T) => Result<U, F, C2>): Err<E, C1>;
2687
- 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];
2688
2349
  /**
2689
- * Executes a side effect on a successful Result without changing it.
2690
- *
2691
- * @remarks When to use: Add side effects (logging, metrics) on Ok without changing the Result.
2692
- *
2693
- * ## When to Use
2694
- *
2695
- * Use `tap()` when:
2696
- * - You need to log, debug, or observe success values
2697
- * - You want to perform side effects in a pipeline
2698
- * - You need to mutate external state based on success
2699
- * - You're debugging and want to inspect values without breaking the chain
2700
- *
2701
- * ## Why Use This
2702
- *
2703
- * - **Non-breaking**: Doesn't change the Result, just performs side effect
2704
- * - **Composable**: Can be inserted anywhere in a pipeline
2705
- * - **Type-preserving**: Returns the same Result type
2706
- * - **Lazy**: Side effect only runs if Result is successful
2707
- *
2708
- * @param r - The Result to tap
2709
- * @param fn - Side effect function called with the success value (return value ignored)
2710
- * @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.
2711
2387
  *
2712
2388
  * @example
2713
2389
  * ```typescript
2714
- * // Log success values
2715
- * const logged = tap(result, user => console.log('Got user:', user.name));
2716
- * // logged === result, but console.log was called
2717
- *
2718
- * // Debug in pipeline
2719
- * const debugged = pipe(
2720
- * fetchUser(id),
2721
- * r => tap(r, user => console.log('Fetched:', user)),
2722
- * r => map(r, user => user.name)
2723
- * );
2724
- *
2725
- * // Mutate external state
2726
- * const tracked = tap(result, data => {
2727
- * analytics.track('operation_success', data);
2728
- * });
2390
+ * const raw = JSON.parse(localStorage.getItem('wf-123') || 'null');
2391
+ * if (looksLikeWorkflowSnapshot(raw)) {
2392
+ * createWorkflow(deps, { snapshot: raw });
2393
+ * }
2729
2394
  * ```
2730
2395
  */
2731
- 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;
2732
2397
  /**
2733
- * Executes a side effect on an error Result without changing it.
2734
- *
2735
- * @remarks When to use: Add side effects (logging, metrics) on Err without changing the Result.
2736
- *
2737
- * ## When to Use
2738
- *
2739
- * Use `tapError()` when:
2740
- * - You need to log, debug, or observe error values
2741
- * - You want to perform side effects on errors in a pipeline
2742
- * - You need to report errors to external systems (logging, monitoring)
2743
- * - You're debugging and want to inspect errors without breaking the chain
2744
- *
2745
- * ## 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.
2746
2415
  *
2747
- * - **Non-breaking**: Doesn't change the Result, just performs side effect
2748
- * - **Composable**: Can be inserted anywhere in a pipeline
2749
- * - **Type-preserving**: Returns the same Result type
2750
- * - **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.
2751
2440
  *
2752
- * @param r - The Result to tap
2753
- * @param fn - Side effect function called with the error and optional cause (return value ignored)
2754
- * @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)).
2755
2445
  *
2756
2446
  * @example
2757
2447
  * ```typescript
2758
- * // Log errors
2759
- * const logged = tapError(result, (error, cause) => {
2760
- * console.error('Error:', error, cause);
2761
- * });
2448
+ * import { postgres } from 'awaitly-postgres';
2449
+ * import { createWorkflow } from 'awaitly/workflow';
2762
2450
  *
2763
- * // Report to error tracking
2764
- * const tracked = tapError(result, (error, cause) => {
2765
- * errorTracker.report(error, cause);
2766
- * });
2451
+ * const store = postgres('postgresql://localhost/mydb');
2452
+ * const workflow = createWorkflow(deps);
2767
2453
  *
2768
- * // Debug in pipeline
2769
- * const debugged = pipe(
2770
- * operation(),
2771
- * r => tapError(r, (err, cause) => console.error('Failed:', err)),
2772
- * r => mapError(r, err => 'FORMATTED_ERROR')
2773
- * );
2454
+ * // Run and persist resume state
2455
+ * const { result, resumeState } = await workflow.runWithState(fn);
2456
+ * await store.save('wf-123', resumeState);
2457
+ *
2458
+ * // Restore
2459
+ * const loaded = await store.load('wf-123');
2460
+ * const resumeState = toResumeState(loaded);
2461
+ * if (resumeState) await workflow.run(fn, { resumeState });
2774
2462
  * ```
2775
2463
  */
2776
- 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
+ }
2777
2482
  /**
2778
- * Transforms the success value of a Result, catching any errors thrown by the transform.
2779
- *
2780
- * @remarks When to use: Transform Ok values with a function that might throw and capture the failure.
2781
- *
2782
- * ## When to Use
2783
- *
2784
- * Use `mapTry()` when:
2785
- * - Your transform function might throw exceptions
2786
- * - You want to convert transform errors to typed errors
2787
- * - You're working with libraries that throw (e.g., JSON.parse, Date parsing)
2788
- * - You need to handle both Result errors and transform exceptions
2789
- *
2790
- * ## Why Use This Instead of `map`
2791
- *
2792
- * - **Exception-safe**: Catches exceptions from the transform function
2793
- * - **Error mapping**: Converts thrown exceptions to typed errors
2794
- * - **Dual error handling**: Handles both Result errors and transform exceptions
2795
- *
2796
- * @param result - The Result to transform
2797
- * @param transform - Function to transform the success value (may throw exceptions)
2798
- * @param onError - Function to map thrown exceptions to a typed error
2799
- * @returns A Result with:
2800
- * - Transformed value if both Result and transform succeed
2801
- * - Original error if Result was an error
2802
- * - Transform error if transform threw an exception
2803
- *
2804
- * @example
2805
- * ```typescript
2806
- * // Safe JSON parsing
2807
- * const parsed = mapTry(
2808
- * ok('{"key": "value"}'),
2809
- * JSON.parse,
2810
- * () => 'PARSE_ERROR' as const
2811
- * );
2812
- *
2813
- * // Safe date parsing
2814
- * const date = mapTry(
2815
- * ok('2024-01-01'),
2816
- * str => new Date(str),
2817
- * () => 'INVALID_DATE' as const
2818
- * );
2819
- *
2820
- * // Transform with error details
2821
- * const processed = mapTry(
2822
- * result,
2823
- * value => riskyTransform(value),
2824
- * (cause) => ({ type: 'TRANSFORM_ERROR' as const, cause })
2825
- * );
2826
- * ```
2483
+ * Options for the in-memory cache adapter.
2827
2484
  */
2828
- 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
+ }
2829
2497
  /**
2830
- * Transforms the error value of a Result, catching any errors thrown by the transform.
2831
- *
2832
- * @remarks When to use: Transform errors when the mapping might throw and you want that captured.
2833
- *
2834
- * ## When to Use
2835
- *
2836
- * Use `mapErrorTry()` when:
2837
- * - Your error transform function might throw exceptions
2838
- * - You're doing complex error transformations (e.g., string formatting, object construction)
2839
- * - You want to handle both Result errors and transform exceptions
2840
- * - You need to safely normalize error types
2498
+ * Create an in-memory StepCache with optional LRU eviction and TTL.
2841
2499
  *
2842
- * ## Why Use This Instead of `mapError`
2843
- *
2844
- * - **Exception-safe**: Catches exceptions from the error transform function
2845
- * - **Error mapping**: Converts thrown exceptions to typed errors
2846
- * - **Dual error handling**: Handles both Result errors and transform exceptions
2847
- *
2848
- * @param result - The Result to transform
2849
- * @param transform - Function to transform the error value (may throw exceptions)
2850
- * @param onError - Function to map thrown exceptions to a typed error
2851
- * @returns A Result with:
2852
- * - Original value if Result was successful
2853
- * - Transformed error if both Result was error and transform succeeded
2854
- * - Transform error if transform threw an exception
2500
+ * @param options - Cache options
2501
+ * @returns StepCache implementation
2855
2502
  *
2856
2503
  * @example
2857
2504
  * ```typescript
2858
- * // Safe error formatting
2859
- * const formatted = mapErrorTry(
2860
- * err('not_found'),
2861
- * e => e.toUpperCase(), // Might throw if e is not a string
2862
- * () => 'FORMAT_ERROR' as const
2863
- * );
2864
- *
2865
- * // Complex error transformation
2866
- * const normalized = mapErrorTry(
2867
- * result,
2868
- * error => ({ type: 'NORMALIZED', message: String(error) }),
2869
- * () => 'TRANSFORM_ERROR' as const
2870
- * );
2505
+ * const cache = createMemoryCache({ maxSize: 1000, ttl: 60000 });
2506
+ * const workflow = createWorkflow(deps, { cache });
2871
2507
  * ```
2872
2508
  */
2873
- 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
+
2874
2516
  /**
2875
- * 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.
2876
2520
  *
2877
- * ## When to Use
2521
+ * ## When Cache is Populated
2878
2522
  *
2879
- * Use `bimap()` when:
2880
- * - You need to transform both success and error in one operation
2881
- * - You're normalizing Results to a common format
2882
- * - You want symmetric transformation of both cases
2883
- * - 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:
2884
2525
  *
2885
- * ## Why Use This Instead of `map` + `mapError`
2526
+ * ```typescript
2527
+ * // Function-wrapped pattern - cache is populated
2528
+ * await step(() => fetchUser("1"), { key: "user:1" });
2886
2529
  *
2887
- * - **Single operation**: Transforms both cases in one call
2888
- * - **Clearer intent**: Shows you're handling both cases symmetrically
2889
- * - **Less code**: Avoids chaining map and mapError
2530
+ * // Direct AsyncResult pattern - cache is also populated
2531
+ * await step(fetchUser("1"), { key: "user:1" });
2532
+ * ```
2890
2533
  *
2891
- * @param r - The Result to transform
2892
- * @param onOk - Function that transforms the success value
2893
- * @param onErr - Function that transforms the error value
2894
- * @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.
2895
2538
  *
2896
2539
  * @example
2897
- * ```typescript
2898
- * // Normalize to API response format
2899
- * const response = bimap(
2900
- * fetchUser(id),
2901
- * user => ({ status: 'success', data: user }),
2902
- * error => ({ status: 'error', code: error })
2903
- * );
2904
- *
2905
- * // Transform types
2906
- * const stringified = bimap(
2907
- * parseNumber(input),
2908
- * n => `Value: ${n}`,
2909
- * e => `Error: ${e}`
2910
- * );
2911
- *
2912
- * // Adapt between error types
2913
- * const adapted = bimap(
2914
- * externalResult,
2915
- * value => internalValue(value),
2916
- * error => internalError(error)
2917
- * );
2918
- * ```
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.
2919
2564
  */
2920
- 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
+ }
2921
2570
  /**
2922
- * Recovers from an error by returning a new Result.
2923
- * Similar to neverthrow's `.orElse()`.
2924
- *
2925
- * @remarks When to use: Recover from Err by returning a fallback Result or retyping the error.
2926
- *
2927
- * ## When to Use
2928
- *
2929
- * Use `orElse()` when:
2930
- * - You want to recover from errors with fallback operations
2931
- * - The recovery might also fail (returns a Result)
2932
- * - You need to chain fallback strategies
2933
- * - You're implementing retry or fallback patterns
2571
+ * Resume state for workflow replay.
2572
+ * Pre-populate step results to skip execution on resume.
2934
2573
  *
2935
- * ## Why Use This
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.
2936
2577
  *
2937
- * - **Fallback chains**: Try alternative operations on failure
2938
- * - **Error recovery**: Convert errors to success with fallback values
2939
- * - **Composable**: Can chain multiple orElse calls for cascading fallbacks
2940
- * - **Type-safe**: TypeScript tracks the error union through recovery
2941
- *
2942
- * @param r - The Result to potentially recover from
2943
- * @param fn - Function that takes the error and returns a new Result (may succeed or fail)
2944
- * @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
2945
2585
  *
2946
2586
  * @example
2947
- * ```typescript
2948
- * // Fallback to default user
2949
- * const user = orElse(
2950
- * fetchUser(id),
2951
- * error => error === 'NOT_FOUND' ? ok(defaultUser) : err(error)
2952
- * );
2953
- *
2954
- * // Try cache, then database, then fail
2955
- * const data = orElse(
2956
- * orElse(
2957
- * fetchFromCache(key),
2958
- * () => fetchFromDatabase(key)
2959
- * ),
2960
- * () => err('DATA_UNAVAILABLE' as const)
2961
- * );
2962
- *
2963
- * // Convert specific errors to success
2964
- * const result = orElse(
2965
- * riskyOperation(),
2966
- * error => error.code === 'RETRY' ? ok(defaultValue) : err(error)
2967
- * );
2968
- * ```
2587
+ * // Resume with saved state
2588
+ * const workflow = createWorkflow({ fetchUser }, {
2589
+ * resumeState: { steps: savedSteps }
2590
+ * });
2969
2591
  */
2970
- 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
+ }
2971
2596
  /**
2972
- * Async version of orElse for recovering from errors with async operations.
2973
- *
2974
- * @param r - The Result or AsyncResult to potentially recover from
2975
- * @param fn - Async function that takes the error and returns a new Result
2976
- * @returns Promise of the original Result if successful, or the result of the recovery function
2977
- *
2978
- * @example
2979
- * ```typescript
2980
- * // Try primary API, fall back to secondary
2981
- * const data = await orElseAsync(
2982
- * await fetchFromPrimaryApi(),
2983
- * async (error) => {
2984
- * if (error === 'UNAVAILABLE') {
2985
- * return await fetchFromSecondaryApi();
2986
- * }
2987
- * return err(error);
2988
- * }
2989
- * );
2990
- * ```
2597
+ * Constraint for Result-returning functions
2598
+ * Used by createWorkflow to ensure only valid functions are passed
2991
2599
  */
2992
- 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>>;
2993
2601
  /**
2994
- * Recovers from an error by returning a plain value (not a Result).
2995
- * Useful when you want to provide a default value on error.
2996
- *
2997
- * ## When to Use
2998
- *
2999
- * Use `recover()` when:
3000
- * - You want to provide a fallback value on error
3001
- * - Recovery cannot fail (unlike orElse which returns a Result)
3002
- * - You're implementing default value patterns
3003
- * - You want to guarantee a successful Result
3004
- *
3005
- * ## Why Use This Instead of `orElse`
3006
- *
3007
- * - **Simpler**: Recovery function returns plain value, not Result
3008
- * - **Guaranteed success**: Always returns ok() after recovery
3009
- * - **Clearer intent**: Shows recovery cannot fail
3010
- *
3011
- * @param r - The Result to potentially recover from
3012
- * @param fn - Function that takes the error and returns a recovery value
3013
- * @returns The original Result if successful, or ok(recoveryValue) if error
3014
- *
3015
- * @example
3016
- * ```typescript
3017
- * // Provide default user on NOT_FOUND
3018
- * const user = recover(
3019
- * fetchUser(id),
3020
- * error => error === 'NOT_FOUND' ? defaultUser : guestUser
3021
- * );
3022
- *
3023
- * // Convert all errors to default
3024
- * const config = recover(
3025
- * loadConfig(),
3026
- * () => defaultConfig
3027
- * );
3028
- *
3029
- * // Recover with error-based defaults
3030
- * const value = recover(
3031
- * parseNumber(input),
3032
- * error => error === 'EMPTY' ? 0 : -1
3033
- * );
3034
- * ```
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'
3035
2605
  */
3036
- 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];
3037
2609
  /**
3038
- * 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
3039
2613
  *
3040
- * @param r - The Result or AsyncResult to potentially recover from
3041
- * @param fn - Async function that takes the error and returns a recovery value
3042
- * @returns Promise of ok(value) - either original or recovered
3043
- *
3044
- * @example
3045
- * ```typescript
3046
- * // Recover by fetching default from API
3047
- * const user = await recoverAsync(
3048
- * await fetchUser(id),
3049
- * async (error) => await fetchDefaultUser()
3050
- * );
3051
- * ```
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`.
3052
2617
  */
3053
- 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]>;
3054
2619
  /**
3055
- * Validates and type-narrows a value to a Result.
3056
- *
3057
- * Since this library uses plain objects for Results, serialization is trivial -
3058
- * the serialized form IS the Result. This function validates the structure and
3059
- * provides type-safe narrowing.
3060
- *
3061
- * ## When to Use
3062
- *
3063
- * Use `hydrate()` when:
3064
- * - Receiving Results over RPC/network
3065
- * - Deserializing Results from storage
3066
- * - Validating untrusted data as Results
2620
+ * Execution-time options that can override creation-time options.
2621
+ * Pass these to `workflow.run(fn, execOptions)` for per-run configuration.
3067
2622
  *
3068
- * @param value - The unknown value to validate as a Result
3069
- * @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.
3070
2624
  *
3071
2625
  * @example
3072
2626
  * ```typescript
3073
- * // Deserialize from JSON
3074
- * const parsed = JSON.parse(jsonString);
3075
- * const result = hydrate<User, ApiError>(parsed);
3076
- * if (result) {
3077
- * // result is Result<User, ApiError>
3078
- * }
2627
+ * const workflow = createWorkflow(deps, { cache, onEvent: defaultHandler });
3079
2628
  *
3080
- * // Validate RPC response
3081
- * const rpcResponse = await fetchFromService();
3082
- * const result = hydrate<Data, ServiceError>(rpcResponse);
3083
- * ```
3084
- */
3085
- declare function hydrate<T, E, C = unknown>(value: unknown): Result<T, E, C> | null;
3086
- /**
3087
- * Type guard to check if a value is a valid serialized Result.
2629
+ * // Normal run uses creation-time options
2630
+ * await workflow(async ({ step }) => { ... });
3088
2631
  *
3089
- * @param value - The value to check
3090
- * @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 });
3091
2634
  *
3092
- * @example
3093
- * ```typescript
3094
- * if (isSerializedResult(data)) {
3095
- * // data is Result<unknown, unknown, unknown>
3096
- * if (data.ok) {
3097
- * console.log(data.value);
3098
- * }
3099
- * }
2635
+ * // Pre-bind defaults with .with() (overridable by .run())
2636
+ * const visualized = workflow.with({ onEvent: viz.handleEvent });
2637
+ * await visualized(async ({ step }) => { ... });
3100
2638
  * ```
3101
2639
  */
3102
- declare function isSerializedResult(value: unknown): value is Result<unknown, unknown, unknown>;
3103
- type AllValues<T extends readonly Result<unknown, unknown, unknown>[]> = {
3104
- [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;
3105
2696
  };
3106
- type AllErrors<T extends readonly Result<unknown, unknown, unknown>[]> = {
3107
- [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;
3108
- }[number];
3109
- type AllCauses<T extends readonly Result<unknown, unknown, unknown>[]> = {
3110
- [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;
3111
- }[number];
3112
- type AllResult<T extends readonly Result<unknown, unknown, unknown>[]> = [
3113
- AllErrors<T>
3114
- ] extends [never] ? Ok<AllValues<T>> : Result<AllValues<T>, AllErrors<T>, AllCauses<T>>;
3115
2697
  /**
3116
- * Combines multiple Results into one, requiring all to succeed.
3117
- *
3118
- * ## When to Use
3119
- *
3120
- * Use `all()` when:
3121
- * - You have multiple independent operations that all must succeed
3122
- * - You want to short-circuit on the first error (fail-fast)
3123
- * - You need all values together (e.g., combining API responses)
3124
- * - Performance matters (stops on first error, doesn't wait for all)
3125
- *
3126
- * ## Why Use This
3127
- *
3128
- * - **Fail-fast**: Stops immediately on first error (better performance)
3129
- * - **Type-safe**: TypeScript infers the array type from input
3130
- * - **Short-circuit**: Doesn't evaluate remaining Results after error
3131
- * - **Composable**: Can be chained with other operations
3132
- *
3133
- * ## Important
3134
- *
3135
- * - **Short-circuits**: Returns first error immediately, doesn't wait for all Results
3136
- * - **All must succeed**: If any Result fails, the entire operation fails
3137
- * - **Use `allSettled`**: If you need to collect all errors (e.g., form validation)
3138
- *
3139
- * @param results - Array of Results to combine (all must succeed)
3140
- * @returns A Result with an array of all success values, or the first error encountered
3141
- *
3142
- * @example
3143
- * ```typescript
3144
- * // Combine multiple successful Results
3145
- * const combined = all([Awaitly.ok(1), Awaitly.ok(2), Awaitly.ok(3)]);
3146
- * // combined: { ok: true, value: [1, 2, 3] }
3147
- *
3148
- * // Short-circuits on first error
3149
- * const error = all([Awaitly.ok(1), Awaitly.err('ERROR'), Awaitly.ok(3)]);
3150
- * // error: { ok: false, error: 'ERROR' }
3151
- * // Note: Awaitly.ok(3) is never evaluated
3152
- *
3153
- * // Combine API responses
3154
- * const data = all([
3155
- * fetchUser(id),
3156
- * fetchPosts(id),
3157
- * fetchComments(id)
3158
- * ]);
3159
- * // data.value: [user, posts, comments] if all succeed
3160
- * ```
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.
3161
2714
  */
3162
- 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
+ };
3163
2788
  /**
3164
- * Combines multiple Results or Promises of Results into one (async version of `all`).
3165
- *
3166
- * ## When to Use
3167
- *
3168
- * Use `allAsync()` when:
3169
- * - You have multiple async operations that all must succeed
3170
- * - You want to run operations in parallel (better performance)
3171
- * - You want to short-circuit on the first error (fail-fast)
3172
- * - You need all values together from parallel operations
3173
- *
3174
- * ## Why Use This Instead of `all`
3175
- *
3176
- * - **Parallel execution**: All Promises start immediately (faster)
3177
- * - **Async support**: Works with Promises and AsyncResults
3178
- * - **Promise rejection handling**: Converts Promise rejections to `PromiseRejectedError`
3179
- *
3180
- * ## Important
3181
- *
3182
- * - **Short-circuits**: Returns first error immediately, cancels remaining operations
3183
- * - **Parallel**: All operations start simultaneously (unlike sequential `andThen`)
3184
- * - **Use `allSettledAsync`**: If you need to collect all errors
3185
- *
3186
- * @param results - Array of Results or Promises of Results to combine (all must succeed)
3187
- * @returns A Promise resolving to a Result with an array of all success values, or the first error
3188
- *
3189
- * @example
3190
- * ```typescript
3191
- * // Parallel API calls
3192
- * const combined = await allAsync([
3193
- * fetchUser('1'),
3194
- * fetchPosts('1'),
3195
- * fetchComments('1')
3196
- * ]);
3197
- * // All three calls start simultaneously
3198
- * // combined: { ok: true, value: [user, posts, comments] } if all succeed
3199
- *
3200
- * // Mix Results and Promises
3201
- * const data = await allAsync([
3202
- * ok(cachedUser), // Already resolved
3203
- * fetchPosts(userId), // Promise
3204
- * ]);
3205
- * ```
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.
3206
2792
  */
3207
- declare function allAsync<const T extends readonly (Result<unknown, unknown, unknown> | Promise<Result<unknown, unknown, unknown>>)[]>(results: T): Promise<Result<{
3208
- [K in keyof T]: T[K] extends Result<infer V, unknown, unknown> | Promise<Result<infer V, unknown, unknown>> ? V : never;
3209
- }, {
3210
- [K in keyof T]: T[K] extends Result<unknown, infer E, unknown> | Promise<Result<unknown, infer E, unknown>> ? E : never;
3211
- }[number] | PromiseRejectedError, {
3212
- [K in keyof T]: T[K] extends Result<unknown, unknown, infer C> | Promise<Result<unknown, unknown, infer C>> ? C : never;
3213
- }[number] | PromiseRejectionCause>>;
3214
- type SettledError<E, C = unknown> = {
3215
- error: E;
3216
- 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;
3217
2877
  };
3218
- type AllSettledResult<T extends readonly Result<unknown, unknown, unknown>[]> = [
3219
- AllErrors<T>
3220
- ] extends [never] ? Ok<AllValues<T>> : Result<AllValues<T>, SettledError<AllErrors<T>, AllCauses<T>>[]>;
3221
2878
  /**
3222
- * Combines multiple Results, collecting all errors instead of short-circuiting.
3223
- *
3224
- * ## When to Use
3225
- *
3226
- * Use `allSettled()` when:
3227
- * - You need to see ALL errors, not just the first one
3228
- * - You're doing form validation (show all field errors)
3229
- * - You want to collect partial results (some succeed, some fail)
3230
- * - You need to process all Results regardless of failures
3231
- *
3232
- * ## Why Use This Instead of `all`
3233
- *
3234
- * - **Collects all errors**: Returns array of all errors, not just first
3235
- * - **No short-circuit**: Evaluates all Results even if some fail
3236
- * - **Partial success**: Can see which operations succeeded and which failed
3237
- * - **Better UX**: Show users all validation errors at once
3238
- *
3239
- * ## Important
3240
- *
3241
- * - **No short-circuit**: All Results are evaluated (slower if many fail early)
3242
- * - **Error array**: Returns array of `{ error, cause }` objects, not single error
3243
- * - **Use `all`**: If you want fail-fast behavior (better performance)
3244
- *
3245
- * @param results - Array of Results to combine (all are evaluated)
3246
- * @returns A Result with:
3247
- * - Array of all success values if all succeed
3248
- * - Array of `{ error, cause }` objects if any fail
3249
- *
3250
- * @example
3251
- * ```typescript
3252
- * // Form validation - show all errors
3253
- * const validated = allSettled([
3254
- * validateEmail(email),
3255
- * validatePassword(password),
3256
- * validateAge(age),
3257
- * ]);
3258
- * // If email and password fail:
3259
- * // { ok: false, error: [
3260
- * // { error: 'INVALID_EMAIL' },
3261
- * // { error: 'WEAK_PASSWORD' }
3262
- * // ]}
3263
- *
3264
- * // Collect partial results
3265
- * const results = allSettled([
3266
- * fetchUser('1'), // succeeds
3267
- * fetchUser('2'), // fails
3268
- * fetchUser('3'), // succeeds
3269
- * ]);
3270
- * // Can see which succeeded and which failed
3271
- * ```
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.
3272
2882
  */
3273
- 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>;
3274
2893
  /**
3275
- * Splits an array of Results into separate arrays of success values and errors.
3276
- *
3277
- * ## When to Use
3278
- *
3279
- * Use `partition()` when:
3280
- * - You have an array of Results and need to separate successes from failures
3281
- * - You want to process successes and errors separately
3282
- * - You're collecting results from multiple operations (some may fail)
3283
- * - You need to handle partial success scenarios
3284
- *
3285
- * ## Why Use This
3286
- *
3287
- * - **Simple separation**: One call splits successes and errors
3288
- * - **Type-safe**: TypeScript knows `values` is `T[]` and `errors` is `E[]`
3289
- * - **No unwrapping**: Doesn't require manual `if (r.ok)` checks
3290
- * - **Preserves order**: Maintains original array order in both arrays
3291
- *
3292
- * ## Common Pattern
3293
- *
3294
- * Often used after `Promise.all()` with Results:
3295
- * ```typescript
3296
- * const results = await Promise.all(ids.map(id => fetchUser(id)));
3297
- * const { values: users, errors } = partition(results);
3298
- * // Process successful users, handle errors separately
3299
- * ```
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.
3300
2905
  *
3301
- * @param results - Array of Results to partition
3302
- * @returns An object with:
3303
- * - `values`: Array of all success values (type `T[]`)
3304
- * - `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.
3305
2960
  *
3306
2961
  * @example
3307
2962
  * ```typescript
3308
- * // Split successes and errors
3309
- * const results = [ok(1), err('ERROR_1'), ok(3), err('ERROR_2')];
3310
- * const { values, errors } = partition(results);
3311
- * // values: [1, 3]
3312
- * // errors: ['ERROR_1', 'ERROR_2']
3313
- *
3314
- * // Process batch operations
3315
- * const userResults = await Promise.all(userIds.map(id => fetchUser(id)));
3316
- * const { values: users, errors: fetchErrors } = partition(userResults);
2963
+ * const controller = new AbortController();
2964
+ * const workflow = createWorkflow(deps, { signal: controller.signal });
3317
2965
  *
3318
- * // Process successful users
3319
- * users.forEach(user => processUser(user));
2966
+ * // Later:
2967
+ * controller.abort('User navigated away');
3320
2968
  *
3321
- * // Handle errors
3322
- * 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
+ * }
3323
2973
  * ```
3324
2974
  */
3325
- declare function partition<T, E, C>(results: readonly Result<T, E, C>[]): {
3326
- values: T[];
3327
- 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;
3328
2981
  };
3329
- type AnyValue<T extends readonly Result<unknown, unknown, unknown>[]> = T[number] extends Result<infer U, unknown, unknown> ? U : never;
3330
- type AnyErrors<T extends readonly Result<unknown, unknown, unknown>[]> = {
3331
- -readonly [K in keyof T]: T[K] extends Result<unknown, infer E, unknown> ? E : never;
3332
- }[number];
3333
- type AnyCauses<T extends readonly Result<unknown, unknown, unknown>[]> = {
3334
- -readonly [K in keyof T]: T[K] extends Result<unknown, unknown, infer C> ? C : never;
3335
- }[number];
3336
2982
  /**
3337
- * Returns the first successful Result from an array (succeeds fast).
3338
- *
3339
- * ## When to Use
3340
- *
3341
- * Use `any()` when:
3342
- * - You have multiple fallback options and need the first that succeeds
3343
- * - You're trying multiple strategies (e.g., cache → DB → API)
3344
- * - You want fail-fast success (stops on first success)
3345
- * - You have redundant data sources and any one will do
3346
- *
3347
- * ## Why Use This
3348
- *
3349
- * - **Succeeds fast**: Returns immediately on first success (better performance)
3350
- * - **Fallback pattern**: Perfect for trying multiple options
3351
- * - **Short-circuits**: Stops evaluating after first success
3352
- * - **Type-safe**: TypeScript infers the success type
3353
- *
3354
- * ## Important
3355
- *
3356
- * - **First success wins**: Returns first successful Result, ignores rest
3357
- * - **All errors**: If all fail, returns first error (not all errors)
3358
- * - **Empty array**: Returns `EmptyInputError` if array is empty
3359
- * - **Use `all`**: If you need ALL to succeed
3360
- *
3361
- * @param results - Array of Results to check (evaluated in order)
3362
- * @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.
3363
2985
  *
3364
2986
  * @example
3365
- * ```typescript
3366
- * // Try multiple fallback strategies
3367
- * const data = any([
3368
- * fetchFromCache(id),
3369
- * fetchFromDB(id),
3370
- * fetchFromAPI(id)
3371
- * ]);
3372
- * // Returns first that succeeds
3373
- *
3374
- * // Try multiple formats
3375
- * const parsed = any([
3376
- * parseJSON(input),
3377
- * parseXML(input),
3378
- * parseYAML(input)
3379
- * ]);
3380
- *
3381
- * // All errors case
3382
- * const allErrors = any([err('A'), err('B'), err('C')]);
3383
- * // allErrors: { ok: false, error: 'A' } (first error)
3384
- * ```
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
+ * };
3385
2994
  */
3386
- declare function any<const T extends readonly Result<unknown, unknown, unknown>[]>(results: T): Result<AnyValue<T>, AnyErrors<T> | EmptyInputError, AnyCauses<T>>;
3387
- type AnyAsyncValue<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = Awaited<T[number]> extends Result<infer U, unknown, unknown> ? U : never;
3388
- type AnyAsyncErrors<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = {
3389
- -readonly [K in keyof T]: Awaited<T[K]> extends Result<unknown, infer E, unknown> ? E : never;
3390
- }[number];
3391
- type AnyAsyncCauses<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = {
3392
- -readonly [K in keyof T]: Awaited<T[K]> extends Result<unknown, unknown, infer C> ? C : never;
3393
- }[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
+ };
3394
3004
  /**
3395
- * Returns the first successful Result from an array of Results or Promises (async version of `any`).
3396
- *
3397
- * ## When to Use
3398
- *
3399
- * Use `anyAsync()` when:
3400
- * - You have multiple async fallback options and need the first that succeeds
3401
- * - You're trying multiple async strategies in parallel (cache → DB → API)
3402
- * - You want fail-fast success from parallel operations
3403
- * - You have redundant async data sources and any one will do
3404
- *
3405
- * ## Why Use This Instead of `any`
3406
- *
3407
- * - **Parallel execution**: All Promises start immediately (faster)
3408
- * - **Async support**: Works with Promises and AsyncResults
3409
- * - **Promise rejection handling**: Converts Promise rejections to `PromiseRejectedError`
3410
- *
3411
- * ## Important
3412
- *
3413
- * - **First success wins**: Returns first successful Result (from any Promise)
3414
- * - **Parallel**: All operations run simultaneously
3415
- * - **All errors**: If all fail, returns first error encountered
3416
- *
3417
- * @param results - Array of Results or Promises of Results to check (all start in parallel)
3418
- * @returns A Promise resolving to the first successful Result, or first error if all fail
3419
- *
3420
- * @example
3421
- * ```typescript
3422
- * // Try multiple async fallbacks in parallel
3423
- * const data = await anyAsync([
3424
- * fetchFromCache(id), // Fastest wins
3425
- * fetchFromDB(id),
3426
- * fetchFromAPI(id)
3427
- * ]);
3428
- *
3429
- * // Try multiple API endpoints
3430
- * const response = await anyAsync([
3431
- * fetch('/api/v1/data'),
3432
- * fetch('/api/v2/data'),
3433
- * fetch('/backup-api/data')
3434
- * ]);
3435
- * ```
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.
3436
3008
  */
3437
- declare function anyAsync<const T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]>(results: T): Promise<Result<AnyAsyncValue<T>, AnyAsyncErrors<T> | EmptyInputError | PromiseRejectedError, AnyAsyncCauses<T> | PromiseRejectionCause>>;
3438
- type AllAsyncValues<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = {
3439
- [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>;
3440
3015
  };
3441
- type AllAsyncErrors<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = {
3442
- [K in keyof T]: Awaited<T[K]> extends Result<unknown, infer E, unknown> ? E : never;
3443
- }[number];
3444
- type AllAsyncCauses<T extends readonly MaybeAsyncResult<unknown, unknown, unknown>[]> = {
3445
- [K in keyof T]: Awaited<T[K]> extends Result<unknown, unknown, infer C> ? C : never;
3446
- }[number];
3447
3016
  /**
3448
- * Combines multiple Results or Promises of Results, collecting all errors (async version of `allSettled`).
3449
- *
3450
- * ## When to Use
3451
- *
3452
- * Use `allSettledAsync()` when:
3453
- * - You have multiple async operations and need ALL errors reported
3454
- * - You're doing async form validation (show all field errors at once)
3455
- * - You want to run operations in parallel and collect all results
3456
- *
3457
- * ## Behavior
3458
- *
3459
- * **Note:** Unlike `Promise.allSettled()`, this returns a Result:
3460
- * - `ok(values[])` if ALL succeed
3461
- * - `err(SettledError[])` if ANY fail (with all collected errors)
3462
- *
3463
- * This is consistent with awaitly's philosophy - all functions return Results.
3464
- * `Promise.allSettled()` always succeeds with per-item status objects; this function
3465
- * returns a single Result indicating overall success or failure.
3466
- *
3467
- * ## Why Use This Instead of `allSettled`
3468
- *
3469
- * - **Parallel execution**: All Promises start immediately (faster)
3470
- * - **Async support**: Works with Promises and AsyncResults
3471
- * - **Promise rejection handling**: Converts Promise rejections to `PromiseRejectedError`
3472
- *
3473
- * ## Important
3474
- *
3475
- * - **No short-circuit**: All operations complete (even if some fail)
3476
- * - **Parallel**: All operations run simultaneously
3477
- * - **Error array**: Returns array of `SettledError` objects (`{ error, cause? }`)
3478
- *
3479
- * @param results - Array of Results or Promises of Results to combine (all are evaluated)
3480
- * @returns A Promise resolving to a Result with:
3481
- * - `ok(values[])` - Array of all success values if ALL succeed
3482
- * - `err(errors[])` - Array of `SettledError` objects if ANY fail
3483
- *
3484
- * @example
3485
- * ```typescript
3486
- * // Async form validation - see all errors at once
3487
- * const validated = await allSettledAsync([
3488
- * validateEmailAsync(email),
3489
- * validatePasswordAsync(password),
3490
- * checkUsernameAvailableAsync(username),
3491
- * ]);
3492
- *
3493
- * if (!validated.ok) {
3494
- * // validated.error is array of all validation failures
3495
- * console.log('Errors:', validated.error.map(e => e.error));
3496
- * }
3497
- *
3498
- * // Parallel API calls with error collection
3499
- * const results = await allSettledAsync([
3500
- * fetchUser('1'),
3501
- * fetchUser('2'),
3502
- * fetchUser('3'),
3503
- * ]);
3504
- * ```
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.
3505
3049
  */
3506
- 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
+ }
3507
3083
 
3508
- 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 WorkflowEvent as ae, type RunStep as af, type RetryOptions as ag, type BackoffStrategy as ah, type BoundSteps as ai, type StepOptions as aj, type RunOptions as ak, type RunOptionsWithCatch as al, type RunOptionsWithoutCatch as am, STEP_TIMEOUT_MARKER as an, type ScopeType as ao, type StepTimeoutError as ap, type StepTimeoutMarkerMeta as aq, type TimeoutOptions as ar, getStepTimeoutMeta as as, isStepTimeoutError as at, run as au, type StepFailureMeta as av, EARLY_EXIT_SYMBOL as aw, type EarlyExit as ax, createEarlyExit as ay, isEarlyExit as az, 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 };