awaitly 1.34.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. package/dist/{duration.d.ts → di-BDlT7InM.d.cts} +15 -1
  2. package/dist/{duration.d.cts → di-BbFFfO8y.d.ts} +15 -1
  3. package/dist/errors-DtXvrCiO.d.cts +708 -0
  4. package/dist/errors-DtXvrCiO.d.ts +708 -0
  5. package/dist/index.cjs +4594 -1
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.d.cts +1970 -141
  8. package/dist/index.d.ts +1970 -141
  9. package/dist/index.js +4398 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/result.cjs +641 -1
  12. package/dist/result.cjs.map +1 -1
  13. package/dist/result.d.cts +35 -5
  14. package/dist/result.d.ts +35 -5
  15. package/dist/result.js +561 -1
  16. package/dist/result.js.map +1 -1
  17. package/dist/testing.cjs +4202 -8
  18. package/dist/testing.cjs.map +1 -1
  19. package/dist/testing.d.cts +2 -6
  20. package/dist/testing.d.ts +2 -6
  21. package/dist/testing.js +4154 -8
  22. package/dist/testing.js.map +1 -1
  23. package/dist/{run-entry-D2MmJFj9.d.cts → types-B8NfNRGX.d.ts} +1152 -1499
  24. package/dist/{run-entry-Dduz-is2.d.ts → types-BZ2f4MRR.d.cts} +1152 -1499
  25. package/dist/workflow.cjs +7096 -6
  26. package/dist/workflow.cjs.map +1 -1
  27. package/dist/workflow.d.cts +3346 -22
  28. package/dist/workflow.d.ts +3346 -22
  29. package/dist/workflow.js +6929 -6
  30. package/dist/workflow.js.map +1 -1
  31. package/package.json +13 -178
  32. package/dist/adapters.cjs +0 -7
  33. package/dist/adapters.cjs.map +0 -1
  34. package/dist/adapters.d.cts +0 -179
  35. package/dist/adapters.d.ts +0 -179
  36. package/dist/adapters.js +0 -7
  37. package/dist/adapters.js.map +0 -1
  38. package/dist/batch.cjs +0 -7
  39. package/dist/batch.cjs.map +0 -1
  40. package/dist/batch.d.cts +0 -200
  41. package/dist/batch.d.ts +0 -200
  42. package/dist/batch.js +0 -7
  43. package/dist/batch.js.map +0 -1
  44. package/dist/bind-deps.cjs +0 -2
  45. package/dist/bind-deps.cjs.map +0 -1
  46. package/dist/bind-deps.d.cts +0 -28
  47. package/dist/bind-deps.d.ts +0 -28
  48. package/dist/bind-deps.js +0 -2
  49. package/dist/bind-deps.js.map +0 -1
  50. package/dist/cache.cjs +0 -2
  51. package/dist/cache.cjs.map +0 -1
  52. package/dist/cache.d.cts +0 -269
  53. package/dist/cache.d.ts +0 -269
  54. package/dist/cache.js +0 -2
  55. package/dist/cache.js.map +0 -1
  56. package/dist/circuit-breaker.cjs +0 -7
  57. package/dist/circuit-breaker.cjs.map +0 -1
  58. package/dist/circuit-breaker.d.cts +0 -211
  59. package/dist/circuit-breaker.d.ts +0 -211
  60. package/dist/circuit-breaker.js +0 -7
  61. package/dist/circuit-breaker.js.map +0 -1
  62. package/dist/conditional.cjs +0 -2
  63. package/dist/conditional.cjs.map +0 -1
  64. package/dist/conditional.d.cts +0 -252
  65. package/dist/conditional.d.ts +0 -252
  66. package/dist/conditional.js +0 -2
  67. package/dist/conditional.js.map +0 -1
  68. package/dist/core.cjs +0 -7
  69. package/dist/core.cjs.map +0 -1
  70. package/dist/core.d.cts +0 -5
  71. package/dist/core.d.ts +0 -5
  72. package/dist/core.js +0 -7
  73. package/dist/core.js.map +0 -1
  74. package/dist/di-COl5oFnR.d.cts +0 -15
  75. package/dist/di-CyDj_JyZ.d.ts +0 -15
  76. package/dist/diagnostics.cjs +0 -8
  77. package/dist/diagnostics.cjs.map +0 -1
  78. package/dist/diagnostics.d.cts +0 -68
  79. package/dist/diagnostics.d.ts +0 -68
  80. package/dist/diagnostics.js +0 -8
  81. package/dist/diagnostics.js.map +0 -1
  82. package/dist/durable.cjs +0 -11
  83. package/dist/durable.cjs.map +0 -1
  84. package/dist/durable.d.cts +0 -9
  85. package/dist/durable.d.ts +0 -9
  86. package/dist/durable.js +0 -11
  87. package/dist/durable.js.map +0 -1
  88. package/dist/duration.cjs +0 -2
  89. package/dist/duration.cjs.map +0 -1
  90. package/dist/duration.js +0 -2
  91. package/dist/duration.js.map +0 -1
  92. package/dist/engine.cjs +0 -11
  93. package/dist/engine.cjs.map +0 -1
  94. package/dist/engine.d.cts +0 -115
  95. package/dist/engine.d.ts +0 -115
  96. package/dist/engine.js +0 -11
  97. package/dist/engine.js.map +0 -1
  98. package/dist/errors.cjs +0 -2
  99. package/dist/errors.cjs.map +0 -1
  100. package/dist/errors.d.cts +0 -361
  101. package/dist/errors.d.ts +0 -361
  102. package/dist/errors.js +0 -2
  103. package/dist/errors.js.map +0 -1
  104. package/dist/fetch.cjs +0 -7
  105. package/dist/fetch.cjs.map +0 -1
  106. package/dist/fetch.d.cts +0 -86
  107. package/dist/fetch.d.ts +0 -86
  108. package/dist/fetch.js +0 -7
  109. package/dist/fetch.js.map +0 -1
  110. package/dist/flow.cjs +0 -7
  111. package/dist/flow.cjs.map +0 -1
  112. package/dist/flow.d.cts +0 -163
  113. package/dist/flow.d.ts +0 -163
  114. package/dist/flow.js +0 -7
  115. package/dist/flow.js.map +0 -1
  116. package/dist/functional.cjs +0 -2
  117. package/dist/functional.cjs.map +0 -1
  118. package/dist/functional.d.cts +0 -444
  119. package/dist/functional.d.ts +0 -444
  120. package/dist/functional.js +0 -2
  121. package/dist/functional.js.map +0 -1
  122. package/dist/guards-BodHXLzX.d.cts +0 -72
  123. package/dist/guards-CeWoQ8fn.d.ts +0 -72
  124. package/dist/hitl-BPE_1UiM.d.cts +0 -468
  125. package/dist/hitl-byp570uC.d.ts +0 -468
  126. package/dist/hitl.cjs +0 -7
  127. package/dist/hitl.cjs.map +0 -1
  128. package/dist/hitl.d.cts +0 -442
  129. package/dist/hitl.d.ts +0 -442
  130. package/dist/hitl.js +0 -7
  131. package/dist/hitl.js.map +0 -1
  132. package/dist/index-BYT3amEz.d.ts +0 -417
  133. package/dist/index-C_ak66jy.d.cts +0 -417
  134. package/dist/match-entry-DjI2bLpD.d.cts +0 -209
  135. package/dist/match-entry-DjI2bLpD.d.ts +0 -209
  136. package/dist/match.cjs +0 -2
  137. package/dist/match.cjs.map +0 -1
  138. package/dist/match.d.cts +0 -1
  139. package/dist/match.d.ts +0 -1
  140. package/dist/match.js +0 -2
  141. package/dist/match.js.map +0 -1
  142. package/dist/otel.cjs +0 -2
  143. package/dist/otel.cjs.map +0 -1
  144. package/dist/otel.d.cts +0 -188
  145. package/dist/otel.d.ts +0 -188
  146. package/dist/otel.js +0 -2
  147. package/dist/otel.js.map +0 -1
  148. package/dist/persistence-entry-DOMx3woy.d.ts +0 -822
  149. package/dist/persistence-entry-ymCA4iDu.d.cts +0 -822
  150. package/dist/persistence.cjs +0 -2
  151. package/dist/persistence.cjs.map +0 -1
  152. package/dist/persistence.d.cts +0 -7
  153. package/dist/persistence.d.ts +0 -7
  154. package/dist/persistence.js +0 -2
  155. package/dist/persistence.js.map +0 -1
  156. package/dist/policies.cjs +0 -2
  157. package/dist/policies.cjs.map +0 -1
  158. package/dist/policies.d.cts +0 -379
  159. package/dist/policies.d.ts +0 -379
  160. package/dist/policies.js +0 -2
  161. package/dist/policies.js.map +0 -1
  162. package/dist/ratelimit.cjs +0 -7
  163. package/dist/ratelimit.cjs.map +0 -1
  164. package/dist/ratelimit.d.cts +0 -458
  165. package/dist/ratelimit.d.ts +0 -458
  166. package/dist/ratelimit.js +0 -7
  167. package/dist/ratelimit.js.map +0 -1
  168. package/dist/reliability.cjs +0 -11
  169. package/dist/reliability.cjs.map +0 -1
  170. package/dist/reliability.d.cts +0 -11
  171. package/dist/reliability.d.ts +0 -11
  172. package/dist/reliability.js +0 -11
  173. package/dist/reliability.js.map +0 -1
  174. package/dist/resolver.cjs +0 -7
  175. package/dist/resolver.cjs.map +0 -1
  176. package/dist/resolver.d.cts +0 -68
  177. package/dist/resolver.d.ts +0 -68
  178. package/dist/resolver.js +0 -7
  179. package/dist/resolver.js.map +0 -1
  180. package/dist/resource.cjs +0 -7
  181. package/dist/resource.cjs.map +0 -1
  182. package/dist/resource.d.cts +0 -174
  183. package/dist/resource.d.ts +0 -174
  184. package/dist/resource.js +0 -7
  185. package/dist/resource.js.map +0 -1
  186. package/dist/result/retry.cjs +0 -2
  187. package/dist/result/retry.cjs.map +0 -1
  188. package/dist/result/retry.d.cts +0 -70
  189. package/dist/result/retry.d.ts +0 -70
  190. package/dist/result/retry.js +0 -2
  191. package/dist/result/retry.js.map +0 -1
  192. package/dist/retry.cjs +0 -2
  193. package/dist/retry.cjs.map +0 -1
  194. package/dist/retry.d.cts +0 -388
  195. package/dist/retry.d.ts +0 -388
  196. package/dist/retry.js +0 -2
  197. package/dist/retry.js.map +0 -1
  198. package/dist/run.cjs +0 -7
  199. package/dist/run.cjs.map +0 -1
  200. package/dist/run.d.cts +0 -4
  201. package/dist/run.d.ts +0 -4
  202. package/dist/run.js +0 -7
  203. package/dist/run.js.map +0 -1
  204. package/dist/saga.cjs +0 -11
  205. package/dist/saga.cjs.map +0 -1
  206. package/dist/saga.d.cts +0 -164
  207. package/dist/saga.d.ts +0 -164
  208. package/dist/saga.js +0 -11
  209. package/dist/saga.js.map +0 -1
  210. package/dist/singleflight.cjs +0 -2
  211. package/dist/singleflight.cjs.map +0 -1
  212. package/dist/singleflight.d.cts +0 -145
  213. package/dist/singleflight.d.ts +0 -145
  214. package/dist/singleflight.js +0 -2
  215. package/dist/singleflight.js.map +0 -1
  216. package/dist/slugs.cjs +0 -2
  217. package/dist/slugs.cjs.map +0 -1
  218. package/dist/slugs.d.cts +0 -67
  219. package/dist/slugs.d.ts +0 -67
  220. package/dist/slugs.js +0 -2
  221. package/dist/slugs.js.map +0 -1
  222. package/dist/streaming.cjs +0 -9
  223. package/dist/streaming.cjs.map +0 -1
  224. package/dist/streaming.d.cts +0 -596
  225. package/dist/streaming.d.ts +0 -596
  226. package/dist/streaming.js +0 -9
  227. package/dist/streaming.js.map +0 -1
  228. package/dist/tagged-error.cjs +0 -2
  229. package/dist/tagged-error.cjs.map +0 -1
  230. package/dist/tagged-error.d.cts +0 -275
  231. package/dist/tagged-error.d.ts +0 -275
  232. package/dist/tagged-error.js +0 -2
  233. package/dist/tagged-error.js.map +0 -1
  234. package/dist/types-DQmzO9f4.d.ts +0 -323
  235. package/dist/types-qBUOYi-4.d.cts +0 -323
  236. package/dist/webhook.cjs +0 -7
  237. package/dist/webhook.cjs.map +0 -1
  238. package/dist/webhook.d.cts +0 -499
  239. package/dist/webhook.d.ts +0 -499
  240. package/dist/webhook.js +0 -7
  241. package/dist/webhook.js.map +0 -1
package/dist/testing.cjs CHANGED
@@ -1,13 +1,4207 @@
1
- "use strict";var Ve=Object.defineProperty;var Jt=Object.getOwnPropertyDescriptor;var zt=Object.getOwnPropertyNames;var Yt=Object.prototype.hasOwnProperty;var Gt=(e,t)=>{for(var r in t)Ve(e,r,{get:t[r],enumerable:!0})},Xt=(e,t,r,m)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of zt(t))!Yt.call(e,a)&&a!==r&&Ve(e,a,{get:()=>t[a],enumerable:!(m=Jt(t,a))||m.enumerable});return e};var Qt=e=>Xt(Ve({},"__esModule",{value:!0}),e);var yr={};Gt(yr,{assertEventEmitted:()=>nt,assertEventNotEmitted:()=>Lt,assertEventSequence:()=>$t,compareSnapshots:()=>Wt,createMockFn:()=>Mt,createSagaHarness:()=>Kt,createSnapshot:()=>It,createTestClock:()=>Ut,createWorkflowHarness:()=>rt,errOutcome:()=>jt,expectErr:()=>st,expectOk:()=>ot,formatEvent:()=>ut,formatEvents:()=>qt,formatResult:()=>Ht,okOutcome:()=>Nt,testWorkflow:()=>et,throwOutcome:()=>Ft,unwrapErr:()=>it,unwrapErrAsync:()=>Vt,unwrapOk:()=>at,unwrapOkAsync:()=>Bt});module.exports=Qt(yr);var Zt={"step-require-id":"step-require-id","step-no-immediate-execution":"step-no-immediate-execution","step-require-thunk-for-key":"step-require-thunk-for-key","step-no-bare-await":"step-no-bare-await","step-no-try-catch-wrap":"step-no-try-catch-wrap","step-stable-cache-keys":"step-stable-cache-keys","workflow-no-floating":"workflow-no-floating","workflow-options-position":"workflow-options-position","workflow-callback-shape":"workflow-callback-shape","workflow-no-callable-form":"workflow-no-callable-form","workflow-no-dynamic-import":"workflow-no-dynamic-import","result-no-floating":"result-no-floating","result-require-handling":"result-require-handling","result-no-double-wrap":"result-no-double-wrap","result-no-manual-propagation":"result-no-manual-propagation","result-no-direct-ok-err":"result-no-direct-ok-err","error-check-unexpected-first":"error-check-unexpected-first","error-access-cause":"error-access-cause","error-normalize":"error-normalize","error-no-throw-in-deps":"error-no-throw-in-deps","concurrency-no-promise-all":"concurrency-no-promise-all","concurrency-no-promise-race":"concurrency-no-promise-race","concurrency-no-promise-allsettled":"concurrency-no-promise-allsettled","runtime-step-timeout":"runtime-step-timeout","runtime-step-aborted":"runtime-step-aborted","runtime-retry-exhausted":"runtime-retry-exhausted","runtime-rate-limit":"runtime-rate-limit","runtime-circuit-open":"runtime-circuit-open","runtime-unexpected":"runtime-unexpected","runtime-resolver-not-found":"runtime-resolver-not-found","runtime-saga-compensation":"runtime-saga-compensation"};function ct(e){return`https://jagreehal.github.io/awaitly/rules/#${e}`}var gr=Object.keys(Zt);var Ue=class extends Error{_tag};function ye(e,t){return class extends Ue{_tag=e;constructor(r,m){let a=t?.message?t.message(r??{}):e;if(super(a),this.name=e,t?.slug!==void 0){if(!t.hint)throw new TypeError(`TaggedError: 'hint' is required when 'slug' is set (slug: "${t.slug}")`);Object.defineProperty(this,"code",{value:t.slug,enumerable:!0,writable:!1,configurable:!1}),Object.defineProperty(this,"hint",{value:t.hint,enumerable:!0,writable:!1,configurable:!1}),Object.defineProperty(this,"docsUrl",{value:ct(t.slug),enumerable:!0,writable:!1,configurable:!1})}if(Object.setPrototypeOf(this,new.target.prototype),r&&typeof r=="object"){let d;if(t?.slug!==void 0){let{_tag:i,name:Y,message:b,stack:x,code:G,hint:l,docsUrl:q,...Q}=r;d=Q}else{let{_tag:i,name:Y,message:b,stack:x,...G}=r;d=G}let S=Object.prototype.hasOwnProperty.call(d,"cause"),g=S?d.cause:void 0;S&&delete d.cause;let I=m?.cause!==void 0;if(S&&I)throw new TypeError("TaggedError: cannot provide 'cause' in props when also setting ErrorOptions.cause");Object.assign(this,d),S&&(this.cause=g),I&&(this.cause=m?.cause)}else m?.cause!==void 0&&(this.cause=m.cause)}}}Object.defineProperty(ye,Symbol.hasInstance,{value:e=>e instanceof Ue});(a=>{function e(d){return d instanceof Error}a.isError=e;function t(d){return d instanceof Ue}a.isTaggedError=t;function r(d,S){let g=d._tag,I=S[g];return I(d)}a.match=r;function m(d,S,g){let I=d._tag,i=S[I];return i?i(d):g(d)}a.matchPartial=m})(ye||={});var pt=class extends ye("TimeoutError",{slug:"runtime-step-timeout",hint:"Increase the step's timeout option, or check why the upstream operation is slow.",message:t=>t.operation?`TimeoutError: ${t.operation} timed out after ${t.ms}ms`:`TimeoutError: Operation timed out after ${t.ms}ms`}){},mt=class extends ye("RetryExhaustedError",{slug:"runtime-retry-exhausted",hint:"All retry attempts failed. Inspect lastError and decide whether to surface it or compensate.",message:t=>t.operation?`RetryExhaustedError: ${t.operation} failed after ${t.attempts} attempts`:`RetryExhaustedError: Operation failed after ${t.attempts} attempts`}){},dt=class extends ye("RateLimitError",{slug:"runtime-rate-limit",hint:"Wait retryAfterMs before retrying, or apply step.cache to deduplicate calls.",message:t=>t.limiterName?`RateLimitError: Rate limit exceeded for ${t.limiterName}${t.retryAfterMs?`, retry after ${t.retryAfterMs}ms`:""}`:`RateLimitError: Rate limit exceeded${t.retryAfterMs?`, retry after ${t.retryAfterMs}ms`:""}`}){},ft=class extends ye("CircuitBreakerOpenError",{slug:"runtime-circuit-open",hint:"The circuit is open. Wait for it to half-open or fall back to a degraded path.",message:t=>`CircuitBreakerOpenError: Circuit ${t.circuitName} is ${t.state??"OPEN"}${t.retryAfterMs?`, retry after ${Math.ceil(t.retryAfterMs/1e3)}s`:""}`}){},Et=class extends ye("ValidationError",{message:t=>`ValidationError: Invalid ${t.field} - ${t.reason}`}){},wt=class extends ye("NotFoundError",{message:t=>t.id?`NotFoundError: ${t.resource} with id ${t.id} not found`:`NotFoundError: ${t.resource} not found`}){},yt=class extends ye("UnauthorizedError",{message:t=>t.reason?`UnauthorizedError: ${t.reason}`:t.action&&t.resource?`UnauthorizedError: Not authorized to ${t.action} ${t.resource}`:"UnauthorizedError: Access denied"}){},kt=class extends ye("NetworkError",{message:t=>t.url?`NetworkError: ${t.reason} (${t.url})`:`NetworkError: ${t.reason}`}){},gt=class extends ye("CompensationError",{slug:"runtime-saga-compensation",hint:"A saga compensation step failed. Inspect compensationError and ensure compensation is idempotent.",message:t=>`CompensationError: Failed to compensate step ${t.step}`}){},Se=class extends ye("UnexpectedError",{slug:"runtime-unexpected",hint:"An unexpected exception escaped a step. Inspect cause; consider returning a typed Result instead of throwing.",message:t=>`UnexpectedError: ${t.cause instanceof Error?t.cause.message:String(t.cause??"unknown")}`}){};function er(e){let t=e.trim().match(/^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)$/i);if(!t)return;let r=parseFloat(t[1]),m=t[2].toLowerCase();return{_tag:"Duration",millis:r*({ms:1,s:1e3,m:6e4,h:36e5,d:864e5}[m]??1)}}function Ke(e){return new Se({cause:e})}function X(e){return{ok:!0,value:e}}function U(e,t){let r=t?.cause;return{ok:!1,error:e,...r!==void 0?{cause:r}:{}}}var St=e=>e.ok;var ht=e=>e instanceof Se||typeof e=="object"&&e!==null&&"_tag"in e&&e._tag==="UnexpectedError";function tr(e){if(e==null)return"unknown";if(typeof e=="string")return e.trim()||"unknown";if(typeof e=="object"){let t=e;if(typeof t._tag=="string"){let r=t._tag.trim();if(r)return r}if(typeof t.tag=="string"){let r=t.tag.trim();if(r)return r}if(typeof t.code=="string"){let r=t.code.trim();if(r)return r}else if(typeof t.code=="number")return String(t.code);if(e instanceof Error&&e.name){let r=e.name.trim();if(r)return r}}return"unknown"}function rr(e,t){if(!(!t||!e))return t[e]}function Je(e){let{intent:t,domain:r,owner:m,tags:a,stateChanges:d,emits:S,calls:g}=e;if(!t&&!r&&!m&&!a?.length&&!d?.length&&!S?.length&&!g?.length)return;let I={};return t&&(I.intent=t),r&&(I.domain=r),m&&(I.owner=m),a?.length&&(I.tags=a),d?.length&&(I.stateChanges=d),S?.length&&(I.emits=S),g?.length&&(I.calls=g),I}function ge(e,t,r,m,a){let d=tr(e),S=rr(d,t),g={tag:d,origin:r};return S!==void 0&&(g.classification=S),m!==void 0&&(g.attempt=m),a!==void 0&&(g.cumulativeDurationMs=a),g}var _e=Symbol.for("step_timeout_marker");function Tt(e){return typeof e!="object"||e===null?!1:e.type==="STEP_TIMEOUT"?!0:_e in e}function nr(e){if(!(typeof e!="object"||e===null)){if(e.type==="STEP_TIMEOUT"){let t=e;return{timeoutMs:t.timeoutMs,stepName:t.stepName,stepKey:t.stepKey,attempt:t.attempt}}if(_e in e)return e[_e]}}var Ct=Symbol("early-exit");function De(e,t){return{[Ct]:!0,error:e,meta:t}}function ve(e){return typeof e=="object"&&e!==null&&e[Ct]===!0}var bt=Symbol("mapper-exception");function Ae(e){return{[bt]:!0,thrown:e}}function or(e){return typeof e=="object"&&e!==null&&e[bt]===!0}function He(e,t){let{backoff:r,initialDelay:m,maxDelay:a,jitter:d}=t,S;switch(r){case"fixed":S=m;break;case"linear":S=m*e;break;case"exponential":S=m*Math.pow(2,e-1);break}if(S=Math.min(S,a),d){let g=S*.25*Math.random();S=S+g}return Math.floor(S)}function qe(e){return new Promise(t=>setTimeout(t,e))}var Rt=Symbol("timeout"),je=Symbol("timeout-option");function sr(e){return typeof e=="object"&&e!==null&&e[je]===!0}async function ar(e,t,r,m){let a=new AbortController,d=t.onTimeout??"error",S=()=>typeof d=="function"?d({name:r.name,key:r.key,ms:t.ms}):t.error??{type:"STEP_TIMEOUT",stepName:r.name,stepKey:r.key,timeoutMs:t.ms,attempt:r.attempt},g;m?.aborted&&a.abort(m.reason);let I;m&&!m.aborted&&(I=()=>a.abort(m.reason),m.addEventListener("abort",I,{once:!0}));let i=new Promise((b,x)=>{g=setTimeout(()=>{if(d!=="disconnect"&&a.abort(),d==="option"){x({[je]:!0,ms:t.ms});return}x({[Rt]:!0,error:S()})},t.ms)}),Y;t.signal?Y=Promise.resolve(e(a.signal)):Y=Promise.resolve(e());try{return await Promise.race([Y,i])}catch(b){if(typeof b=="object"&&b!==null&&b[je]===!0)throw{[je]:!0,ms:t.ms};if(typeof b=="object"&&b!==null&&b[Rt]===!0){d==="disconnect"&&Y.catch(()=>{});let x=b.error;if(typeof x=="object"&&x!==null&&x.type!=="STEP_TIMEOUT"){let G={timeoutMs:t.ms,stepName:r.name,stepKey:r.key,attempt:r.attempt};_e in x?x[_e]=G:Object.defineProperty(x,_e,{value:G,enumerable:!1,writable:!0,configurable:!1})}throw x}throw b}finally{clearTimeout(g),I&&m&&m.removeEventListener("abort",I)}}var Oe={backoff:"exponential",initialDelay:100,maxDelay:3e4,jitter:!0,shouldRetry:()=>!0,onRetry:()=>{}};async function Fe(e,t){let{onError:r,onEvent:m,catchUnexpected:a,workflowId:d,workflowName:S,context:g,_workflowSignal:I}=t&&typeof t=="object"?t:{},i=d??crypto.randomUUID(),Y=a??Ke,b=[],x=0,G=f=>f??`step_${++x}`,l=f=>{let ee=f.context!==void 0||g===void 0?f:{...f,context:g},ae=S!==void 0&&ee.workflowName===void 0?{...ee,workflowName:S}:ee;if(ae.type==="step_success"){let me=ae.stepId;for(let ue=b.length-1;ue>=0;ue--){let le=b[ue];if(le.type==="race"&&!le.winnerId){le.winnerId=me;break}}}m?.(ae,g)},q=De,Q=f=>ve(f),W=(f,ee)=>f,fe=f=>typeof f=="function"?!1:!!(f&&typeof f=="object"&&"ok"in f||f&&typeof f=="object"&&"then"in f&&typeof f.then=="function");try{let ee=function(c){let y={};for(let[n,u]of Object.entries(c))if(typeof u=="function")y[n]=u;else if(u&&typeof u=="object"&&"fn"in u)y[n]=u.fn;else throw new TypeError(`step.all: operation "${n}" must be a function or { fn, errors? } object`);return y},ae=function(c,y){let n=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let u=performance.now(),o=!1;b.push({scopeId:n,type:"parallel"});let k=()=>{if(o)return;o=!0;let h=b.findIndex(A=>A.scopeId===n);h!==-1&&b.splice(h,1),l({type:"scope_end",workflowId:i,scopeId:n,ts:Date.now(),durationMs:performance.now()-u})};l({type:"scope_start",workflowId:i,scopeId:n,scopeType:"parallel",name:c,ts:Date.now()});try{let h=await y();if(k(),!h.ok)throw r?.(h.error,c,g),q(h.error,{origin:"result",resultCause:h.cause});return h.value}catch(h){throw k(),h}})()},me=function(c,y){let n=Object.keys(c),u=y.name??`Parallel(${n.join(", ")})`,o=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let k=performance.now(),h=!1;b.push({scopeId:o,type:"parallel"});let A=()=>{if(h)return;h=!0;let p=b.findIndex(_=>_.scopeId===o);p!==-1&&b.splice(p,1),l({type:"scope_end",workflowId:i,scopeId:o,ts:Date.now(),durationMs:performance.now()-k})};l({type:"scope_start",workflowId:i,scopeId:o,scopeType:"parallel",name:u,ts:Date.now()});try{let p=await new Promise(F=>{if(n.length===0){F([]);return}let J=!1,re=n.length,N=new Array(n.length);for(let Z=0;Z<n.length;Z++){let K=n[Z],H=Z;Promise.resolve(c[K]()).catch(P=>U({type:"PROMISE_REJECTED",cause:P},{cause:{type:"PROMISE_REJECTION",reason:P}})).then(P=>{if(!J){if(!P.ok){J=!0,F([{key:K,result:P}]);return}N[H]={key:K,result:P},re--,re===0&&F(N)}})}});A();let _={};for(let{key:F,result:J}of p){if(!J.ok)throw r?.(J.error,F,g),q(J.error,{origin:"result",resultCause:J.cause});_[F]=J.value}return _}catch(p){throw A(),p}})()};var ke=ee,$=ae,V=me;let f=(c,y,n)=>(async()=>{if(typeof c!="string"||c.length===0)throw new Error('[awaitly] step() requires an explicit string ID as the first argument. Example: step("fetchUser", () => fetchUser(id))');let u=n??{},o=Je(u),k=c,h=u.key??c,A=u.key??c,{description:p,retry:_,timeout:F}=u,J=G(h),re=m,N=re?performance.now():0,K=fe(y)?()=>y:y,P={attempts:Math.max(1,_?.attempts??1),backoff:_?.backoff??Oe.backoff,initialDelay:_?.initialDelay??Oe.initialDelay,maxDelay:_?.maxDelay??Oe.maxDelay,jitter:_?.jitter??Oe.jitter,shouldRetry:_?.shouldRetry??Oe.shouldRetry,onRetry:_?.onRetry??Oe.onRetry};m&&l({type:"step_start",workflowId:i,stepId:J,stepKey:h,name:k,description:p,ts:Date.now(),...o&&{metadata:o}});let Re;for(let s=1;s<=P.attempts;s++){let w=re?performance.now():0;try{let E;if(F?E=await ar(K,F,{name:k,key:h,attempt:s},I):E=await K(),E.ok){let z=performance.now()-N;return l({type:"step_success",workflowId:i,stepId:J,stepKey:h,name:k,description:p,ts:Date.now(),durationMs:z,...o&&{metadata:o}}),A&&l({type:"step_complete",workflowId:i,stepKey:A,name:k,description:p,ts:Date.now(),durationMs:z,result:E,...o&&{metadata:o}}),E.value}if(Re=E,s<P.attempts&&P.shouldRetry(E.error,s)){let z=He(s,P);l({type:"step_retry",workflowId:i,stepId:J,stepKey:h,name:k,ts:Date.now(),attempt:s+1,maxAttempts:P.attempts,delayMs:z,error:E.error,...o&&{metadata:o},diagnostics:ge(E.error,u.errorMeta,"result",s,performance.now()-N)}),P.onRetry(E.error,s,z),await qe(z);continue}P.attempts>1&&l({type:"step_retries_exhausted",workflowId:i,stepId:J,stepKey:h,name:k,ts:Date.now(),durationMs:performance.now()-N,attempts:s,lastError:E.error,...o&&{metadata:o},diagnostics:ge(E.error,u.errorMeta,"result",s,performance.now()-N)});break}catch(E){let z=performance.now()-w;if(sr(E)){let C=E.ms;l({type:"step_timeout",workflowId:i,stepId:J,stepKey:h,name:k,ts:Date.now(),timeoutMs:C,attempt:s,...o&&{metadata:o},diagnostics:ge(E,u.errorMeta,"timeout",s)}),l({type:"step_success",workflowId:i,stepId:J,stepKey:h,name:k,description:p,ts:Date.now(),durationMs:performance.now()-N,...o&&{metadata:o}}),A&&l({type:"step_complete",workflowId:i,stepKey:A,name:k,description:p,ts:Date.now(),durationMs:performance.now()-N,result:X(void 0),...o&&{metadata:o}});return}if(Q(E))throw l({type:"step_aborted",workflowId:i,stepId:J,stepKey:h,name:k,description:p,ts:Date.now(),durationMs:z,...o&&{metadata:o}}),E;if(Tt(E)){let C=nr(E),D=F?.ms??C?.timeoutMs??0;if(l({type:"step_timeout",workflowId:i,stepId:J,stepKey:h,name:k,ts:Date.now(),timeoutMs:D,attempt:s,...o&&{metadata:o},diagnostics:ge(E,u.errorMeta,"timeout",s)}),s<P.attempts&&P.shouldRetry(E,s)){let j=He(s,P);l({type:"step_retry",workflowId:i,stepId:J,stepKey:h,name:k,ts:Date.now(),attempt:s+1,maxAttempts:P.attempts,delayMs:j,error:E,...o&&{metadata:o},diagnostics:ge(E,u.errorMeta,"timeout",s,performance.now()-N)}),P.onRetry(E,s,j),await qe(j);continue}P.attempts>1&&l({type:"step_retries_exhausted",workflowId:i,stepId:J,stepKey:h,name:k,ts:Date.now(),durationMs:performance.now()-N,attempts:s,lastError:E,...o&&{metadata:o},diagnostics:ge(E,u.errorMeta,"timeout",s,performance.now()-N)});let O=performance.now()-N;throw l({type:"step_error",workflowId:i,stepId:J,stepKey:h,name:k,description:p,ts:Date.now(),durationMs:O,error:E,...o&&{metadata:o},diagnostics:ge(E,u.errorMeta,"timeout",s,O)}),A&&l({type:"step_complete",workflowId:i,stepKey:A,name:k,description:p,ts:Date.now(),durationMs:O,result:U(E,{cause:E}),meta:{origin:"throw",thrown:E},...o&&{metadata:o}}),r?.(E,k,g),q(E,{origin:"throw",thrown:E})}if(s<P.attempts&&P.shouldRetry(E,s)){let C=He(s,P);l({type:"step_retry",workflowId:i,stepId:J,stepKey:h,name:k,ts:Date.now(),attempt:s+1,maxAttempts:P.attempts,delayMs:C,error:E,...o&&{metadata:o},diagnostics:ge(E,u.errorMeta,"throw",s,performance.now()-N)}),P.onRetry(E,s,C),await qe(C);continue}P.attempts>1&&!Tt(E)&&l({type:"step_retries_exhausted",workflowId:i,stepId:J,stepKey:h,name:k,ts:Date.now(),durationMs:performance.now()-N,attempts:s,lastError:E,...o&&{metadata:o},diagnostics:ge(E,u.errorMeta,"throw",s,performance.now()-N)});let T=performance.now()-N,v;try{v=Y(E)}catch(C){throw Ae(C)}throw l({type:"step_error",workflowId:i,stepId:J,stepKey:h,name:k,description:p,ts:Date.now(),durationMs:T,error:v,...o&&{metadata:o},diagnostics:ge(E,u.errorMeta,"throw",s,T)}),A&&l({type:"step_complete",workflowId:i,stepKey:A,name:k,description:p,ts:Date.now(),durationMs:T,result:U(v,{cause:E}),meta:{origin:"throw",thrown:E},...o&&{metadata:o}}),r?.(v,k,g),q(v,{origin:"throw",thrown:E})}}let Te=Re,ce=performance.now()-N,he=W(Te.error,{origin:"result",resultCause:Te.cause});throw l({type:"step_error",workflowId:i,stepId:J,stepKey:h,name:k,description:p,ts:Date.now(),durationMs:ce,error:he,...o&&{metadata:o},diagnostics:ge(Te.error,u.errorMeta,"result",P.attempts,ce)}),A&&l({type:"step_complete",workflowId:i,stepKey:A,name:k,description:p,ts:Date.now(),durationMs:ce,result:Te,meta:{origin:"result",resultCause:Te.cause},...o&&{metadata:o}}),r?.(he,k,g),q(he,{origin:"result",resultCause:Te.cause})})();f.try=(c,y,n)=>{if(typeof c!="string"||c.length===0)throw new Error('[awaitly] step.try() requires an explicit string ID as the first argument. Example: step.try("parse", () => JSON.parse(str), { error: "PARSE_ERROR" })');let u="error"in n?()=>n.error:n.onError;if(n.retry||n.timeout)return f.retry(c,async()=>{try{return X(await y())}catch(p){return U(u(p),{cause:p})}},{attempts:n.retry?.attempts??1,...n.retry??{},key:n.key,timeout:n.timeout});let o=n.key??c,k=c,h=c,A=m;return(async()=>{let p=A?performance.now():0;m&&l({type:"step_start",workflowId:i,stepId:h,stepKey:o,name:k,ts:Date.now()});try{let _=await y(),F=performance.now()-p;return l({type:"step_success",workflowId:i,stepId:h,stepKey:o,name:k,ts:Date.now(),durationMs:F}),o&&l({type:"step_complete",workflowId:i,stepKey:o,name:k,ts:Date.now(),durationMs:F,result:X(_)}),_}catch(_){let F=u(_),J=performance.now()-p,re=W(F,{origin:"throw",thrown:_});throw l({type:"step_error",workflowId:i,stepId:h,stepKey:o,name:k,ts:Date.now(),durationMs:J,error:re}),o&&l({type:"step_complete",workflowId:i,stepKey:o,name:k,ts:Date.now(),durationMs:J,result:U(F,{cause:_}),meta:{origin:"throw",thrown:_}}),r?.(re,k,g),q(re,{origin:"throw",thrown:_})}})()},f.fromResult=(c,y,n)=>{if(typeof c!="string"||c.length===0)throw new Error('[awaitly] step.fromResult() requires an explicit string ID as the first argument. Example: step.fromResult("callProvider", () => callProvider(input), { onError: (e) => ({ type: "FAILED" }) })');let u=n.key??c,o=c,k=c,h="error"in n?()=>n.error:n.onError,A=m;return(async()=>{let p=A?performance.now():0;m&&l({type:"step_start",workflowId:i,stepId:k,stepKey:u,name:o,ts:Date.now()});let _=await y();if(_.ok){let F=performance.now()-p;return l({type:"step_success",workflowId:i,stepId:k,stepKey:u,name:o,ts:Date.now(),durationMs:F}),u&&l({type:"step_complete",workflowId:i,stepKey:u,name:o,ts:Date.now(),durationMs:F,result:X(_.value)}),_.value}else{let F=h(_.error),J=performance.now()-p,re=W(F,{origin:"result",resultCause:_.error});throw l({type:"step_error",workflowId:i,stepId:k,stepKey:u,name:o,ts:Date.now(),durationMs:J,error:re}),u&&l({type:"step_complete",workflowId:i,stepKey:u,name:o,ts:Date.now(),durationMs:J,result:U(F,{cause:_.error}),meta:{origin:"result",resultCause:_.error}}),r?.(re,o,g),q(re,{origin:"result",resultCause:_.error})}})()},f.fromNullable=(c,y,n,u)=>{if(typeof c!="string"||c.length===0)throw new Error('[awaitly] step.fromNullable() requires an explicit string ID as the first argument. Example: step.fromNullable("getUser", () => db.find(id), () => ({ type: "NOT_FOUND" }))');return f(c,async()=>{let o=await y();return o!=null?X(o):U(n())},u)},f.retry=(c,y,n)=>{if(typeof c!="string"||c.length===0)throw new Error('[awaitly] step.retry() requires an explicit string ID as the first argument. Example: step.retry("fetchData", () => fetchData(), { attempts: 3 })');return f(c,y,{key:n.key??c,retry:{attempts:n.attempts,backoff:n.backoff,initialDelay:n.initialDelay,maxDelay:n.maxDelay,jitter:n.jitter,shouldRetry:n.shouldRetry,onRetry:n.onRetry},timeout:n.timeout})},f.withTimeout=(c,y,n)=>{if(typeof c!="string"||c.length===0)throw new Error('[awaitly] step.withTimeout() requires an explicit string ID as the first argument. Example: step.withTimeout("slowOp", () => slowOp(), { ms: 5000 })');return f(c,y,{key:n.key??c,timeout:n})},f.sleep=(c,y,n)=>{if(typeof c!="string"||c.length===0)throw new Error('[awaitly] step.sleep() requires an explicit string ID as the first argument. Example: step.sleep("delay", "5s")');let u=typeof y=="string"?er(y):y;if(!u)throw new Error(`step.sleep: invalid duration '${y}'`);let o=u.millis,k=n?.signal;return f(c,async()=>{if(I?.aborted||k?.aborted){let h=new Error("Sleep aborted");throw h.name="AbortError",h}return new Promise((h,A)=>{let p={timeoutId:void 0},_=()=>{p.timeoutId&&clearTimeout(p.timeoutId);let F=new Error("Sleep aborted");F.name="AbortError",A(F)};I?.addEventListener("abort",_,{once:!0}),k?.addEventListener("abort",_,{once:!0}),p.timeoutId=setTimeout(()=>{I?.removeEventListener("abort",_),k?.removeEventListener("abort",_),h(X(void 0))},o)})},{key:n?.key??c,description:n?.description})},f.all=((...c)=>{if(typeof c[0]!="string")throw new TypeError("step.all(name, ...): first argument must be a string (step name). Example: step.all('Fetch data', { user: () => fetchUser(), posts: () => fetchPosts() })");let y=c[0],n=c[1];if(typeof n=="function")return ae(y,n);if(n&&typeof n=="object"&&!Array.isArray(n)){let o=ee(n);return me(o,{name:y})}throw new TypeError("step.all(name, ...): second argument must be a function (array form) or an object of operations (object form).")}),f.race=(c,y)=>{let n=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let u=performance.now(),o=!1,k={scopeId:n,type:"race",winnerId:void 0};b.push(k);let h=()=>{if(o)return;o=!0;let A=b.findIndex(p=>p.scopeId===n);A!==-1&&b.splice(A,1),l({type:"scope_end",workflowId:i,scopeId:n,ts:Date.now(),durationMs:performance.now()-u,winnerId:k.winnerId})};l({type:"scope_start",workflowId:i,scopeId:n,scopeType:"race",name:c,ts:Date.now()});try{let A=await y();if(h(),!A.ok)throw r?.(A.error,c,g),q(A.error,{origin:"result",resultCause:A.cause});return A.value}catch(A){throw h(),A}})()},f.if=(c,y,n)=>n(),f.label=f.if,f.branch=async(c,y)=>{let{condition:n,then:u,else:o}=y;if(n())return await u();if(o)return await o()},f.arm=(c,y)=>({fn:c,errors:y}),f.forEach=async(c,y,n)=>{let u=[],o=n.maxIterations,k=0,h="run"in n,A=Symbol.asyncIterator in y?y:(async function*(){yield*y})();for await(let p of A){if(o!==void 0&&k>=o)break;let _;h?_=await n.run(p,k):_=await n.item.handler(p,k,f),u.push(_),k++}return u},f.item=c=>({__forEachItemHandler:!0,handler:c}),f.dep=(c,y)=>y,f.workflow=(c,y,n)=>f(c,y,n),f.map=async(c,y,n,u)=>{let o=u?.concurrency??y.length;return f(c,()=>o>=y.length?xt(y.map((k,h)=>n(k,h))):(async()=>{let k=[];for(let h=0;h<y.length;h+=o){let A=y.slice(h,h+o),p=await xt(A.map((_,F)=>n(_,h+F)));if(!p.ok)return p;k.push(...p.value)}return X(k)})(),{key:u?.key})},f.withFallback=(c,y,n)=>{if(typeof c!="string"||c.length===0)throw new Error('[awaitly] step.withFallback() requires an explicit string ID as the first argument. Example: step.withFallback("getUser", () => fetchUser(id), { fallback: () => fetchFromCache(id) })');let u=n.key??c,o=c,k=G(u),h=m;return(async()=>{let A=h?performance.now():0;m&&l({type:"step_start",workflowId:i,stepId:k,stepKey:u,name:o,ts:Date.now()});let p;try{p=await y()}catch(N){if(Q(N))throw l({type:"step_aborted",workflowId:i,stepId:k,stepKey:u,name:o,ts:Date.now(),durationMs:performance.now()-A}),N;let Z;try{Z=Y(N)}catch(H){throw Ae(H)}if(n.on!==void 0&&n.on!==Z){let H=performance.now()-A;throw l({type:"step_error",workflowId:i,stepId:k,stepKey:u,name:o,ts:Date.now(),durationMs:H,error:Z}),u&&l({type:"step_complete",workflowId:i,stepKey:u,name:o,ts:Date.now(),durationMs:H,result:U(Z,{cause:N}),meta:{origin:"throw",thrown:N}}),r?.(Z,o,g),q(Z,{origin:"throw",thrown:N})}let K;try{K=await n.fallback()}catch(H){if(Q(H))throw l({type:"step_aborted",workflowId:i,stepId:k,stepKey:u,name:o,ts:Date.now(),durationMs:performance.now()-A}),H;let P;try{P=Y(H)}catch(Te){throw Ae(Te)}let Re=performance.now()-A;throw l({type:"step_error",workflowId:i,stepId:k,stepKey:u,name:o,ts:Date.now(),durationMs:Re,error:P}),u&&l({type:"step_complete",workflowId:i,stepKey:u,name:o,ts:Date.now(),durationMs:Re,result:U(P,{cause:H}),meta:{origin:"throw",thrown:H}}),r?.(P,o,g),q(P,{origin:"throw",thrown:H})}if(K.ok){let H=performance.now()-A;return l({type:"step_success",workflowId:i,stepId:k,stepKey:u,name:o,ts:Date.now(),durationMs:H}),u&&l({type:"step_complete",workflowId:i,stepKey:u,name:o,ts:Date.now(),durationMs:H,result:K,meta:{origin:"fallback",fallbackUsed:!0,fallbackReason:String(Z)}}),K.value}else{let H=performance.now()-A,P=W(K.error,{origin:"result",resultCause:K.cause});throw l({type:"step_error",workflowId:i,stepId:k,stepKey:u,name:o,ts:Date.now(),durationMs:H,error:P}),u&&l({type:"step_complete",workflowId:i,stepKey:u,name:o,ts:Date.now(),durationMs:H,result:K,meta:{origin:"result",resultCause:K.cause}}),r?.(P,o,g),q(P,{origin:"result",resultCause:K.cause})}}if(p.ok){let N=performance.now()-A;return l({type:"step_success",workflowId:i,stepId:k,stepKey:u,name:o,ts:Date.now(),durationMs:N}),u&&l({type:"step_complete",workflowId:i,stepKey:u,name:o,ts:Date.now(),durationMs:N,result:p}),p.value}let _=p.error;if(n.on!==void 0&&n.on!==_){let N=performance.now()-A,Z=W(_,{origin:"result",resultCause:p.cause});throw l({type:"step_error",workflowId:i,stepId:k,stepKey:u,name:o,ts:Date.now(),durationMs:N,error:Z}),u&&l({type:"step_complete",workflowId:i,stepKey:u,name:o,ts:Date.now(),durationMs:N,result:p,meta:{origin:"result",resultCause:p.cause}}),r?.(Z,o,g),q(Z,{origin:"result",resultCause:p.cause})}let F;try{F=await n.fallback()}catch(N){if(Q(N))throw l({type:"step_aborted",workflowId:i,stepId:k,stepKey:u,name:o,ts:Date.now(),durationMs:performance.now()-A}),N;let Z;try{Z=Y(N)}catch(H){throw Ae(H)}let K=performance.now()-A;throw l({type:"step_error",workflowId:i,stepId:k,stepKey:u,name:o,ts:Date.now(),durationMs:K,error:Z}),u&&l({type:"step_complete",workflowId:i,stepKey:u,name:o,ts:Date.now(),durationMs:K,result:U(Z,{cause:N}),meta:{origin:"throw",thrown:N}}),r?.(Z,o,g),q(Z,{origin:"throw",thrown:N})}if(F.ok){let N=performance.now()-A;return l({type:"step_success",workflowId:i,stepId:k,stepKey:u,name:o,ts:Date.now(),durationMs:N}),u&&l({type:"step_complete",workflowId:i,stepKey:u,name:o,ts:Date.now(),durationMs:N,result:F,meta:{origin:"fallback",fallbackUsed:!0,fallbackReason:String(_)}}),F.value}let J=performance.now()-A,re=W(F.error,{origin:"result",resultCause:F.cause});throw l({type:"step_error",workflowId:i,stepId:k,stepKey:u,name:o,ts:Date.now(),durationMs:J,error:re}),u&&l({type:"step_complete",workflowId:i,stepKey:u,name:o,ts:Date.now(),durationMs:J,result:F,meta:{origin:"result",resultCause:F.cause}}),r?.(re,o,g),q(re,{origin:"result",resultCause:F.cause})})()},f.withResource=(c,y)=>{if(typeof c!="string"||c.length===0)throw new Error('[awaitly] step.withResource() requires an explicit string ID as the first argument. Example: step.withResource("useDb", { acquire: () => connect(), use: (db) => query(db), release: (db) => db.close() })');let n=c,u=c,o=G(n),k=m;return(async()=>{let h=k?performance.now():0;m&&l({type:"step_start",workflowId:i,stepId:o,stepKey:n,name:u,ts:Date.now()});let A;try{A=await y.acquire()}catch(K){if(Q(K))throw l({type:"step_aborted",workflowId:i,stepId:o,stepKey:n,name:u,ts:Date.now(),durationMs:performance.now()-h}),K;let H;try{H=Y(K)}catch(Re){throw Ae(Re)}let P=performance.now()-h;throw l({type:"step_error",workflowId:i,stepId:o,stepKey:n,name:u,ts:Date.now(),durationMs:P,error:H}),n&&l({type:"step_complete",workflowId:i,stepKey:n,name:u,ts:Date.now(),durationMs:P,result:U(H,{cause:K}),meta:{origin:"throw",thrown:K}}),r?.(H,u,g),q(H,{origin:"throw",thrown:K})}if(!A.ok){let K=performance.now()-h,H=W(A.error,{origin:"result",resultCause:A.cause});throw l({type:"step_error",workflowId:i,stepId:o,stepKey:n,name:u,ts:Date.now(),durationMs:K,error:H}),n&&l({type:"step_complete",workflowId:i,stepKey:n,name:u,ts:Date.now(),durationMs:K,result:A,meta:{origin:"result",resultCause:A.cause}}),r?.(H,u,g),q(H,{origin:"result",resultCause:A.cause})}let p=A.value,_,F,J=!1;try{_=await y.use(p)}catch(K){if(Q(K)){try{await y.release(p)}catch(H){console.warn(`[awaitly] step.withResource("${c}"): release threw after earlyExit:`,H)}throw K}F=K,J=!0}try{await y.release(p)}catch(K){console.warn(`[awaitly] step.withResource("${c}"): release threw:`,K)}if(J){let K;try{K=Y(F)}catch(P){throw Ae(P)}let H=performance.now()-h;throw l({type:"step_error",workflowId:i,stepId:o,stepKey:n,name:u,ts:Date.now(),durationMs:H,error:K}),n&&l({type:"step_complete",workflowId:i,stepKey:n,name:u,ts:Date.now(),durationMs:H,result:U(K,{cause:F}),meta:{origin:"throw",thrown:F}}),r?.(K,u,g),q(K,{origin:"throw",thrown:F})}let re=_;if(re.ok){let K=performance.now()-h;return l({type:"step_success",workflowId:i,stepId:o,stepKey:n,name:u,ts:Date.now(),durationMs:K}),n&&l({type:"step_complete",workflowId:i,stepKey:n,name:u,ts:Date.now(),durationMs:K,result:re}),re.value}let N=performance.now()-h,Z=W(re.error,{origin:"result",resultCause:re.cause});throw l({type:"step_error",workflowId:i,stepId:o,stepKey:n,name:u,ts:Date.now(),durationMs:N,error:Z}),n&&l({type:"step_complete",workflowId:i,stepKey:n,name:u,ts:Date.now(),durationMs:N,result:re,meta:{origin:"result",resultCause:re.cause}}),r?.(Z,u,g),q(Z,{origin:"result",resultCause:re.cause})})()};let le=await e({step:f});if(process.env.NODE_ENV!=="production"&&le!==null&&typeof le=="object"&&"ok"in le&&typeof le.ok=="boolean"){let c=le;(c.ok===!0&&"value"in c||c.ok===!1&&"error"in c)&&console.warn(`awaitly: Workflow executor returned a Result-like object. Return raw values, not ok() or err().
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/testing-entry.ts
21
+ var testing_entry_exports = {};
22
+ __export(testing_entry_exports, {
23
+ assertEventEmitted: () => assertEventEmitted,
24
+ assertEventNotEmitted: () => assertEventNotEmitted,
25
+ assertEventSequence: () => assertEventSequence,
26
+ compareSnapshots: () => compareSnapshots,
27
+ createMockFn: () => createMockFn,
28
+ createSagaHarness: () => createSagaHarness,
29
+ createSnapshot: () => createSnapshot,
30
+ createTestClock: () => createTestClock,
31
+ createWorkflowHarness: () => createWorkflowHarness,
32
+ errOutcome: () => errOutcome,
33
+ expectErr: () => expectErr,
34
+ expectOk: () => expectOk,
35
+ formatEvent: () => formatEvent,
36
+ formatEvents: () => formatEvents,
37
+ formatResult: () => formatResult,
38
+ okOutcome: () => okOutcome,
39
+ testWorkflow: () => testWorkflow,
40
+ throwOutcome: () => throwOutcome,
41
+ unwrapErr: () => unwrapErr,
42
+ unwrapErrAsync: () => unwrapErrAsync,
43
+ unwrapOk: () => unwrapOk,
44
+ unwrapOkAsync: () => unwrapOkAsync
45
+ });
46
+ module.exports = __toCommonJS(testing_entry_exports);
47
+
48
+ // src/slugs.ts
49
+ var AWAITLY_SLUGS = {
50
+ // --- step-* ---
51
+ "step-require-id": "step-require-id",
52
+ "step-no-immediate-execution": "step-no-immediate-execution",
53
+ "step-require-thunk-for-key": "step-require-thunk-for-key",
54
+ "step-no-bare-await": "step-no-bare-await",
55
+ "step-no-try-catch-wrap": "step-no-try-catch-wrap",
56
+ "step-stable-cache-keys": "step-stable-cache-keys",
57
+ // --- workflow-* ---
58
+ "workflow-no-floating": "workflow-no-floating",
59
+ "workflow-options-position": "workflow-options-position",
60
+ "workflow-callback-shape": "workflow-callback-shape",
61
+ "workflow-no-callable-form": "workflow-no-callable-form",
62
+ "workflow-no-dynamic-import": "workflow-no-dynamic-import",
63
+ "workflow-prefer-step-if": "workflow-prefer-step-if",
64
+ "workflow-prefer-step-foreach": "workflow-prefer-step-foreach",
65
+ // --- result-* ---
66
+ "result-no-floating": "result-no-floating",
67
+ "result-require-handling": "result-require-handling",
68
+ "result-no-double-wrap": "result-no-double-wrap",
69
+ "result-no-manual-propagation": "result-no-manual-propagation",
70
+ "result-no-direct-ok-err": "result-no-direct-ok-err",
71
+ // --- error-* ---
72
+ "error-check-unexpected-first": "error-check-unexpected-first",
73
+ "error-access-cause": "error-access-cause",
74
+ "error-normalize": "error-normalize",
75
+ "error-no-throw-in-deps": "error-no-throw-in-deps",
76
+ // --- concurrency-* ---
77
+ "concurrency-no-promise-all": "concurrency-no-promise-all",
78
+ "concurrency-no-promise-race": "concurrency-no-promise-race",
79
+ "concurrency-no-promise-allsettled": "concurrency-no-promise-allsettled",
80
+ // --- runtime-* ---
81
+ "runtime-step-timeout": "runtime-step-timeout",
82
+ "runtime-step-aborted": "runtime-step-aborted",
83
+ "runtime-retry-exhausted": "runtime-retry-exhausted",
84
+ "runtime-rate-limit": "runtime-rate-limit",
85
+ "runtime-circuit-open": "runtime-circuit-open",
86
+ "runtime-unexpected": "runtime-unexpected",
87
+ "runtime-resolver-not-found": "runtime-resolver-not-found",
88
+ "runtime-saga-compensation": "runtime-saga-compensation"
89
+ };
90
+ function slugDocsUrl(slug) {
91
+ return `https://jagreehal.github.io/awaitly/rules/#${slug}`;
92
+ }
93
+ var ALL_SLUGS = Object.keys(
94
+ AWAITLY_SLUGS
95
+ );
96
+
97
+ // src/tagged-error.ts
98
+ var InternalTaggedErrorBase = class extends Error {
99
+ type;
100
+ /** @deprecated Use `type`. */
101
+ _tag;
102
+ };
103
+ function TaggedError(tag, options) {
104
+ return class extends InternalTaggedErrorBase {
105
+ type = tag;
106
+ /** @deprecated Use `type`. */
107
+ _tag = tag;
108
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
109
+ constructor(props, errorOptions) {
110
+ const message = options?.message ? options.message(props ?? {}) : tag;
111
+ super(message);
112
+ this.name = tag;
113
+ if (options?.slug !== void 0) {
114
+ if (!options.hint) {
115
+ throw new TypeError(
116
+ `TaggedError: 'hint' is required when 'slug' is set (slug: "${options.slug}")`
117
+ );
118
+ }
119
+ Object.defineProperty(this, "code", {
120
+ value: options.slug,
121
+ enumerable: true,
122
+ writable: false,
123
+ configurable: false
124
+ });
125
+ Object.defineProperty(this, "hint", {
126
+ value: options.hint,
127
+ enumerable: true,
128
+ writable: false,
129
+ configurable: false
130
+ });
131
+ Object.defineProperty(this, "docsUrl", {
132
+ value: slugDocsUrl(options.slug),
133
+ enumerable: true,
134
+ writable: false,
135
+ configurable: false
136
+ });
137
+ }
138
+ Object.setPrototypeOf(this, new.target.prototype);
139
+ if (props && typeof props === "object") {
140
+ let safeProps;
141
+ if (options?.slug !== void 0) {
142
+ const {
143
+ _tag: _,
144
+ type: _t,
145
+ name: _n,
146
+ message: _m,
147
+ stack: _s,
148
+ code: _c,
149
+ hint: _h,
150
+ docsUrl: _d,
151
+ ...rest
152
+ } = props;
153
+ safeProps = rest;
154
+ } else {
155
+ const {
156
+ _tag: _,
157
+ type: _t,
158
+ name: _n,
159
+ message: _m,
160
+ stack: _s,
161
+ ...rest
162
+ } = props;
163
+ safeProps = rest;
164
+ }
165
+ const hasUserCause = Object.prototype.hasOwnProperty.call(
166
+ safeProps,
167
+ "cause"
168
+ );
169
+ const userCause = hasUserCause ? safeProps.cause : void 0;
170
+ if (hasUserCause) {
171
+ delete safeProps.cause;
172
+ }
173
+ const hasOptionsCause = errorOptions?.cause !== void 0;
174
+ if (hasUserCause && hasOptionsCause) {
175
+ throw new TypeError(
176
+ "TaggedError: cannot provide 'cause' in props when also setting ErrorOptions.cause"
177
+ );
178
+ }
179
+ Object.assign(this, safeProps);
180
+ if (hasUserCause) {
181
+ this.cause = userCause;
182
+ }
183
+ if (hasOptionsCause) {
184
+ this.cause = errorOptions?.cause;
185
+ }
186
+ } else if (errorOptions?.cause !== void 0) {
187
+ this.cause = errorOptions.cause;
188
+ }
189
+ }
190
+ };
191
+ }
192
+ Object.defineProperty(TaggedError, Symbol.hasInstance, {
193
+ value: (instance) => instance instanceof InternalTaggedErrorBase
194
+ });
195
+ ((TaggedError2) => {
196
+ function isError(value) {
197
+ return value instanceof Error;
198
+ }
199
+ TaggedError2.isError = isError;
200
+ function isTaggedError(value) {
201
+ return value instanceof InternalTaggedErrorBase;
202
+ }
203
+ TaggedError2.isTaggedError = isTaggedError;
204
+ function match(error, handlers) {
205
+ const tag = error._tag;
206
+ const handler = handlers[tag];
207
+ return handler(
208
+ error
209
+ );
210
+ }
211
+ TaggedError2.match = match;
212
+ function matchPartial(error, handlers, otherwise) {
213
+ const tag = error._tag;
214
+ const handler = handlers[tag];
215
+ if (handler) {
216
+ return handler(
217
+ error
218
+ );
219
+ }
220
+ return otherwise(error);
221
+ }
222
+ TaggedError2.matchPartial = matchPartial;
223
+ })(TaggedError || (TaggedError = {}));
224
+
225
+ // src/errors.ts
226
+ var UnexpectedError = class extends (/* @__PURE__ */ TaggedError("UnexpectedError", {
227
+ slug: "runtime-unexpected",
228
+ hint: "An unexpected exception escaped a step. Inspect cause; consider returning a typed Result instead of throwing.",
229
+ message: (p) => `UnexpectedError: ${p.cause instanceof Error ? p.cause.message : String(p.cause ?? "unknown")}`
230
+ })) {
231
+ };
232
+
233
+ // src/result/index.ts
234
+ function ok(value) {
235
+ return { ok: true, value };
236
+ }
237
+
238
+ // src/core/bound-steps.ts
239
+ var isDepResultShaped = (value) => typeof value === "object" && value !== null && "ok" in value && typeof value.ok === "boolean" && (value.ok ? "value" in value : "error" in value);
240
+ var bindSteps = (deps, step) => {
241
+ const steps = {};
242
+ const invocationCounts = /* @__PURE__ */ new Map();
243
+ for (const key of Object.keys(deps)) {
244
+ const dep = deps[key];
245
+ if (typeof dep !== "function") continue;
246
+ steps[key] = (...args) => {
247
+ const count = (invocationCounts.get(key) ?? 0) + 1;
248
+ invocationCounts.set(key, count);
249
+ const stepKey = count === 1 ? key : `${key}#${count}`;
250
+ return step(stepKey, async () => {
251
+ const value = await dep(...args);
252
+ return isDepResultShaped(value) ? value : ok(value);
253
+ });
254
+ };
255
+ }
256
+ return steps;
257
+ };
258
+
259
+ // src/duration.ts
260
+ function millis(ms) {
261
+ return { _tag: "Duration", millis: ms };
262
+ }
263
+ function seconds(s) {
264
+ return { _tag: "Duration", millis: s * 1e3 };
265
+ }
266
+ function minutes(m) {
267
+ return { _tag: "Duration", millis: m * 60 * 1e3 };
268
+ }
269
+ function hours(h) {
270
+ return { _tag: "Duration", millis: h * 60 * 60 * 1e3 };
271
+ }
272
+ function days(d) {
273
+ return { _tag: "Duration", millis: d * 24 * 60 * 60 * 1e3 };
274
+ }
275
+ function toMillis(duration) {
276
+ return duration.millis;
277
+ }
278
+ function parse(input) {
279
+ const match = input.trim().match(/^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)$/i);
280
+ if (!match) return void 0;
281
+ const value = parseFloat(match[1]);
282
+ const unit = match[2].toLowerCase();
283
+ switch (unit) {
284
+ case "ms":
285
+ return millis(value);
286
+ case "s":
287
+ return seconds(value);
288
+ case "m":
289
+ return minutes(value);
290
+ case "h":
291
+ return hours(value);
292
+ case "d":
293
+ return days(value);
294
+ default:
295
+ return void 0;
296
+ }
297
+ }
298
+
299
+ // src/core/index.ts
300
+ function parseDurationString(input) {
301
+ const match = input.trim().match(/^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)$/i);
302
+ if (!match) return void 0;
303
+ const value = parseFloat(match[1]);
304
+ const unit = match[2].toLowerCase();
305
+ const multipliers = { ms: 1, s: 1e3, m: 6e4, h: 36e5, d: 864e5 };
306
+ return { _tag: "Duration", millis: value * (multipliers[unit] ?? 1) };
307
+ }
308
+ function defaultCatchUnexpected(cause) {
309
+ return new UnexpectedError({ cause });
310
+ }
311
+ function ok2(value) {
312
+ return { ok: true, value };
313
+ }
314
+ function err(error, options) {
315
+ const cause = options?.cause;
316
+ return { ok: false, error, ...cause !== void 0 ? { cause } : {} };
317
+ }
318
+ var isOk = (r) => r.ok;
319
+ var isUnexpectedError = (e) => e instanceof UnexpectedError || typeof e === "object" && e !== null && "_tag" in e && e._tag === "UnexpectedError";
320
+ function extractErrorTag(error) {
321
+ if (error == null) return "unknown";
322
+ if (typeof error === "string") return error.trim() || "unknown";
323
+ if (typeof error === "object") {
324
+ const tagged = error;
325
+ if (typeof tagged._tag === "string") {
326
+ const trimmed = tagged._tag.trim();
327
+ if (trimmed) return trimmed;
328
+ }
329
+ if (typeof tagged.tag === "string") {
330
+ const trimmed = tagged.tag.trim();
331
+ if (trimmed) return trimmed;
332
+ }
333
+ if (typeof tagged.code === "string") {
334
+ const trimmed = tagged.code.trim();
335
+ if (trimmed) return trimmed;
336
+ } else if (typeof tagged.code === "number") {
337
+ return String(tagged.code);
338
+ }
339
+ if (error instanceof Error && error.name) {
340
+ const trimmed = error.name.trim();
341
+ if (trimmed) return trimmed;
342
+ }
343
+ }
344
+ return "unknown";
345
+ }
346
+ function lookupErrorClassification(tag, errorMeta) {
347
+ if (!errorMeta || !tag) return void 0;
348
+ return errorMeta[tag];
349
+ }
350
+ function extractStepMetadata(options) {
351
+ const { intent, domain, owner, tags, stateChanges, emits, calls } = options;
352
+ if (!intent && !domain && !owner && !tags?.length && !stateChanges?.length && !emits?.length && !calls?.length) {
353
+ return void 0;
354
+ }
355
+ const metadata = {};
356
+ if (intent) metadata.intent = intent;
357
+ if (domain) metadata.domain = domain;
358
+ if (owner) metadata.owner = owner;
359
+ if (tags?.length) metadata.tags = tags;
360
+ if (stateChanges?.length) metadata.stateChanges = stateChanges;
361
+ if (emits?.length) metadata.emits = emits;
362
+ if (calls?.length) metadata.calls = calls;
363
+ return metadata;
364
+ }
365
+ function buildStepErrorPayload(error, errorMeta, origin, attempt, cumulativeDurationMs) {
366
+ const tag = extractErrorTag(error);
367
+ const classification = lookupErrorClassification(tag, errorMeta);
368
+ const diagnostics = { tag, origin };
369
+ if (classification !== void 0) diagnostics.classification = classification;
370
+ if (attempt !== void 0) diagnostics.attempt = attempt;
371
+ if (cumulativeDurationMs !== void 0) diagnostics.cumulativeDurationMs = cumulativeDurationMs;
372
+ return diagnostics;
373
+ }
374
+ var STEP_TIMEOUT_MARKER = /* @__PURE__ */ Symbol.for("step_timeout_marker");
375
+ function isStepTimeoutError(e) {
376
+ if (typeof e !== "object" || e === null) {
377
+ return false;
378
+ }
379
+ if (e.type === "STEP_TIMEOUT") {
380
+ return true;
381
+ }
382
+ return STEP_TIMEOUT_MARKER in e;
383
+ }
384
+ function getStepTimeoutMeta(e) {
385
+ if (typeof e !== "object" || e === null) {
386
+ return void 0;
387
+ }
388
+ if (e.type === "STEP_TIMEOUT") {
389
+ const err2 = e;
390
+ return {
391
+ timeoutMs: err2.timeoutMs,
392
+ stepName: err2.stepName,
393
+ stepKey: err2.stepKey,
394
+ attempt: err2.attempt
395
+ };
396
+ }
397
+ if (STEP_TIMEOUT_MARKER in e) {
398
+ return e[STEP_TIMEOUT_MARKER];
399
+ }
400
+ return void 0;
401
+ }
402
+ var EARLY_EXIT_SYMBOL = /* @__PURE__ */ Symbol("early-exit");
403
+ function createEarlyExit(error, meta) {
404
+ return {
405
+ [EARLY_EXIT_SYMBOL]: true,
406
+ error,
407
+ meta
408
+ };
409
+ }
410
+ function isEarlyExit(e) {
411
+ return typeof e === "object" && e !== null && e[EARLY_EXIT_SYMBOL] === true;
412
+ }
413
+ var MAPPER_EXCEPTION_SYMBOL = /* @__PURE__ */ Symbol("mapper-exception");
414
+ function createMapperException(thrown) {
415
+ return { [MAPPER_EXCEPTION_SYMBOL]: true, thrown };
416
+ }
417
+ function isMapperException(e) {
418
+ return typeof e === "object" && e !== null && e[MAPPER_EXCEPTION_SYMBOL] === true;
419
+ }
420
+ function calculateRetryDelay(attempt, options) {
421
+ const { backoff, initialDelay, maxDelay, jitter } = options;
422
+ let delay;
423
+ switch (backoff) {
424
+ case "fixed":
425
+ delay = initialDelay;
426
+ break;
427
+ case "linear":
428
+ delay = initialDelay * attempt;
429
+ break;
430
+ case "exponential":
431
+ delay = initialDelay * Math.pow(2, attempt - 1);
432
+ break;
433
+ }
434
+ delay = Math.min(delay, maxDelay);
435
+ if (jitter) {
436
+ const jitterAmount = delay * 0.25 * Math.random();
437
+ delay = delay + jitterAmount;
438
+ }
439
+ return Math.floor(delay);
440
+ }
441
+ function sleep(ms) {
442
+ return new Promise((resolve) => setTimeout(resolve, ms));
443
+ }
444
+ var TIMEOUT_SYMBOL = /* @__PURE__ */ Symbol("timeout");
445
+ var TIMEOUT_OPTION_SYMBOL = /* @__PURE__ */ Symbol("timeout-option");
446
+ function isTimeoutOptionMarker(value) {
447
+ return typeof value === "object" && value !== null && value[TIMEOUT_OPTION_SYMBOL] === true;
448
+ }
449
+ async function executeWithTimeout(operation, options, stepInfo, externalSignal) {
450
+ const controller = new AbortController();
451
+ const behavior = options.onTimeout ?? "error";
452
+ const createTimeoutError = () => {
453
+ if (typeof behavior === "function") {
454
+ return behavior({
455
+ name: stepInfo.name,
456
+ key: stepInfo.key,
457
+ ms: options.ms
458
+ });
459
+ }
460
+ return options.error ?? {
461
+ type: "STEP_TIMEOUT",
462
+ stepName: stepInfo.name,
463
+ stepKey: stepInfo.key,
464
+ timeoutMs: options.ms,
465
+ attempt: stepInfo.attempt
466
+ };
467
+ };
468
+ let timeoutId;
469
+ if (externalSignal?.aborted) {
470
+ controller.abort(externalSignal.reason);
471
+ }
472
+ let externalAbortHandler;
473
+ if (externalSignal && !externalSignal.aborted) {
474
+ externalAbortHandler = () => controller.abort(externalSignal.reason);
475
+ externalSignal.addEventListener("abort", externalAbortHandler, { once: true });
476
+ }
477
+ const timeoutPromise = new Promise((_, reject) => {
478
+ timeoutId = setTimeout(() => {
479
+ if (behavior !== "disconnect") {
480
+ controller.abort();
481
+ }
482
+ if (behavior === "option") {
483
+ reject({ [TIMEOUT_OPTION_SYMBOL]: true, ms: options.ms });
484
+ return;
485
+ }
486
+ reject({ [TIMEOUT_SYMBOL]: true, error: createTimeoutError() });
487
+ }, options.ms);
488
+ });
489
+ let operationPromise;
490
+ if (options.signal) {
491
+ operationPromise = Promise.resolve(
492
+ operation(controller.signal)
493
+ );
494
+ } else {
495
+ operationPromise = Promise.resolve(operation());
496
+ }
497
+ try {
498
+ const result = await Promise.race([operationPromise, timeoutPromise]);
499
+ return result;
500
+ } catch (error) {
501
+ if (typeof error === "object" && error !== null && error[TIMEOUT_OPTION_SYMBOL] === true) {
502
+ throw { [TIMEOUT_OPTION_SYMBOL]: true, ms: options.ms };
503
+ }
504
+ if (typeof error === "object" && error !== null && error[TIMEOUT_SYMBOL] === true) {
505
+ if (behavior === "disconnect") {
506
+ operationPromise.catch(() => {
507
+ });
508
+ }
509
+ const errorToThrow = error.error;
510
+ if (typeof errorToThrow === "object" && errorToThrow !== null && errorToThrow.type !== "STEP_TIMEOUT") {
511
+ const meta = {
512
+ timeoutMs: options.ms,
513
+ stepName: stepInfo.name,
514
+ stepKey: stepInfo.key,
515
+ attempt: stepInfo.attempt
516
+ };
517
+ if (STEP_TIMEOUT_MARKER in errorToThrow) {
518
+ errorToThrow[STEP_TIMEOUT_MARKER] = meta;
519
+ } else {
520
+ Object.defineProperty(errorToThrow, STEP_TIMEOUT_MARKER, {
521
+ value: meta,
522
+ enumerable: false,
523
+ writable: true,
524
+ configurable: false
525
+ });
526
+ }
527
+ }
528
+ throw errorToThrow;
529
+ }
530
+ throw error;
531
+ } finally {
532
+ clearTimeout(timeoutId);
533
+ if (externalAbortHandler && externalSignal) {
534
+ externalSignal.removeEventListener("abort", externalAbortHandler);
535
+ }
536
+ }
537
+ }
538
+ var DEFAULT_RETRY_CONFIG = {
539
+ backoff: "exponential",
540
+ initialDelay: 100,
541
+ maxDelay: 3e4,
542
+ jitter: true,
543
+ shouldRetry: () => true,
544
+ onRetry: () => {
545
+ }
546
+ };
547
+ async function runFn(fnOrDeps, optionsOrFn, maybeOptions) {
548
+ if (typeof fnOrDeps !== "function") {
549
+ const deps = fnOrDeps;
550
+ const boundFn = optionsOrFn;
551
+ if (typeof boundFn !== "function") {
552
+ throw new TypeError(
553
+ "[awaitly] run(deps, fn) requires a callback as the second argument. Example: run({ getUser }, async (s) => s.getUser(id))"
554
+ );
555
+ }
556
+ const classicRun = runFn;
557
+ return classicRun(
558
+ ({ step }) => boundFn(bindSteps(deps, step), { step }),
559
+ maybeOptions
560
+ );
561
+ }
562
+ const fn = fnOrDeps;
563
+ const options = optionsOrFn;
564
+ const {
565
+ onError,
566
+ onEvent,
567
+ catchUnexpected,
568
+ workflowId: providedWorkflowId,
569
+ workflowName,
570
+ context,
571
+ graph,
572
+ _workflowSignal
573
+ } = options && typeof options === "object" ? options : {};
574
+ const workflowId = providedWorkflowId ?? crypto.randomUUID();
575
+ const declaredIds = graph ? new Set(
576
+ Array.isArray(graph) ? graph : graph.states.map((state) => state.semanticId ?? state.id)
577
+ ) : void 0;
578
+ const declaredPatterns = declaredIds ? [...declaredIds].filter((id) => id.includes("{")).map(
579
+ (id) => new RegExp(
580
+ `^${id.replaceAll(/[.*+?^$()[\]\\|]/g, String.raw`\$&`).replaceAll(/\{[^}]*\}/g, ".+")}$`
581
+ )
582
+ ) : void 0;
583
+ const assertDeclared = (id, kind) => {
584
+ if (!declaredIds || declaredIds.has(id)) return;
585
+ if (declaredPatterns?.some((re) => re.test(id))) return;
586
+ throw new Error(
587
+ `[awaitly] ${kind} id "${id}" is not in the declared workflow graph. Declared ids: ${[...declaredIds].join(", ")}. Either add it to the graph or remove the graph option.`
588
+ );
589
+ };
590
+ const effectiveCatchUnexpected = catchUnexpected ?? defaultCatchUnexpected;
591
+ const activeScopeStack = [];
592
+ let stepIdCounter = 0;
593
+ const generateStepId = (stepKey) => {
594
+ return stepKey ?? `step_${++stepIdCounter}`;
595
+ };
596
+ const emitEvent = (event) => {
597
+ const eventWithContext = event.context !== void 0 || context === void 0 ? event : { ...event, context };
598
+ const eventWithName = workflowName !== void 0 && eventWithContext.workflowName === void 0 ? { ...eventWithContext, workflowName } : eventWithContext;
599
+ if (eventWithName.type === "step_success") {
600
+ const stepId = eventWithName.stepId;
601
+ for (let i = activeScopeStack.length - 1; i >= 0; i--) {
602
+ const scope = activeScopeStack[i];
603
+ if (scope.type === "race" && !scope.winnerId) {
604
+ scope.winnerId = stepId;
605
+ break;
606
+ }
607
+ }
608
+ }
609
+ onEvent?.(eventWithName, context);
610
+ };
611
+ const earlyExit = createEarlyExit;
612
+ const isEarlyExitE = (e) => isEarlyExit(e);
613
+ const wrapForStep = (error, _meta) => {
614
+ return error;
615
+ };
616
+ const isResultLike = (value) => {
617
+ if (typeof value === "function") return false;
618
+ if (value && typeof value === "object" && "ok" in value) return true;
619
+ if (value && typeof value === "object" && "then" in value && typeof value.then === "function") return true;
620
+ return false;
621
+ };
622
+ try {
623
+ let normalizeParallelOperations2 = function(rawOperations) {
624
+ const out = {};
625
+ for (const [key, value2] of Object.entries(rawOperations)) {
626
+ if (typeof value2 === "function") {
627
+ out[key] = value2;
628
+ } else if (value2 && typeof value2 === "object" && "fn" in value2) {
629
+ out[key] = value2.fn;
630
+ } else {
631
+ throw new TypeError(`step.all: operation "${key}" must be a function or { fn, errors? } object`);
632
+ }
633
+ }
634
+ return out;
635
+ }, executeParallelArray2 = function(name, operation) {
636
+ const scopeId = `scope_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
637
+ return (async () => {
638
+ const startTime = performance.now();
639
+ let scopeEnded = false;
640
+ activeScopeStack.push({ scopeId, type: "parallel" });
641
+ const emitScopeEnd = () => {
642
+ if (scopeEnded) return;
643
+ scopeEnded = true;
644
+ const idx = activeScopeStack.findIndex((s) => s.scopeId === scopeId);
645
+ if (idx !== -1) activeScopeStack.splice(idx, 1);
646
+ emitEvent({
647
+ type: "scope_end",
648
+ workflowId,
649
+ scopeId,
650
+ ts: Date.now(),
651
+ durationMs: performance.now() - startTime
652
+ });
653
+ };
654
+ emitEvent({
655
+ type: "scope_start",
656
+ workflowId,
657
+ scopeId,
658
+ scopeType: "parallel",
659
+ name,
660
+ ts: Date.now()
661
+ });
662
+ try {
663
+ const result = await operation();
664
+ emitScopeEnd();
665
+ if (!result.ok) {
666
+ onError?.(result.error, name, context);
667
+ throw earlyExit(result.error, {
668
+ origin: "result",
669
+ resultCause: result.cause
670
+ });
671
+ }
672
+ return result.value;
673
+ } catch (error) {
674
+ emitScopeEnd();
675
+ throw error;
676
+ }
677
+ })();
678
+ }, executeParallelNamed2 = function(operations, options2) {
679
+ const keys = Object.keys(operations);
680
+ const name = options2.name ?? `Parallel(${keys.join(", ")})`;
681
+ const scopeId = `scope_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
682
+ return (async () => {
683
+ const startTime = performance.now();
684
+ let scopeEnded = false;
685
+ activeScopeStack.push({ scopeId, type: "parallel" });
686
+ const emitScopeEnd = () => {
687
+ if (scopeEnded) return;
688
+ scopeEnded = true;
689
+ const idx = activeScopeStack.findIndex((s) => s.scopeId === scopeId);
690
+ if (idx !== -1) activeScopeStack.splice(idx, 1);
691
+ emitEvent({
692
+ type: "scope_end",
693
+ workflowId,
694
+ scopeId,
695
+ ts: Date.now(),
696
+ durationMs: performance.now() - startTime
697
+ });
698
+ };
699
+ emitEvent({
700
+ type: "scope_start",
701
+ workflowId,
702
+ scopeId,
703
+ scopeType: "parallel",
704
+ name,
705
+ ts: Date.now()
706
+ });
707
+ try {
708
+ const results = await new Promise((resolve) => {
709
+ if (keys.length === 0) {
710
+ resolve([]);
711
+ return;
712
+ }
713
+ let settled = false;
714
+ let pendingCount = keys.length;
715
+ const resultArray = new Array(keys.length);
716
+ for (let i = 0; i < keys.length; i++) {
717
+ const key = keys[i];
718
+ const index = i;
719
+ Promise.resolve(operations[key]()).catch((reason) => err(
720
+ { type: "PROMISE_REJECTED", cause: reason },
721
+ { cause: { type: "PROMISE_REJECTION", reason } }
722
+ )).then((result) => {
723
+ if (settled) return;
724
+ if (!result.ok) {
725
+ settled = true;
726
+ resolve([{ key, result }]);
727
+ return;
728
+ }
729
+ resultArray[index] = { key, result };
730
+ pendingCount--;
731
+ if (pendingCount === 0) {
732
+ resolve(resultArray);
733
+ }
734
+ });
735
+ }
736
+ });
737
+ emitScopeEnd();
738
+ const output = {};
739
+ for (const { key, result } of results) {
740
+ if (!result.ok) {
741
+ onError?.(result.error, key, context);
742
+ throw earlyExit(result.error, {
743
+ origin: "result",
744
+ resultCause: result.cause
745
+ });
746
+ }
747
+ output[key] = result.value;
748
+ }
749
+ return output;
750
+ } catch (error) {
751
+ emitScopeEnd();
752
+ throw error;
753
+ }
754
+ })();
755
+ };
756
+ var normalizeParallelOperations = normalizeParallelOperations2, executeParallelArray = executeParallelArray2, executeParallelNamed = executeParallelNamed2;
757
+ const stepFn = (id, operationOrResult, stepOptions) => {
758
+ return (async () => {
759
+ if (typeof id !== "string" || id.length === 0) {
760
+ throw new Error(
761
+ '[awaitly] step() requires an explicit string ID as the first argument. Example: step("fetchUser", () => fetchUser(id))'
762
+ );
763
+ }
764
+ assertDeclared(id, "step");
765
+ const parsedOptions = stepOptions ?? {};
766
+ const stepMetadata = extractStepMetadata(parsedOptions);
767
+ const stepName = id;
768
+ const stepKey = parsedOptions.key ?? id;
769
+ const explicitKey = parsedOptions.key ?? id;
770
+ const { description: stepDescription, retry: retryConfig, timeout: timeoutConfig } = parsedOptions;
771
+ const stepId = generateStepId(stepKey);
772
+ const hasEventListeners = onEvent;
773
+ const overallStartTime = hasEventListeners ? performance.now() : 0;
774
+ const isDirectResult = isResultLike(operationOrResult);
775
+ const operation = isDirectResult ? () => operationOrResult : operationOrResult;
776
+ const maxAttempts = Math.max(1, retryConfig?.attempts ?? 1);
777
+ const effectiveRetry = {
778
+ attempts: maxAttempts,
779
+ backoff: retryConfig?.backoff ?? DEFAULT_RETRY_CONFIG.backoff,
780
+ initialDelay: retryConfig?.initialDelay ?? DEFAULT_RETRY_CONFIG.initialDelay,
781
+ maxDelay: retryConfig?.maxDelay ?? DEFAULT_RETRY_CONFIG.maxDelay,
782
+ jitter: retryConfig?.jitter ?? DEFAULT_RETRY_CONFIG.jitter,
783
+ shouldRetry: retryConfig?.shouldRetry ?? DEFAULT_RETRY_CONFIG.shouldRetry,
784
+ onRetry: retryConfig?.onRetry ?? DEFAULT_RETRY_CONFIG.onRetry
785
+ };
786
+ if (onEvent) {
787
+ emitEvent({
788
+ type: "step_start",
789
+ workflowId,
790
+ stepId,
791
+ stepKey,
792
+ name: stepName,
793
+ description: stepDescription,
794
+ ts: Date.now(),
795
+ ...stepMetadata && { metadata: stepMetadata }
796
+ });
797
+ }
798
+ let lastResult;
799
+ for (let attempt = 1; attempt <= effectiveRetry.attempts; attempt++) {
800
+ const attemptStartTime = hasEventListeners ? performance.now() : 0;
801
+ try {
802
+ let result;
803
+ if (timeoutConfig) {
804
+ result = await executeWithTimeout(
805
+ operation,
806
+ timeoutConfig,
807
+ { name: stepName, key: stepKey, attempt },
808
+ _workflowSignal
809
+ );
810
+ } else {
811
+ result = await operation();
812
+ }
813
+ if (result.ok) {
814
+ const durationMs = performance.now() - overallStartTime;
815
+ emitEvent({
816
+ type: "step_success",
817
+ workflowId,
818
+ stepId,
819
+ stepKey,
820
+ name: stepName,
821
+ description: stepDescription,
822
+ ts: Date.now(),
823
+ durationMs,
824
+ ...stepMetadata && { metadata: stepMetadata }
825
+ });
826
+ if (explicitKey) {
827
+ emitEvent({
828
+ type: "step_complete",
829
+ workflowId,
830
+ stepKey: explicitKey,
831
+ name: stepName,
832
+ description: stepDescription,
833
+ ts: Date.now(),
834
+ durationMs,
835
+ result,
836
+ ...stepMetadata && { metadata: stepMetadata }
837
+ });
838
+ }
839
+ return result.value;
840
+ }
841
+ lastResult = result;
842
+ if (attempt < effectiveRetry.attempts && effectiveRetry.shouldRetry(result.error, attempt)) {
843
+ const delay = calculateRetryDelay(attempt, effectiveRetry);
844
+ emitEvent({
845
+ type: "step_retry",
846
+ workflowId,
847
+ stepId,
848
+ stepKey,
849
+ name: stepName,
850
+ ts: Date.now(),
851
+ attempt: attempt + 1,
852
+ maxAttempts: effectiveRetry.attempts,
853
+ delayMs: delay,
854
+ error: result.error,
855
+ ...stepMetadata && { metadata: stepMetadata },
856
+ diagnostics: buildStepErrorPayload(result.error, parsedOptions.errorMeta, "result", attempt, performance.now() - overallStartTime)
857
+ });
858
+ effectiveRetry.onRetry(result.error, attempt, delay);
859
+ await sleep(delay);
860
+ continue;
861
+ }
862
+ if (effectiveRetry.attempts > 1) {
863
+ emitEvent({
864
+ type: "step_retries_exhausted",
865
+ workflowId,
866
+ stepId,
867
+ stepKey,
868
+ name: stepName,
869
+ ts: Date.now(),
870
+ durationMs: performance.now() - overallStartTime,
871
+ attempts: attempt,
872
+ lastError: result.error,
873
+ ...stepMetadata && { metadata: stepMetadata },
874
+ diagnostics: buildStepErrorPayload(result.error, parsedOptions.errorMeta, "result", attempt, performance.now() - overallStartTime)
875
+ });
876
+ }
877
+ break;
878
+ } catch (thrown) {
879
+ const durationMs = performance.now() - attemptStartTime;
880
+ if (isTimeoutOptionMarker(thrown)) {
881
+ const timeoutMs = thrown.ms;
882
+ emitEvent({
883
+ type: "step_timeout",
884
+ workflowId,
885
+ stepId,
886
+ stepKey,
887
+ name: stepName,
888
+ ts: Date.now(),
889
+ timeoutMs,
890
+ attempt,
891
+ ...stepMetadata && { metadata: stepMetadata },
892
+ diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, "timeout", attempt)
893
+ });
894
+ emitEvent({
895
+ type: "step_success",
896
+ workflowId,
897
+ stepId,
898
+ stepKey,
899
+ name: stepName,
900
+ description: stepDescription,
901
+ ts: Date.now(),
902
+ durationMs: performance.now() - overallStartTime,
903
+ ...stepMetadata && { metadata: stepMetadata }
904
+ });
905
+ if (explicitKey) {
906
+ emitEvent({
907
+ type: "step_complete",
908
+ workflowId,
909
+ stepKey: explicitKey,
910
+ name: stepName,
911
+ description: stepDescription,
912
+ ts: Date.now(),
913
+ durationMs: performance.now() - overallStartTime,
914
+ result: ok2(void 0),
915
+ ...stepMetadata && { metadata: stepMetadata }
916
+ });
917
+ }
918
+ return void 0;
919
+ }
920
+ if (isEarlyExitE(thrown)) {
921
+ emitEvent({
922
+ type: "step_aborted",
923
+ workflowId,
924
+ stepId,
925
+ stepKey,
926
+ name: stepName,
927
+ description: stepDescription,
928
+ ts: Date.now(),
929
+ durationMs,
930
+ ...stepMetadata && { metadata: stepMetadata }
931
+ });
932
+ throw thrown;
933
+ }
934
+ if (isStepTimeoutError(thrown)) {
935
+ const timeoutMeta = getStepTimeoutMeta(thrown);
936
+ const timeoutMs = timeoutConfig?.ms ?? timeoutMeta?.timeoutMs ?? 0;
937
+ emitEvent({
938
+ type: "step_timeout",
939
+ workflowId,
940
+ stepId,
941
+ stepKey,
942
+ name: stepName,
943
+ ts: Date.now(),
944
+ timeoutMs,
945
+ attempt,
946
+ ...stepMetadata && { metadata: stepMetadata },
947
+ diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, "timeout", attempt)
948
+ });
949
+ if (attempt < effectiveRetry.attempts && effectiveRetry.shouldRetry(thrown, attempt)) {
950
+ const delay = calculateRetryDelay(attempt, effectiveRetry);
951
+ emitEvent({
952
+ type: "step_retry",
953
+ workflowId,
954
+ stepId,
955
+ stepKey,
956
+ name: stepName,
957
+ ts: Date.now(),
958
+ attempt: attempt + 1,
959
+ maxAttempts: effectiveRetry.attempts,
960
+ delayMs: delay,
961
+ error: thrown,
962
+ ...stepMetadata && { metadata: stepMetadata },
963
+ diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, "timeout", attempt, performance.now() - overallStartTime)
964
+ });
965
+ effectiveRetry.onRetry(thrown, attempt, delay);
966
+ await sleep(delay);
967
+ continue;
968
+ }
969
+ if (effectiveRetry.attempts > 1) {
970
+ emitEvent({
971
+ type: "step_retries_exhausted",
972
+ workflowId,
973
+ stepId,
974
+ stepKey,
975
+ name: stepName,
976
+ ts: Date.now(),
977
+ durationMs: performance.now() - overallStartTime,
978
+ attempts: attempt,
979
+ lastError: thrown,
980
+ ...stepMetadata && { metadata: stepMetadata },
981
+ diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, "timeout", attempt, performance.now() - overallStartTime)
982
+ });
983
+ }
984
+ const totalDurationMs3 = performance.now() - overallStartTime;
985
+ emitEvent({
986
+ type: "step_error",
987
+ workflowId,
988
+ stepId,
989
+ stepKey,
990
+ name: stepName,
991
+ description: stepDescription,
992
+ ts: Date.now(),
993
+ durationMs: totalDurationMs3,
994
+ error: thrown,
995
+ ...stepMetadata && { metadata: stepMetadata },
996
+ diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, "timeout", attempt, totalDurationMs3)
997
+ });
998
+ if (explicitKey) {
999
+ emitEvent({
1000
+ type: "step_complete",
1001
+ workflowId,
1002
+ stepKey: explicitKey,
1003
+ name: stepName,
1004
+ description: stepDescription,
1005
+ ts: Date.now(),
1006
+ durationMs: totalDurationMs3,
1007
+ result: err(thrown, { cause: thrown }),
1008
+ meta: { origin: "throw", thrown },
1009
+ ...stepMetadata && { metadata: stepMetadata }
1010
+ });
1011
+ }
1012
+ onError?.(thrown, stepName, context);
1013
+ throw earlyExit(thrown, { origin: "throw", thrown });
1014
+ }
1015
+ if (attempt < effectiveRetry.attempts && effectiveRetry.shouldRetry(thrown, attempt)) {
1016
+ const delay = calculateRetryDelay(attempt, effectiveRetry);
1017
+ emitEvent({
1018
+ type: "step_retry",
1019
+ workflowId,
1020
+ stepId,
1021
+ stepKey,
1022
+ name: stepName,
1023
+ ts: Date.now(),
1024
+ attempt: attempt + 1,
1025
+ maxAttempts: effectiveRetry.attempts,
1026
+ delayMs: delay,
1027
+ error: thrown,
1028
+ ...stepMetadata && { metadata: stepMetadata },
1029
+ diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, "throw", attempt, performance.now() - overallStartTime)
1030
+ });
1031
+ effectiveRetry.onRetry(thrown, attempt, delay);
1032
+ await sleep(delay);
1033
+ continue;
1034
+ }
1035
+ if (effectiveRetry.attempts > 1 && !isStepTimeoutError(thrown)) {
1036
+ emitEvent({
1037
+ type: "step_retries_exhausted",
1038
+ workflowId,
1039
+ stepId,
1040
+ stepKey,
1041
+ name: stepName,
1042
+ ts: Date.now(),
1043
+ durationMs: performance.now() - overallStartTime,
1044
+ attempts: attempt,
1045
+ lastError: thrown,
1046
+ ...stepMetadata && { metadata: stepMetadata },
1047
+ diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, "throw", attempt, performance.now() - overallStartTime)
1048
+ });
1049
+ }
1050
+ const totalDurationMs2 = performance.now() - overallStartTime;
1051
+ let mappedError;
1052
+ try {
1053
+ mappedError = effectiveCatchUnexpected(thrown);
1054
+ } catch (mapperError) {
1055
+ throw createMapperException(mapperError);
1056
+ }
1057
+ emitEvent({
1058
+ type: "step_error",
1059
+ workflowId,
1060
+ stepId,
1061
+ stepKey,
1062
+ name: stepName,
1063
+ description: stepDescription,
1064
+ ts: Date.now(),
1065
+ durationMs: totalDurationMs2,
1066
+ error: mappedError,
1067
+ ...stepMetadata && { metadata: stepMetadata },
1068
+ diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, "throw", attempt, totalDurationMs2)
1069
+ });
1070
+ if (explicitKey) {
1071
+ emitEvent({
1072
+ type: "step_complete",
1073
+ workflowId,
1074
+ stepKey: explicitKey,
1075
+ name: stepName,
1076
+ description: stepDescription,
1077
+ ts: Date.now(),
1078
+ durationMs: totalDurationMs2,
1079
+ result: err(mappedError, { cause: thrown }),
1080
+ meta: { origin: "throw", thrown },
1081
+ ...stepMetadata && { metadata: stepMetadata }
1082
+ });
1083
+ }
1084
+ onError?.(mappedError, stepName, context);
1085
+ throw earlyExit(mappedError, { origin: "throw", thrown });
1086
+ }
1087
+ }
1088
+ const errorResult = lastResult;
1089
+ const totalDurationMs = performance.now() - overallStartTime;
1090
+ const wrappedError = wrapForStep(errorResult.error, {
1091
+ origin: "result",
1092
+ resultCause: errorResult.cause
1093
+ });
1094
+ emitEvent({
1095
+ type: "step_error",
1096
+ workflowId,
1097
+ stepId,
1098
+ stepKey,
1099
+ name: stepName,
1100
+ description: stepDescription,
1101
+ ts: Date.now(),
1102
+ durationMs: totalDurationMs,
1103
+ error: wrappedError,
1104
+ ...stepMetadata && { metadata: stepMetadata },
1105
+ diagnostics: buildStepErrorPayload(errorResult.error, parsedOptions.errorMeta, "result", effectiveRetry.attempts, totalDurationMs)
1106
+ });
1107
+ if (explicitKey) {
1108
+ emitEvent({
1109
+ type: "step_complete",
1110
+ workflowId,
1111
+ stepKey: explicitKey,
1112
+ name: stepName,
1113
+ description: stepDescription,
1114
+ ts: Date.now(),
1115
+ durationMs: totalDurationMs,
1116
+ result: errorResult,
1117
+ meta: { origin: "result", resultCause: errorResult.cause },
1118
+ ...stepMetadata && { metadata: stepMetadata }
1119
+ });
1120
+ }
1121
+ onError?.(wrappedError, stepName, context);
1122
+ throw earlyExit(wrappedError, {
1123
+ origin: "result",
1124
+ resultCause: errorResult.cause
1125
+ });
1126
+ })();
1127
+ };
1128
+ stepFn.try = (id, operation, opts) => {
1129
+ if (typeof id !== "string" || id.length === 0) {
1130
+ throw new Error(
1131
+ '[awaitly] step.try() requires an explicit string ID as the first argument. Example: step.try("parse", () => JSON.parse(str), { error: "PARSE_ERROR" })'
1132
+ );
1133
+ }
1134
+ assertDeclared(id, "step");
1135
+ const mapToError = "error" in opts ? () => opts.error : opts.onError;
1136
+ if (opts.retry || opts.timeout) {
1137
+ return stepFn.retry(
1138
+ id,
1139
+ async () => {
1140
+ try {
1141
+ return ok2(await operation());
1142
+ } catch (cause) {
1143
+ return err(mapToError(cause), { cause });
1144
+ }
1145
+ },
1146
+ {
1147
+ attempts: opts.retry?.attempts ?? 1,
1148
+ ...opts.retry ?? {},
1149
+ key: opts.key,
1150
+ timeout: opts.timeout
1151
+ }
1152
+ );
1153
+ }
1154
+ const stepKey = opts.key ?? id;
1155
+ const stepName = id;
1156
+ const stepId = id;
1157
+ const hasEventListeners = onEvent;
1158
+ return (async () => {
1159
+ const startTime = hasEventListeners ? performance.now() : 0;
1160
+ if (onEvent) {
1161
+ emitEvent({
1162
+ type: "step_start",
1163
+ workflowId,
1164
+ stepId,
1165
+ stepKey,
1166
+ name: stepName,
1167
+ ts: Date.now()
1168
+ });
1169
+ }
1170
+ try {
1171
+ const value2 = await operation();
1172
+ const durationMs = performance.now() - startTime;
1173
+ emitEvent({
1174
+ type: "step_success",
1175
+ workflowId,
1176
+ stepId,
1177
+ stepKey,
1178
+ name: stepName,
1179
+ ts: Date.now(),
1180
+ durationMs
1181
+ });
1182
+ if (stepKey) {
1183
+ emitEvent({
1184
+ type: "step_complete",
1185
+ workflowId,
1186
+ stepKey,
1187
+ name: stepName,
1188
+ ts: Date.now(),
1189
+ durationMs,
1190
+ result: ok2(value2)
1191
+ });
1192
+ }
1193
+ return value2;
1194
+ } catch (error) {
1195
+ const mapped = mapToError(error);
1196
+ const durationMs = performance.now() - startTime;
1197
+ const wrappedError = wrapForStep(mapped, { origin: "throw", thrown: error });
1198
+ emitEvent({
1199
+ type: "step_error",
1200
+ workflowId,
1201
+ stepId,
1202
+ stepKey,
1203
+ name: stepName,
1204
+ ts: Date.now(),
1205
+ durationMs,
1206
+ error: wrappedError
1207
+ });
1208
+ if (stepKey) {
1209
+ emitEvent({
1210
+ type: "step_complete",
1211
+ workflowId,
1212
+ stepKey,
1213
+ name: stepName,
1214
+ ts: Date.now(),
1215
+ durationMs,
1216
+ result: err(mapped, { cause: error }),
1217
+ meta: { origin: "throw", thrown: error }
1218
+ });
1219
+ }
1220
+ onError?.(wrappedError, stepName, context);
1221
+ throw earlyExit(wrappedError, { origin: "throw", thrown: error });
1222
+ }
1223
+ })();
1224
+ };
1225
+ stepFn.fromResult = (id, operation, opts) => {
1226
+ if (typeof id !== "string" || id.length === 0) {
1227
+ throw new Error(
1228
+ '[awaitly] step.fromResult() requires an explicit string ID as the first argument. Example: step.fromResult("callProvider", () => callProvider(input), { onError: (e) => ({ type: "FAILED" }) })'
1229
+ );
1230
+ }
1231
+ assertDeclared(id, "step");
1232
+ const stepKey = opts.key ?? id;
1233
+ const stepName = id;
1234
+ const stepId = id;
1235
+ const mapToError = "error" in opts ? () => opts.error : opts.onError;
1236
+ const hasEventListeners = onEvent;
1237
+ return (async () => {
1238
+ const startTime = hasEventListeners ? performance.now() : 0;
1239
+ if (onEvent) {
1240
+ emitEvent({
1241
+ type: "step_start",
1242
+ workflowId,
1243
+ stepId,
1244
+ stepKey,
1245
+ name: stepName,
1246
+ ts: Date.now()
1247
+ });
1248
+ }
1249
+ const result = await operation();
1250
+ if (result.ok) {
1251
+ const durationMs = performance.now() - startTime;
1252
+ emitEvent({
1253
+ type: "step_success",
1254
+ workflowId,
1255
+ stepId,
1256
+ stepKey,
1257
+ name: stepName,
1258
+ ts: Date.now(),
1259
+ durationMs
1260
+ });
1261
+ if (stepKey) {
1262
+ emitEvent({
1263
+ type: "step_complete",
1264
+ workflowId,
1265
+ stepKey,
1266
+ name: stepName,
1267
+ ts: Date.now(),
1268
+ durationMs,
1269
+ result: ok2(result.value)
1270
+ });
1271
+ }
1272
+ return result.value;
1273
+ } else {
1274
+ const mapped = mapToError(result.error);
1275
+ const durationMs = performance.now() - startTime;
1276
+ const wrappedError = wrapForStep(mapped, {
1277
+ origin: "result",
1278
+ resultCause: result.error
1279
+ });
1280
+ emitEvent({
1281
+ type: "step_error",
1282
+ workflowId,
1283
+ stepId,
1284
+ stepKey,
1285
+ name: stepName,
1286
+ ts: Date.now(),
1287
+ durationMs,
1288
+ error: wrappedError
1289
+ });
1290
+ if (stepKey) {
1291
+ emitEvent({
1292
+ type: "step_complete",
1293
+ workflowId,
1294
+ stepKey,
1295
+ name: stepName,
1296
+ ts: Date.now(),
1297
+ durationMs,
1298
+ result: err(mapped, { cause: result.error }),
1299
+ meta: { origin: "result", resultCause: result.error }
1300
+ });
1301
+ }
1302
+ onError?.(wrappedError, stepName, context);
1303
+ throw earlyExit(wrappedError, {
1304
+ origin: "result",
1305
+ resultCause: result.error
1306
+ });
1307
+ }
1308
+ })();
1309
+ };
1310
+ stepFn.fromNullable = (id, operation, onNull, options2) => {
1311
+ if (typeof id !== "string" || id.length === 0) {
1312
+ throw new Error(
1313
+ '[awaitly] step.fromNullable() requires an explicit string ID as the first argument. Example: step.fromNullable("getUser", () => db.find(id), () => ({ type: "NOT_FOUND" }))'
1314
+ );
1315
+ }
1316
+ return stepFn(
1317
+ id,
1318
+ async () => {
1319
+ const value2 = await operation();
1320
+ return value2 != null ? ok2(value2) : err(onNull());
1321
+ },
1322
+ options2
1323
+ );
1324
+ };
1325
+ stepFn.retry = (id, operation, options2) => {
1326
+ if (typeof id !== "string" || id.length === 0) {
1327
+ throw new Error(
1328
+ '[awaitly] step.retry() requires an explicit string ID as the first argument. Example: step.retry("fetchData", () => fetchData(), { attempts: 3 })'
1329
+ );
1330
+ }
1331
+ return stepFn(id, operation, {
1332
+ key: options2.key ?? id,
1333
+ retry: {
1334
+ attempts: options2.attempts,
1335
+ backoff: options2.backoff,
1336
+ initialDelay: options2.initialDelay,
1337
+ maxDelay: options2.maxDelay,
1338
+ jitter: options2.jitter,
1339
+ shouldRetry: options2.shouldRetry,
1340
+ onRetry: options2.onRetry
1341
+ },
1342
+ timeout: options2.timeout
1343
+ });
1344
+ };
1345
+ stepFn.withTimeout = (id, operation, options2) => {
1346
+ if (typeof id !== "string" || id.length === 0) {
1347
+ throw new Error(
1348
+ '[awaitly] step.withTimeout() requires an explicit string ID as the first argument. Example: step.withTimeout("slowOp", () => slowOp(), { ms: 5000 })'
1349
+ );
1350
+ }
1351
+ return stepFn(
1352
+ id,
1353
+ operation,
1354
+ {
1355
+ key: options2.key ?? id,
1356
+ timeout: options2
1357
+ }
1358
+ );
1359
+ };
1360
+ stepFn.sleep = (id, duration, options2) => {
1361
+ if (typeof id !== "string" || id.length === 0) {
1362
+ throw new Error(
1363
+ '[awaitly] step.sleep() requires an explicit string ID as the first argument. Example: step.sleep("delay", "5s")'
1364
+ );
1365
+ }
1366
+ const d = typeof duration === "string" ? parseDurationString(duration) : duration;
1367
+ if (!d) {
1368
+ throw new Error(`step.sleep: invalid duration '${duration}'`);
1369
+ }
1370
+ const ms = d.millis;
1371
+ const userSignal = options2?.signal;
1372
+ return stepFn(
1373
+ id,
1374
+ async () => {
1375
+ if (_workflowSignal?.aborted || userSignal?.aborted) {
1376
+ const e = new Error("Sleep aborted");
1377
+ e.name = "AbortError";
1378
+ throw e;
1379
+ }
1380
+ return new Promise((resolve, reject) => {
1381
+ const state = { timeoutId: void 0 };
1382
+ const onAbort = () => {
1383
+ if (state.timeoutId) clearTimeout(state.timeoutId);
1384
+ const e = new Error("Sleep aborted");
1385
+ e.name = "AbortError";
1386
+ reject(e);
1387
+ };
1388
+ _workflowSignal?.addEventListener("abort", onAbort, { once: true });
1389
+ userSignal?.addEventListener("abort", onAbort, { once: true });
1390
+ state.timeoutId = setTimeout(() => {
1391
+ _workflowSignal?.removeEventListener("abort", onAbort);
1392
+ userSignal?.removeEventListener("abort", onAbort);
1393
+ resolve(ok2(void 0));
1394
+ }, ms);
1395
+ });
1396
+ },
1397
+ {
1398
+ key: options2?.key ?? id,
1399
+ description: options2?.description
1400
+ }
1401
+ );
1402
+ };
1403
+ stepFn.all = ((...args) => {
1404
+ if (typeof args[0] !== "string") {
1405
+ throw new TypeError(
1406
+ "step.all(name, ...): first argument must be a string (step name). Example: step.all('Fetch data', { user: () => fetchUser(), posts: () => fetchPosts() })"
1407
+ );
1408
+ }
1409
+ const name = args[0];
1410
+ const second = args[1];
1411
+ if (typeof second === "function") {
1412
+ return executeParallelArray2(name, second);
1413
+ }
1414
+ if (second && typeof second === "object" && !Array.isArray(second)) {
1415
+ const rawOperations = second;
1416
+ const normalizedOperations = normalizeParallelOperations2(rawOperations);
1417
+ return executeParallelNamed2(normalizedOperations, { name });
1418
+ }
1419
+ throw new TypeError(
1420
+ "step.all(name, ...): second argument must be a function (array form) or an object of operations (object form)."
1421
+ );
1422
+ });
1423
+ stepFn.race = (name, operation) => {
1424
+ const scopeId = `scope_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
1425
+ return (async () => {
1426
+ const startTime = performance.now();
1427
+ let scopeEnded = false;
1428
+ const scopeEntry = { scopeId, type: "race", winnerId: void 0 };
1429
+ activeScopeStack.push(scopeEntry);
1430
+ const emitScopeEnd = () => {
1431
+ if (scopeEnded) return;
1432
+ scopeEnded = true;
1433
+ const idx = activeScopeStack.findIndex((s) => s.scopeId === scopeId);
1434
+ if (idx !== -1) activeScopeStack.splice(idx, 1);
1435
+ emitEvent({
1436
+ type: "scope_end",
1437
+ workflowId,
1438
+ scopeId,
1439
+ ts: Date.now(),
1440
+ durationMs: performance.now() - startTime,
1441
+ winnerId: scopeEntry.winnerId
1442
+ });
1443
+ };
1444
+ emitEvent({
1445
+ type: "scope_start",
1446
+ workflowId,
1447
+ scopeId,
1448
+ scopeType: "race",
1449
+ name,
1450
+ ts: Date.now()
1451
+ });
1452
+ try {
1453
+ const result = await operation();
1454
+ emitScopeEnd();
1455
+ if (!result.ok) {
1456
+ onError?.(result.error, name, context);
1457
+ throw earlyExit(result.error, {
1458
+ origin: "result",
1459
+ resultCause: result.cause
1460
+ });
1461
+ }
1462
+ return result.value;
1463
+ } catch (error) {
1464
+ emitScopeEnd();
1465
+ throw error;
1466
+ }
1467
+ })();
1468
+ };
1469
+ stepFn.if = (id, conditionLabel, condition) => {
1470
+ assertDeclared(id, "decision");
1471
+ const value2 = condition();
1472
+ emitEvent({
1473
+ type: "decision",
1474
+ workflowId,
1475
+ decisionId: id,
1476
+ label: conditionLabel,
1477
+ branch: value2 ? "then" : "else",
1478
+ value: value2,
1479
+ ts: Date.now()
1480
+ });
1481
+ return value2;
1482
+ };
1483
+ stepFn.label = stepFn.if;
1484
+ stepFn.branch = async (id, options2) => {
1485
+ const { condition, then: thenFn, else: elseFn } = options2;
1486
+ assertDeclared(id, "decision");
1487
+ const conditionResult = condition();
1488
+ const branch = conditionResult ? "then" : "else";
1489
+ const startTime = performance.now();
1490
+ emitEvent({
1491
+ type: "decision",
1492
+ workflowId,
1493
+ decisionId: id,
1494
+ label: options2.conditionLabel,
1495
+ branch,
1496
+ value: conditionResult,
1497
+ phase: "start",
1498
+ ts: Date.now()
1499
+ });
1500
+ const emitEnd = () => {
1501
+ emitEvent({
1502
+ type: "decision",
1503
+ workflowId,
1504
+ decisionId: id,
1505
+ label: options2.conditionLabel,
1506
+ branch,
1507
+ value: conditionResult,
1508
+ phase: "end",
1509
+ durationMs: performance.now() - startTime,
1510
+ ts: Date.now()
1511
+ });
1512
+ };
1513
+ try {
1514
+ if (conditionResult) {
1515
+ return await thenFn();
1516
+ } else if (elseFn) {
1517
+ return await elseFn();
1518
+ }
1519
+ return void 0;
1520
+ } finally {
1521
+ emitEnd();
1522
+ }
1523
+ };
1524
+ stepFn.arm = (fn2, errors) => {
1525
+ return { fn: fn2, errors };
1526
+ };
1527
+ stepFn.forEach = async (_id, items, options2) => {
1528
+ const results = [];
1529
+ const maxIterations = options2.maxIterations;
1530
+ let index = 0;
1531
+ const isRunForm = "run" in options2;
1532
+ const asyncItems = Symbol.asyncIterator in items ? items : (async function* () {
1533
+ yield* items;
1534
+ })();
1535
+ for await (const item of asyncItems) {
1536
+ if (maxIterations !== void 0 && index >= maxIterations) {
1537
+ break;
1538
+ }
1539
+ let result;
1540
+ if (isRunForm) {
1541
+ const runOptions = options2;
1542
+ result = await runOptions.run(item, index);
1543
+ } else {
1544
+ const itemOptions = options2;
1545
+ result = await itemOptions.item.handler(item, index, stepFn);
1546
+ }
1547
+ results.push(result);
1548
+ index++;
1549
+ }
1550
+ return results;
1551
+ };
1552
+ stepFn.item = (handler) => {
1553
+ return {
1554
+ __forEachItemHandler: true,
1555
+ handler
1556
+ };
1557
+ };
1558
+ stepFn.dep = (_name, fn2) => {
1559
+ return fn2;
1560
+ };
1561
+ stepFn.workflow = (id, getter, options2) => {
1562
+ return stepFn(id, getter, options2);
1563
+ };
1564
+ stepFn.map = async (id, items, mapper, options2) => {
1565
+ const concurrency = options2?.concurrency ?? items.length;
1566
+ return stepFn(
1567
+ id,
1568
+ () => {
1569
+ if (concurrency >= items.length) {
1570
+ return allAsync(items.map((item, index) => mapper(item, index)));
1571
+ } else {
1572
+ return (async () => {
1573
+ const results = [];
1574
+ for (let i = 0; i < items.length; i += concurrency) {
1575
+ const batch = items.slice(i, i + concurrency);
1576
+ const batchResult = await allAsync(
1577
+ batch.map((item, batchIndex) => mapper(item, i + batchIndex))
1578
+ );
1579
+ if (!batchResult.ok) {
1580
+ return batchResult;
1581
+ }
1582
+ results.push(...batchResult.value);
1583
+ }
1584
+ return ok2(results);
1585
+ })();
1586
+ }
1587
+ },
1588
+ { key: options2?.key }
1589
+ );
1590
+ };
1591
+ stepFn.withFallback = (id, operation, options2) => {
1592
+ if (typeof id !== "string" || id.length === 0) {
1593
+ throw new Error(
1594
+ '[awaitly] step.withFallback() requires an explicit string ID as the first argument. Example: step.withFallback("getUser", () => fetchUser(id), { fallback: () => fetchFromCache(id) })'
1595
+ );
1596
+ }
1597
+ assertDeclared(id, "step");
1598
+ const stepKey = options2.key ?? id;
1599
+ const stepName = id;
1600
+ const stepId = generateStepId(stepKey);
1601
+ const hasEventListeners = onEvent;
1602
+ return (async () => {
1603
+ const startTime = hasEventListeners ? performance.now() : 0;
1604
+ if (onEvent) {
1605
+ emitEvent({
1606
+ type: "step_start",
1607
+ workflowId,
1608
+ stepId,
1609
+ stepKey,
1610
+ name: stepName,
1611
+ ts: Date.now()
1612
+ });
1613
+ }
1614
+ let primaryResult;
1615
+ try {
1616
+ primaryResult = await operation();
1617
+ } catch (thrown) {
1618
+ if (isEarlyExitE(thrown)) {
1619
+ emitEvent({
1620
+ type: "step_aborted",
1621
+ workflowId,
1622
+ stepId,
1623
+ stepKey,
1624
+ name: stepName,
1625
+ ts: Date.now(),
1626
+ durationMs: performance.now() - startTime
1627
+ });
1628
+ throw thrown;
1629
+ }
1630
+ let mappedError;
1631
+ try {
1632
+ mappedError = effectiveCatchUnexpected(thrown);
1633
+ } catch (mapperError) {
1634
+ throw createMapperException(mapperError);
1635
+ }
1636
+ if (options2.on !== void 0 && options2.on !== mappedError) {
1637
+ const durationMs2 = performance.now() - startTime;
1638
+ emitEvent({
1639
+ type: "step_error",
1640
+ workflowId,
1641
+ stepId,
1642
+ stepKey,
1643
+ name: stepName,
1644
+ ts: Date.now(),
1645
+ durationMs: durationMs2,
1646
+ error: mappedError
1647
+ });
1648
+ if (stepKey) {
1649
+ emitEvent({
1650
+ type: "step_complete",
1651
+ workflowId,
1652
+ stepKey,
1653
+ name: stepName,
1654
+ ts: Date.now(),
1655
+ durationMs: durationMs2,
1656
+ result: err(mappedError, { cause: thrown }),
1657
+ meta: { origin: "throw", thrown }
1658
+ });
1659
+ }
1660
+ onError?.(mappedError, stepName, context);
1661
+ throw earlyExit(mappedError, { origin: "throw", thrown });
1662
+ }
1663
+ let fallbackResultFromThrow;
1664
+ try {
1665
+ fallbackResultFromThrow = await options2.fallback();
1666
+ } catch (fallbackThrown) {
1667
+ if (isEarlyExitE(fallbackThrown)) {
1668
+ emitEvent({
1669
+ type: "step_aborted",
1670
+ workflowId,
1671
+ stepId,
1672
+ stepKey,
1673
+ name: stepName,
1674
+ ts: Date.now(),
1675
+ durationMs: performance.now() - startTime
1676
+ });
1677
+ throw fallbackThrown;
1678
+ }
1679
+ let fallbackMappedError;
1680
+ try {
1681
+ fallbackMappedError = effectiveCatchUnexpected(fallbackThrown);
1682
+ } catch (mapperError) {
1683
+ throw createMapperException(mapperError);
1684
+ }
1685
+ const durationMs2 = performance.now() - startTime;
1686
+ emitEvent({
1687
+ type: "step_error",
1688
+ workflowId,
1689
+ stepId,
1690
+ stepKey,
1691
+ name: stepName,
1692
+ ts: Date.now(),
1693
+ durationMs: durationMs2,
1694
+ error: fallbackMappedError
1695
+ });
1696
+ if (stepKey) {
1697
+ emitEvent({
1698
+ type: "step_complete",
1699
+ workflowId,
1700
+ stepKey,
1701
+ name: stepName,
1702
+ ts: Date.now(),
1703
+ durationMs: durationMs2,
1704
+ result: err(fallbackMappedError, { cause: fallbackThrown }),
1705
+ meta: { origin: "throw", thrown: fallbackThrown }
1706
+ });
1707
+ }
1708
+ onError?.(fallbackMappedError, stepName, context);
1709
+ throw earlyExit(fallbackMappedError, { origin: "throw", thrown: fallbackThrown });
1710
+ }
1711
+ if (fallbackResultFromThrow.ok) {
1712
+ const durationMs2 = performance.now() - startTime;
1713
+ emitEvent({
1714
+ type: "step_success",
1715
+ workflowId,
1716
+ stepId,
1717
+ stepKey,
1718
+ name: stepName,
1719
+ ts: Date.now(),
1720
+ durationMs: durationMs2
1721
+ });
1722
+ if (stepKey) {
1723
+ emitEvent({
1724
+ type: "step_complete",
1725
+ workflowId,
1726
+ stepKey,
1727
+ name: stepName,
1728
+ ts: Date.now(),
1729
+ durationMs: durationMs2,
1730
+ result: fallbackResultFromThrow,
1731
+ meta: { origin: "fallback", fallbackUsed: true, fallbackReason: String(mappedError) }
1732
+ });
1733
+ }
1734
+ return fallbackResultFromThrow.value;
1735
+ } else {
1736
+ const durationMs2 = performance.now() - startTime;
1737
+ const wrappedError2 = wrapForStep(fallbackResultFromThrow.error, {
1738
+ origin: "result",
1739
+ resultCause: fallbackResultFromThrow.cause
1740
+ });
1741
+ emitEvent({
1742
+ type: "step_error",
1743
+ workflowId,
1744
+ stepId,
1745
+ stepKey,
1746
+ name: stepName,
1747
+ ts: Date.now(),
1748
+ durationMs: durationMs2,
1749
+ error: wrappedError2
1750
+ });
1751
+ if (stepKey) {
1752
+ emitEvent({
1753
+ type: "step_complete",
1754
+ workflowId,
1755
+ stepKey,
1756
+ name: stepName,
1757
+ ts: Date.now(),
1758
+ durationMs: durationMs2,
1759
+ result: fallbackResultFromThrow,
1760
+ meta: { origin: "result", resultCause: fallbackResultFromThrow.cause }
1761
+ });
1762
+ }
1763
+ onError?.(wrappedError2, stepName, context);
1764
+ throw earlyExit(wrappedError2, {
1765
+ origin: "result",
1766
+ resultCause: fallbackResultFromThrow.cause
1767
+ });
1768
+ }
1769
+ }
1770
+ if (primaryResult.ok) {
1771
+ const durationMs2 = performance.now() - startTime;
1772
+ emitEvent({
1773
+ type: "step_success",
1774
+ workflowId,
1775
+ stepId,
1776
+ stepKey,
1777
+ name: stepName,
1778
+ ts: Date.now(),
1779
+ durationMs: durationMs2
1780
+ });
1781
+ if (stepKey) {
1782
+ emitEvent({
1783
+ type: "step_complete",
1784
+ workflowId,
1785
+ stepKey,
1786
+ name: stepName,
1787
+ ts: Date.now(),
1788
+ durationMs: durationMs2,
1789
+ result: primaryResult
1790
+ });
1791
+ }
1792
+ return primaryResult.value;
1793
+ }
1794
+ const primaryError = primaryResult.error;
1795
+ if (options2.on !== void 0 && options2.on !== primaryError) {
1796
+ const durationMs2 = performance.now() - startTime;
1797
+ const wrappedError2 = wrapForStep(primaryError, {
1798
+ origin: "result",
1799
+ resultCause: primaryResult.cause
1800
+ });
1801
+ emitEvent({
1802
+ type: "step_error",
1803
+ workflowId,
1804
+ stepId,
1805
+ stepKey,
1806
+ name: stepName,
1807
+ ts: Date.now(),
1808
+ durationMs: durationMs2,
1809
+ error: wrappedError2
1810
+ });
1811
+ if (stepKey) {
1812
+ emitEvent({
1813
+ type: "step_complete",
1814
+ workflowId,
1815
+ stepKey,
1816
+ name: stepName,
1817
+ ts: Date.now(),
1818
+ durationMs: durationMs2,
1819
+ result: primaryResult,
1820
+ meta: { origin: "result", resultCause: primaryResult.cause }
1821
+ });
1822
+ }
1823
+ onError?.(wrappedError2, stepName, context);
1824
+ throw earlyExit(wrappedError2, {
1825
+ origin: "result",
1826
+ resultCause: primaryResult.cause
1827
+ });
1828
+ }
1829
+ let fallbackResult;
1830
+ try {
1831
+ fallbackResult = await options2.fallback();
1832
+ } catch (thrown) {
1833
+ if (isEarlyExitE(thrown)) {
1834
+ emitEvent({
1835
+ type: "step_aborted",
1836
+ workflowId,
1837
+ stepId,
1838
+ stepKey,
1839
+ name: stepName,
1840
+ ts: Date.now(),
1841
+ durationMs: performance.now() - startTime
1842
+ });
1843
+ throw thrown;
1844
+ }
1845
+ let mappedError;
1846
+ try {
1847
+ mappedError = effectiveCatchUnexpected(thrown);
1848
+ } catch (mapperError) {
1849
+ throw createMapperException(mapperError);
1850
+ }
1851
+ const durationMs2 = performance.now() - startTime;
1852
+ emitEvent({
1853
+ type: "step_error",
1854
+ workflowId,
1855
+ stepId,
1856
+ stepKey,
1857
+ name: stepName,
1858
+ ts: Date.now(),
1859
+ durationMs: durationMs2,
1860
+ error: mappedError
1861
+ });
1862
+ if (stepKey) {
1863
+ emitEvent({
1864
+ type: "step_complete",
1865
+ workflowId,
1866
+ stepKey,
1867
+ name: stepName,
1868
+ ts: Date.now(),
1869
+ durationMs: durationMs2,
1870
+ result: err(mappedError, { cause: thrown }),
1871
+ meta: { origin: "throw", thrown }
1872
+ });
1873
+ }
1874
+ onError?.(mappedError, stepName, context);
1875
+ throw earlyExit(mappedError, { origin: "throw", thrown });
1876
+ }
1877
+ if (fallbackResult.ok) {
1878
+ const durationMs2 = performance.now() - startTime;
1879
+ emitEvent({
1880
+ type: "step_success",
1881
+ workflowId,
1882
+ stepId,
1883
+ stepKey,
1884
+ name: stepName,
1885
+ ts: Date.now(),
1886
+ durationMs: durationMs2
1887
+ });
1888
+ if (stepKey) {
1889
+ emitEvent({
1890
+ type: "step_complete",
1891
+ workflowId,
1892
+ stepKey,
1893
+ name: stepName,
1894
+ ts: Date.now(),
1895
+ durationMs: durationMs2,
1896
+ result: fallbackResult,
1897
+ meta: { origin: "fallback", fallbackUsed: true, fallbackReason: String(primaryError) }
1898
+ });
1899
+ }
1900
+ return fallbackResult.value;
1901
+ }
1902
+ const durationMs = performance.now() - startTime;
1903
+ const wrappedError = wrapForStep(fallbackResult.error, {
1904
+ origin: "result",
1905
+ resultCause: fallbackResult.cause
1906
+ });
1907
+ emitEvent({
1908
+ type: "step_error",
1909
+ workflowId,
1910
+ stepId,
1911
+ stepKey,
1912
+ name: stepName,
1913
+ ts: Date.now(),
1914
+ durationMs,
1915
+ error: wrappedError
1916
+ });
1917
+ if (stepKey) {
1918
+ emitEvent({
1919
+ type: "step_complete",
1920
+ workflowId,
1921
+ stepKey,
1922
+ name: stepName,
1923
+ ts: Date.now(),
1924
+ durationMs,
1925
+ result: fallbackResult,
1926
+ meta: { origin: "result", resultCause: fallbackResult.cause }
1927
+ });
1928
+ }
1929
+ onError?.(wrappedError, stepName, context);
1930
+ throw earlyExit(wrappedError, {
1931
+ origin: "result",
1932
+ resultCause: fallbackResult.cause
1933
+ });
1934
+ })();
1935
+ };
1936
+ stepFn.withResource = (id, options2) => {
1937
+ if (typeof id !== "string" || id.length === 0) {
1938
+ throw new Error(
1939
+ '[awaitly] step.withResource() requires an explicit string ID as the first argument. Example: step.withResource("useDb", { acquire: () => connect(), use: (db) => query(db), release: (db) => db.close() })'
1940
+ );
1941
+ }
1942
+ assertDeclared(id, "step");
1943
+ const stepKey = id;
1944
+ const stepName = id;
1945
+ const stepId = generateStepId(stepKey);
1946
+ const hasEventListeners = onEvent;
1947
+ return (async () => {
1948
+ const startTime = hasEventListeners ? performance.now() : 0;
1949
+ if (onEvent) {
1950
+ emitEvent({
1951
+ type: "step_start",
1952
+ workflowId,
1953
+ stepId,
1954
+ stepKey,
1955
+ name: stepName,
1956
+ ts: Date.now()
1957
+ });
1958
+ }
1959
+ let acquireResult;
1960
+ try {
1961
+ acquireResult = await options2.acquire();
1962
+ } catch (thrown) {
1963
+ if (isEarlyExitE(thrown)) {
1964
+ emitEvent({
1965
+ type: "step_aborted",
1966
+ workflowId,
1967
+ stepId,
1968
+ stepKey,
1969
+ name: stepName,
1970
+ ts: Date.now(),
1971
+ durationMs: performance.now() - startTime
1972
+ });
1973
+ throw thrown;
1974
+ }
1975
+ let mappedError;
1976
+ try {
1977
+ mappedError = effectiveCatchUnexpected(thrown);
1978
+ } catch (mapperError) {
1979
+ throw createMapperException(mapperError);
1980
+ }
1981
+ const durationMs2 = performance.now() - startTime;
1982
+ emitEvent({
1983
+ type: "step_error",
1984
+ workflowId,
1985
+ stepId,
1986
+ stepKey,
1987
+ name: stepName,
1988
+ ts: Date.now(),
1989
+ durationMs: durationMs2,
1990
+ error: mappedError
1991
+ });
1992
+ if (stepKey) {
1993
+ emitEvent({
1994
+ type: "step_complete",
1995
+ workflowId,
1996
+ stepKey,
1997
+ name: stepName,
1998
+ ts: Date.now(),
1999
+ durationMs: durationMs2,
2000
+ result: err(mappedError, { cause: thrown }),
2001
+ meta: { origin: "throw", thrown }
2002
+ });
2003
+ }
2004
+ onError?.(mappedError, stepName, context);
2005
+ throw earlyExit(mappedError, { origin: "throw", thrown });
2006
+ }
2007
+ if (!acquireResult.ok) {
2008
+ const durationMs2 = performance.now() - startTime;
2009
+ const wrappedError2 = wrapForStep(acquireResult.error, {
2010
+ origin: "result",
2011
+ resultCause: acquireResult.cause
2012
+ });
2013
+ emitEvent({
2014
+ type: "step_error",
2015
+ workflowId,
2016
+ stepId,
2017
+ stepKey,
2018
+ name: stepName,
2019
+ ts: Date.now(),
2020
+ durationMs: durationMs2,
2021
+ error: wrappedError2
2022
+ });
2023
+ if (stepKey) {
2024
+ emitEvent({
2025
+ type: "step_complete",
2026
+ workflowId,
2027
+ stepKey,
2028
+ name: stepName,
2029
+ ts: Date.now(),
2030
+ durationMs: durationMs2,
2031
+ result: acquireResult,
2032
+ meta: { origin: "result", resultCause: acquireResult.cause }
2033
+ });
2034
+ }
2035
+ onError?.(wrappedError2, stepName, context);
2036
+ throw earlyExit(wrappedError2, {
2037
+ origin: "result",
2038
+ resultCause: acquireResult.cause
2039
+ });
2040
+ }
2041
+ const resource = acquireResult.value;
2042
+ let useResult;
2043
+ let useThrown;
2044
+ let useThrewNonResult = false;
2045
+ try {
2046
+ useResult = await options2.use(resource);
2047
+ } catch (thrown) {
2048
+ if (isEarlyExitE(thrown)) {
2049
+ try {
2050
+ await options2.release(resource);
2051
+ } catch (releaseErr) {
2052
+ console.warn(
2053
+ `[awaitly] step.withResource("${id}"): release threw after earlyExit:`,
2054
+ releaseErr
2055
+ );
2056
+ }
2057
+ throw thrown;
2058
+ }
2059
+ useThrown = thrown;
2060
+ useThrewNonResult = true;
2061
+ }
2062
+ try {
2063
+ await options2.release(resource);
2064
+ } catch (releaseErr) {
2065
+ console.warn(
2066
+ `[awaitly] step.withResource("${id}"): release threw:`,
2067
+ releaseErr
2068
+ );
2069
+ }
2070
+ if (useThrewNonResult) {
2071
+ let mappedError;
2072
+ try {
2073
+ mappedError = effectiveCatchUnexpected(useThrown);
2074
+ } catch (mapperError) {
2075
+ throw createMapperException(mapperError);
2076
+ }
2077
+ const durationMs2 = performance.now() - startTime;
2078
+ emitEvent({
2079
+ type: "step_error",
2080
+ workflowId,
2081
+ stepId,
2082
+ stepKey,
2083
+ name: stepName,
2084
+ ts: Date.now(),
2085
+ durationMs: durationMs2,
2086
+ error: mappedError
2087
+ });
2088
+ if (stepKey) {
2089
+ emitEvent({
2090
+ type: "step_complete",
2091
+ workflowId,
2092
+ stepKey,
2093
+ name: stepName,
2094
+ ts: Date.now(),
2095
+ durationMs: durationMs2,
2096
+ result: err(mappedError, { cause: useThrown }),
2097
+ meta: { origin: "throw", thrown: useThrown }
2098
+ });
2099
+ }
2100
+ onError?.(mappedError, stepName, context);
2101
+ throw earlyExit(mappedError, { origin: "throw", thrown: useThrown });
2102
+ }
2103
+ const result = useResult;
2104
+ if (result.ok) {
2105
+ const durationMs2 = performance.now() - startTime;
2106
+ emitEvent({
2107
+ type: "step_success",
2108
+ workflowId,
2109
+ stepId,
2110
+ stepKey,
2111
+ name: stepName,
2112
+ ts: Date.now(),
2113
+ durationMs: durationMs2
2114
+ });
2115
+ if (stepKey) {
2116
+ emitEvent({
2117
+ type: "step_complete",
2118
+ workflowId,
2119
+ stepKey,
2120
+ name: stepName,
2121
+ ts: Date.now(),
2122
+ durationMs: durationMs2,
2123
+ result
2124
+ });
2125
+ }
2126
+ return result.value;
2127
+ }
2128
+ const durationMs = performance.now() - startTime;
2129
+ const wrappedError = wrapForStep(result.error, {
2130
+ origin: "result",
2131
+ resultCause: result.cause
2132
+ });
2133
+ emitEvent({
2134
+ type: "step_error",
2135
+ workflowId,
2136
+ stepId,
2137
+ stepKey,
2138
+ name: stepName,
2139
+ ts: Date.now(),
2140
+ durationMs,
2141
+ error: wrappedError
2142
+ });
2143
+ if (stepKey) {
2144
+ emitEvent({
2145
+ type: "step_complete",
2146
+ workflowId,
2147
+ stepKey,
2148
+ name: stepName,
2149
+ ts: Date.now(),
2150
+ durationMs,
2151
+ result,
2152
+ meta: { origin: "result", resultCause: result.cause }
2153
+ });
2154
+ }
2155
+ onError?.(wrappedError, stepName, context);
2156
+ throw earlyExit(wrappedError, {
2157
+ origin: "result",
2158
+ resultCause: result.cause
2159
+ });
2160
+ })();
2161
+ };
2162
+ const step = stepFn;
2163
+ const value = await fn({ step });
2164
+ if (process.env.NODE_ENV !== "production" && value !== null && typeof value === "object" && "ok" in value && typeof value.ok === "boolean") {
2165
+ const maybeResult = value;
2166
+ if (maybeResult.ok === true && "value" in maybeResult || maybeResult.ok === false && "error" in maybeResult) {
2167
+ console.warn(
2168
+ `awaitly: Workflow executor returned a Result-like object. Return raw values, not ok() or err().
2
2169
 
3
2170
  Incorrect: return ok({ data });
4
2171
  Correct: return { data };
5
2172
 
6
- See: https://jagreehal.github.io/awaitly/guides/troubleshooting/#returning-ok-from-workflow-executor-double-wrapping`)}return X(le)}catch(f){if(or(f))throw f.thrown;if(Q(f)){let ae=f.meta.origin==="throw"?f.meta.thrown:f.meta.origin==="result"?f.meta.resultCause:void 0;return U(f.error,{cause:ae})}let ee=Y(f);return r?.(ee,"unexpected",g),U(ee,{cause:f})}}Fe.strict=(e,t)=>Fe(e,t);async function xt(e){return e.length===0?X([]):new Promise(t=>{let r=!1,m=e.length,a=new Array(e.length);for(let d=0;d<e.length;d++){let S=d;Promise.resolve(e[S]).catch(g=>U({type:"PROMISE_REJECTED",cause:g},{cause:{type:"PROMISE_REJECTION",reason:g}})).then(g=>{if(!r){if(!g.ok){r=!0,t(g);return}a[S]=g.value,m--,m===0&&t(X(a))}})}})}function vt(e){return e.type==="step_complete"}function ze(e){return typeof e=="object"&&e!==null&&e.type==="WORKFLOW_CANCELLED"}var $e=class extends Error{constructor(r,m,a){super(r);this.stepId=m;this.originalError=a;this.name="SnapshotDecodeError"}};function Ye(e){if(e.type==="error"){let t=new Error(e.message);return t.name=e.name,e.stack&&(t.stack=e.stack),e.cause&&(t.cause=Ye(e.cause)),t}return e.value!==void 0?e.value:e.stringRepresentation}function ir(e){return typeof e=="object"&&e!==null&&e.__cachedMeta===!0}function be(e,t,r){return U(e,{cause:{__cachedMeta:!0,originalCause:r,meta:t}})}function Ne(e){return ir(e)?e.meta:{origin:"result",resultCause:e}}function At(){let e=new Map;return{handleEvent:t=>{vt(t)&&e.set(t.stepKey,{result:t.result,meta:t.meta})},getResumeState:()=>({steps:new Map(e)}),clear:()=>e.clear()}}var ur="STREAM_WRITE_ERROR",lr="STREAM_READ_ERROR",cr="STREAM_CLOSE_ERROR";var pr="STREAM_ENDED";function Le(e,t,r){return{type:ur,reason:e,message:t,...r!==void 0?{cause:r}:{}}}function Ge(e,t,r){return{type:lr,reason:e,message:t,...r!==void 0?{cause:r}:{}}}function Xe(e,t,r){return{type:cr,reason:e,message:t,...r!==void 0?{cause:r}:{}}}function Be(e){return{type:pr,finalPosition:e}}function Ot(e={}){let t=e.highWaterMark??16,r=e.lowWaterMark??Math.floor(t/2),m=e.onStateChange,a="flowing",d=0,S=[];function g(i){if(a!==i&&(a=i,m?.(i),i==="flowing"&&S.length>0)){let Y=S;S=[];for(let b of Y)b()}}function I(){a==="flowing"&&d>=t?g("paused"):a==="paused"&&d<=r&&g("flowing")}return{get state(){return a},get bufferedCount(){return d},get highWaterMark(){return t},get lowWaterMark(){return r},increment(){d++,I()},decrement(){d>0&&(d--,I())},setCount(i){d=Math.max(0,i),I()},waitForDrain(){return a==="flowing"?Promise.resolve():new Promise(i=>{S.push(i)})},reset(){d=0,S=[],g("flowing")}}}function mr(e){return{_tag:"Duration",millis:e}}function dr(e){return{_tag:"Duration",millis:e*1e3}}function fr(e){return{_tag:"Duration",millis:e*60*1e3}}function Er(e){return{_tag:"Duration",millis:e*60*60*1e3}}function wr(e){return{_tag:"Duration",millis:e*24*60*60*1e3}}function _t(e){return e.millis}function Dt(e){let t=e.trim().match(/^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)$/i);if(!t)return;let r=parseFloat(t[1]);switch(t[2].toLowerCase()){case"ms":return mr(r);case"s":return dr(r);case"m":return fr(r);case"h":return Er(r);case"d":return wr(r);default:return}}async function Pt(e,t){let r=e["~standard"].validate(t),m=r instanceof Promise?await r:r;return m.issues?U({type:"INPUT_VALIDATION_ERROR",issues:m.issues.map(a=>({message:a.message,path:a.path?.map(d=>typeof d=="object"?d.key:d)})),message:`Input validation failed: ${m.issues.map(a=>a.message).join(", ")}`}):X(m.value)}function Qe(e,t){let r=m=>((...a)=>{let d=a.at(-1),S=a.length>0&&typeof d=="object"&&d!==null&&!Array.isArray(d)&&typeof d!="function",g=S?d:void 0,I=S?a.slice(0,-1):a,i={...t,...g?.deps??{}},Y=g?{...g,deps:i}:{deps:i};return e[m](...I,Y)});return{run:r("run"),runWithState:r("runWithState"),withDeps(m){return Qe(e,{...t,...m})}}}function Ze(e,t,r){if(typeof e!="string"||e.length===0)throw new TypeError("createWorkflow(workflowName, deps, options?): first argument must be a non-empty string. Example: createWorkflow('checkout', { chargeCard, sendEmail })");let m=t??{},a=r;async function d(i,Y,b){let x=i??crypto.randomUUID(),G=b?.deps?{...m,...b.deps}:m,l=[],q=b?.createContext??a?.createContext,Q=q?await q():void 0,W=b?.signal??a?.signal,fe=b?.onEvent??a?.onEvent,ke=b?.onError??a?.onError,$=b?.shouldRun??a?.shouldRun,V=b?.onBeforeStart??a?.onBeforeStart,f=b?.onAfterStep??a?.onAfterStep,ee=b?.resumeState??a?.resumeState,ae=a?.catchUnexpected??Ke,me={},ue=(b?.devWarnings??a?.devWarnings)===!0&&process.env.NODE_ENV!=="production",le=new Set,c=new Set,y={workflowId:x,onEvent:fe,context:Q!==void 0?Q:void 0,signal:W,input:{},ref:s=>me[s],set:(s,w)=>{ue&&!le.has(s)&&(le.add(s),console.warn(`awaitly: ctx.set('${s}', ...) is deprecated for static analysis. Use step('id', fn, { out: '${s}' }) instead.`)),me[s]=w},get:s=>(ue&&!c.has(s)&&(c.add(s),console.warn(`awaitly: ctx.get('${s}') is deprecated for static analysis. Use ctx.ref('${s}') instead for tracked dependencies.`)),me[s])},n=s=>{let w=s.context!==void 0||Q===void 0?s:{...s,context:Q},E=w.workflowName===void 0?{...w,workflowName:e}:w;fe?.(E,Q)},u=(s,w)=>{let E={type:"WORKFLOW_CANCELLED",reason:s,lastStepKey:w};return U(ae(E),{cause:E})};if(W?.aborted){let s=typeof W.reason=="string"?W.reason:W.reason instanceof Error?W.reason.message:void 0;return n({type:"workflow_cancelled",workflowId:x,ts:Date.now(),durationMs:0,reason:s}),u(s)}if($){let s=performance.now();try{let w=await $(x,Q),E=performance.now()-s;if(n({type:"hook_should_run",workflowId:x,ts:Date.now(),durationMs:E,result:w,skipped:!w}),!w){let z=new Error("Workflow skipped by shouldRun hook");return U(ae(z),{cause:z})}}catch(w){let E=performance.now()-s;return n({type:"hook_should_run_error",workflowId:x,ts:Date.now(),durationMs:E,error:w}),U(ae(w),{cause:w})}}if(V){let s=performance.now();try{let w=await V(x,Q),E=performance.now()-s;if(n({type:"hook_before_start",workflowId:x,ts:Date.now(),durationMs:E,result:w,skipped:!w}),!w){let z=new Error("Workflow skipped by onBeforeStart hook");return U(ae(z),{cause:z})}}catch(w){let E=performance.now()-s;return n({type:"hook_before_start_error",workflowId:x,ts:Date.now(),durationMs:E,error:w}),U(ae(w),{cause:w})}}let o=a?.inputSchema,k=a?.input;if(o){let s=await Pt(o,k);if(!s.ok)return U(s.error);y.input=s.value}else k!==void 0&&(y.input=k);let h=Date.now(),A=performance.now();n({type:"workflow_start",workflowId:x,ts:h});let p=b?.cache??a?.cache,_=b?.streamStore??a?.streamStore;if(ee&&!p&&(p=new Map),ee&&p){let s=typeof ee=="function"?await ee():ee;s.steps instanceof Map||(console.warn(`awaitly: resumeState.steps is not a Map (got ${typeof s.steps}). This usually happens when state is serialized with JSON.stringify() directly.
7
- Use stringifyState() and parseState() from 'awaitly/persistence' instead:
8
- import { stringifyState, parseState } from 'awaitly/persistence';
9
- const json = stringifyState(state); // Save this
10
- const restored = parseState(json); // Load this`),typeof s.steps=="object"&&s.steps!==null&&(s.steps=new Map(Object.entries(s.steps))));for(let[w,E]of s.steps){let{result:z,meta:T}=E;if(z.ok)p.set(w,z);else{let v=T??{origin:"result",resultCause:z.cause};p.set(w,be(z.error,v,z.cause))}}}let F=b?.snapshot??a?.snapshot,J=a?.serialization;if(F&&!ee){p||(p=new Map);let s=F,w=J?.decode;for(let[E,z]of Object.entries(s.steps))if(Object.prototype.hasOwnProperty.call(s.steps,E))try{if(z.ok){let T=w?w(z.value):z.value;p.set(E,X(T))}else{let T=w?w(z.error):z.error,v=Ye(z.cause),C=z.meta?.origin==="throw"?{origin:"throw",thrown:v}:{origin:"result",resultCause:v};p.set(E,be(T,C,v))}}catch(T){throw new $e(`Failed to decode step "${E}": ${T instanceof Error?T.message:String(T)}`,E,T instanceof Error?T:void 0)}}let re=!1,N,Z,K=()=>{re=!0,N=typeof W?.reason=="string"?W.reason:W?.reason instanceof Error?W.reason.message:void 0};W&&!W.aborted&&W.addEventListener("abort",K,{once:!0});let H=()=>{if(re||W?.aborted)throw{type:"WORKFLOW_CANCELLED",reason:N??(typeof W?.reason=="string"?W.reason:W?.reason instanceof Error?W.reason.message:void 0),lastStepKey:Z}},P=async(s,w,E)=>{if(!f)return;let z=performance.now();try{await f(s,w,x,Q);let T=performance.now()-z;n({type:"hook_after_step",workflowId:x,stepKey:s,ts:Date.now(),durationMs:T})}catch(T){let v=performance.now()-z;throw n({type:"hook_after_step_error",workflowId:x,stepKey:s,ts:Date.now(),durationMs:v,error:T}),T}},Re=s=>{let w=async(T,v,C)=>{if(typeof T!="string")throw new Error('[awaitly] step() requires a string ID as the first argument. Example: step("fetchUser", () => fetchUser(id))');let D=T,O=C??{},j=D,R=Object.prototype.hasOwnProperty.call(O,"key")?O.key:D,{ttl:L,out:oe}=O;H();let ne=Je(O);if(R&&p&&p.has(R)){n({type:"step_cache_hit",workflowId:x,stepKey:R,name:j,ts:Date.now(),...ne&&{metadata:ne}});let M=p.get(R);if(M.ok)return Z=R,oe&&(me[oe]=M.value),M.value;let B=Ne(M.cause);throw De(M.error,B)}R&&p&&n({type:"step_cache_miss",workflowId:x,stepKey:R,name:j,ts:Date.now(),...ne&&{metadata:ne}});try{let M=await s(D,v,O);return oe&&(me[oe]=M),O.compensate&&l.push({stepName:j,value:M,compensate:O.compensate}),R&&(Z=R,p&&p.set(R,X(M),L?{ttl:L}:void 0),await P(R,X(M))),M}catch(M){if(R&&ve(M)){let B=M,pe=B.meta.origin==="result"?B.meta.resultCause:B.meta.origin==="throw"?B.meta.thrown:void 0,te=be(B.error,B.meta,pe);p&&p.set(R,te,L?{ttl:L}:void 0),await P(R,te,B.meta)}throw M}};w.try=async(T,v,C)=>{let{ttl:D}=C,O=C.key??T,j=T;if(p&&p.has(O)){n({type:"step_cache_hit",workflowId:x,stepKey:O,name:j,ts:Date.now()});let R=p.get(O);if(R.ok)return R.value;let L=Ne(R.cause);throw De(R.error,L)}p&&n({type:"step_cache_miss",workflowId:x,stepKey:O,name:j,ts:Date.now()});try{let R=await s.try(T,v,{...C,key:O});return C.compensate&&l.push({stepName:j,value:R,compensate:C.compensate}),p&&p.set(O,X(R),D?{ttl:D}:void 0),await P(O,X(R)),R}catch(R){if(ve(R)){let L=R,oe=L.meta.origin==="result"?L.meta.resultCause:L.meta.origin==="throw"?L.meta.thrown:void 0,ne=be(L.error,L.meta,oe);p&&p.set(O,ne,D?{ttl:D}:void 0),await P(O,ne,L.meta)}throw R}},w.fromResult=async(T,v,C)=>{let{ttl:D}=C,O=C.key??T,j=T;if(p&&p.has(O)){n({type:"step_cache_hit",workflowId:x,stepKey:O,name:j,ts:Date.now()});let R=p.get(O);if(R.ok)return R.value;let L=Ne(R.cause);throw De(R.error,L)}p&&n({type:"step_cache_miss",workflowId:x,stepKey:O,name:j,ts:Date.now()});try{let R=await s.fromResult(T,v,{...C,key:O});return p&&p.set(O,X(R),D?{ttl:D}:void 0),await P(O,X(R)),R}catch(R){if(ve(R)){let L=R,oe=L.meta.origin==="result"?L.meta.resultCause:L.meta.origin==="throw"?L.meta.thrown:void 0,ne=be(L.error,L.meta,oe);p&&p.set(O,ne,D?{ttl:D}:void 0),await P(O,ne,L.meta)}throw R}},w.race=s.race,w.withFallback=async(T,v,C)=>{let D=C.key??T,O=T;if(p&&p.has(D)){n({type:"step_cache_hit",workflowId:x,stepKey:D,name:O,ts:Date.now()});let j=p.get(D);if(j.ok)return j.value;let R=Ne(j.cause);throw De(j.error,R)}p&&n({type:"step_cache_miss",workflowId:x,stepKey:D,name:O,ts:Date.now()});try{let j=await s.withFallback(T,v,C);return p&&p.set(D,X(j)),await P(D,X(j)),j}catch(j){if(ve(j)){let R=j,L=R.meta.origin==="result"?R.meta.resultCause:R.meta.origin==="throw"?R.meta.thrown:void 0,oe=be(R.error,R.meta,L);p&&p.set(D,oe),await P(D,oe,R.meta)}throw j}},w.withResource=async(T,v)=>{let C=T;try{let D=await s.withResource(T,v);return await P(C,X(D)),D}catch(D){if(ve(D)){let O=D,j=O.meta.origin==="result"?O.meta.resultCause:O.meta.origin==="throw"?O.meta.thrown:void 0,R=be(O.error,O.meta,j);await P(C,R,O.meta)}throw D}},w.retry=(T,v,C)=>{let D={key:C.key,retry:{attempts:C.attempts,backoff:C.backoff,initialDelay:C.initialDelay,maxDelay:C.maxDelay,jitter:C.jitter,shouldRetry:C.shouldRetry,onRetry:C.onRetry},timeout:C.timeout,ttl:C.ttl};return w(T,v,D)},w.withTimeout=(T,v,C)=>{let D={key:C.key,timeout:C,ttl:C.ttl};return w(T,v,D)},w.sleep=(T,v,C)=>{if(typeof T!="string"||T.length===0)throw new Error('[awaitly] step.sleep() requires an explicit string ID as the first argument. Example: step.sleep("delay", "5s")');let D=typeof v=="string"?Dt(v):v;if(!D)throw new Error(`step.sleep: invalid duration '${v}'`);let O=_t(D),j=C?.signal;return w(T,async()=>{if(W?.aborted||j?.aborted){let L=new Error("Sleep aborted");throw L.name="AbortError",L}return new Promise((L,oe)=>{let ne={timeoutId:void 0},M=()=>{ne.timeoutId&&clearTimeout(ne.timeoutId);let B=new Error("Sleep aborted");B.name="AbortError",oe(B)};W?.addEventListener("abort",M,{once:!0}),j?.addEventListener("abort",M,{once:!0}),ne.timeoutId=setTimeout(()=>{W?.removeEventListener("abort",M),j?.removeEventListener("abort",M),L(X(void 0))},O)})},{key:C?.key,ttl:C?.ttl,description:C?.description})};let E=new Map,z=new Map;return w.getWritable=T=>{let v=T?.namespace??"default",C=T?.highWaterMark??16;if(!_)throw new Error("streamStore is required to use getWritable(). Pass a streamStore to createWorkflow options.");let D=`${x}:${v}`,O=E.get(D);if(O&&!O.closed&&!O.aborted)return O.writer;let j=Ot({highWaterMark:C,onStateChange:B=>{n({type:"stream_backpressure",workflowId:x,namespace:v,bufferedCount:j.bufferedCount,state:B,ts:Date.now()})}}),R=0,L=!0,oe=!1,ne=!1;n({type:"stream_created",workflowId:x,namespace:v,ts:Date.now()});let M={async write(B){if(ne)return U(Le("closed","Stream is closed"));if(oe)return U(Le("aborted","Stream was aborted"));j.state==="paused"&&await j.waitForDrain();let pe={value:B,position:R,ts:Date.now()},te=await _.append(x,v,pe);return te.ok?(n({type:"stream_write",workflowId:x,namespace:v,position:R,ts:Date.now()}),R++,j.increment(),X(void 0)):(n({type:"stream_error",workflowId:x,namespace:v,error:te.error,position:R,ts:Date.now()}),U(Le("store_error",te.error.message,te.error)))},async close(){if(ne)return U(Xe("already_closed","Stream is already closed"));let B=await _.closeStream(x,v);return B.ok?(ne=!0,L=!1,n({type:"stream_close",workflowId:x,namespace:v,finalPosition:R,ts:Date.now()}),E.delete(D),X(void 0)):U(Xe("store_error",B.error.message,B.error))},abort(B){oe=!0,L=!1,ne=!0,n({type:"stream_error",workflowId:x,namespace:v,error:B,position:R,ts:Date.now()}),E.delete(D)},get writable(){return L},get position(){return R},get namespace(){return v}};return E.set(D,{writer:M,backpressure:j,aborted:oe,closed:ne}),M},w.getReadable=T=>{let v=T?.namespace??"default",C=T?.startIndex??0,D=T?.pollInterval??10,O=T?.pollTimeout??3e4;if(!_)throw new Error("streamStore is required to use getReadable(). Pass a streamStore to createWorkflow options.");let j=`${x}:${v}:${C}`,R=z.get(j);if(R&&!R.closed)return R.reader;let L=()=>{let xe=`${x}:${v}`,ie=E.get(xe);ie&&ie.backpressure.decrement()},oe=C,ne=!0,M=!1,B=[],pe=0,te={async read(){if(M)return U(Ge("closed","Reader is closed"));if(pe<B.length){let we=B[pe++];return oe=we.position+1,L(),n({type:"stream_read",workflowId:x,namespace:v,position:we.position,ts:Date.now()}),X(we.value)}let xe=`${x}:${v}`,ie=Date.now(),Ee=E.has(xe),se=await _.getMetadata(x,v),de=se.ok&&se.value!==void 0;for(;Date.now()-ie<O;){let we=await _.read(x,v,oe,100);if(!we.ok)return U(Ge("store_error",we.error.message,we.error));let Me=we.value;if(Me.length>0){B=Me,pe=1;let We=Me[0];return oe=We.position+1,L(),n({type:"stream_read",workflowId:x,namespace:v,position:We.position,ts:Date.now()}),X(We.value)}let Ie=E.has(xe),Ce=await _.getMetadata(x,v),lt=Ce.ok&&Ce.value!==void 0;if(Ie&&(Ee=!0),lt&&(de=!0),Ce.ok&&Ce.value?.closed)return ne=!1,U(Be(oe));if(Ee&&!Ie&&!lt)return ne=!1,U(Be(oe));de&&!Ie&&Ce.ok&&Ce.value?.closed,await new Promise(We=>setTimeout(We,D))}return ne=!1,U(Be(oe))},close(){M=!0,ne=!1,B=[],z.delete(j)},get readable(){return ne},get position(){return oe},get namespace(){return v}};return z.set(j,{reader:te,position:oe,closed:M}),te},w.streamForEach=async(T,v,C)=>{let D=C?.checkpointInterval??1,O=C?.concurrency??1,j=[],R=0,L=-1,oe=M=>typeof M=="object"&&M!==null&&"read"in M&&typeof M.read=="function",ne=async(M,B,pe,te)=>{let ie=D>0&&B%D===0?`stream-foreach:${te}:pos-${pe}`:void 0,Ee=ie??`stream-item-${pe}`,se=await w(Ee,()=>v(M,B),{key:ie});return{index:B,position:pe,result:se}};if(oe(T))if(O<=1){let M=T.position,B=await T.read();for(;B.ok;){let pe=B.value,{result:te}=await ne(pe,R,M,T.namespace);j.push(te),L=M,R++,M=T.position,B=await T.read()}}else{let M=new Map,B=0,pe=0,te=new Array(O).fill(null),xe=async()=>{for(let we=0;we<te.length;we++)if(te[we]===null)return we;let se=te.filter(we=>we!==null),de=await Promise.race(se);return M.set(de.index,{position:de.position,result:de.result}),te[de.slotIndex]=null,de.slotIndex},ie=T.position,Ee=await T.read();for(;Ee.ok;){let se=await xe(),de=B,we=ie,Me=Ee.value,Ie=se;te[se]=ne(Me,de,we,T.namespace).then(Ce=>({slotIndex:Ie,...Ce})),pe++,B++,ie=T.position,Ee=await T.read()}for(let se=0;se<te.length;se++)if(te[se]!==null){let de=await te[se];M.set(de.index,{position:de.position,result:de.result})}for(let se=0;se<pe;se++){let de=M.get(se);de&&(j.push(de.result),L=de.position,R++)}}else if(O<=1){let M=0;for await(let B of T){let{result:pe}=await ne(B,M,M,"async-iterable");j.push(pe),L=M,R++,M++}}else{let M=new Map,B=0,pe=0,te=new Array(O).fill(null),xe=async()=>{for(let se=0;se<te.length;se++)if(te[se]===null)return se;let ie=te.filter(se=>se!==null),Ee=await Promise.race(ie);return M.set(Ee.index,Ee.result),te[Ee.slotIndex]=null,Ee.slotIndex};for await(let ie of T){let Ee=await xe(),se=B,de=Ee;te[Ee]=ne(ie,se,se,"async-iterable").then(we=>({slotIndex:de,...we})),pe++,B++}for(let ie=0;ie<te.length;ie++)if(te[ie]!==null){let Ee=await te[ie];M.set(Ee.index,Ee.result)}for(let ie=0;ie<pe;ie++)M.has(ie)&&(j.push(M.get(ie)),L=ie,R++)}return{results:j,processedCount:R,lastPosition:L}},w.if=s.if,w.label=s.label,w.branch=s.branch,w.arm=s.arm,w.forEach=s.forEach,w.item=s.item,w.dep=s.dep,w.workflow=(T,v,C)=>w(T,v,C),w.all=(T,v,C)=>{let D=C!==void 0&&Object.prototype.hasOwnProperty.call(C,"key")?C:{...C,key:void 0};return w(T,async()=>X(await s.all(T,v)),D)},w.map=(T,v,C,D)=>{let O=D!==void 0&&Object.prototype.hasOwnProperty.call(D,"key")?D:{...D,key:void 0};return w(T,async()=>X(await s.map(T,v,C,D)),O)},w},Te=({step:s})=>Y({step:Re(s),deps:G,ctx:y}),ce;try{ce=await Fe(Te,{onError:ke,onEvent:fe,catchUnexpected:ae,workflowId:x,workflowName:e,context:Q,_workflowSignal:W})}finally{W&&W.removeEventListener("abort",K)}if(!ce.ok&&l.length>0){let s=[];for(let w=l.length-1;w>=0;w--){let E=l[w];try{await E.compensate(E.value)}catch(z){s.push({stepName:E.stepName,error:z})}}if(s.length>0){let w={type:"SAGA_COMPENSATION_ERROR",originalError:ce.error,compensationErrors:s};ce=U(w,{cause:ce.cause})}}let he=performance.now()-A;if(!ce.ok){let s;if(ze(ce.cause)&&(s=ce.cause),!s&&re&&ht(ce.error)){let w=ce.cause;w!=null&&typeof w=="object"&&"name"in w&&w.name==="AbortError"&&(s={type:"WORKFLOW_CANCELLED",reason:N??(typeof W?.reason=="string"?W.reason:W?.reason instanceof Error?W.reason.message:void 0),lastStepKey:Z})}if(s)return n({type:"workflow_cancelled",workflowId:x,ts:Date.now(),durationMs:he,reason:s.reason,lastStepKey:s.lastStepKey}),s&&!ze(ce.cause)?U(ce.error,{cause:s}):ce}if(ce.ok&&re){let s=N??(typeof W?.reason=="string"?W.reason:W?.reason instanceof Error?W.reason.message:void 0);n({type:"workflow_cancelled",workflowId:x,ts:Date.now(),durationMs:he,reason:s,lastStepKey:Z});let w={type:"WORKFLOW_CANCELLED",reason:s,lastStepKey:Z};return U(ae(w),{cause:w})}return ce.ok?n({type:"workflow_success",workflowId:x,ts:Date.now(),durationMs:he}):n({type:"workflow_error",workflowId:x,ts:Date.now(),durationMs:he,error:ce.error}),ce}function S(i,Y,b){let x,G,l;return typeof i=="string"?(x=i,G=Y,l=b):(G=i,l=Y),d(x,G,l)}async function g(i,Y,b){let x,G,l;typeof i=="string"?(x=i,G=Y,l=b):(G=i,l=Y);let q=At(),Q=l?.onEvent,fe={...l,onEvent:(V,f)=>{q.handleEvent(V);try{Q?.(V,f)}catch{}}},ke,$;try{ke=await d(x,G,fe)}catch(V){let f=a?.catchUnexpected??Ke;ke=U(f(V),{cause:V})}finally{$=q.getResumeState()}return{result:ke,resumeState:$}}let I={withDeps:i=>Qe(I,i),run:S,runWithState:g};return I}async function et(e,t,r){let m=[],a={},d=[],S=b=>{if(m.push(b),b.type==="step_complete"&&b.stepKey){let x={output:b.result.ok?b.result.value:void 0,durationMs:b.durationMs,result:b.result};a[b.stepKey]=x,d.push(b.stepKey)}},g=Ze("test-workflow",e),I=performance.now(),i=await g.run(t,{onEvent:S,signal:r?.signal}),Y=performance.now()-I;return{result:i,steps:a,events:m,durationMs:Y,stepOrder:d}}function tt(e){return typeof e=="object"&&e!==null&&"__earlyExit"in e&&e.__earlyExit===!0}function rt(e,t={}){let{recordInvocations:r=!0,clock:m=Date.now}=t,a=[],d=new Map,S=0,g=[];function I($){a=[...$],S=0,d.clear()}function i($,V){d.set($,V)}function Y($){if($&&d.has($))return d.get($);if(S<a.length)return a[S++]}function b(){let $=async(V,f,ee)=>{let ae,me,ue;typeof V=="string"?(ae=V,me=f,ue=ee??{}):(me=V,typeof f=="string"?(ae=f,ue={}):(ue=f??{},ae=ue.key??"step"));let le=m(),c={name:ae,key:ue.key,order:g.length,timestamp:le};r&&g.push(c);let y=Y(ae);if(y)switch(c.durationMs=m()-le,y.type){case"ok":return c.result=X(y.value),y.value;case"err":throw c.result=U(y.error),{__earlyExit:!0,error:y.error};case"throw":throw y.error}let n=typeof me=="function"?await me():await me;if(c.durationMs=m()-le,c.result=n,!n.ok)throw{__earlyExit:!0,error:n.error};return n.value};return $.try=async(V,f,ee)=>{let ae,me,ue;typeof V=="string"?(ae=V,me=f,ue=ee):(me=V,ue=f,ae=ue.key??"step");let le=m(),c={name:ae,key:"key"in ue?ue.key:void 0,order:g.length,timestamp:le};r&&g.push(c);let y=Y(ae);if(y)switch(c.durationMs=m()-le,y.type){case"ok":return c.result=X(y.value),y.value;case"err":throw c.result=U(y.error),{__earlyExit:!0,error:y.error};case"throw":throw y.error}try{let n=await me();return c.durationMs=m()-le,c.result=X(n),n}catch(n){c.durationMs=m()-le;let u="error"in ue?ue.error:ue.onError(n);throw c.result=U(u),{__earlyExit:!0,error:u}}},$}async function x($){let V=b();try{let f=await $({step:V,deps:e});return X(f)}catch(f){return tt(f)?U(f.error):U(new Se({cause:f}))}}async function G($,V){let f=b();try{let ee=await V({step:f,deps:e,input:$});return X(ee)}catch(ee){return tt(ee)?U(ee.error):U(new Se({cause:ee}))}}function l(){return[...g]}function q($){let V=g.map(ee=>ee.name??ee.key??"unnamed").filter(ee=>ee!=="unnamed"),f=JSON.stringify(V)===JSON.stringify($);return{passed:f,message:f?`Steps invoked in order: ${$.join(", ")}`:`Expected steps [${$.join(", ")}] but got [${V.join(", ")}]`,expected:$,actual:V}}function Q($){let V=g.some(f=>f.name===$||f.key===$);return{passed:V,message:V?`Step "${$}" was invoked`:`Step "${$}" was NOT invoked`,expected:$,actual:V}}function W($){let V=g.some(f=>f.name===$||f.key===$);return{passed:!V,message:V?`Step "${$}" was invoked but should not have been`:`Step "${$}" was correctly NOT invoked`,expected:"not called",actual:V?"called":"not called"}}function fe($,V){let f=$.ok===V.ok&&($.ok?JSON.stringify($.value)===JSON.stringify(V.value):JSON.stringify($.error)===JSON.stringify(V.error));return{passed:f,message:f?"Result matches expected":"Result does not match expected",expected:V,actual:$}}function ke(){a=[],d.clear(),S=0,g=[]}return{script:I,scriptStep:i,run:x,runWithInput:G,getInvocations:l,assertSteps:q,assertStepCalled:Q,assertStepNotCalled:W,assertResult:fe,reset:ke}}function Mt(){let e,t=[],r=[],m=((...a)=>{if(r.push(a),t.length>0)return Promise.resolve(t.shift());if(e)return Promise.resolve(e);throw new Error("Mock function called without configured return value")});return m.returns=a=>(e=a,m),m.returnsOnce=a=>(t.push(a),m),m.getCalls=()=>[...r],m.getCallCount=()=>r.length,m.reset=()=>{e=void 0,t.length=0,r.length=0},m}function It(e,t,r){let m=e.reduce((a,d)=>a+(d.durationMs??0),0);return{invocations:e.map(a=>({...a,timestamp:0})),result:t,events:r?.map(a=>({...a,ts:0})),durationMs:m}}function Wt(e,t){let r=[];e.invocations.length!==t.invocations.length&&r.push(`Invocation count: ${e.invocations.length} vs ${t.invocations.length}`);let m=Math.max(e.invocations.length,t.invocations.length);for(let a=0;a<m;a++){let d=e.invocations[a],S=t.invocations[a];if(!d){r.push(`Step ${a}: missing in first snapshot`);continue}if(!S){r.push(`Step ${a}: missing in second snapshot`);continue}d.name!==S.name&&r.push(`Step ${a} name: "${d.name}" vs "${S.name}"`),d.key!==S.key&&r.push(`Step ${a} key: "${d.key}" vs "${S.key}"`),d.result?.ok!==S.result?.ok&&r.push(`Step ${a} result: ${d.result?.ok?"ok":"err"} vs ${S.result?.ok?"ok":"err"}`)}return e.result.ok!==t.result.ok&&r.push(`Final result: ${e.result.ok?"ok":"err"} vs ${t.result.ok?"ok":"err"}`),{equal:r.length===0,differences:r}}function Ut(e=0){let t=e;return{now:()=>t,advance:r=>{t+=r},set:r=>{t=r},reset:()=>{t=e}}}function Nt(e){return{type:"ok",value:e}}function jt(e){return{type:"err",error:e}}function Ft(e){return{type:"throw",error:e}}function Kt(e,t={}){let{clock:r=Date.now}=t,m=rt(e,t),a=[],d=[];async function S(G){a=[],d=[];let l={step:async(Q,W)=>{try{let fe=await m.run(async({step:ke})=>ke("saga-step",Q));if(!fe.ok)throw await q(),{__earlyExit:!0,error:fe.error};return W?.compensate&&d.push({value:fe.value,compensate:W.compensate}),fe.value}catch(fe){throw d.length>0&&await q(),fe}}};async function q(){let Q=[...d].reverse();d=[];for(let{name:W,value:fe,compensate:ke}of Q)try{await ke(fe),a.push({stepName:W,order:a.length,value:fe,timestamp:r()})}catch($){console.error(`Compensation failed for step "${W}":`,$)}}try{let Q=await G({saga:l,deps:e});return X(Q)}catch(Q){return tt(Q)?U(Q.error):(await q(),U(new Se({cause:Q})))}}function g(){return[...a]}function I(G){let l=a.map(Q=>Q.stepName),q=JSON.stringify(l)===JSON.stringify(G);return{passed:q,message:q?`Compensations ran in order: ${G.join(" \u2192 ")}`:`Expected compensations [${G.join(" \u2192 ")}] but got [${l.join(" \u2192 ")}]`,expected:G,actual:l}}function i(G){let l=a.some(q=>q.stepName===G);return{passed:l,message:l?`Step "${G}" was compensated`:`Step "${G}" was NOT compensated`,expected:G,actual:l}}function Y(G){let l=a.some(q=>q.stepName===G);return{passed:!l,message:l?`Step "${G}" was compensated but should not have been`:`Step "${G}" was correctly NOT compensated`,expected:"not compensated",actual:l?"compensated":"not compensated"}}let b=m.reset;function x(){b(),a=[],d=[]}return{...m,reset:x,getCompensations:g,assertCompensationOrder:I,assertCompensated:i,assertNotCompensated:Y,runSaga:S}}function $t(e,t,r={}){let{strict:m=!0}=r,a=t.map(I=>{let[i,Y]=I.split(":");return{type:i,name:Y}}),S=(m?e:e.filter(I=>a.some(i=>I.type===i.type))).map(I=>{let i="name"in I?I.name:void 0,Y="stepKey"in I?I.stepKey:void 0,b=i??Y;return b?`${I.type}:${b}`:I.type}),g=JSON.stringify(S)===JSON.stringify(t);return{passed:g,message:g?`Event sequence matches: ${t.join(" \u2192 ")}`:`Event sequence mismatch.
11
- Expected: ${t.join(" \u2192 ")}
12
- Actual: ${S.join(" \u2192 ")}`,expected:t,actual:S}}function nt(e,t){let r=e.find(m=>Object.entries(t).every(([a,d])=>{let S=m[a];return typeof d=="object"&&d!==null?JSON.stringify(S)===JSON.stringify(d):S===d}));return{passed:!!r,message:r?`Event matching ${JSON.stringify(t)} was emitted`:`No event matching ${JSON.stringify(t)} was found`,expected:t,actual:r??"not found"}}function Lt(e,t){let r=nt(e,t);return{passed:!r.passed,message:r.passed?`Event matching ${JSON.stringify(t)} was found but should not have been`:`Correctly, no event matching ${JSON.stringify(t)} was emitted`,expected:"not emitted",actual:r.actual}}function ot(e){if(!e.ok)throw new Error(`Expected Ok result, got Err: ${JSON.stringify(e.error,null,2)}`)}function st(e){if(e.ok)throw new Error(`Expected Err result, got Ok: ${JSON.stringify(e.value,null,2)}`)}function at(e){return ot(e),e.value}function it(e){return st(e),e.error}async function Bt(e){return at(await e)}async function Vt(e){return it(await e)}function Ht(e){return St(e)?`Ok(${Pe(e.value)})`:`Err(${Pe(e.error)})`}function Pe(e){if(e===null)return"null";if(e===void 0)return"undefined";if(typeof e=="string")return`'${e}'`;if(typeof e=="number"||typeof e=="boolean")return String(e);if(typeof e=="function")return`[Function: ${e.name||"anonymous"}]`;if(Array.isArray(e))return e.length===0?"[]":e.length<=3?`[${e.map(Pe).join(", ")}]`:`[${e.slice(0,3).map(Pe).join(", ")}, ... (${e.length} items)]`;if(typeof e=="object"){let t=e,r=Object.keys(t);return r.length===0?"{}":r.length<=4?`{ ${r.map(d=>`${d}: ${Pe(t[d])}`).join(", ")} }`:`{ ${r.slice(0,3).map(a=>`${a}: ${Pe(t[a])}`).join(", ")}, ... (${r.length} keys) }`}return String(e)}function ut(e){let t=e.type,r="name"in e?e.name:void 0,m="stepKey"in e?e.stepKey:void 0,a=r??m;return a?`${t}:${a}`:t}function qt(e){return e.map(ut).join(" \u2192 ")}0&&(module.exports={assertEventEmitted,assertEventNotEmitted,assertEventSequence,compareSnapshots,createMockFn,createSagaHarness,createSnapshot,createTestClock,createWorkflowHarness,errOutcome,expectErr,expectOk,formatEvent,formatEvents,formatResult,okOutcome,testWorkflow,throwOutcome,unwrapErr,unwrapErrAsync,unwrapOk,unwrapOkAsync});
2173
+ See: https://jagreehal.github.io/awaitly/guides/troubleshooting/#returning-ok-from-workflow-executor-double-wrapping`
2174
+ );
2175
+ }
2176
+ }
2177
+ return ok2(value);
2178
+ } catch (error) {
2179
+ if (isMapperException(error)) {
2180
+ throw error.thrown;
2181
+ }
2182
+ if (isEarlyExitE(error)) {
2183
+ const originalCause = error.meta.origin === "throw" ? error.meta.thrown : error.meta.origin === "result" ? error.meta.resultCause : void 0;
2184
+ return err(error.error, { cause: originalCause });
2185
+ }
2186
+ const mapped = effectiveCatchUnexpected(error);
2187
+ onError?.(mapped, "unexpected", context);
2188
+ return err(mapped, { cause: error });
2189
+ }
2190
+ }
2191
+ var runStrict = (fn, options) => {
2192
+ return runFn(fn, options);
2193
+ };
2194
+ var run = /* @__PURE__ */ Object.assign(runFn, { strict: runStrict });
2195
+ async function allAsync(results) {
2196
+ if (results.length === 0) {
2197
+ return ok2([]);
2198
+ }
2199
+ return new Promise((resolve) => {
2200
+ let settled = false;
2201
+ let pendingCount = results.length;
2202
+ const values = new Array(results.length);
2203
+ for (let i = 0; i < results.length; i++) {
2204
+ const index = i;
2205
+ Promise.resolve(results[index]).catch((reason) => err(
2206
+ { type: "PROMISE_REJECTED", cause: reason },
2207
+ { cause: { type: "PROMISE_REJECTION", reason } }
2208
+ )).then((result) => {
2209
+ if (settled) return;
2210
+ if (!result.ok) {
2211
+ settled = true;
2212
+ resolve(result);
2213
+ return;
2214
+ }
2215
+ values[index] = result.value;
2216
+ pendingCount--;
2217
+ if (pendingCount === 0) {
2218
+ resolve(ok2(values));
2219
+ }
2220
+ });
2221
+ }
2222
+ });
2223
+ }
2224
+
2225
+ // src/workflow/guards.ts
2226
+ function isStepComplete(event) {
2227
+ return event.type === "step_complete";
2228
+ }
2229
+ function isWorkflowCancelled(error) {
2230
+ return typeof error === "object" && error !== null && error.type === "WORKFLOW_CANCELLED";
2231
+ }
2232
+
2233
+ // src/persistence.ts
2234
+ var SnapshotDecodeError = class extends Error {
2235
+ constructor(message, stepId, originalError) {
2236
+ super(message);
2237
+ this.stepId = stepId;
2238
+ this.originalError = originalError;
2239
+ this.name = "SnapshotDecodeError";
2240
+ }
2241
+ stepId;
2242
+ originalError;
2243
+ };
2244
+ function deserializeCauseNew(serialized) {
2245
+ if (serialized.type === "error") {
2246
+ const error = new Error(serialized.message);
2247
+ error.name = serialized.name;
2248
+ if (serialized.stack) {
2249
+ error.stack = serialized.stack;
2250
+ }
2251
+ if (serialized.cause) {
2252
+ error.cause = deserializeCauseNew(serialized.cause);
2253
+ }
2254
+ return error;
2255
+ }
2256
+ return serialized.value !== void 0 ? serialized.value : serialized.stringRepresentation;
2257
+ }
2258
+
2259
+ // src/workflow/cache-encoding.ts
2260
+ function isCachedErrorCause(cause) {
2261
+ return typeof cause === "object" && cause !== null && cause.__cachedMeta === true;
2262
+ }
2263
+ function encodeCachedError(error, meta, originalCause) {
2264
+ return err(error, {
2265
+ cause: { __cachedMeta: true, originalCause, meta }
2266
+ });
2267
+ }
2268
+ function decodeCachedMeta(cause) {
2269
+ if (isCachedErrorCause(cause)) {
2270
+ return cause.meta;
2271
+ }
2272
+ return { origin: "result", resultCause: cause };
2273
+ }
2274
+
2275
+ // src/workflow/resume-state.ts
2276
+ function createResumeStateCollector() {
2277
+ const steps = /* @__PURE__ */ new Map();
2278
+ return {
2279
+ handleEvent: (event) => {
2280
+ if (isStepComplete(event)) {
2281
+ steps.set(event.stepKey, { result: event.result, meta: event.meta });
2282
+ }
2283
+ },
2284
+ getResumeState: () => ({ steps: new Map(steps) }),
2285
+ clear: () => steps.clear()
2286
+ };
2287
+ }
2288
+
2289
+ // src/streaming/types.ts
2290
+ var STREAM_WRITE_ERROR = "STREAM_WRITE_ERROR";
2291
+ var STREAM_READ_ERROR = "STREAM_READ_ERROR";
2292
+ var STREAM_CLOSE_ERROR = "STREAM_CLOSE_ERROR";
2293
+ var STREAM_ENDED = "STREAM_ENDED";
2294
+ function streamWriteError(reason, message, cause) {
2295
+ return {
2296
+ type: STREAM_WRITE_ERROR,
2297
+ reason,
2298
+ message,
2299
+ ...cause !== void 0 ? { cause } : {}
2300
+ };
2301
+ }
2302
+ function streamReadError(reason, message, cause) {
2303
+ return {
2304
+ type: STREAM_READ_ERROR,
2305
+ reason,
2306
+ message,
2307
+ ...cause !== void 0 ? { cause } : {}
2308
+ };
2309
+ }
2310
+ function streamCloseError(reason, message, cause) {
2311
+ return {
2312
+ type: STREAM_CLOSE_ERROR,
2313
+ reason,
2314
+ message,
2315
+ ...cause !== void 0 ? { cause } : {}
2316
+ };
2317
+ }
2318
+ function streamEnded(finalPosition) {
2319
+ return {
2320
+ type: STREAM_ENDED,
2321
+ finalPosition
2322
+ };
2323
+ }
2324
+
2325
+ // src/streaming/backpressure.ts
2326
+ function createBackpressureController(options = {}) {
2327
+ const highWaterMark = options.highWaterMark ?? 16;
2328
+ const lowWaterMark = options.lowWaterMark ?? Math.floor(highWaterMark / 2);
2329
+ const onStateChange = options.onStateChange;
2330
+ let state = "flowing";
2331
+ let bufferedCount = 0;
2332
+ let drainResolvers = [];
2333
+ function updateState(newState) {
2334
+ if (state !== newState) {
2335
+ state = newState;
2336
+ onStateChange?.(newState);
2337
+ if (newState === "flowing" && drainResolvers.length > 0) {
2338
+ const resolvers = drainResolvers;
2339
+ drainResolvers = [];
2340
+ for (const resolve of resolvers) {
2341
+ resolve();
2342
+ }
2343
+ }
2344
+ }
2345
+ }
2346
+ function checkState() {
2347
+ if (state === "flowing" && bufferedCount >= highWaterMark) {
2348
+ updateState("paused");
2349
+ } else if (state === "paused" && bufferedCount <= lowWaterMark) {
2350
+ updateState("flowing");
2351
+ }
2352
+ }
2353
+ return {
2354
+ get state() {
2355
+ return state;
2356
+ },
2357
+ get bufferedCount() {
2358
+ return bufferedCount;
2359
+ },
2360
+ get highWaterMark() {
2361
+ return highWaterMark;
2362
+ },
2363
+ get lowWaterMark() {
2364
+ return lowWaterMark;
2365
+ },
2366
+ increment() {
2367
+ bufferedCount++;
2368
+ checkState();
2369
+ },
2370
+ decrement() {
2371
+ if (bufferedCount > 0) {
2372
+ bufferedCount--;
2373
+ checkState();
2374
+ }
2375
+ },
2376
+ setCount(count) {
2377
+ bufferedCount = Math.max(0, count);
2378
+ checkState();
2379
+ },
2380
+ waitForDrain() {
2381
+ if (state === "flowing") {
2382
+ return Promise.resolve();
2383
+ }
2384
+ return new Promise((resolve) => {
2385
+ drainResolvers.push(resolve);
2386
+ });
2387
+ },
2388
+ reset() {
2389
+ bufferedCount = 0;
2390
+ drainResolvers = [];
2391
+ updateState("flowing");
2392
+ }
2393
+ };
2394
+ }
2395
+
2396
+ // src/workflow/validation.ts
2397
+ async function validateInput(schema, input) {
2398
+ const result = schema["~standard"].validate(input);
2399
+ const resolved = result instanceof Promise ? await result : result;
2400
+ if (resolved.issues) {
2401
+ return err({
2402
+ type: "INPUT_VALIDATION_ERROR",
2403
+ issues: resolved.issues.map((i) => ({
2404
+ message: i.message,
2405
+ path: i.path?.map(
2406
+ (p) => typeof p === "object" ? p.key : p
2407
+ )
2408
+ })),
2409
+ message: `Input validation failed: ${resolved.issues.map((i) => i.message).join(", ")}`
2410
+ });
2411
+ }
2412
+ return ok2(resolved.value);
2413
+ }
2414
+
2415
+ // src/di.ts
2416
+ function withDeps(workflow, overrides) {
2417
+ const forward = (method) => ((...args) => {
2418
+ const last = args.at(-1);
2419
+ const hasConfig = args.length > 0 && typeof last === "object" && last !== null && !Array.isArray(last) && typeof last !== "function";
2420
+ const config = hasConfig ? last : void 0;
2421
+ const head = hasConfig ? args.slice(0, -1) : args;
2422
+ const mergedDeps = { ...overrides, ...config?.deps ?? {} };
2423
+ const mergedConfig = config ? { ...config, deps: mergedDeps } : { deps: mergedDeps };
2424
+ return workflow[method](...head, mergedConfig);
2425
+ });
2426
+ return {
2427
+ run: forward("run"),
2428
+ runWithState: forward("runWithState"),
2429
+ withDeps(nextOverrides) {
2430
+ return withDeps(workflow, { ...overrides, ...nextOverrides });
2431
+ }
2432
+ };
2433
+ }
2434
+
2435
+ // src/workflow/execute.ts
2436
+ function createWorkflow(workflowName, deps, options) {
2437
+ if (typeof workflowName !== "string" || workflowName.length === 0) {
2438
+ throw new TypeError(
2439
+ "createWorkflow(workflowName, deps, options?): first argument must be a non-empty string. Example: createWorkflow('checkout', { chargeCard, sendEmail })"
2440
+ );
2441
+ }
2442
+ const depsActual = deps ?? {};
2443
+ const optionsActual = options;
2444
+ async function internalExecute(runName, userFn, config) {
2445
+ const workflowId = runName ?? crypto.randomUUID();
2446
+ const effectiveDeps = config?.deps ? { ...depsActual, ...config.deps } : depsActual;
2447
+ const compensations = [];
2448
+ const createContextFn = config?.createContext ?? optionsActual?.createContext;
2449
+ const context = createContextFn ? await createContextFn() : void 0;
2450
+ const workflowSignal = config?.signal ?? optionsActual?.signal;
2451
+ const onEventHandler = config?.onEvent ?? optionsActual?.onEvent;
2452
+ const onErrorHandler = config?.onError ?? optionsActual?.onError;
2453
+ const shouldRunHook = config?.shouldRun ?? optionsActual?.shouldRun;
2454
+ const onBeforeStartHook = config?.onBeforeStart ?? optionsActual?.onBeforeStart;
2455
+ const onAfterStepHook = config?.onAfterStep ?? optionsActual?.onAfterStep;
2456
+ const resumeStateOption = config?.resumeState ?? optionsActual?.resumeState;
2457
+ const catchUnexpected = optionsActual?.catchUnexpected ?? defaultCatchUnexpected;
2458
+ const declaredGraph = config?.graph ?? optionsActual?.graph;
2459
+ const workflowData = {};
2460
+ const devWarnings = (config?.devWarnings ?? optionsActual?.devWarnings) === true && process.env.NODE_ENV !== "production";
2461
+ const ctxSetWarned = /* @__PURE__ */ new Set();
2462
+ const ctxGetWarned = /* @__PURE__ */ new Set();
2463
+ const workflowContext = {
2464
+ workflowId,
2465
+ onEvent: onEventHandler,
2466
+ context: context !== void 0 ? context : void 0,
2467
+ signal: workflowSignal,
2468
+ // Data store for static analysis
2469
+ input: {},
2470
+ ref: (key) => workflowData[key],
2471
+ set: (key, value) => {
2472
+ if (devWarnings && !ctxSetWarned.has(key)) {
2473
+ ctxSetWarned.add(key);
2474
+ console.warn(
2475
+ `awaitly: ctx.set('${key}', ...) is deprecated for static analysis. Use step('id', fn, { out: '${key}' }) instead.`
2476
+ );
2477
+ }
2478
+ workflowData[key] = value;
2479
+ },
2480
+ get: (key) => {
2481
+ if (devWarnings && !ctxGetWarned.has(key)) {
2482
+ ctxGetWarned.add(key);
2483
+ console.warn(
2484
+ `awaitly: ctx.get('${key}') is deprecated for static analysis. Use ctx.ref('${key}') instead for tracked dependencies.`
2485
+ );
2486
+ }
2487
+ return workflowData[key];
2488
+ }
2489
+ };
2490
+ const emitEvent = (event) => {
2491
+ const eventWithContext = event.context !== void 0 || context === void 0 ? event : { ...event, context };
2492
+ const eventWithName = eventWithContext.workflowName === void 0 ? { ...eventWithContext, workflowName } : eventWithContext;
2493
+ onEventHandler?.(eventWithName, context);
2494
+ };
2495
+ const createCancelledResult = (reason, lastStepKey2) => {
2496
+ const cancelledError = {
2497
+ type: "WORKFLOW_CANCELLED",
2498
+ reason,
2499
+ lastStepKey: lastStepKey2
2500
+ };
2501
+ return err(catchUnexpected(cancelledError), { cause: cancelledError });
2502
+ };
2503
+ if (workflowSignal?.aborted) {
2504
+ const reason = typeof workflowSignal.reason === "string" ? workflowSignal.reason : workflowSignal.reason instanceof Error ? workflowSignal.reason.message : void 0;
2505
+ emitEvent({
2506
+ type: "workflow_cancelled",
2507
+ workflowId,
2508
+ ts: Date.now(),
2509
+ durationMs: 0,
2510
+ reason
2511
+ });
2512
+ return createCancelledResult(reason);
2513
+ }
2514
+ if (shouldRunHook) {
2515
+ const hookStartTime = performance.now();
2516
+ try {
2517
+ const shouldRunResult = await shouldRunHook(workflowId, context);
2518
+ const hookDuration = performance.now() - hookStartTime;
2519
+ emitEvent({
2520
+ type: "hook_should_run",
2521
+ workflowId,
2522
+ ts: Date.now(),
2523
+ durationMs: hookDuration,
2524
+ result: shouldRunResult,
2525
+ skipped: !shouldRunResult
2526
+ });
2527
+ if (!shouldRunResult) {
2528
+ const skipCause = new Error("Workflow skipped by shouldRun hook");
2529
+ return err(catchUnexpected(skipCause), { cause: skipCause });
2530
+ }
2531
+ } catch (thrown) {
2532
+ const hookDuration = performance.now() - hookStartTime;
2533
+ emitEvent({
2534
+ type: "hook_should_run_error",
2535
+ workflowId,
2536
+ ts: Date.now(),
2537
+ durationMs: hookDuration,
2538
+ error: thrown
2539
+ });
2540
+ return err(catchUnexpected(thrown), { cause: thrown });
2541
+ }
2542
+ }
2543
+ if (onBeforeStartHook) {
2544
+ const hookStartTime = performance.now();
2545
+ try {
2546
+ const beforeStartResult = await onBeforeStartHook(workflowId, context);
2547
+ const hookDuration = performance.now() - hookStartTime;
2548
+ emitEvent({
2549
+ type: "hook_before_start",
2550
+ workflowId,
2551
+ ts: Date.now(),
2552
+ durationMs: hookDuration,
2553
+ result: beforeStartResult,
2554
+ skipped: !beforeStartResult
2555
+ });
2556
+ if (!beforeStartResult) {
2557
+ const skipCause = new Error("Workflow skipped by onBeforeStart hook");
2558
+ return err(catchUnexpected(skipCause), { cause: skipCause });
2559
+ }
2560
+ } catch (thrown) {
2561
+ const hookDuration = performance.now() - hookStartTime;
2562
+ emitEvent({
2563
+ type: "hook_before_start_error",
2564
+ workflowId,
2565
+ ts: Date.now(),
2566
+ durationMs: hookDuration,
2567
+ error: thrown
2568
+ });
2569
+ return err(catchUnexpected(thrown), { cause: thrown });
2570
+ }
2571
+ }
2572
+ const inputSchema = optionsActual?.inputSchema;
2573
+ const inputValue = optionsActual?.input;
2574
+ if (inputSchema) {
2575
+ const validationResult = await validateInput(inputSchema, inputValue);
2576
+ if (!validationResult.ok) {
2577
+ return err(validationResult.error);
2578
+ }
2579
+ workflowContext.input = validationResult.value;
2580
+ } else if (inputValue !== void 0) {
2581
+ workflowContext.input = inputValue;
2582
+ }
2583
+ const startTs = Date.now();
2584
+ const startTime = performance.now();
2585
+ emitEvent({
2586
+ type: "workflow_start",
2587
+ workflowId,
2588
+ ts: startTs
2589
+ });
2590
+ let cache = config?.cache ?? optionsActual?.cache;
2591
+ const streamStore = config?.streamStore ?? optionsActual?.streamStore;
2592
+ if (resumeStateOption && !cache) {
2593
+ cache = /* @__PURE__ */ new Map();
2594
+ }
2595
+ if (resumeStateOption && cache) {
2596
+ const resumeState = typeof resumeStateOption === "function" ? await resumeStateOption() : resumeStateOption;
2597
+ if (!(resumeState.steps instanceof Map)) {
2598
+ console.warn(
2599
+ `awaitly: resumeState.steps is not a Map (got ${typeof resumeState.steps}). This usually happens when state is serialized with JSON.stringify() directly.
2600
+ Use serializeResumeState() and deserializeResumeState() from 'awaitly/workflow' instead:
2601
+ import { serializeResumeState, deserializeResumeState } from 'awaitly/workflow';
2602
+ const json = JSON.stringify(serializeResumeState(state)); // Save this
2603
+ const restored = deserializeResumeState(JSON.parse(json)); // Load this`
2604
+ );
2605
+ if (typeof resumeState.steps === "object" && resumeState.steps !== null) {
2606
+ resumeState.steps = new Map(Object.entries(resumeState.steps));
2607
+ }
2608
+ }
2609
+ for (const [key, entry] of resumeState.steps) {
2610
+ const { result: result2, meta } = entry;
2611
+ if (result2.ok) {
2612
+ cache.set(key, result2);
2613
+ } else {
2614
+ const effectiveMeta = meta ?? { origin: "result", resultCause: result2.cause };
2615
+ cache.set(key, encodeCachedError(result2.error, effectiveMeta, result2.cause));
2616
+ }
2617
+ }
2618
+ }
2619
+ const snapshotOption = config?.snapshot ?? optionsActual?.snapshot;
2620
+ const snapshotSerialization = optionsActual?.serialization;
2621
+ if (snapshotOption && !resumeStateOption) {
2622
+ if (!cache) {
2623
+ cache = /* @__PURE__ */ new Map();
2624
+ }
2625
+ const snapshot = snapshotOption;
2626
+ const decode = snapshotSerialization?.decode;
2627
+ for (const [stepId, stepResult] of Object.entries(snapshot.steps)) {
2628
+ if (!Object.prototype.hasOwnProperty.call(snapshot.steps, stepId)) {
2629
+ continue;
2630
+ }
2631
+ try {
2632
+ if (stepResult.ok) {
2633
+ const value = decode ? decode(stepResult.value) : stepResult.value;
2634
+ cache.set(stepId, ok2(value));
2635
+ } else {
2636
+ const errorValue = decode ? decode(stepResult.error) : stepResult.error;
2637
+ const deserializedCause = deserializeCauseNew(stepResult.cause);
2638
+ const meta = stepResult.meta?.origin === "throw" ? { origin: "throw", thrown: deserializedCause } : { origin: "result", resultCause: deserializedCause };
2639
+ cache.set(stepId, encodeCachedError(errorValue, meta, deserializedCause));
2640
+ }
2641
+ } catch (e) {
2642
+ throw new SnapshotDecodeError(
2643
+ `Failed to decode step "${stepId}": ${e instanceof Error ? e.message : String(e)}`,
2644
+ stepId,
2645
+ e instanceof Error ? e : void 0
2646
+ );
2647
+ }
2648
+ }
2649
+ }
2650
+ let abortedDuringExecution = false;
2651
+ let abortReason;
2652
+ let lastStepKey;
2653
+ const abortHandler = () => {
2654
+ abortedDuringExecution = true;
2655
+ abortReason = typeof workflowSignal?.reason === "string" ? workflowSignal.reason : workflowSignal?.reason instanceof Error ? workflowSignal.reason.message : void 0;
2656
+ };
2657
+ if (workflowSignal && !workflowSignal.aborted) {
2658
+ workflowSignal.addEventListener("abort", abortHandler, { once: true });
2659
+ }
2660
+ const checkCancellation = () => {
2661
+ if (abortedDuringExecution || workflowSignal?.aborted) {
2662
+ const reason = abortReason ?? (typeof workflowSignal?.reason === "string" ? workflowSignal.reason : workflowSignal?.reason instanceof Error ? workflowSignal.reason.message : void 0);
2663
+ const cancelledError = {
2664
+ type: "WORKFLOW_CANCELLED",
2665
+ reason,
2666
+ lastStepKey
2667
+ };
2668
+ throw cancelledError;
2669
+ }
2670
+ };
2671
+ const callOnAfterStepHook = async (stepKey, result2, _meta) => {
2672
+ if (!onAfterStepHook) return;
2673
+ const hookStartTime = performance.now();
2674
+ try {
2675
+ await onAfterStepHook(stepKey, result2, workflowId, context);
2676
+ const hookDuration = performance.now() - hookStartTime;
2677
+ emitEvent({
2678
+ type: "hook_after_step",
2679
+ workflowId,
2680
+ stepKey,
2681
+ ts: Date.now(),
2682
+ durationMs: hookDuration
2683
+ });
2684
+ } catch (thrown) {
2685
+ const hookDuration = performance.now() - hookStartTime;
2686
+ emitEvent({
2687
+ type: "hook_after_step_error",
2688
+ workflowId,
2689
+ stepKey,
2690
+ ts: Date.now(),
2691
+ durationMs: hookDuration,
2692
+ error: thrown
2693
+ });
2694
+ throw thrown;
2695
+ }
2696
+ };
2697
+ const createCachedStep = (realStep) => {
2698
+ const cachedStepFn = async (idOrOperationOrResult, operationOrOptions, stepOptions) => {
2699
+ if (typeof idOrOperationOrResult !== "string") {
2700
+ throw new Error(
2701
+ '[awaitly] step() requires a string ID as the first argument. Example: step("fetchUser", () => fetchUser(id))'
2702
+ );
2703
+ }
2704
+ const id = idOrOperationOrResult;
2705
+ const opts = stepOptions ?? {};
2706
+ const name = id;
2707
+ const key = Object.prototype.hasOwnProperty.call(opts, "key") ? opts.key : id;
2708
+ const { ttl, out } = opts;
2709
+ checkCancellation();
2710
+ const stepMetadata = extractStepMetadata(opts);
2711
+ if (key && cache && cache.has(key)) {
2712
+ emitEvent({
2713
+ type: "step_cache_hit",
2714
+ workflowId,
2715
+ stepKey: key,
2716
+ name,
2717
+ ts: Date.now(),
2718
+ ...stepMetadata && { metadata: stepMetadata }
2719
+ });
2720
+ const cached = cache.get(key);
2721
+ if (cached.ok) {
2722
+ lastStepKey = key;
2723
+ if (out) {
2724
+ workflowData[out] = cached.value;
2725
+ }
2726
+ return cached.value;
2727
+ }
2728
+ const meta = decodeCachedMeta(cached.cause);
2729
+ throw createEarlyExit(cached.error, meta);
2730
+ }
2731
+ if (key && cache) {
2732
+ emitEvent({
2733
+ type: "step_cache_miss",
2734
+ workflowId,
2735
+ stepKey: key,
2736
+ name,
2737
+ ts: Date.now(),
2738
+ ...stepMetadata && { metadata: stepMetadata }
2739
+ });
2740
+ }
2741
+ try {
2742
+ const value = await realStep(
2743
+ id,
2744
+ operationOrOptions,
2745
+ opts
2746
+ );
2747
+ if (out) {
2748
+ workflowData[out] = value;
2749
+ }
2750
+ if (opts.compensate) {
2751
+ compensations.push({
2752
+ stepName: name,
2753
+ value,
2754
+ compensate: opts.compensate
2755
+ });
2756
+ }
2757
+ if (key) {
2758
+ lastStepKey = key;
2759
+ if (cache) {
2760
+ cache.set(key, ok2(value), ttl ? { ttl } : void 0);
2761
+ }
2762
+ await callOnAfterStepHook(key, ok2(value));
2763
+ }
2764
+ return value;
2765
+ } catch (thrown) {
2766
+ if (key && isEarlyExit(thrown)) {
2767
+ const exit = thrown;
2768
+ const originalCause = exit.meta.origin === "result" ? exit.meta.resultCause : exit.meta.origin === "throw" ? exit.meta.thrown : void 0;
2769
+ const errorResult = encodeCachedError(exit.error, exit.meta, originalCause);
2770
+ if (cache) {
2771
+ cache.set(key, errorResult, ttl ? { ttl } : void 0);
2772
+ }
2773
+ await callOnAfterStepHook(key, errorResult, exit.meta);
2774
+ }
2775
+ throw thrown;
2776
+ }
2777
+ };
2778
+ cachedStepFn.try = async (id, operation, opts) => {
2779
+ const { ttl } = opts;
2780
+ const key = opts.key ?? id;
2781
+ const name = id;
2782
+ if (cache && cache.has(key)) {
2783
+ emitEvent({
2784
+ type: "step_cache_hit",
2785
+ workflowId,
2786
+ stepKey: key,
2787
+ name,
2788
+ ts: Date.now()
2789
+ });
2790
+ const cached = cache.get(key);
2791
+ if (cached.ok) {
2792
+ return cached.value;
2793
+ }
2794
+ const meta = decodeCachedMeta(cached.cause);
2795
+ throw createEarlyExit(cached.error, meta);
2796
+ }
2797
+ if (cache) {
2798
+ emitEvent({
2799
+ type: "step_cache_miss",
2800
+ workflowId,
2801
+ stepKey: key,
2802
+ name,
2803
+ ts: Date.now()
2804
+ });
2805
+ }
2806
+ try {
2807
+ const value = await realStep.try(id, operation, { ...opts, key });
2808
+ if (opts.compensate) {
2809
+ compensations.push({
2810
+ stepName: name,
2811
+ value,
2812
+ compensate: opts.compensate
2813
+ });
2814
+ }
2815
+ if (cache) {
2816
+ cache.set(key, ok2(value), ttl ? { ttl } : void 0);
2817
+ }
2818
+ await callOnAfterStepHook(key, ok2(value));
2819
+ return value;
2820
+ } catch (thrown) {
2821
+ if (isEarlyExit(thrown)) {
2822
+ const exit = thrown;
2823
+ const originalCause = exit.meta.origin === "result" ? exit.meta.resultCause : exit.meta.origin === "throw" ? exit.meta.thrown : void 0;
2824
+ const errorResult = encodeCachedError(exit.error, exit.meta, originalCause);
2825
+ if (cache) {
2826
+ cache.set(key, errorResult, ttl ? { ttl } : void 0);
2827
+ }
2828
+ await callOnAfterStepHook(key, errorResult, exit.meta);
2829
+ }
2830
+ throw thrown;
2831
+ }
2832
+ };
2833
+ cachedStepFn.fromResult = async (id, operation, opts) => {
2834
+ const { ttl } = opts;
2835
+ const key = opts.key ?? id;
2836
+ const name = id;
2837
+ if (cache && cache.has(key)) {
2838
+ emitEvent({
2839
+ type: "step_cache_hit",
2840
+ workflowId,
2841
+ stepKey: key,
2842
+ name,
2843
+ ts: Date.now()
2844
+ });
2845
+ const cached = cache.get(key);
2846
+ if (cached.ok) {
2847
+ return cached.value;
2848
+ }
2849
+ const meta = decodeCachedMeta(cached.cause);
2850
+ throw createEarlyExit(cached.error, meta);
2851
+ }
2852
+ if (cache) {
2853
+ emitEvent({
2854
+ type: "step_cache_miss",
2855
+ workflowId,
2856
+ stepKey: key,
2857
+ name,
2858
+ ts: Date.now()
2859
+ });
2860
+ }
2861
+ try {
2862
+ const value = await realStep.fromResult(id, operation, { ...opts, key });
2863
+ if (cache) {
2864
+ cache.set(key, ok2(value), ttl ? { ttl } : void 0);
2865
+ }
2866
+ await callOnAfterStepHook(key, ok2(value));
2867
+ return value;
2868
+ } catch (thrown) {
2869
+ if (isEarlyExit(thrown)) {
2870
+ const exit = thrown;
2871
+ const originalCause = exit.meta.origin === "result" ? exit.meta.resultCause : exit.meta.origin === "throw" ? exit.meta.thrown : void 0;
2872
+ const errorResult = encodeCachedError(exit.error, exit.meta, originalCause);
2873
+ if (cache) {
2874
+ cache.set(key, errorResult, ttl ? { ttl } : void 0);
2875
+ }
2876
+ await callOnAfterStepHook(key, errorResult, exit.meta);
2877
+ }
2878
+ throw thrown;
2879
+ }
2880
+ };
2881
+ cachedStepFn.race = realStep.race;
2882
+ cachedStepFn.withFallback = async (id, operation, options2) => {
2883
+ const key = options2.key ?? id;
2884
+ const name = id;
2885
+ if (cache && cache.has(key)) {
2886
+ emitEvent({
2887
+ type: "step_cache_hit",
2888
+ workflowId,
2889
+ stepKey: key,
2890
+ name,
2891
+ ts: Date.now()
2892
+ });
2893
+ const cached = cache.get(key);
2894
+ if (cached.ok) {
2895
+ return cached.value;
2896
+ }
2897
+ const meta = decodeCachedMeta(cached.cause);
2898
+ throw createEarlyExit(cached.error, meta);
2899
+ }
2900
+ if (cache) {
2901
+ emitEvent({
2902
+ type: "step_cache_miss",
2903
+ workflowId,
2904
+ stepKey: key,
2905
+ name,
2906
+ ts: Date.now()
2907
+ });
2908
+ }
2909
+ try {
2910
+ const value = await realStep.withFallback(
2911
+ id,
2912
+ operation,
2913
+ options2
2914
+ );
2915
+ if (cache) {
2916
+ cache.set(key, ok2(value));
2917
+ }
2918
+ await callOnAfterStepHook(key, ok2(value));
2919
+ return value;
2920
+ } catch (thrown) {
2921
+ if (isEarlyExit(thrown)) {
2922
+ const exit = thrown;
2923
+ const originalCause = exit.meta.origin === "result" ? exit.meta.resultCause : exit.meta.origin === "throw" ? exit.meta.thrown : void 0;
2924
+ const errorResult = encodeCachedError(exit.error, exit.meta, originalCause);
2925
+ if (cache) {
2926
+ cache.set(key, errorResult);
2927
+ }
2928
+ await callOnAfterStepHook(key, errorResult, exit.meta);
2929
+ }
2930
+ throw thrown;
2931
+ }
2932
+ };
2933
+ cachedStepFn.withResource = async (id, options2) => {
2934
+ const key = id;
2935
+ try {
2936
+ const value = await realStep.withResource(id, options2);
2937
+ await callOnAfterStepHook(key, ok2(value));
2938
+ return value;
2939
+ } catch (thrown) {
2940
+ if (isEarlyExit(thrown)) {
2941
+ const exit = thrown;
2942
+ const originalCause = exit.meta.origin === "result" ? exit.meta.resultCause : exit.meta.origin === "throw" ? exit.meta.thrown : void 0;
2943
+ const errorResult = encodeCachedError(exit.error, exit.meta, originalCause);
2944
+ await callOnAfterStepHook(key, errorResult, exit.meta);
2945
+ }
2946
+ throw thrown;
2947
+ }
2948
+ };
2949
+ cachedStepFn.retry = (id, operation, options2) => {
2950
+ const stepOptions = {
2951
+ key: options2.key,
2952
+ // explicitly pass so undefined = don't cache
2953
+ retry: {
2954
+ attempts: options2.attempts,
2955
+ backoff: options2.backoff,
2956
+ initialDelay: options2.initialDelay,
2957
+ maxDelay: options2.maxDelay,
2958
+ jitter: options2.jitter,
2959
+ shouldRetry: options2.shouldRetry,
2960
+ onRetry: options2.onRetry
2961
+ },
2962
+ timeout: options2.timeout,
2963
+ ttl: options2.ttl
2964
+ };
2965
+ return cachedStepFn(id, operation, stepOptions);
2966
+ };
2967
+ cachedStepFn.withTimeout = (id, operation, options2) => {
2968
+ const stepOptions = {
2969
+ key: options2.key,
2970
+ timeout: options2,
2971
+ ttl: options2.ttl
2972
+ };
2973
+ return cachedStepFn(
2974
+ id,
2975
+ operation,
2976
+ stepOptions
2977
+ );
2978
+ };
2979
+ cachedStepFn.sleep = (id, duration, options2) => {
2980
+ if (typeof id !== "string" || id.length === 0) {
2981
+ throw new Error(
2982
+ '[awaitly] step.sleep() requires an explicit string ID as the first argument. Example: step.sleep("delay", "5s")'
2983
+ );
2984
+ }
2985
+ const d = typeof duration === "string" ? parse(duration) : duration;
2986
+ if (!d) {
2987
+ throw new Error(`step.sleep: invalid duration '${duration}'`);
2988
+ }
2989
+ const ms = toMillis(d);
2990
+ const userSignal = options2?.signal;
2991
+ const sleepOperation = async () => {
2992
+ if (workflowSignal?.aborted || userSignal?.aborted) {
2993
+ const e = new Error("Sleep aborted");
2994
+ e.name = "AbortError";
2995
+ throw e;
2996
+ }
2997
+ return new Promise((resolve, reject) => {
2998
+ const state = {
2999
+ timeoutId: void 0
3000
+ };
3001
+ const onAbort = () => {
3002
+ if (state.timeoutId) clearTimeout(state.timeoutId);
3003
+ const e = new Error("Sleep aborted");
3004
+ e.name = "AbortError";
3005
+ reject(e);
3006
+ };
3007
+ workflowSignal?.addEventListener("abort", onAbort, { once: true });
3008
+ userSignal?.addEventListener("abort", onAbort, { once: true });
3009
+ state.timeoutId = setTimeout(() => {
3010
+ workflowSignal?.removeEventListener("abort", onAbort);
3011
+ userSignal?.removeEventListener("abort", onAbort);
3012
+ resolve(ok2(void 0));
3013
+ }, ms);
3014
+ });
3015
+ };
3016
+ return cachedStepFn(id, sleepOperation, {
3017
+ key: options2?.key,
3018
+ ttl: options2?.ttl,
3019
+ description: options2?.description
3020
+ });
3021
+ };
3022
+ const activeWriters = /* @__PURE__ */ new Map();
3023
+ const activeReaders = /* @__PURE__ */ new Map();
3024
+ cachedStepFn.getWritable = (options2) => {
3025
+ const namespace = options2?.namespace ?? "default";
3026
+ const highWaterMark = options2?.highWaterMark ?? 16;
3027
+ if (!streamStore) {
3028
+ throw new Error(
3029
+ "streamStore is required to use getWritable(). Pass a streamStore to createWorkflow options."
3030
+ );
3031
+ }
3032
+ const existingKey = `${workflowId}:${namespace}`;
3033
+ const existing = activeWriters.get(existingKey);
3034
+ if (existing && !existing.closed && !existing.aborted) {
3035
+ return existing.writer;
3036
+ }
3037
+ const backpressure = createBackpressureController({
3038
+ highWaterMark,
3039
+ onStateChange: (state) => {
3040
+ emitEvent({
3041
+ type: "stream_backpressure",
3042
+ workflowId,
3043
+ namespace,
3044
+ bufferedCount: backpressure.bufferedCount,
3045
+ state,
3046
+ ts: Date.now()
3047
+ });
3048
+ }
3049
+ });
3050
+ let position = 0;
3051
+ let writable = true;
3052
+ let aborted = false;
3053
+ let closed = false;
3054
+ emitEvent({
3055
+ type: "stream_created",
3056
+ workflowId,
3057
+ namespace,
3058
+ ts: Date.now()
3059
+ });
3060
+ const writer = {
3061
+ async write(value) {
3062
+ if (closed) {
3063
+ return err(streamWriteError("closed", "Stream is closed"));
3064
+ }
3065
+ if (aborted) {
3066
+ return err(streamWriteError("aborted", "Stream was aborted"));
3067
+ }
3068
+ if (backpressure.state === "paused") {
3069
+ await backpressure.waitForDrain();
3070
+ }
3071
+ const item = {
3072
+ value,
3073
+ position,
3074
+ ts: Date.now()
3075
+ };
3076
+ const result2 = await streamStore.append(workflowId, namespace, item);
3077
+ if (!result2.ok) {
3078
+ emitEvent({
3079
+ type: "stream_error",
3080
+ workflowId,
3081
+ namespace,
3082
+ error: result2.error,
3083
+ position,
3084
+ ts: Date.now()
3085
+ });
3086
+ return err(streamWriteError("store_error", result2.error.message, result2.error));
3087
+ }
3088
+ emitEvent({
3089
+ type: "stream_write",
3090
+ workflowId,
3091
+ namespace,
3092
+ position,
3093
+ ts: Date.now()
3094
+ });
3095
+ position++;
3096
+ backpressure.increment();
3097
+ return ok2(void 0);
3098
+ },
3099
+ async close() {
3100
+ if (closed) {
3101
+ return err(streamCloseError("already_closed", "Stream is already closed"));
3102
+ }
3103
+ const result2 = await streamStore.closeStream(workflowId, namespace);
3104
+ if (!result2.ok) {
3105
+ return err(streamCloseError("store_error", result2.error.message, result2.error));
3106
+ }
3107
+ closed = true;
3108
+ writable = false;
3109
+ emitEvent({
3110
+ type: "stream_close",
3111
+ workflowId,
3112
+ namespace,
3113
+ finalPosition: position,
3114
+ ts: Date.now()
3115
+ });
3116
+ activeWriters.delete(existingKey);
3117
+ return ok2(void 0);
3118
+ },
3119
+ abort(reason) {
3120
+ aborted = true;
3121
+ writable = false;
3122
+ closed = true;
3123
+ emitEvent({
3124
+ type: "stream_error",
3125
+ workflowId,
3126
+ namespace,
3127
+ error: reason,
3128
+ position,
3129
+ ts: Date.now()
3130
+ });
3131
+ activeWriters.delete(existingKey);
3132
+ },
3133
+ get writable() {
3134
+ return writable;
3135
+ },
3136
+ get position() {
3137
+ return position;
3138
+ },
3139
+ get namespace() {
3140
+ return namespace;
3141
+ }
3142
+ };
3143
+ activeWriters.set(existingKey, {
3144
+ writer,
3145
+ backpressure,
3146
+ aborted,
3147
+ closed
3148
+ });
3149
+ return writer;
3150
+ };
3151
+ cachedStepFn.getReadable = (options2) => {
3152
+ const namespace = options2?.namespace ?? "default";
3153
+ const startIndex = options2?.startIndex ?? 0;
3154
+ const pollInterval = options2?.pollInterval ?? 10;
3155
+ const pollTimeout = options2?.pollTimeout ?? 3e4;
3156
+ if (!streamStore) {
3157
+ throw new Error(
3158
+ "streamStore is required to use getReadable(). Pass a streamStore to createWorkflow options."
3159
+ );
3160
+ }
3161
+ const existingKey = `${workflowId}:${namespace}:${startIndex}`;
3162
+ const existing = activeReaders.get(existingKey);
3163
+ if (existing && !existing.closed) {
3164
+ return existing.reader;
3165
+ }
3166
+ const decrementBackpressure = () => {
3167
+ const writerKey = `${workflowId}:${namespace}`;
3168
+ const activeWriter = activeWriters.get(writerKey);
3169
+ if (activeWriter) {
3170
+ activeWriter.backpressure.decrement();
3171
+ }
3172
+ };
3173
+ let position = startIndex;
3174
+ let readable = true;
3175
+ let closed = false;
3176
+ let bufferedItems = [];
3177
+ let bufferIndex = 0;
3178
+ const reader = {
3179
+ async read() {
3180
+ if (closed) {
3181
+ return err(streamReadError("closed", "Reader is closed"));
3182
+ }
3183
+ if (bufferIndex < bufferedItems.length) {
3184
+ const item = bufferedItems[bufferIndex++];
3185
+ position = item.position + 1;
3186
+ decrementBackpressure();
3187
+ emitEvent({
3188
+ type: "stream_read",
3189
+ workflowId,
3190
+ namespace,
3191
+ position: item.position,
3192
+ ts: Date.now()
3193
+ });
3194
+ return ok2(item.value);
3195
+ }
3196
+ const writerKey = `${workflowId}:${namespace}`;
3197
+ const pollStart = Date.now();
3198
+ let hasSeenWriter = activeWriters.has(writerKey);
3199
+ const initialMetaResult = await streamStore.getMetadata(workflowId, namespace);
3200
+ let hasSeenMetadata = initialMetaResult.ok && initialMetaResult.value !== void 0;
3201
+ while (Date.now() - pollStart < pollTimeout) {
3202
+ const result2 = await streamStore.read(workflowId, namespace, position, 100);
3203
+ if (!result2.ok) {
3204
+ return err(streamReadError("store_error", result2.error.message, result2.error));
3205
+ }
3206
+ const items = result2.value;
3207
+ if (items.length > 0) {
3208
+ bufferedItems = items;
3209
+ bufferIndex = 1;
3210
+ const item = items[0];
3211
+ position = item.position + 1;
3212
+ decrementBackpressure();
3213
+ emitEvent({
3214
+ type: "stream_read",
3215
+ workflowId,
3216
+ namespace,
3217
+ position: item.position,
3218
+ ts: Date.now()
3219
+ });
3220
+ return ok2(item.value);
3221
+ }
3222
+ const writerActive = activeWriters.has(writerKey);
3223
+ const metaResult = await streamStore.getMetadata(workflowId, namespace);
3224
+ const metadataExists = metaResult.ok && metaResult.value !== void 0;
3225
+ if (writerActive) hasSeenWriter = true;
3226
+ if (metadataExists) hasSeenMetadata = true;
3227
+ if (metaResult.ok && metaResult.value?.closed) {
3228
+ readable = false;
3229
+ return err(streamEnded(position));
3230
+ }
3231
+ if (hasSeenWriter && !writerActive && !metadataExists) {
3232
+ readable = false;
3233
+ return err(streamEnded(position));
3234
+ }
3235
+ if (hasSeenMetadata && !writerActive && metaResult.ok && !metaResult.value?.closed) {
3236
+ }
3237
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
3238
+ }
3239
+ readable = false;
3240
+ return err(streamEnded(position));
3241
+ },
3242
+ close() {
3243
+ closed = true;
3244
+ readable = false;
3245
+ bufferedItems = [];
3246
+ activeReaders.delete(existingKey);
3247
+ },
3248
+ get readable() {
3249
+ return readable;
3250
+ },
3251
+ get position() {
3252
+ return position;
3253
+ },
3254
+ get namespace() {
3255
+ return namespace;
3256
+ }
3257
+ };
3258
+ activeReaders.set(existingKey, {
3259
+ reader,
3260
+ position,
3261
+ closed
3262
+ });
3263
+ return reader;
3264
+ };
3265
+ cachedStepFn.streamForEach = async (source, processor, options2) => {
3266
+ const checkpointInterval = options2?.checkpointInterval ?? 1;
3267
+ const concurrency = options2?.concurrency ?? 1;
3268
+ const results = [];
3269
+ let processedCount = 0;
3270
+ let lastPosition = -1;
3271
+ const isStreamReader = (s) => {
3272
+ return typeof s === "object" && s !== null && "read" in s && typeof s.read === "function";
3273
+ };
3274
+ const processItem = async (item, itemIndex, itemPosition, namespace) => {
3275
+ const shouldCheckpoint = checkpointInterval > 0 && itemIndex % checkpointInterval === 0;
3276
+ const stepKey = shouldCheckpoint ? `stream-foreach:${namespace}:pos-${itemPosition}` : void 0;
3277
+ const stepId = stepKey ?? `stream-item-${itemPosition}`;
3278
+ const stepResult = await cachedStepFn(
3279
+ stepId,
3280
+ () => processor(item, itemIndex),
3281
+ { key: stepKey }
3282
+ );
3283
+ return { index: itemIndex, position: itemPosition, result: stepResult };
3284
+ };
3285
+ if (isStreamReader(source)) {
3286
+ if (concurrency <= 1) {
3287
+ let itemPosition = source.position;
3288
+ let readResult = await source.read();
3289
+ while (readResult.ok) {
3290
+ const item = readResult.value;
3291
+ const { result: result2 } = await processItem(item, processedCount, itemPosition, source.namespace);
3292
+ results.push(result2);
3293
+ lastPosition = itemPosition;
3294
+ processedCount++;
3295
+ itemPosition = source.position;
3296
+ readResult = await source.read();
3297
+ }
3298
+ } else {
3299
+ const resultsMap = /* @__PURE__ */ new Map();
3300
+ let itemIndex = 0;
3301
+ let totalItems = 0;
3302
+ const slots = new Array(concurrency).fill(null);
3303
+ const getSlot = async () => {
3304
+ for (let i = 0; i < slots.length; i++) {
3305
+ if (slots[i] === null) return i;
3306
+ }
3307
+ const activePromises = slots.filter((s) => s !== null);
3308
+ const completed = await Promise.race(activePromises);
3309
+ resultsMap.set(completed.index, { position: completed.position, result: completed.result });
3310
+ slots[completed.slotIndex] = null;
3311
+ return completed.slotIndex;
3312
+ };
3313
+ let itemPosition = source.position;
3314
+ let readResult = await source.read();
3315
+ while (readResult.ok) {
3316
+ const slotIndex = await getSlot();
3317
+ const currentIndex = itemIndex;
3318
+ const currentPosition = itemPosition;
3319
+ const currentItem = readResult.value;
3320
+ const currentSlot = slotIndex;
3321
+ slots[slotIndex] = processItem(currentItem, currentIndex, currentPosition, source.namespace).then((r) => ({ slotIndex: currentSlot, ...r }));
3322
+ totalItems++;
3323
+ itemIndex++;
3324
+ itemPosition = source.position;
3325
+ readResult = await source.read();
3326
+ }
3327
+ for (let i = 0; i < slots.length; i++) {
3328
+ if (slots[i] !== null) {
3329
+ const result2 = await slots[i];
3330
+ resultsMap.set(result2.index, { position: result2.position, result: result2.result });
3331
+ }
3332
+ }
3333
+ for (let i = 0; i < totalItems; i++) {
3334
+ const entry = resultsMap.get(i);
3335
+ if (entry) {
3336
+ results.push(entry.result);
3337
+ lastPosition = entry.position;
3338
+ processedCount++;
3339
+ }
3340
+ }
3341
+ }
3342
+ } else {
3343
+ if (concurrency <= 1) {
3344
+ let index = 0;
3345
+ for await (const item of source) {
3346
+ const { result: result2 } = await processItem(item, index, index, "async-iterable");
3347
+ results.push(result2);
3348
+ lastPosition = index;
3349
+ processedCount++;
3350
+ index++;
3351
+ }
3352
+ } else {
3353
+ const resultsMap = /* @__PURE__ */ new Map();
3354
+ let itemIndex = 0;
3355
+ let totalItems = 0;
3356
+ const slots = new Array(concurrency).fill(null);
3357
+ const getSlot = async () => {
3358
+ for (let i = 0; i < slots.length; i++) {
3359
+ if (slots[i] === null) return i;
3360
+ }
3361
+ const activePromises = slots.filter((s) => s !== null);
3362
+ const completed = await Promise.race(activePromises);
3363
+ resultsMap.set(completed.index, completed.result);
3364
+ slots[completed.slotIndex] = null;
3365
+ return completed.slotIndex;
3366
+ };
3367
+ for await (const item of source) {
3368
+ const slotIndex = await getSlot();
3369
+ const currentIndex = itemIndex;
3370
+ const currentSlot = slotIndex;
3371
+ slots[slotIndex] = processItem(item, currentIndex, currentIndex, "async-iterable").then((r) => ({ slotIndex: currentSlot, ...r }));
3372
+ totalItems++;
3373
+ itemIndex++;
3374
+ }
3375
+ for (let i = 0; i < slots.length; i++) {
3376
+ if (slots[i] !== null) {
3377
+ const result2 = await slots[i];
3378
+ resultsMap.set(result2.index, result2.result);
3379
+ }
3380
+ }
3381
+ for (let i = 0; i < totalItems; i++) {
3382
+ if (resultsMap.has(i)) {
3383
+ results.push(resultsMap.get(i));
3384
+ lastPosition = i;
3385
+ processedCount++;
3386
+ }
3387
+ }
3388
+ }
3389
+ }
3390
+ return {
3391
+ results,
3392
+ processedCount,
3393
+ lastPosition
3394
+ };
3395
+ };
3396
+ cachedStepFn.if = realStep.if;
3397
+ cachedStepFn.label = realStep.label;
3398
+ cachedStepFn.branch = realStep.branch;
3399
+ cachedStepFn.arm = realStep.arm;
3400
+ cachedStepFn.forEach = realStep.forEach;
3401
+ cachedStepFn.item = realStep.item;
3402
+ cachedStepFn.dep = realStep.dep;
3403
+ cachedStepFn.workflow = (id, getter, options2) => cachedStepFn(id, getter, options2);
3404
+ cachedStepFn.all = (id, shape, options2) => {
3405
+ const opts = options2 !== void 0 && Object.prototype.hasOwnProperty.call(options2, "key") ? options2 : { ...options2, key: void 0 };
3406
+ return cachedStepFn(id, async () => ok2(await realStep.all(id, shape)), opts);
3407
+ };
3408
+ cachedStepFn.map = (id, items, mapper, options2) => {
3409
+ const opts = options2 !== void 0 && Object.prototype.hasOwnProperty.call(options2, "key") ? options2 : { ...options2, key: void 0 };
3410
+ return cachedStepFn(id, async () => ok2(await realStep.map(id, items, mapper, options2)), opts);
3411
+ };
3412
+ return cachedStepFn;
3413
+ };
3414
+ const wrappedFn = ({ step }) => {
3415
+ const cachedStep = createCachedStep(step);
3416
+ return userFn({
3417
+ step: cachedStep,
3418
+ steps: bindSteps(effectiveDeps ?? {}, cachedStep),
3419
+ deps: effectiveDeps,
3420
+ ctx: workflowContext
3421
+ });
3422
+ };
3423
+ let result;
3424
+ try {
3425
+ result = await run(wrappedFn, {
3426
+ onError: onErrorHandler,
3427
+ onEvent: onEventHandler,
3428
+ catchUnexpected,
3429
+ workflowId,
3430
+ workflowName,
3431
+ context,
3432
+ graph: declaredGraph,
3433
+ _workflowSignal: workflowSignal
3434
+ });
3435
+ } finally {
3436
+ if (workflowSignal) {
3437
+ workflowSignal.removeEventListener("abort", abortHandler);
3438
+ }
3439
+ }
3440
+ if (!result.ok && compensations.length > 0) {
3441
+ const compensationErrors = [];
3442
+ for (let i = compensations.length - 1; i >= 0; i--) {
3443
+ const comp = compensations[i];
3444
+ try {
3445
+ await comp.compensate(comp.value);
3446
+ } catch (compErr) {
3447
+ compensationErrors.push({ stepName: comp.stepName, error: compErr });
3448
+ }
3449
+ }
3450
+ if (compensationErrors.length > 0) {
3451
+ const sagaError = {
3452
+ type: "SAGA_COMPENSATION_ERROR",
3453
+ originalError: result.error,
3454
+ compensationErrors
3455
+ };
3456
+ result = err(sagaError, { cause: result.cause });
3457
+ }
3458
+ }
3459
+ const durationMs = performance.now() - startTime;
3460
+ if (!result.ok) {
3461
+ let cancelledError;
3462
+ if (isWorkflowCancelled(result.cause)) {
3463
+ cancelledError = result.cause;
3464
+ }
3465
+ if (!cancelledError && abortedDuringExecution && isUnexpectedError(result.error)) {
3466
+ const thrown = result.cause;
3467
+ const isAbortError = thrown != null && typeof thrown === "object" && "name" in thrown && thrown.name === "AbortError";
3468
+ if (isAbortError) {
3469
+ const reason = abortReason ?? (typeof workflowSignal?.reason === "string" ? workflowSignal.reason : workflowSignal?.reason instanceof Error ? workflowSignal.reason.message : void 0);
3470
+ cancelledError = {
3471
+ type: "WORKFLOW_CANCELLED",
3472
+ reason,
3473
+ lastStepKey
3474
+ };
3475
+ }
3476
+ }
3477
+ if (cancelledError) {
3478
+ emitEvent({
3479
+ type: "workflow_cancelled",
3480
+ workflowId,
3481
+ ts: Date.now(),
3482
+ durationMs,
3483
+ reason: cancelledError.reason,
3484
+ lastStepKey: cancelledError.lastStepKey
3485
+ });
3486
+ if (cancelledError && !isWorkflowCancelled(result.cause)) {
3487
+ return err(result.error, { cause: cancelledError });
3488
+ }
3489
+ return result;
3490
+ }
3491
+ }
3492
+ if (result.ok && abortedDuringExecution) {
3493
+ const reason = abortReason ?? (typeof workflowSignal?.reason === "string" ? workflowSignal.reason : workflowSignal?.reason instanceof Error ? workflowSignal.reason.message : void 0);
3494
+ emitEvent({
3495
+ type: "workflow_cancelled",
3496
+ workflowId,
3497
+ ts: Date.now(),
3498
+ durationMs,
3499
+ reason,
3500
+ lastStepKey
3501
+ });
3502
+ const cancelledError = {
3503
+ type: "WORKFLOW_CANCELLED",
3504
+ reason,
3505
+ lastStepKey
3506
+ };
3507
+ return err(catchUnexpected(cancelledError), { cause: cancelledError });
3508
+ }
3509
+ if (result.ok) {
3510
+ emitEvent({
3511
+ type: "workflow_success",
3512
+ workflowId,
3513
+ ts: Date.now(),
3514
+ durationMs
3515
+ });
3516
+ } else {
3517
+ emitEvent({
3518
+ type: "workflow_error",
3519
+ workflowId,
3520
+ ts: Date.now(),
3521
+ durationMs,
3522
+ error: result.error
3523
+ });
3524
+ }
3525
+ return result;
3526
+ }
3527
+ function runMethod(fnOrName, maybeFnOrConfig, maybeConfig) {
3528
+ let runName;
3529
+ let fn;
3530
+ let config;
3531
+ if (typeof fnOrName === "string") {
3532
+ runName = fnOrName;
3533
+ fn = maybeFnOrConfig;
3534
+ config = maybeConfig;
3535
+ } else {
3536
+ fn = fnOrName;
3537
+ config = maybeFnOrConfig;
3538
+ }
3539
+ return internalExecute(runName, fn, config);
3540
+ }
3541
+ async function runWithStateMethod(fnOrName, maybeFnOrConfig, maybeConfig) {
3542
+ let runName;
3543
+ let fn;
3544
+ let config;
3545
+ if (typeof fnOrName === "string") {
3546
+ runName = fnOrName;
3547
+ fn = maybeFnOrConfig;
3548
+ config = maybeConfig;
3549
+ } else {
3550
+ fn = fnOrName;
3551
+ config = maybeFnOrConfig;
3552
+ }
3553
+ const collector = createResumeStateCollector();
3554
+ const userOnEvent = config?.onEvent;
3555
+ const mergedOnEvent = (event, ctx) => {
3556
+ collector.handleEvent(event);
3557
+ try {
3558
+ userOnEvent?.(event, ctx);
3559
+ } catch {
3560
+ }
3561
+ };
3562
+ const mergedConfig = {
3563
+ ...config,
3564
+ onEvent: mergedOnEvent
3565
+ };
3566
+ let result;
3567
+ let resumeState;
3568
+ try {
3569
+ result = await internalExecute(runName, fn, mergedConfig);
3570
+ } catch (thrown) {
3571
+ const catchUnexpected = optionsActual?.catchUnexpected ?? defaultCatchUnexpected;
3572
+ result = err(catchUnexpected(thrown), { cause: thrown });
3573
+ } finally {
3574
+ resumeState = collector.getResumeState();
3575
+ }
3576
+ return { result, resumeState };
3577
+ }
3578
+ const workflow = {
3579
+ withDeps: (overrides) => withDeps(workflow, overrides),
3580
+ run: runMethod,
3581
+ runWithState: runWithStateMethod
3582
+ };
3583
+ return workflow;
3584
+ }
3585
+
3586
+ // src/testing/test-runner.ts
3587
+ async function testWorkflow(deps, fn, options) {
3588
+ const events = [];
3589
+ const steps = {};
3590
+ const stepOrder = [];
3591
+ const onEvent = (event) => {
3592
+ events.push(event);
3593
+ if (event.type === "step_complete" && event.stepKey) {
3594
+ const stepResult = {
3595
+ output: event.result.ok ? event.result.value : void 0,
3596
+ durationMs: event.durationMs,
3597
+ result: event.result
3598
+ };
3599
+ steps[event.stepKey] = stepResult;
3600
+ stepOrder.push(event.stepKey);
3601
+ }
3602
+ };
3603
+ const workflow = createWorkflow("test-workflow", deps);
3604
+ const start = performance.now();
3605
+ const result = await workflow.run(fn, {
3606
+ onEvent,
3607
+ signal: options?.signal
3608
+ });
3609
+ const durationMs = performance.now() - start;
3610
+ return {
3611
+ result,
3612
+ steps,
3613
+ events,
3614
+ durationMs,
3615
+ stepOrder
3616
+ };
3617
+ }
3618
+
3619
+ // src/testing/index.ts
3620
+ function isTestEarlyExit(e) {
3621
+ return typeof e === "object" && e !== null && "__earlyExit" in e && e.__earlyExit === true;
3622
+ }
3623
+ function createWorkflowHarness(deps, options = {}) {
3624
+ const { recordInvocations = true, clock = Date.now } = options;
3625
+ let scriptedOutcomes = [];
3626
+ const namedOutcomes = /* @__PURE__ */ new Map();
3627
+ let invocationIndex = 0;
3628
+ let invocations = [];
3629
+ function script(outcomes) {
3630
+ scriptedOutcomes = [...outcomes];
3631
+ invocationIndex = 0;
3632
+ namedOutcomes.clear();
3633
+ }
3634
+ function scriptStep(nameOrKey, outcome) {
3635
+ namedOutcomes.set(nameOrKey, outcome);
3636
+ }
3637
+ function getNextOutcome(nameOrKey) {
3638
+ if (nameOrKey && namedOutcomes.has(nameOrKey)) {
3639
+ return namedOutcomes.get(nameOrKey);
3640
+ }
3641
+ if (invocationIndex < scriptedOutcomes.length) {
3642
+ return scriptedOutcomes[invocationIndex++];
3643
+ }
3644
+ return void 0;
3645
+ }
3646
+ function createMockStep() {
3647
+ const mockStep = async (nameOrOperation, operationOrOptions, maybeOptions) => {
3648
+ let name;
3649
+ let operationOrResult;
3650
+ let opts;
3651
+ if (typeof nameOrOperation === "string") {
3652
+ name = nameOrOperation;
3653
+ operationOrResult = operationOrOptions;
3654
+ opts = maybeOptions ?? {};
3655
+ } else {
3656
+ operationOrResult = nameOrOperation;
3657
+ if (typeof operationOrOptions === "string") {
3658
+ name = operationOrOptions;
3659
+ opts = {};
3660
+ } else {
3661
+ opts = operationOrOptions ?? {};
3662
+ name = opts.key ?? "step";
3663
+ }
3664
+ }
3665
+ const startTime = clock();
3666
+ const invocation = {
3667
+ name,
3668
+ key: opts.key,
3669
+ order: invocations.length,
3670
+ timestamp: startTime
3671
+ };
3672
+ if (recordInvocations) {
3673
+ invocations.push(invocation);
3674
+ }
3675
+ const outcome = getNextOutcome(name);
3676
+ if (outcome) {
3677
+ invocation.durationMs = clock() - startTime;
3678
+ switch (outcome.type) {
3679
+ case "ok":
3680
+ invocation.result = ok2(outcome.value);
3681
+ return outcome.value;
3682
+ case "err":
3683
+ invocation.result = err(outcome.error);
3684
+ throw { __earlyExit: true, error: outcome.error };
3685
+ case "throw":
3686
+ throw outcome.error;
3687
+ }
3688
+ }
3689
+ const result = typeof operationOrResult === "function" ? await operationOrResult() : await operationOrResult;
3690
+ invocation.durationMs = clock() - startTime;
3691
+ invocation.result = result;
3692
+ if (!result.ok) {
3693
+ throw { __earlyExit: true, error: result.error };
3694
+ }
3695
+ return result.value;
3696
+ };
3697
+ mockStep.try = async (nameOrOperation, operationOrOpts, maybeOpts) => {
3698
+ let name;
3699
+ let operation;
3700
+ let opts;
3701
+ if (typeof nameOrOperation === "string") {
3702
+ name = nameOrOperation;
3703
+ operation = operationOrOpts;
3704
+ opts = maybeOpts;
3705
+ } else {
3706
+ operation = nameOrOperation;
3707
+ opts = operationOrOpts;
3708
+ name = opts.key ?? "step";
3709
+ }
3710
+ const startTime = clock();
3711
+ const invocation = {
3712
+ name,
3713
+ key: "key" in opts ? opts.key : void 0,
3714
+ order: invocations.length,
3715
+ timestamp: startTime
3716
+ };
3717
+ if (recordInvocations) {
3718
+ invocations.push(invocation);
3719
+ }
3720
+ const outcome = getNextOutcome(name);
3721
+ if (outcome) {
3722
+ invocation.durationMs = clock() - startTime;
3723
+ switch (outcome.type) {
3724
+ case "ok":
3725
+ invocation.result = ok2(outcome.value);
3726
+ return outcome.value;
3727
+ case "err":
3728
+ invocation.result = err(outcome.error);
3729
+ throw { __earlyExit: true, error: outcome.error };
3730
+ case "throw":
3731
+ throw outcome.error;
3732
+ }
3733
+ }
3734
+ try {
3735
+ const value = await operation();
3736
+ invocation.durationMs = clock() - startTime;
3737
+ invocation.result = ok2(value);
3738
+ return value;
3739
+ } catch (error) {
3740
+ invocation.durationMs = clock() - startTime;
3741
+ const mappedError = "error" in opts ? opts.error : opts.onError(error);
3742
+ invocation.result = err(mappedError);
3743
+ throw { __earlyExit: true, error: mappedError };
3744
+ }
3745
+ };
3746
+ return mockStep;
3747
+ }
3748
+ async function run2(fn) {
3749
+ const mockStep = createMockStep();
3750
+ try {
3751
+ const value = await fn({ step: mockStep, deps });
3752
+ return ok2(value);
3753
+ } catch (error) {
3754
+ if (isTestEarlyExit(error)) {
3755
+ return err(error.error);
3756
+ }
3757
+ return err(new UnexpectedError({ cause: error }));
3758
+ }
3759
+ }
3760
+ async function runWithInput(input, fn) {
3761
+ const mockStep = createMockStep();
3762
+ try {
3763
+ const value = await fn({ step: mockStep, deps, input });
3764
+ return ok2(value);
3765
+ } catch (error) {
3766
+ if (isTestEarlyExit(error)) {
3767
+ return err(error.error);
3768
+ }
3769
+ return err(new UnexpectedError({ cause: error }));
3770
+ }
3771
+ }
3772
+ function getInvocations() {
3773
+ return [...invocations];
3774
+ }
3775
+ function assertSteps(expectedNames) {
3776
+ const actualNames = invocations.map((inv) => inv.name ?? inv.key ?? "unnamed").filter((n) => n !== "unnamed");
3777
+ const passed = JSON.stringify(actualNames) === JSON.stringify(expectedNames);
3778
+ return {
3779
+ passed,
3780
+ message: passed ? `Steps invoked in order: ${expectedNames.join(", ")}` : `Expected steps [${expectedNames.join(", ")}] but got [${actualNames.join(", ")}]`,
3781
+ expected: expectedNames,
3782
+ actual: actualNames
3783
+ };
3784
+ }
3785
+ function assertStepCalled(nameOrKey) {
3786
+ const found = invocations.some(
3787
+ (inv) => inv.name === nameOrKey || inv.key === nameOrKey
3788
+ );
3789
+ return {
3790
+ passed: found,
3791
+ message: found ? `Step "${nameOrKey}" was invoked` : `Step "${nameOrKey}" was NOT invoked`,
3792
+ expected: nameOrKey,
3793
+ actual: found
3794
+ };
3795
+ }
3796
+ function assertStepNotCalled(nameOrKey) {
3797
+ const found = invocations.some(
3798
+ (inv) => inv.name === nameOrKey || inv.key === nameOrKey
3799
+ );
3800
+ return {
3801
+ passed: !found,
3802
+ message: !found ? `Step "${nameOrKey}" was correctly NOT invoked` : `Step "${nameOrKey}" was invoked but should not have been`,
3803
+ expected: "not called",
3804
+ actual: found ? "called" : "not called"
3805
+ };
3806
+ }
3807
+ function assertResult(result, expected) {
3808
+ const passed = result.ok === expected.ok && (result.ok ? JSON.stringify(result.value) === JSON.stringify(expected.value) : JSON.stringify(result.error) === JSON.stringify(expected.error));
3809
+ return {
3810
+ passed,
3811
+ message: passed ? `Result matches expected` : `Result does not match expected`,
3812
+ expected,
3813
+ actual: result
3814
+ };
3815
+ }
3816
+ function reset() {
3817
+ scriptedOutcomes = [];
3818
+ namedOutcomes.clear();
3819
+ invocationIndex = 0;
3820
+ invocations = [];
3821
+ }
3822
+ return {
3823
+ script,
3824
+ scriptStep,
3825
+ run: run2,
3826
+ runWithInput,
3827
+ getInvocations,
3828
+ assertSteps,
3829
+ assertStepCalled,
3830
+ assertStepNotCalled,
3831
+ assertResult,
3832
+ reset
3833
+ };
3834
+ }
3835
+ function createMockFn() {
3836
+ let defaultReturn;
3837
+ const returnQueue = [];
3838
+ const calls = [];
3839
+ const fn = ((...args) => {
3840
+ calls.push(args);
3841
+ if (returnQueue.length > 0) {
3842
+ return Promise.resolve(returnQueue.shift());
3843
+ }
3844
+ if (defaultReturn) {
3845
+ return Promise.resolve(defaultReturn);
3846
+ }
3847
+ throw new Error("Mock function called without configured return value");
3848
+ });
3849
+ fn.returns = (result) => {
3850
+ defaultReturn = result;
3851
+ return fn;
3852
+ };
3853
+ fn.returnsOnce = (result) => {
3854
+ returnQueue.push(result);
3855
+ return fn;
3856
+ };
3857
+ fn.getCalls = () => [...calls];
3858
+ fn.getCallCount = () => calls.length;
3859
+ fn.reset = () => {
3860
+ defaultReturn = void 0;
3861
+ returnQueue.length = 0;
3862
+ calls.length = 0;
3863
+ };
3864
+ return fn;
3865
+ }
3866
+ function createSnapshot(invocations, result, events) {
3867
+ const totalDuration = invocations.reduce(
3868
+ (sum, inv) => sum + (inv.durationMs ?? 0),
3869
+ 0
3870
+ );
3871
+ return {
3872
+ invocations: invocations.map((inv) => ({
3873
+ ...inv,
3874
+ // Normalize timestamps for comparison
3875
+ timestamp: 0
3876
+ })),
3877
+ result,
3878
+ events: events?.map((e) => ({
3879
+ ...e,
3880
+ ts: 0
3881
+ // Normalize timestamps
3882
+ })),
3883
+ durationMs: totalDuration
3884
+ };
3885
+ }
3886
+ function compareSnapshots(snapshot1, snapshot2) {
3887
+ const differences = [];
3888
+ if (snapshot1.invocations.length !== snapshot2.invocations.length) {
3889
+ differences.push(
3890
+ `Invocation count: ${snapshot1.invocations.length} vs ${snapshot2.invocations.length}`
3891
+ );
3892
+ }
3893
+ const maxLen = Math.max(
3894
+ snapshot1.invocations.length,
3895
+ snapshot2.invocations.length
3896
+ );
3897
+ for (let i = 0; i < maxLen; i++) {
3898
+ const inv1 = snapshot1.invocations[i];
3899
+ const inv2 = snapshot2.invocations[i];
3900
+ if (!inv1) {
3901
+ differences.push(`Step ${i}: missing in first snapshot`);
3902
+ continue;
3903
+ }
3904
+ if (!inv2) {
3905
+ differences.push(`Step ${i}: missing in second snapshot`);
3906
+ continue;
3907
+ }
3908
+ if (inv1.name !== inv2.name) {
3909
+ differences.push(`Step ${i} name: "${inv1.name}" vs "${inv2.name}"`);
3910
+ }
3911
+ if (inv1.key !== inv2.key) {
3912
+ differences.push(`Step ${i} key: "${inv1.key}" vs "${inv2.key}"`);
3913
+ }
3914
+ if (inv1.result?.ok !== inv2.result?.ok) {
3915
+ differences.push(
3916
+ `Step ${i} result: ${inv1.result?.ok ? "ok" : "err"} vs ${inv2.result?.ok ? "ok" : "err"}`
3917
+ );
3918
+ }
3919
+ }
3920
+ if (snapshot1.result.ok !== snapshot2.result.ok) {
3921
+ differences.push(
3922
+ `Final result: ${snapshot1.result.ok ? "ok" : "err"} vs ${snapshot2.result.ok ? "ok" : "err"}`
3923
+ );
3924
+ }
3925
+ return {
3926
+ equal: differences.length === 0,
3927
+ differences
3928
+ };
3929
+ }
3930
+ function createTestClock(startTime = 0) {
3931
+ let currentTime = startTime;
3932
+ return {
3933
+ now: () => currentTime,
3934
+ advance: (ms) => {
3935
+ currentTime += ms;
3936
+ },
3937
+ set: (time) => {
3938
+ currentTime = time;
3939
+ },
3940
+ reset: () => {
3941
+ currentTime = startTime;
3942
+ }
3943
+ };
3944
+ }
3945
+ function okOutcome(value) {
3946
+ return { type: "ok", value };
3947
+ }
3948
+ function errOutcome(error) {
3949
+ return { type: "err", error };
3950
+ }
3951
+ function throwOutcome(error) {
3952
+ return { type: "throw", error };
3953
+ }
3954
+ function createSagaHarness(deps, options = {}) {
3955
+ const { clock = Date.now } = options;
3956
+ const baseHarness = createWorkflowHarness(deps, options);
3957
+ let compensations = [];
3958
+ let compensationStack = [];
3959
+ async function runSaga(fn) {
3960
+ compensations = [];
3961
+ compensationStack = [];
3962
+ const sagaContext = {
3963
+ step: async (operation, stepOptions) => {
3964
+ try {
3965
+ const result = await baseHarness.run(
3966
+ async ({ step }) => step("saga-step", operation)
3967
+ );
3968
+ if (!result.ok) {
3969
+ await runCompensations();
3970
+ throw { __earlyExit: true, error: result.error };
3971
+ }
3972
+ if (stepOptions?.compensate) {
3973
+ compensationStack.push({
3974
+ value: result.value,
3975
+ compensate: stepOptions.compensate
3976
+ });
3977
+ }
3978
+ return result.value;
3979
+ } catch (error) {
3980
+ if (compensationStack.length > 0) {
3981
+ await runCompensations();
3982
+ }
3983
+ throw error;
3984
+ }
3985
+ }
3986
+ };
3987
+ async function runCompensations() {
3988
+ const toCompensate = [...compensationStack].reverse();
3989
+ compensationStack = [];
3990
+ for (const { name, value, compensate } of toCompensate) {
3991
+ try {
3992
+ await compensate(value);
3993
+ compensations.push({
3994
+ stepName: name,
3995
+ order: compensations.length,
3996
+ value,
3997
+ timestamp: clock()
3998
+ });
3999
+ } catch (error) {
4000
+ console.error(`Compensation failed for step "${name}":`, error);
4001
+ }
4002
+ }
4003
+ }
4004
+ try {
4005
+ const value = await fn({ saga: sagaContext, deps });
4006
+ return ok2(value);
4007
+ } catch (error) {
4008
+ if (isTestEarlyExit(error)) {
4009
+ return err(error.error);
4010
+ }
4011
+ await runCompensations();
4012
+ return err(new UnexpectedError({ cause: error }));
4013
+ }
4014
+ }
4015
+ function getCompensations() {
4016
+ return [...compensations];
4017
+ }
4018
+ function assertCompensationOrder(expectedStepNames) {
4019
+ const actualNames = compensations.map((c) => c.stepName);
4020
+ const passed = JSON.stringify(actualNames) === JSON.stringify(expectedStepNames);
4021
+ return {
4022
+ passed,
4023
+ message: passed ? `Compensations ran in order: ${expectedStepNames.join(" \u2192 ")}` : `Expected compensations [${expectedStepNames.join(" \u2192 ")}] but got [${actualNames.join(" \u2192 ")}]`,
4024
+ expected: expectedStepNames,
4025
+ actual: actualNames
4026
+ };
4027
+ }
4028
+ function assertCompensated(stepName) {
4029
+ const found = compensations.some((c) => c.stepName === stepName);
4030
+ return {
4031
+ passed: found,
4032
+ message: found ? `Step "${stepName}" was compensated` : `Step "${stepName}" was NOT compensated`,
4033
+ expected: stepName,
4034
+ actual: found
4035
+ };
4036
+ }
4037
+ function assertNotCompensated(stepName) {
4038
+ const found = compensations.some((c) => c.stepName === stepName);
4039
+ return {
4040
+ passed: !found,
4041
+ message: !found ? `Step "${stepName}" was correctly NOT compensated` : `Step "${stepName}" was compensated but should not have been`,
4042
+ expected: "not compensated",
4043
+ actual: found ? "compensated" : "not compensated"
4044
+ };
4045
+ }
4046
+ const originalReset = baseHarness.reset;
4047
+ function reset() {
4048
+ originalReset();
4049
+ compensations = [];
4050
+ compensationStack = [];
4051
+ }
4052
+ return {
4053
+ ...baseHarness,
4054
+ reset,
4055
+ getCompensations,
4056
+ assertCompensationOrder,
4057
+ assertCompensated,
4058
+ assertNotCompensated,
4059
+ runSaga
4060
+ };
4061
+ }
4062
+ function assertEventSequence(events, expectedSequence, options = {}) {
4063
+ const { strict = true } = options;
4064
+ const expected = expectedSequence.map((s) => {
4065
+ const [type, name] = s.split(":");
4066
+ return { type, name };
4067
+ });
4068
+ const relevantEvents = strict ? events : events.filter((e) => expected.some((exp) => e.type === exp.type));
4069
+ const actual = relevantEvents.map((e) => {
4070
+ const name = "name" in e ? e.name : void 0;
4071
+ const stepKey = "stepKey" in e ? e.stepKey : void 0;
4072
+ const identifier = name ?? stepKey;
4073
+ return identifier ? `${e.type}:${identifier}` : e.type;
4074
+ });
4075
+ const passed = JSON.stringify(actual) === JSON.stringify(expectedSequence);
4076
+ return {
4077
+ passed,
4078
+ message: passed ? `Event sequence matches: ${expectedSequence.join(" \u2192 ")}` : `Event sequence mismatch.
4079
+ Expected: ${expectedSequence.join(" \u2192 ")}
4080
+ Actual: ${actual.join(" \u2192 ")}`,
4081
+ expected: expectedSequence,
4082
+ actual
4083
+ };
4084
+ }
4085
+ function assertEventEmitted(events, expected) {
4086
+ const found = events.find((e) => {
4087
+ return Object.entries(expected).every(([key, value]) => {
4088
+ const eventValue = e[key];
4089
+ if (typeof value === "object" && value !== null) {
4090
+ return JSON.stringify(eventValue) === JSON.stringify(value);
4091
+ }
4092
+ return eventValue === value;
4093
+ });
4094
+ });
4095
+ return {
4096
+ passed: !!found,
4097
+ message: found ? `Event matching ${JSON.stringify(expected)} was emitted` : `No event matching ${JSON.stringify(expected)} was found`,
4098
+ expected,
4099
+ actual: found ?? "not found"
4100
+ };
4101
+ }
4102
+ function assertEventNotEmitted(events, expected) {
4103
+ const result = assertEventEmitted(events, expected);
4104
+ return {
4105
+ passed: !result.passed,
4106
+ message: result.passed ? `Event matching ${JSON.stringify(expected)} was found but should not have been` : `Correctly, no event matching ${JSON.stringify(expected)} was emitted`,
4107
+ expected: "not emitted",
4108
+ actual: result.actual
4109
+ };
4110
+ }
4111
+ function expectOk(result) {
4112
+ if (!result.ok) {
4113
+ throw new Error(
4114
+ `Expected Ok result, got Err: ${JSON.stringify(result.error, null, 2)}`
4115
+ );
4116
+ }
4117
+ }
4118
+ function expectErr(result) {
4119
+ if (result.ok) {
4120
+ throw new Error(
4121
+ `Expected Err result, got Ok: ${JSON.stringify(result.value, null, 2)}`
4122
+ );
4123
+ }
4124
+ }
4125
+ function unwrapOk(result) {
4126
+ expectOk(result);
4127
+ return result.value;
4128
+ }
4129
+ function unwrapErr(result) {
4130
+ expectErr(result);
4131
+ return result.error;
4132
+ }
4133
+ async function unwrapOkAsync(result) {
4134
+ return unwrapOk(await result);
4135
+ }
4136
+ async function unwrapErrAsync(result) {
4137
+ return unwrapErr(await result);
4138
+ }
4139
+ function formatResult(result) {
4140
+ if (isOk(result)) {
4141
+ return `Ok(${formatValue(result.value)})`;
4142
+ }
4143
+ return `Err(${formatValue(result.error)})`;
4144
+ }
4145
+ function formatValue(value) {
4146
+ if (value === null) return "null";
4147
+ if (value === void 0) return "undefined";
4148
+ if (typeof value === "string") return `'${value}'`;
4149
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
4150
+ if (typeof value === "function") return `[Function: ${value.name || "anonymous"}]`;
4151
+ if (Array.isArray(value)) {
4152
+ if (value.length === 0) return "[]";
4153
+ if (value.length <= 3) return `[${value.map(formatValue).join(", ")}]`;
4154
+ return `[${value.slice(0, 3).map(formatValue).join(", ")}, ... (${value.length} items)]`;
4155
+ }
4156
+ if (typeof value === "object") {
4157
+ const obj = value;
4158
+ const keys = Object.keys(obj);
4159
+ if (keys.length === 0) return "{}";
4160
+ if (keys.length <= 4) {
4161
+ const entries = keys.map((k) => `${k}: ${formatValue(obj[k])}`).join(", ");
4162
+ return `{ ${entries} }`;
4163
+ }
4164
+ const sample = keys.slice(0, 3).map((k) => `${k}: ${formatValue(obj[k])}`).join(", ");
4165
+ return `{ ${sample}, ... (${keys.length} keys) }`;
4166
+ }
4167
+ return String(value);
4168
+ }
4169
+ function formatEvent(event) {
4170
+ const type = event.type;
4171
+ const name = "name" in event ? event.name : void 0;
4172
+ const stepKey = "stepKey" in event ? event.stepKey : void 0;
4173
+ const identifier = name ?? stepKey;
4174
+ if (identifier) {
4175
+ return `${type}:${identifier}`;
4176
+ }
4177
+ return type;
4178
+ }
4179
+ function formatEvents(events) {
4180
+ return events.map(formatEvent).join(" \u2192 ");
4181
+ }
4182
+ // Annotate the CommonJS export names for ESM import in node:
4183
+ 0 && (module.exports = {
4184
+ assertEventEmitted,
4185
+ assertEventNotEmitted,
4186
+ assertEventSequence,
4187
+ compareSnapshots,
4188
+ createMockFn,
4189
+ createSagaHarness,
4190
+ createSnapshot,
4191
+ createTestClock,
4192
+ createWorkflowHarness,
4193
+ errOutcome,
4194
+ expectErr,
4195
+ expectOk,
4196
+ formatEvent,
4197
+ formatEvents,
4198
+ formatResult,
4199
+ okOutcome,
4200
+ testWorkflow,
4201
+ throwOutcome,
4202
+ unwrapErr,
4203
+ unwrapErrAsync,
4204
+ unwrapOk,
4205
+ unwrapOkAsync
4206
+ });
13
4207
  //# sourceMappingURL=testing.cjs.map