awaitly 1.35.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. package/dist/{duration.d.ts → di-BDlT7InM.d.cts} +15 -1
  2. package/dist/{duration.d.cts → di-BbFFfO8y.d.ts} +15 -1
  3. package/dist/errors-DtXvrCiO.d.cts +708 -0
  4. package/dist/errors-DtXvrCiO.d.ts +708 -0
  5. package/dist/index.cjs +4594 -1
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.d.cts +1970 -141
  8. package/dist/index.d.ts +1970 -141
  9. package/dist/index.js +4398 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/result.cjs +641 -1
  12. package/dist/result.cjs.map +1 -1
  13. package/dist/result.d.cts +29 -4
  14. package/dist/result.d.ts +29 -4
  15. package/dist/result.js +561 -1
  16. package/dist/result.js.map +1 -1
  17. package/dist/testing.cjs +4202 -8
  18. package/dist/testing.cjs.map +1 -1
  19. package/dist/testing.d.cts +2 -6
  20. package/dist/testing.d.ts +2 -6
  21. package/dist/testing.js +4154 -8
  22. package/dist/testing.js.map +1 -1
  23. package/dist/{run-entry-DGs0tySr.d.cts → types-B8NfNRGX.d.ts} +1078 -1502
  24. package/dist/{run-entry-BOuNyVoO.d.ts → types-BZ2f4MRR.d.cts} +1078 -1502
  25. package/dist/workflow.cjs +7096 -6
  26. package/dist/workflow.cjs.map +1 -1
  27. package/dist/workflow.d.cts +3346 -22
  28. package/dist/workflow.d.ts +3346 -22
  29. package/dist/workflow.js +6929 -6
  30. package/dist/workflow.js.map +1 -1
  31. package/package.json +3 -168
  32. package/dist/adapters.cjs +0 -7
  33. package/dist/adapters.cjs.map +0 -1
  34. package/dist/adapters.d.cts +0 -179
  35. package/dist/adapters.d.ts +0 -179
  36. package/dist/adapters.js +0 -7
  37. package/dist/adapters.js.map +0 -1
  38. package/dist/batch.cjs +0 -7
  39. package/dist/batch.cjs.map +0 -1
  40. package/dist/batch.d.cts +0 -200
  41. package/dist/batch.d.ts +0 -200
  42. package/dist/batch.js +0 -7
  43. package/dist/batch.js.map +0 -1
  44. package/dist/bind-deps.cjs +0 -2
  45. package/dist/bind-deps.cjs.map +0 -1
  46. package/dist/bind-deps.d.cts +0 -28
  47. package/dist/bind-deps.d.ts +0 -28
  48. package/dist/bind-deps.js +0 -2
  49. package/dist/bind-deps.js.map +0 -1
  50. package/dist/cache.cjs +0 -2
  51. package/dist/cache.cjs.map +0 -1
  52. package/dist/cache.d.cts +0 -269
  53. package/dist/cache.d.ts +0 -269
  54. package/dist/cache.js +0 -2
  55. package/dist/cache.js.map +0 -1
  56. package/dist/circuit-breaker.cjs +0 -7
  57. package/dist/circuit-breaker.cjs.map +0 -1
  58. package/dist/circuit-breaker.d.cts +0 -211
  59. package/dist/circuit-breaker.d.ts +0 -211
  60. package/dist/circuit-breaker.js +0 -7
  61. package/dist/circuit-breaker.js.map +0 -1
  62. package/dist/conditional.cjs +0 -2
  63. package/dist/conditional.cjs.map +0 -1
  64. package/dist/conditional.d.cts +0 -252
  65. package/dist/conditional.d.ts +0 -252
  66. package/dist/conditional.js +0 -2
  67. package/dist/conditional.js.map +0 -1
  68. package/dist/core.cjs +0 -7
  69. package/dist/core.cjs.map +0 -1
  70. package/dist/core.d.cts +0 -5
  71. package/dist/core.d.ts +0 -5
  72. package/dist/core.js +0 -7
  73. package/dist/core.js.map +0 -1
  74. package/dist/di-By77n4Fa.d.ts +0 -15
  75. package/dist/di-OJfsohf-.d.cts +0 -15
  76. package/dist/diagnostics.cjs +0 -8
  77. package/dist/diagnostics.cjs.map +0 -1
  78. package/dist/diagnostics.d.cts +0 -68
  79. package/dist/diagnostics.d.ts +0 -68
  80. package/dist/diagnostics.js +0 -8
  81. package/dist/diagnostics.js.map +0 -1
  82. package/dist/durable.cjs +0 -11
  83. package/dist/durable.cjs.map +0 -1
  84. package/dist/durable.d.cts +0 -9
  85. package/dist/durable.d.ts +0 -9
  86. package/dist/durable.js +0 -11
  87. package/dist/durable.js.map +0 -1
  88. package/dist/duration.cjs +0 -2
  89. package/dist/duration.cjs.map +0 -1
  90. package/dist/duration.js +0 -2
  91. package/dist/duration.js.map +0 -1
  92. package/dist/engine.cjs +0 -11
  93. package/dist/engine.cjs.map +0 -1
  94. package/dist/engine.d.cts +0 -115
  95. package/dist/engine.d.ts +0 -115
  96. package/dist/engine.js +0 -11
  97. package/dist/engine.js.map +0 -1
  98. package/dist/errors.cjs +0 -2
  99. package/dist/errors.cjs.map +0 -1
  100. package/dist/errors.d.cts +0 -361
  101. package/dist/errors.d.ts +0 -361
  102. package/dist/errors.js +0 -2
  103. package/dist/errors.js.map +0 -1
  104. package/dist/fetch.cjs +0 -7
  105. package/dist/fetch.cjs.map +0 -1
  106. package/dist/fetch.d.cts +0 -86
  107. package/dist/fetch.d.ts +0 -86
  108. package/dist/fetch.js +0 -7
  109. package/dist/fetch.js.map +0 -1
  110. package/dist/flow.cjs +0 -7
  111. package/dist/flow.cjs.map +0 -1
  112. package/dist/flow.d.cts +0 -163
  113. package/dist/flow.d.ts +0 -163
  114. package/dist/flow.js +0 -7
  115. package/dist/flow.js.map +0 -1
  116. package/dist/functional.cjs +0 -2
  117. package/dist/functional.cjs.map +0 -1
  118. package/dist/functional.d.cts +0 -444
  119. package/dist/functional.d.ts +0 -444
  120. package/dist/functional.js +0 -2
  121. package/dist/functional.js.map +0 -1
  122. package/dist/guards-4sV7mTqj.d.cts +0 -72
  123. package/dist/guards-BIX05ALH.d.ts +0 -72
  124. package/dist/hitl-DFn4Xa_l.d.cts +0 -468
  125. package/dist/hitl-DU5VpKq7.d.ts +0 -468
  126. package/dist/hitl.cjs +0 -7
  127. package/dist/hitl.cjs.map +0 -1
  128. package/dist/hitl.d.cts +0 -442
  129. package/dist/hitl.d.ts +0 -442
  130. package/dist/hitl.js +0 -7
  131. package/dist/hitl.js.map +0 -1
  132. package/dist/index-CnvBryQB.d.ts +0 -417
  133. package/dist/index-DEZEf8Fs.d.cts +0 -417
  134. package/dist/match-entry-DjI2bLpD.d.cts +0 -209
  135. package/dist/match-entry-DjI2bLpD.d.ts +0 -209
  136. package/dist/match.cjs +0 -2
  137. package/dist/match.cjs.map +0 -1
  138. package/dist/match.d.cts +0 -1
  139. package/dist/match.d.ts +0 -1
  140. package/dist/match.js +0 -2
  141. package/dist/match.js.map +0 -1
  142. package/dist/otel.cjs +0 -2
  143. package/dist/otel.cjs.map +0 -1
  144. package/dist/otel.d.cts +0 -188
  145. package/dist/otel.d.ts +0 -188
  146. package/dist/otel.js +0 -2
  147. package/dist/otel.js.map +0 -1
  148. package/dist/persistence-entry-B-8PjnSR.d.cts +0 -831
  149. package/dist/persistence-entry-D8zRkLiT.d.ts +0 -831
  150. package/dist/persistence.cjs +0 -2
  151. package/dist/persistence.cjs.map +0 -1
  152. package/dist/persistence.d.cts +0 -7
  153. package/dist/persistence.d.ts +0 -7
  154. package/dist/persistence.js +0 -2
  155. package/dist/persistence.js.map +0 -1
  156. package/dist/policies.cjs +0 -2
  157. package/dist/policies.cjs.map +0 -1
  158. package/dist/policies.d.cts +0 -379
  159. package/dist/policies.d.ts +0 -379
  160. package/dist/policies.js +0 -2
  161. package/dist/policies.js.map +0 -1
  162. package/dist/ratelimit.cjs +0 -7
  163. package/dist/ratelimit.cjs.map +0 -1
  164. package/dist/ratelimit.d.cts +0 -458
  165. package/dist/ratelimit.d.ts +0 -458
  166. package/dist/ratelimit.js +0 -7
  167. package/dist/ratelimit.js.map +0 -1
  168. package/dist/reliability.cjs +0 -11
  169. package/dist/reliability.cjs.map +0 -1
  170. package/dist/reliability.d.cts +0 -11
  171. package/dist/reliability.d.ts +0 -11
  172. package/dist/reliability.js +0 -11
  173. package/dist/reliability.js.map +0 -1
  174. package/dist/resolver.cjs +0 -7
  175. package/dist/resolver.cjs.map +0 -1
  176. package/dist/resolver.d.cts +0 -68
  177. package/dist/resolver.d.ts +0 -68
  178. package/dist/resolver.js +0 -7
  179. package/dist/resolver.js.map +0 -1
  180. package/dist/resource.cjs +0 -7
  181. package/dist/resource.cjs.map +0 -1
  182. package/dist/resource.d.cts +0 -174
  183. package/dist/resource.d.ts +0 -174
  184. package/dist/resource.js +0 -7
  185. package/dist/resource.js.map +0 -1
  186. package/dist/result/retry.cjs +0 -2
  187. package/dist/result/retry.cjs.map +0 -1
  188. package/dist/result/retry.d.cts +0 -70
  189. package/dist/result/retry.d.ts +0 -70
  190. package/dist/result/retry.js +0 -2
  191. package/dist/result/retry.js.map +0 -1
  192. package/dist/retry.cjs +0 -2
  193. package/dist/retry.cjs.map +0 -1
  194. package/dist/retry.d.cts +0 -388
  195. package/dist/retry.d.ts +0 -388
  196. package/dist/retry.js +0 -2
  197. package/dist/retry.js.map +0 -1
  198. package/dist/run.cjs +0 -7
  199. package/dist/run.cjs.map +0 -1
  200. package/dist/run.d.cts +0 -4
  201. package/dist/run.d.ts +0 -4
  202. package/dist/run.js +0 -7
  203. package/dist/run.js.map +0 -1
  204. package/dist/saga.cjs +0 -11
  205. package/dist/saga.cjs.map +0 -1
  206. package/dist/saga.d.cts +0 -164
  207. package/dist/saga.d.ts +0 -164
  208. package/dist/saga.js +0 -11
  209. package/dist/saga.js.map +0 -1
  210. package/dist/singleflight.cjs +0 -2
  211. package/dist/singleflight.cjs.map +0 -1
  212. package/dist/singleflight.d.cts +0 -145
  213. package/dist/singleflight.d.ts +0 -145
  214. package/dist/singleflight.js +0 -2
  215. package/dist/singleflight.js.map +0 -1
  216. package/dist/slugs.cjs +0 -2
  217. package/dist/slugs.cjs.map +0 -1
  218. package/dist/slugs.d.cts +0 -67
  219. package/dist/slugs.d.ts +0 -67
  220. package/dist/slugs.js +0 -2
  221. package/dist/slugs.js.map +0 -1
  222. package/dist/streaming.cjs +0 -9
  223. package/dist/streaming.cjs.map +0 -1
  224. package/dist/streaming.d.cts +0 -596
  225. package/dist/streaming.d.ts +0 -596
  226. package/dist/streaming.js +0 -9
  227. package/dist/streaming.js.map +0 -1
  228. package/dist/tagged-error.cjs +0 -2
  229. package/dist/tagged-error.cjs.map +0 -1
  230. package/dist/tagged-error.d.cts +0 -275
  231. package/dist/tagged-error.d.ts +0 -275
  232. package/dist/tagged-error.js +0 -2
  233. package/dist/tagged-error.js.map +0 -1
  234. package/dist/types-BziYHFkD.d.ts +0 -323
  235. package/dist/types-C5jLEUqY.d.cts +0 -323
  236. package/dist/webhook.cjs +0 -7
  237. package/dist/webhook.cjs.map +0 -1
  238. package/dist/webhook.d.cts +0 -499
  239. package/dist/webhook.d.ts +0 -499
  240. package/dist/webhook.js +0 -7
  241. package/dist/webhook.js.map +0 -1
package/dist/saga.d.cts DELETED
@@ -1,164 +0,0 @@
1
- import { R as Result, c as AsyncResult } from './run-entry-DGs0tySr.cjs';
2
- import { c as Workflow, A as AnyResultFn, h as WorkflowOptions, E as ErrorsOfDeps } from './persistence-entry-B-8PjnSR.cjs';
3
- import { UnexpectedError } from './errors.cjs';
4
- import './types-C5jLEUqY.cjs';
5
- import '@standard-schema/spec';
6
- import './tagged-error.cjs';
7
- import './slugs.cjs';
8
-
9
- /**
10
- * Saga / Compensation Pattern
11
- *
12
- * Compensation is a first-class step option on every workflow. Pass `{ compensate }`
13
- * to any step and the workflow will run compensations in reverse order if anything
14
- * downstream fails.
15
- *
16
- * `createSagaWorkflow` is a thin alias for `createWorkflow` whose result error union
17
- * also includes `SagaCompensationError` — useful when you know you'll be using
18
- * compensation and want the type system to remind you.
19
- *
20
- * @example
21
- * ```typescript
22
- * import { createSagaWorkflow, isSagaCompensationError } from 'awaitly/saga';
23
- *
24
- * const checkout = createSagaWorkflow('checkout', {
25
- * reserveInventory, releaseInventory,
26
- * chargeCard, refundPayment,
27
- * sendEmail,
28
- * });
29
- *
30
- * const result = await checkout.run(async ({ step, deps }) => {
31
- * const r = await step('reserve', () => deps.reserveInventory(items), {
32
- * compensate: (r) => deps.releaseInventory(r.id),
33
- * });
34
- * const p = await step('charge', () => deps.chargeCard(amount), {
35
- * compensate: (p) => deps.refundPayment(p.id),
36
- * });
37
- * await step('notify', () => deps.sendEmail(userId));
38
- * return { r, p };
39
- * });
40
- *
41
- * if (!result.ok && isSagaCompensationError(result.error)) {
42
- * // result.error.originalError — what triggered the rollback
43
- * // result.error.compensationErrors — which cleanups failed
44
- * }
45
- * ```
46
- */
47
-
48
- /** A compensation action to run on rollback. */
49
- type CompensationAction<T> = (value: T) => void | Promise<void>;
50
- /** Options for a saga step (kept for back-compat — `compensate` lives on `StepOptions`). */
51
- interface SagaStepOptions<T> {
52
- compensate?: CompensationAction<T>;
53
- }
54
- /**
55
- * @deprecated Use `WorkflowOptions` from `awaitly/workflow`. Kept as an alias for back-compat.
56
- */
57
- type SagaWorkflowOptions<E> = {
58
- onError?: (error: E | UnexpectedError | SagaCompensationError, stepName?: string) => void;
59
- onEvent?: (event: unknown) => void;
60
- throwOnCompensationFailure?: boolean;
61
- };
62
- /** Error returned when one or more compensation actions fail. */
63
- interface SagaCompensationError {
64
- type: "SAGA_COMPENSATION_ERROR";
65
- /** The original error that triggered the rollback. */
66
- originalError: unknown;
67
- /** Errors from failed compensation actions. */
68
- compensationErrors: Array<{
69
- stepName?: string;
70
- error: unknown;
71
- }>;
72
- }
73
- /** Type guard for SagaCompensationError. */
74
- declare function isSagaCompensationError(error: unknown): error is SagaCompensationError;
75
- /**
76
- * A `Workflow` whose result error union includes `SagaCompensationError`.
77
- * Identical to `Workflow` at runtime — only the static type is widened.
78
- */
79
- type SagaWorkflow<E, U = UnexpectedError, Deps = unknown, C = void> = Workflow<E | SagaCompensationError, U, Deps, C>;
80
- /**
81
- * Create a workflow that uses compensation. Identical to `createWorkflow` —
82
- * only the result type is widened to include `SagaCompensationError`.
83
- *
84
- * Prefer this when you intend to use `step(..., { compensate })` so the type
85
- * system reminds you to handle the SAGA_COMPENSATION_ERROR case.
86
- *
87
- * @example
88
- * ```typescript
89
- * const saga = createSagaWorkflow('checkout', { reserve, release, charge, refund });
90
- *
91
- * const result = await saga.run(async ({ step, deps }) => {
92
- * const r = await step('reserve', () => deps.reserve(...), {
93
- * compensate: (r) => deps.release(r.id),
94
- * });
95
- * await step('charge', () => deps.charge(...), {
96
- * compensate: (p) => deps.refund(p.id),
97
- * });
98
- * return r;
99
- * });
100
- * ```
101
- */
102
- declare function createSagaWorkflow<const Deps extends Readonly<Record<string, AnyResultFn>>, U = UnexpectedError, C = void>(workflowName: string, deps: Deps, options?: WorkflowOptions<ErrorsOfDeps<Deps>, U, C>): SagaWorkflow<ErrorsOfDeps<Deps>, U, Deps, C>;
103
- /** Saga events emitted by `runSaga` for observability. */
104
- type SagaEvent = {
105
- type: "saga_start";
106
- sagaId: string;
107
- ts: number;
108
- } | {
109
- type: "saga_success";
110
- sagaId: string;
111
- ts: number;
112
- durationMs: number;
113
- } | {
114
- type: "saga_error";
115
- sagaId: string;
116
- ts: number;
117
- durationMs: number;
118
- error: unknown;
119
- } | {
120
- type: "saga_compensation_start";
121
- sagaId: string;
122
- ts: number;
123
- stepCount: number;
124
- } | {
125
- type: "saga_compensation_step";
126
- sagaId: string;
127
- stepName?: string;
128
- ts: number;
129
- success: boolean;
130
- error?: unknown;
131
- } | {
132
- type: "saga_compensation_end";
133
- sagaId: string;
134
- ts: number;
135
- durationMs: number;
136
- success: boolean;
137
- failedCount: number;
138
- };
139
- type SagaResult<T, E> = Result<T, E | UnexpectedError | SagaCompensationError, unknown>;
140
- /** Saga step function — like RunStep but every step takes an optional compensate. */
141
- interface SagaStep<E = unknown> {
142
- <T, StepE extends E, StepC = unknown>(name: string, operation: () => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>, options?: SagaStepOptions<T>): Promise<T>;
143
- try: <T, Err extends E>(name: string, operation: () => T | Promise<T>, options: {
144
- error: Err;
145
- compensate?: CompensationAction<T>;
146
- } | {
147
- onError: (cause: unknown) => Err;
148
- compensate?: CompensationAction<T>;
149
- }) => Promise<T>;
150
- }
151
- /**
152
- * Run a saga with explicit error typing — for cases where you don't have a
153
- * deps object to infer errors from. Most users should reach for
154
- * `createSagaWorkflow` (or just `createWorkflow` with `step({ compensate })`).
155
- */
156
- declare function runSaga<T, E>(fn: (context: {
157
- step: SagaStep<E>;
158
- }) => Promise<T>, options?: {
159
- onError?: (error: E | UnexpectedError | SagaCompensationError) => void;
160
- onEvent?: (event: SagaEvent) => void;
161
- throwOnCompensationFailure?: boolean;
162
- }): Promise<SagaResult<T, E>>;
163
-
164
- export { type CompensationAction, type SagaCompensationError, type SagaEvent, type SagaResult, type SagaStep, type SagaStepOptions, type SagaWorkflow, type SagaWorkflowOptions, createSagaWorkflow, isSagaCompensationError, runSaga };
package/dist/saga.d.ts DELETED
@@ -1,164 +0,0 @@
1
- import { R as Result, c as AsyncResult } from './run-entry-BOuNyVoO.js';
2
- import { c as Workflow, A as AnyResultFn, h as WorkflowOptions, E as ErrorsOfDeps } from './persistence-entry-D8zRkLiT.js';
3
- import { UnexpectedError } from './errors.js';
4
- import './types-BziYHFkD.js';
5
- import '@standard-schema/spec';
6
- import './tagged-error.js';
7
- import './slugs.js';
8
-
9
- /**
10
- * Saga / Compensation Pattern
11
- *
12
- * Compensation is a first-class step option on every workflow. Pass `{ compensate }`
13
- * to any step and the workflow will run compensations in reverse order if anything
14
- * downstream fails.
15
- *
16
- * `createSagaWorkflow` is a thin alias for `createWorkflow` whose result error union
17
- * also includes `SagaCompensationError` — useful when you know you'll be using
18
- * compensation and want the type system to remind you.
19
- *
20
- * @example
21
- * ```typescript
22
- * import { createSagaWorkflow, isSagaCompensationError } from 'awaitly/saga';
23
- *
24
- * const checkout = createSagaWorkflow('checkout', {
25
- * reserveInventory, releaseInventory,
26
- * chargeCard, refundPayment,
27
- * sendEmail,
28
- * });
29
- *
30
- * const result = await checkout.run(async ({ step, deps }) => {
31
- * const r = await step('reserve', () => deps.reserveInventory(items), {
32
- * compensate: (r) => deps.releaseInventory(r.id),
33
- * });
34
- * const p = await step('charge', () => deps.chargeCard(amount), {
35
- * compensate: (p) => deps.refundPayment(p.id),
36
- * });
37
- * await step('notify', () => deps.sendEmail(userId));
38
- * return { r, p };
39
- * });
40
- *
41
- * if (!result.ok && isSagaCompensationError(result.error)) {
42
- * // result.error.originalError — what triggered the rollback
43
- * // result.error.compensationErrors — which cleanups failed
44
- * }
45
- * ```
46
- */
47
-
48
- /** A compensation action to run on rollback. */
49
- type CompensationAction<T> = (value: T) => void | Promise<void>;
50
- /** Options for a saga step (kept for back-compat — `compensate` lives on `StepOptions`). */
51
- interface SagaStepOptions<T> {
52
- compensate?: CompensationAction<T>;
53
- }
54
- /**
55
- * @deprecated Use `WorkflowOptions` from `awaitly/workflow`. Kept as an alias for back-compat.
56
- */
57
- type SagaWorkflowOptions<E> = {
58
- onError?: (error: E | UnexpectedError | SagaCompensationError, stepName?: string) => void;
59
- onEvent?: (event: unknown) => void;
60
- throwOnCompensationFailure?: boolean;
61
- };
62
- /** Error returned when one or more compensation actions fail. */
63
- interface SagaCompensationError {
64
- type: "SAGA_COMPENSATION_ERROR";
65
- /** The original error that triggered the rollback. */
66
- originalError: unknown;
67
- /** Errors from failed compensation actions. */
68
- compensationErrors: Array<{
69
- stepName?: string;
70
- error: unknown;
71
- }>;
72
- }
73
- /** Type guard for SagaCompensationError. */
74
- declare function isSagaCompensationError(error: unknown): error is SagaCompensationError;
75
- /**
76
- * A `Workflow` whose result error union includes `SagaCompensationError`.
77
- * Identical to `Workflow` at runtime — only the static type is widened.
78
- */
79
- type SagaWorkflow<E, U = UnexpectedError, Deps = unknown, C = void> = Workflow<E | SagaCompensationError, U, Deps, C>;
80
- /**
81
- * Create a workflow that uses compensation. Identical to `createWorkflow` —
82
- * only the result type is widened to include `SagaCompensationError`.
83
- *
84
- * Prefer this when you intend to use `step(..., { compensate })` so the type
85
- * system reminds you to handle the SAGA_COMPENSATION_ERROR case.
86
- *
87
- * @example
88
- * ```typescript
89
- * const saga = createSagaWorkflow('checkout', { reserve, release, charge, refund });
90
- *
91
- * const result = await saga.run(async ({ step, deps }) => {
92
- * const r = await step('reserve', () => deps.reserve(...), {
93
- * compensate: (r) => deps.release(r.id),
94
- * });
95
- * await step('charge', () => deps.charge(...), {
96
- * compensate: (p) => deps.refund(p.id),
97
- * });
98
- * return r;
99
- * });
100
- * ```
101
- */
102
- declare function createSagaWorkflow<const Deps extends Readonly<Record<string, AnyResultFn>>, U = UnexpectedError, C = void>(workflowName: string, deps: Deps, options?: WorkflowOptions<ErrorsOfDeps<Deps>, U, C>): SagaWorkflow<ErrorsOfDeps<Deps>, U, Deps, C>;
103
- /** Saga events emitted by `runSaga` for observability. */
104
- type SagaEvent = {
105
- type: "saga_start";
106
- sagaId: string;
107
- ts: number;
108
- } | {
109
- type: "saga_success";
110
- sagaId: string;
111
- ts: number;
112
- durationMs: number;
113
- } | {
114
- type: "saga_error";
115
- sagaId: string;
116
- ts: number;
117
- durationMs: number;
118
- error: unknown;
119
- } | {
120
- type: "saga_compensation_start";
121
- sagaId: string;
122
- ts: number;
123
- stepCount: number;
124
- } | {
125
- type: "saga_compensation_step";
126
- sagaId: string;
127
- stepName?: string;
128
- ts: number;
129
- success: boolean;
130
- error?: unknown;
131
- } | {
132
- type: "saga_compensation_end";
133
- sagaId: string;
134
- ts: number;
135
- durationMs: number;
136
- success: boolean;
137
- failedCount: number;
138
- };
139
- type SagaResult<T, E> = Result<T, E | UnexpectedError | SagaCompensationError, unknown>;
140
- /** Saga step function — like RunStep but every step takes an optional compensate. */
141
- interface SagaStep<E = unknown> {
142
- <T, StepE extends E, StepC = unknown>(name: string, operation: () => Result<T, StepE, StepC> | AsyncResult<T, StepE, StepC>, options?: SagaStepOptions<T>): Promise<T>;
143
- try: <T, Err extends E>(name: string, operation: () => T | Promise<T>, options: {
144
- error: Err;
145
- compensate?: CompensationAction<T>;
146
- } | {
147
- onError: (cause: unknown) => Err;
148
- compensate?: CompensationAction<T>;
149
- }) => Promise<T>;
150
- }
151
- /**
152
- * Run a saga with explicit error typing — for cases where you don't have a
153
- * deps object to infer errors from. Most users should reach for
154
- * `createSagaWorkflow` (or just `createWorkflow` with `step({ compensate })`).
155
- */
156
- declare function runSaga<T, E>(fn: (context: {
157
- step: SagaStep<E>;
158
- }) => Promise<T>, options?: {
159
- onError?: (error: E | UnexpectedError | SagaCompensationError) => void;
160
- onEvent?: (event: SagaEvent) => void;
161
- throwOnCompensationFailure?: boolean;
162
- }): Promise<SagaResult<T, E>>;
163
-
164
- export { type CompensationAction, type SagaCompensationError, type SagaEvent, type SagaResult, type SagaStep, type SagaStepOptions, type SagaWorkflow, type SagaWorkflowOptions, createSagaWorkflow, isSagaCompensationError, runSaga };
package/dist/saga.js DELETED
@@ -1,11 +0,0 @@
1
- var ht={"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 Qe(e){return`https://jagreehal.github.io/awaitly/rules/#${e}`}var Ht=Object.keys(ht);var Ue=class extends Error{_tag};function de(e,t){return class extends Ue{_tag=e;constructor(c,_){let w=t?.message?t.message(c??{}):e;if(super(w),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:Qe(t.slug),enumerable:!0,writable:!1,configurable:!1})}if(Object.setPrototypeOf(this,new.target.prototype),c&&typeof c=="object"){let p;if(t?.slug!==void 0){let{_tag:v,name:W,message:D,stack:r,code:J,hint:z,docsUrl:ce,...se}=c;p=se}else{let{_tag:v,name:W,message:D,stack:r,...J}=c;p=J}let A=Object.prototype.hasOwnProperty.call(p,"cause"),F=A?p.cause:void 0;A&&delete p.cause;let Y=_?.cause!==void 0;if(A&&Y)throw new TypeError("TaggedError: cannot provide 'cause' in props when also setting ErrorOptions.cause");Object.assign(this,p),A&&(this.cause=F),Y&&(this.cause=_?.cause)}else _?.cause!==void 0&&(this.cause=_.cause)}}}Object.defineProperty(de,Symbol.hasInstance,{value:e=>e instanceof Ue});(w=>{function e(p){return p instanceof Error}w.isError=e;function t(p){return p instanceof Ue}w.isTaggedError=t;function c(p,A){let F=p._tag,Y=A[F];return Y(p)}w.match=c;function _(p,A,F){let Y=p._tag,v=A[Y];return v?v(p):F(p)}w.matchPartial=_})(de||={});var et=class extends de("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`}){},tt=class extends de("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`}){},rt=class extends de("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`:""}`}){},nt=class extends de("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`:""}`}){},ot=class extends de("ValidationError",{message:t=>`ValidationError: Invalid ${t.field} - ${t.reason}`}){},st=class extends de("NotFoundError",{message:t=>t.id?`NotFoundError: ${t.resource} with id ${t.id} not found`:`NotFoundError: ${t.resource} not found`}){},at=class extends de("UnauthorizedError",{message:t=>t.reason?`UnauthorizedError: ${t.reason}`:t.action&&t.resource?`UnauthorizedError: Not authorized to ${t.action} ${t.resource}`:"UnauthorizedError: Access denied"}){},it=class extends de("NetworkError",{message:t=>t.url?`NetworkError: ${t.reason} (${t.url})`:`NetworkError: ${t.reason}`}){},ut=class extends de("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}`}){},ve=class extends de("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 lt(e){return{ok:!0,value:e}}var Ct=e=>typeof e=="object"&&e!==null&&"ok"in e&&typeof e.ok=="boolean"&&(e.ok?"value"in e:"error"in e),We=(e,t)=>{let c={},_=new Map;for(let w of Object.keys(e)){let p=e[w];typeof p=="function"&&(c[w]=(...A)=>{let F=(_.get(w)??0)+1;_.set(w,F);let Y=F===1?w:`${w}#${F}`;return t(Y,async()=>{let v=await p(...A);return Ct(v)?v:lt(v)})})}return c};function St(e){let t=e.trim().match(/^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)$/i);if(!t)return;let c=parseFloat(t[1]),_=t[2].toLowerCase();return{_tag:"Duration",millis:c*({ms:1,s:1e3,m:6e4,h:36e5,d:864e5}[_]??1)}}function Fe(e){return new ve({cause:e})}function Z(e){return{ok:!0,value:e}}function j(e,t){let c=t?.cause;return{ok:!1,error:e,...c!==void 0?{cause:c}:{}}}var mt=e=>e instanceof ve||typeof e=="object"&&e!==null&&"_tag"in e&&e._tag==="UnexpectedError";function bt(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 c=t._tag.trim();if(c)return c}if(typeof t.tag=="string"){let c=t.tag.trim();if(c)return c}if(typeof t.code=="string"){let c=t.code.trim();if(c)return c}else if(typeof t.code=="number")return String(t.code);if(e instanceof Error&&e.name){let c=e.name.trim();if(c)return c}}return"unknown"}function At(e,t){if(!(!t||!e))return t[e]}function qe(e){let{intent:t,domain:c,owner:_,tags:w,stateChanges:p,emits:A,calls:F}=e;if(!t&&!c&&!_&&!w?.length&&!p?.length&&!A?.length&&!F?.length)return;let Y={};return t&&(Y.intent=t),c&&(Y.domain=c),_&&(Y.owner=_),w?.length&&(Y.tags=w),p?.length&&(Y.stateChanges=p),A?.length&&(Y.emits=A),F?.length&&(Y.calls=F),Y}function we(e,t,c,_,w){let p=bt(e),A=At(p,t),F={tag:p,origin:c};return A!==void 0&&(F.classification=A),_!==void 0&&(F.attempt=_),w!==void 0&&(F.cumulativeDurationMs=w),F}var Oe=Symbol.for("step_timeout_marker");function ct(e){return typeof e!="object"||e===null?!1:e.type==="STEP_TIMEOUT"?!0:Oe in e}function vt(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(Oe in e)return e[Oe]}}var Et=Symbol("early-exit");function Re(e,t){return{[Et]:!0,error:e,meta:t}}function ge(e){return typeof e=="object"&&e!==null&&e[Et]===!0}var ft=Symbol("mapper-exception");function Pe(e){return{[ft]:!0,thrown:e}}function Pt(e){return typeof e=="object"&&e!==null&&e[ft]===!0}function $e(e,t){let{backoff:c,initialDelay:_,maxDelay:w,jitter:p}=t,A;switch(c){case"fixed":A=_;break;case"linear":A=_*e;break;case"exponential":A=_*Math.pow(2,e-1);break}if(A=Math.min(A,w),p){let F=A*.25*Math.random();A=A+F}return Math.floor(A)}function He(e){return new Promise(t=>setTimeout(t,e))}var pt=Symbol("timeout"),je=Symbol("timeout-option");function _t(e){return typeof e=="object"&&e!==null&&e[je]===!0}async function Ot(e,t,c,_){let w=new AbortController,p=t.onTimeout??"error",A=()=>typeof p=="function"?p({name:c.name,key:c.key,ms:t.ms}):t.error??{type:"STEP_TIMEOUT",stepName:c.name,stepKey:c.key,timeoutMs:t.ms,attempt:c.attempt},F;_?.aborted&&w.abort(_.reason);let Y;_&&!_.aborted&&(Y=()=>w.abort(_.reason),_.addEventListener("abort",Y,{once:!0}));let v=new Promise((D,r)=>{F=setTimeout(()=>{if(p!=="disconnect"&&w.abort(),p==="option"){r({[je]:!0,ms:t.ms});return}r({[pt]:!0,error:A()})},t.ms)}),W;t.signal?W=Promise.resolve(e(w.signal)):W=Promise.resolve(e());try{return await Promise.race([W,v])}catch(D){if(typeof D=="object"&&D!==null&&D[je]===!0)throw{[je]:!0,ms:t.ms};if(typeof D=="object"&&D!==null&&D[pt]===!0){p==="disconnect"&&W.catch(()=>{});let r=D.error;if(typeof r=="object"&&r!==null&&r.type!=="STEP_TIMEOUT"){let J={timeoutMs:t.ms,stepName:c.name,stepKey:c.key,attempt:c.attempt};Oe in r?r[Oe]=J:Object.defineProperty(r,Oe,{value:J,enumerable:!1,writable:!0,configurable:!1})}throw r}throw D}finally{clearTimeout(F),Y&&_&&_.removeEventListener("abort",Y)}}var _e={backoff:"exponential",initialDelay:100,maxDelay:3e4,jitter:!0,shouldRetry:()=>!0,onRetry:()=>{}};async function Ne(e,t,c){if(typeof e!="function"){let k=e,le=t;if(typeof le!="function")throw new TypeError("[awaitly] run(deps, fn) requires a callback as the second argument. Example: run({ getUser }, async (s) => s.getUser(id))");return Ne(({step:ke})=>le(We(k,ke),{step:ke}),c)}let _=e,w=t,{onError:p,onEvent:A,catchUnexpected:F,workflowId:Y,workflowName:v,context:W,_workflowSignal:D}=w&&typeof w=="object"?w:{},r=Y??crypto.randomUUID(),J=F??Fe,z=[],ce=0,se=k=>k??`step_${++ce}`,i=k=>{let le=k.context!==void 0||W===void 0?k:{...k,context:W},Ee=v!==void 0&&le.workflowName===void 0?{...le,workflowName:v}:le;if(Ee.type==="step_success"){let ke=Ee.stepId;for(let he=z.length-1;he>=0;he--){let L=z[he];if(L.type==="race"&&!L.winnerId){L.winnerId=ke;break}}}A?.(Ee,W)},ne=Re,me=k=>ge(k),pe=(k,le)=>k,ye=k=>typeof k=="function"?!1:!!(k&&typeof k=="object"&&"ok"in k||k&&typeof k=="object"&&"then"in k&&typeof k.then=="function");try{let le=function(m){let R={};for(let[s,a]of Object.entries(m))if(typeof a=="function")R[s]=a;else if(a&&typeof a=="object"&&"fn"in a)R[s]=a.fn;else throw new TypeError(`step.all: operation "${s}" must be a function or { fn, errors? } object`);return R},Ee=function(m,R){let s=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let a=performance.now(),n=!1;z.push({scopeId:s,type:"parallel"});let o=()=>{if(n)return;n=!0;let y=z.findIndex(x=>x.scopeId===s);y!==-1&&z.splice(y,1),i({type:"scope_end",workflowId:r,scopeId:s,ts:Date.now(),durationMs:performance.now()-a})};i({type:"scope_start",workflowId:r,scopeId:s,scopeType:"parallel",name:m,ts:Date.now()});try{let y=await R();if(o(),!y.ok)throw p?.(y.error,m,W),ne(y.error,{origin:"result",resultCause:y.cause});return y.value}catch(y){throw o(),y}})()},ke=function(m,R){let s=Object.keys(m),a=R.name??`Parallel(${s.join(", ")})`,n=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let o=performance.now(),y=!1;z.push({scopeId:n,type:"parallel"});let x=()=>{if(y)return;y=!0;let b=z.findIndex(O=>O.scopeId===n);b!==-1&&z.splice(b,1),i({type:"scope_end",workflowId:r,scopeId:n,ts:Date.now(),durationMs:performance.now()-o})};i({type:"scope_start",workflowId:r,scopeId:n,scopeType:"parallel",name:a,ts:Date.now()});try{let b=await new Promise(I=>{if(s.length===0){I([]);return}let B=!1,ee=s.length,N=new Array(s.length);for(let H=0;H<s.length;H++){let K=s[H],$=H;Promise.resolve(m[K]()).catch(h=>j({type:"PROMISE_REJECTED",cause:h},{cause:{type:"PROMISE_REJECTION",reason:h}})).then(h=>{if(!B){if(!h.ok){B=!0,I([{key:K,result:h}]);return}N[$]={key:K,result:h},ee--,ee===0&&I(N)}})}});x();let O={};for(let{key:I,result:B}of b){if(!B.ok)throw p?.(B.error,I,W),ne(B.error,{origin:"result",resultCause:B.cause});O[I]=B.value}return O}catch(b){throw x(),b}})()};var be=le,Ae=Ee,xe=ke;let k=(m,R,s)=>(async()=>{if(typeof m!="string"||m.length===0)throw new Error('[awaitly] step() requires an explicit string ID as the first argument. Example: step("fetchUser", () => fetchUser(id))');let a=s??{},n=qe(a),o=m,y=a.key??m,x=a.key??m,{description:b,retry:O,timeout:I}=a,B=se(y),ee=A,N=ee?performance.now():0,K=ye(R)?()=>R:R,h={attempts:Math.max(1,O?.attempts??1),backoff:O?.backoff??_e.backoff,initialDelay:O?.initialDelay??_e.initialDelay,maxDelay:O?.maxDelay??_e.maxDelay,jitter:O?.jitter??_e.jitter,shouldRetry:O?.shouldRetry??_e.shouldRetry,onRetry:O?.onRetry??_e.onRetry};A&&i({type:"step_start",workflowId:r,stepId:B,stepKey:y,name:o,description:b,ts:Date.now(),...n&&{metadata:n}});let fe;for(let T=1;T<=h.attempts;T++){let f=ee?performance.now():0;try{let u;if(I?u=await Ot(K,I,{name:o,key:y,attempt:T},D):u=await K(),u.ok){let g=performance.now()-N;return i({type:"step_success",workflowId:r,stepId:B,stepKey:y,name:o,description:b,ts:Date.now(),durationMs:g,...n&&{metadata:n}}),x&&i({type:"step_complete",workflowId:r,stepKey:x,name:o,description:b,ts:Date.now(),durationMs:g,result:u,...n&&{metadata:n}}),u.value}if(fe=u,T<h.attempts&&h.shouldRetry(u.error,T)){let g=$e(T,h);i({type:"step_retry",workflowId:r,stepId:B,stepKey:y,name:o,ts:Date.now(),attempt:T+1,maxAttempts:h.attempts,delayMs:g,error:u.error,...n&&{metadata:n},diagnostics:we(u.error,a.errorMeta,"result",T,performance.now()-N)}),h.onRetry(u.error,T,g),await He(g);continue}h.attempts>1&&i({type:"step_retries_exhausted",workflowId:r,stepId:B,stepKey:y,name:o,ts:Date.now(),durationMs:performance.now()-N,attempts:T,lastError:u.error,...n&&{metadata:n},diagnostics:we(u.error,a.errorMeta,"result",T,performance.now()-N)});break}catch(u){let g=performance.now()-f;if(_t(u)){let P=u.ms;i({type:"step_timeout",workflowId:r,stepId:B,stepKey:y,name:o,ts:Date.now(),timeoutMs:P,attempt:T,...n&&{metadata:n},diagnostics:we(u,a.errorMeta,"timeout",T)}),i({type:"step_success",workflowId:r,stepId:B,stepKey:y,name:o,description:b,ts:Date.now(),durationMs:performance.now()-N,...n&&{metadata:n}}),x&&i({type:"step_complete",workflowId:r,stepKey:x,name:o,description:b,ts:Date.now(),durationMs:performance.now()-N,result:Z(void 0),...n&&{metadata:n}});return}if(me(u))throw i({type:"step_aborted",workflowId:r,stepId:B,stepKey:y,name:o,description:b,ts:Date.now(),durationMs:g,...n&&{metadata:n}}),u;if(ct(u)){let P=vt(u),E=I?.ms??P?.timeoutMs??0;if(i({type:"step_timeout",workflowId:r,stepId:B,stepKey:y,name:o,ts:Date.now(),timeoutMs:E,attempt:T,...n&&{metadata:n},diagnostics:we(u,a.errorMeta,"timeout",T)}),T<h.attempts&&h.shouldRetry(u,T)){let G=$e(T,h);i({type:"step_retry",workflowId:r,stepId:B,stepKey:y,name:o,ts:Date.now(),attempt:T+1,maxAttempts:h.attempts,delayMs:G,error:u,...n&&{metadata:n},diagnostics:we(u,a.errorMeta,"timeout",T,performance.now()-N)}),h.onRetry(u,T,G),await He(G);continue}h.attempts>1&&i({type:"step_retries_exhausted",workflowId:r,stepId:B,stepKey:y,name:o,ts:Date.now(),durationMs:performance.now()-N,attempts:T,lastError:u,...n&&{metadata:n},diagnostics:we(u,a.errorMeta,"timeout",T,performance.now()-N)});let U=performance.now()-N;throw i({type:"step_error",workflowId:r,stepId:B,stepKey:y,name:o,description:b,ts:Date.now(),durationMs:U,error:u,...n&&{metadata:n},diagnostics:we(u,a.errorMeta,"timeout",T,U)}),x&&i({type:"step_complete",workflowId:r,stepKey:x,name:o,description:b,ts:Date.now(),durationMs:U,result:j(u,{cause:u}),meta:{origin:"throw",thrown:u},...n&&{metadata:n}}),p?.(u,o,W),ne(u,{origin:"throw",thrown:u})}if(T<h.attempts&&h.shouldRetry(u,T)){let P=$e(T,h);i({type:"step_retry",workflowId:r,stepId:B,stepKey:y,name:o,ts:Date.now(),attempt:T+1,maxAttempts:h.attempts,delayMs:P,error:u,...n&&{metadata:n},diagnostics:we(u,a.errorMeta,"throw",T,performance.now()-N)}),h.onRetry(u,T,P),await He(P);continue}h.attempts>1&&!ct(u)&&i({type:"step_retries_exhausted",workflowId:r,stepId:B,stepKey:y,name:o,ts:Date.now(),durationMs:performance.now()-N,attempts:T,lastError:u,...n&&{metadata:n},diagnostics:we(u,a.errorMeta,"throw",T,performance.now()-N)});let S=performance.now()-N,C;try{C=J(u)}catch(P){throw Pe(P)}throw i({type:"step_error",workflowId:r,stepId:B,stepKey:y,name:o,description:b,ts:Date.now(),durationMs:S,error:C,...n&&{metadata:n},diagnostics:we(u,a.errorMeta,"throw",T,S)}),x&&i({type:"step_complete",workflowId:r,stepKey:x,name:o,description:b,ts:Date.now(),durationMs:S,result:j(C,{cause:u}),meta:{origin:"throw",thrown:u},...n&&{metadata:n}}),p?.(C,o,W),ne(C,{origin:"throw",thrown:u})}}let l=fe,d=performance.now()-N,q=pe(l.error,{origin:"result",resultCause:l.cause});throw i({type:"step_error",workflowId:r,stepId:B,stepKey:y,name:o,description:b,ts:Date.now(),durationMs:d,error:q,...n&&{metadata:n},diagnostics:we(l.error,a.errorMeta,"result",h.attempts,d)}),x&&i({type:"step_complete",workflowId:r,stepKey:x,name:o,description:b,ts:Date.now(),durationMs:d,result:l,meta:{origin:"result",resultCause:l.cause},...n&&{metadata:n}}),p?.(q,o,W),ne(q,{origin:"result",resultCause:l.cause})})();k.try=(m,R,s)=>{if(typeof m!="string"||m.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 a="error"in s?()=>s.error:s.onError;if(s.retry||s.timeout)return k.retry(m,async()=>{try{return Z(await R())}catch(b){return j(a(b),{cause:b})}},{attempts:s.retry?.attempts??1,...s.retry??{},key:s.key,timeout:s.timeout});let n=s.key??m,o=m,y=m,x=A;return(async()=>{let b=x?performance.now():0;A&&i({type:"step_start",workflowId:r,stepId:y,stepKey:n,name:o,ts:Date.now()});try{let O=await R(),I=performance.now()-b;return i({type:"step_success",workflowId:r,stepId:y,stepKey:n,name:o,ts:Date.now(),durationMs:I}),n&&i({type:"step_complete",workflowId:r,stepKey:n,name:o,ts:Date.now(),durationMs:I,result:Z(O)}),O}catch(O){let I=a(O),B=performance.now()-b,ee=pe(I,{origin:"throw",thrown:O});throw i({type:"step_error",workflowId:r,stepId:y,stepKey:n,name:o,ts:Date.now(),durationMs:B,error:ee}),n&&i({type:"step_complete",workflowId:r,stepKey:n,name:o,ts:Date.now(),durationMs:B,result:j(I,{cause:O}),meta:{origin:"throw",thrown:O}}),p?.(ee,o,W),ne(ee,{origin:"throw",thrown:O})}})()},k.fromResult=(m,R,s)=>{if(typeof m!="string"||m.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 a=s.key??m,n=m,o=m,y="error"in s?()=>s.error:s.onError,x=A;return(async()=>{let b=x?performance.now():0;A&&i({type:"step_start",workflowId:r,stepId:o,stepKey:a,name:n,ts:Date.now()});let O=await R();if(O.ok){let I=performance.now()-b;return i({type:"step_success",workflowId:r,stepId:o,stepKey:a,name:n,ts:Date.now(),durationMs:I}),a&&i({type:"step_complete",workflowId:r,stepKey:a,name:n,ts:Date.now(),durationMs:I,result:Z(O.value)}),O.value}else{let I=y(O.error),B=performance.now()-b,ee=pe(I,{origin:"result",resultCause:O.error});throw i({type:"step_error",workflowId:r,stepId:o,stepKey:a,name:n,ts:Date.now(),durationMs:B,error:ee}),a&&i({type:"step_complete",workflowId:r,stepKey:a,name:n,ts:Date.now(),durationMs:B,result:j(I,{cause:O.error}),meta:{origin:"result",resultCause:O.error}}),p?.(ee,n,W),ne(ee,{origin:"result",resultCause:O.error})}})()},k.fromNullable=(m,R,s,a)=>{if(typeof m!="string"||m.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 k(m,async()=>{let n=await R();return n!=null?Z(n):j(s())},a)},k.retry=(m,R,s)=>{if(typeof m!="string"||m.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 k(m,R,{key:s.key??m,retry:{attempts:s.attempts,backoff:s.backoff,initialDelay:s.initialDelay,maxDelay:s.maxDelay,jitter:s.jitter,shouldRetry:s.shouldRetry,onRetry:s.onRetry},timeout:s.timeout})},k.withTimeout=(m,R,s)=>{if(typeof m!="string"||m.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 k(m,R,{key:s.key??m,timeout:s})},k.sleep=(m,R,s)=>{if(typeof m!="string"||m.length===0)throw new Error('[awaitly] step.sleep() requires an explicit string ID as the first argument. Example: step.sleep("delay", "5s")');let a=typeof R=="string"?St(R):R;if(!a)throw new Error(`step.sleep: invalid duration '${R}'`);let n=a.millis,o=s?.signal;return k(m,async()=>{if(D?.aborted||o?.aborted){let y=new Error("Sleep aborted");throw y.name="AbortError",y}return new Promise((y,x)=>{let b={timeoutId:void 0},O=()=>{b.timeoutId&&clearTimeout(b.timeoutId);let I=new Error("Sleep aborted");I.name="AbortError",x(I)};D?.addEventListener("abort",O,{once:!0}),o?.addEventListener("abort",O,{once:!0}),b.timeoutId=setTimeout(()=>{D?.removeEventListener("abort",O),o?.removeEventListener("abort",O),y(Z(void 0))},n)})},{key:s?.key??m,description:s?.description})},k.all=((...m)=>{if(typeof m[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 R=m[0],s=m[1];if(typeof s=="function")return Ee(R,s);if(s&&typeof s=="object"&&!Array.isArray(s)){let n=le(s);return ke(n,{name:R})}throw new TypeError("step.all(name, ...): second argument must be a function (array form) or an object of operations (object form).")}),k.race=(m,R)=>{let s=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let a=performance.now(),n=!1,o={scopeId:s,type:"race",winnerId:void 0};z.push(o);let y=()=>{if(n)return;n=!0;let x=z.findIndex(b=>b.scopeId===s);x!==-1&&z.splice(x,1),i({type:"scope_end",workflowId:r,scopeId:s,ts:Date.now(),durationMs:performance.now()-a,winnerId:o.winnerId})};i({type:"scope_start",workflowId:r,scopeId:s,scopeType:"race",name:m,ts:Date.now()});try{let x=await R();if(y(),!x.ok)throw p?.(x.error,m,W),ne(x.error,{origin:"result",resultCause:x.cause});return x.value}catch(x){throw y(),x}})()},k.if=(m,R,s)=>s(),k.label=k.if,k.branch=async(m,R)=>{let{condition:s,then:a,else:n}=R;if(s())return await a();if(n)return await n()},k.arm=(m,R)=>({fn:m,errors:R}),k.forEach=async(m,R,s)=>{let a=[],n=s.maxIterations,o=0,y="run"in s,x=Symbol.asyncIterator in R?R:(async function*(){yield*R})();for await(let b of x){if(n!==void 0&&o>=n)break;let O;y?O=await s.run(b,o):O=await s.item.handler(b,o,k),a.push(O),o++}return a},k.item=m=>({__forEachItemHandler:!0,handler:m}),k.dep=(m,R)=>R,k.workflow=(m,R,s)=>k(m,R,s),k.map=async(m,R,s,a)=>{let n=a?.concurrency??R.length;return k(m,()=>n>=R.length?dt(R.map((o,y)=>s(o,y))):(async()=>{let o=[];for(let y=0;y<R.length;y+=n){let x=R.slice(y,y+n),b=await dt(x.map((O,I)=>s(O,y+I)));if(!b.ok)return b;o.push(...b.value)}return Z(o)})(),{key:a?.key})},k.withFallback=(m,R,s)=>{if(typeof m!="string"||m.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 a=s.key??m,n=m,o=se(a),y=A;return(async()=>{let x=y?performance.now():0;A&&i({type:"step_start",workflowId:r,stepId:o,stepKey:a,name:n,ts:Date.now()});let b;try{b=await R()}catch(N){if(me(N))throw i({type:"step_aborted",workflowId:r,stepId:o,stepKey:a,name:n,ts:Date.now(),durationMs:performance.now()-x}),N;let H;try{H=J(N)}catch($){throw Pe($)}if(s.on!==void 0&&s.on!==H){let $=performance.now()-x;throw i({type:"step_error",workflowId:r,stepId:o,stepKey:a,name:n,ts:Date.now(),durationMs:$,error:H}),a&&i({type:"step_complete",workflowId:r,stepKey:a,name:n,ts:Date.now(),durationMs:$,result:j(H,{cause:N}),meta:{origin:"throw",thrown:N}}),p?.(H,n,W),ne(H,{origin:"throw",thrown:N})}let K;try{K=await s.fallback()}catch($){if(me($))throw i({type:"step_aborted",workflowId:r,stepId:o,stepKey:a,name:n,ts:Date.now(),durationMs:performance.now()-x}),$;let h;try{h=J($)}catch(l){throw Pe(l)}let fe=performance.now()-x;throw i({type:"step_error",workflowId:r,stepId:o,stepKey:a,name:n,ts:Date.now(),durationMs:fe,error:h}),a&&i({type:"step_complete",workflowId:r,stepKey:a,name:n,ts:Date.now(),durationMs:fe,result:j(h,{cause:$}),meta:{origin:"throw",thrown:$}}),p?.(h,n,W),ne(h,{origin:"throw",thrown:$})}if(K.ok){let $=performance.now()-x;return i({type:"step_success",workflowId:r,stepId:o,stepKey:a,name:n,ts:Date.now(),durationMs:$}),a&&i({type:"step_complete",workflowId:r,stepKey:a,name:n,ts:Date.now(),durationMs:$,result:K,meta:{origin:"fallback",fallbackUsed:!0,fallbackReason:String(H)}}),K.value}else{let $=performance.now()-x,h=pe(K.error,{origin:"result",resultCause:K.cause});throw i({type:"step_error",workflowId:r,stepId:o,stepKey:a,name:n,ts:Date.now(),durationMs:$,error:h}),a&&i({type:"step_complete",workflowId:r,stepKey:a,name:n,ts:Date.now(),durationMs:$,result:K,meta:{origin:"result",resultCause:K.cause}}),p?.(h,n,W),ne(h,{origin:"result",resultCause:K.cause})}}if(b.ok){let N=performance.now()-x;return i({type:"step_success",workflowId:r,stepId:o,stepKey:a,name:n,ts:Date.now(),durationMs:N}),a&&i({type:"step_complete",workflowId:r,stepKey:a,name:n,ts:Date.now(),durationMs:N,result:b}),b.value}let O=b.error;if(s.on!==void 0&&s.on!==O){let N=performance.now()-x,H=pe(O,{origin:"result",resultCause:b.cause});throw i({type:"step_error",workflowId:r,stepId:o,stepKey:a,name:n,ts:Date.now(),durationMs:N,error:H}),a&&i({type:"step_complete",workflowId:r,stepKey:a,name:n,ts:Date.now(),durationMs:N,result:b,meta:{origin:"result",resultCause:b.cause}}),p?.(H,n,W),ne(H,{origin:"result",resultCause:b.cause})}let I;try{I=await s.fallback()}catch(N){if(me(N))throw i({type:"step_aborted",workflowId:r,stepId:o,stepKey:a,name:n,ts:Date.now(),durationMs:performance.now()-x}),N;let H;try{H=J(N)}catch($){throw Pe($)}let K=performance.now()-x;throw i({type:"step_error",workflowId:r,stepId:o,stepKey:a,name:n,ts:Date.now(),durationMs:K,error:H}),a&&i({type:"step_complete",workflowId:r,stepKey:a,name:n,ts:Date.now(),durationMs:K,result:j(H,{cause:N}),meta:{origin:"throw",thrown:N}}),p?.(H,n,W),ne(H,{origin:"throw",thrown:N})}if(I.ok){let N=performance.now()-x;return i({type:"step_success",workflowId:r,stepId:o,stepKey:a,name:n,ts:Date.now(),durationMs:N}),a&&i({type:"step_complete",workflowId:r,stepKey:a,name:n,ts:Date.now(),durationMs:N,result:I,meta:{origin:"fallback",fallbackUsed:!0,fallbackReason:String(O)}}),I.value}let B=performance.now()-x,ee=pe(I.error,{origin:"result",resultCause:I.cause});throw i({type:"step_error",workflowId:r,stepId:o,stepKey:a,name:n,ts:Date.now(),durationMs:B,error:ee}),a&&i({type:"step_complete",workflowId:r,stepKey:a,name:n,ts:Date.now(),durationMs:B,result:I,meta:{origin:"result",resultCause:I.cause}}),p?.(ee,n,W),ne(ee,{origin:"result",resultCause:I.cause})})()},k.withResource=(m,R)=>{if(typeof m!="string"||m.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 s=m,a=m,n=se(s),o=A;return(async()=>{let y=o?performance.now():0;A&&i({type:"step_start",workflowId:r,stepId:n,stepKey:s,name:a,ts:Date.now()});let x;try{x=await R.acquire()}catch(K){if(me(K))throw i({type:"step_aborted",workflowId:r,stepId:n,stepKey:s,name:a,ts:Date.now(),durationMs:performance.now()-y}),K;let $;try{$=J(K)}catch(fe){throw Pe(fe)}let h=performance.now()-y;throw i({type:"step_error",workflowId:r,stepId:n,stepKey:s,name:a,ts:Date.now(),durationMs:h,error:$}),s&&i({type:"step_complete",workflowId:r,stepKey:s,name:a,ts:Date.now(),durationMs:h,result:j($,{cause:K}),meta:{origin:"throw",thrown:K}}),p?.($,a,W),ne($,{origin:"throw",thrown:K})}if(!x.ok){let K=performance.now()-y,$=pe(x.error,{origin:"result",resultCause:x.cause});throw i({type:"step_error",workflowId:r,stepId:n,stepKey:s,name:a,ts:Date.now(),durationMs:K,error:$}),s&&i({type:"step_complete",workflowId:r,stepKey:s,name:a,ts:Date.now(),durationMs:K,result:x,meta:{origin:"result",resultCause:x.cause}}),p?.($,a,W),ne($,{origin:"result",resultCause:x.cause})}let b=x.value,O,I,B=!1;try{O=await R.use(b)}catch(K){if(me(K)){try{await R.release(b)}catch($){console.warn(`[awaitly] step.withResource("${m}"): release threw after earlyExit:`,$)}throw K}I=K,B=!0}try{await R.release(b)}catch(K){console.warn(`[awaitly] step.withResource("${m}"): release threw:`,K)}if(B){let K;try{K=J(I)}catch(h){throw Pe(h)}let $=performance.now()-y;throw i({type:"step_error",workflowId:r,stepId:n,stepKey:s,name:a,ts:Date.now(),durationMs:$,error:K}),s&&i({type:"step_complete",workflowId:r,stepKey:s,name:a,ts:Date.now(),durationMs:$,result:j(K,{cause:I}),meta:{origin:"throw",thrown:I}}),p?.(K,a,W),ne(K,{origin:"throw",thrown:I})}let ee=O;if(ee.ok){let K=performance.now()-y;return i({type:"step_success",workflowId:r,stepId:n,stepKey:s,name:a,ts:Date.now(),durationMs:K}),s&&i({type:"step_complete",workflowId:r,stepKey:s,name:a,ts:Date.now(),durationMs:K,result:ee}),ee.value}let N=performance.now()-y,H=pe(ee.error,{origin:"result",resultCause:ee.cause});throw i({type:"step_error",workflowId:r,stepId:n,stepKey:s,name:a,ts:Date.now(),durationMs:N,error:H}),s&&i({type:"step_complete",workflowId:r,stepKey:s,name:a,ts:Date.now(),durationMs:N,result:ee,meta:{origin:"result",resultCause:ee.cause}}),p?.(H,a,W),ne(H,{origin:"result",resultCause:ee.cause})})()};let L=await _({step:k});if(process.env.NODE_ENV!=="production"&&L!==null&&typeof L=="object"&&"ok"in L&&typeof L.ok=="boolean"){let m=L;(m.ok===!0&&"value"in m||m.ok===!1&&"error"in m)&&console.warn(`awaitly: Workflow executor returned a Result-like object. Return raw values, not ok() or err().
2
-
3
- Incorrect: return ok({ data });
4
- Correct: return { data };
5
-
6
- See: https://jagreehal.github.io/awaitly/guides/troubleshooting/#returning-ok-from-workflow-executor-double-wrapping`)}return Z(L)}catch(k){if(Pt(k))throw k.thrown;if(me(k)){let Ee=k.meta.origin==="throw"?k.meta.thrown:k.meta.origin==="result"?k.meta.resultCause:void 0;return j(k.error,{cause:Ee})}let le=J(k);return p?.(le,"unexpected",W),j(le,{cause:k})}}Ne.strict=(e,t)=>Ne(e,t);async function dt(e){return e.length===0?Z([]):new Promise(t=>{let c=!1,_=e.length,w=new Array(e.length);for(let p=0;p<e.length;p++){let A=p;Promise.resolve(e[A]).catch(F=>j({type:"PROMISE_REJECTED",cause:F},{cause:{type:"PROMISE_REJECTION",reason:F}})).then(F=>{if(!c){if(!F.ok){c=!0,t(F);return}w[A]=F.value,_--,_===0&&t(Z(w))}})}})}var Dt="STREAM_WRITE_ERROR",Mt="STREAM_READ_ERROR",It="STREAM_CLOSE_ERROR";var Ut="STREAM_ENDED";function Be(e,t,c){return{type:Dt,reason:e,message:t,...c!==void 0?{cause:c}:{}}}function ze(e,t,c){return{type:Mt,reason:e,message:t,...c!==void 0?{cause:c}:{}}}function Je(e,t,c){return{type:It,reason:e,message:t,...c!==void 0?{cause:c}:{}}}function Ve(e){return{type:Ut,finalPosition:e}}function wt(e={}){let t=e.highWaterMark??16,c=e.lowWaterMark??Math.floor(t/2),_=e.onStateChange,w="flowing",p=0,A=[];function F(v){if(w!==v&&(w=v,_?.(v),v==="flowing"&&A.length>0)){let W=A;A=[];for(let D of W)D()}}function Y(){w==="flowing"&&p>=t?F("paused"):w==="paused"&&p<=c&&F("flowing")}return{get state(){return w},get bufferedCount(){return p},get highWaterMark(){return t},get lowWaterMark(){return c},increment(){p++,Y()},decrement(){p>0&&(p--,Y())},setCount(v){p=Math.max(0,v),Y()},waitForDrain(){return w==="flowing"?Promise.resolve():new Promise(v=>{A.push(v)})},reset(){p=0,A=[],F("flowing")}}}function Wt(e){return{_tag:"Duration",millis:e}}function Nt(e){return{_tag:"Duration",millis:e*1e3}}function Kt(e){return{_tag:"Duration",millis:e*60*1e3}}function jt(e){return{_tag:"Duration",millis:e*60*60*1e3}}function Ft(e){return{_tag:"Duration",millis:e*24*60*60*1e3}}function yt(e){return e.millis}function kt(e){let t=e.trim().match(/^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)$/i);if(!t)return;let c=parseFloat(t[1]);switch(t[2].toLowerCase()){case"ms":return Wt(c);case"s":return Nt(c);case"m":return Kt(c);case"h":return jt(c);case"d":return Ft(c);default:return}}function gt(e){return e.type==="step_complete"}function Ye(e){return typeof e=="object"&&e!==null&&e.type==="WORKFLOW_CANCELLED"}function Tt(){let e=new Map;return{handleEvent:t=>{gt(t)&&e.set(t.stepKey,{result:t.result,meta:t.meta})},getResumeState:()=>({steps:new Map(e)}),clear:()=>e.clear()}}function Bt(e){return typeof e=="object"&&e!==null&&e.__cachedMeta===!0}function Se(e,t,c){return j(e,{cause:{__cachedMeta:!0,originalCause:c,meta:t}})}function Ke(e){return Bt(e)?e.meta:{origin:"result",resultCause:e}}async function Rt(e,t){let c=e["~standard"].validate(t),_=c instanceof Promise?await c:c;return _.issues?j({type:"INPUT_VALIDATION_ERROR",issues:_.issues.map(w=>({message:w.message,path:w.path?.map(p=>typeof p=="object"?p.key:p)})),message:`Input validation failed: ${_.issues.map(w=>w.message).join(", ")}`}):Z(_.value)}function Ge(e,t){let c=_=>((...w)=>{let p=w.at(-1),A=w.length>0&&typeof p=="object"&&p!==null&&!Array.isArray(p)&&typeof p!="function",F=A?p:void 0,Y=A?w.slice(0,-1):w,v={...t,...F?.deps??{}},W=F?{...F,deps:v}:{deps:v};return e[_](...Y,W)});return{run:c("run"),runWithState:c("runWithState"),withDeps(_){return Ge(e,{...t,..._})}}}var Le=class extends Error{constructor(c,_,w){super(c);this.stepId=_;this.originalError=w;this.name="SnapshotDecodeError"}stepId;originalError};function Xe(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=Xe(e.cause)),t}return e.value!==void 0?e.value:e.stringRepresentation}function xt(e,t,c){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 _=t??{},w=c;async function p(v,W,D){let r=v??crypto.randomUUID(),J=D?.deps?{..._,...D.deps}:_,z=[],ce=D?.createContext??w?.createContext,se=ce?await ce():void 0,i=D?.signal??w?.signal,ne=D?.onEvent??w?.onEvent,me=D?.onError??w?.onError,pe=D?.shouldRun??w?.shouldRun,ye=D?.onBeforeStart??w?.onBeforeStart,be=D?.onAfterStep??w?.onAfterStep,Ae=D?.resumeState??w?.resumeState,xe=w?.catchUnexpected??Fe,k={},le=(D?.devWarnings??w?.devWarnings)===!0&&process.env.NODE_ENV!=="production",Ee=new Set,ke=new Set,he={workflowId:r,onEvent:ne,context:se!==void 0?se:void 0,signal:i,input:{},ref:l=>k[l],set:(l,d)=>{le&&!Ee.has(l)&&(Ee.add(l),console.warn(`awaitly: ctx.set('${l}', ...) is deprecated for static analysis. Use step('id', fn, { out: '${l}' }) instead.`)),k[l]=d},get:l=>(le&&!ke.has(l)&&(ke.add(l),console.warn(`awaitly: ctx.get('${l}') is deprecated for static analysis. Use ctx.ref('${l}') instead for tracked dependencies.`)),k[l])},L=l=>{let d=l.context!==void 0||se===void 0?l:{...l,context:se},q=d.workflowName===void 0?{...d,workflowName:e}:d;ne?.(q,se)},m=(l,d)=>{let q={type:"WORKFLOW_CANCELLED",reason:l,lastStepKey:d};return j(xe(q),{cause:q})};if(i?.aborted){let l=typeof i.reason=="string"?i.reason:i.reason instanceof Error?i.reason.message:void 0;return L({type:"workflow_cancelled",workflowId:r,ts:Date.now(),durationMs:0,reason:l}),m(l)}if(pe){let l=performance.now();try{let d=await pe(r,se),q=performance.now()-l;if(L({type:"hook_should_run",workflowId:r,ts:Date.now(),durationMs:q,result:d,skipped:!d}),!d){let T=new Error("Workflow skipped by shouldRun hook");return j(xe(T),{cause:T})}}catch(d){let q=performance.now()-l;return L({type:"hook_should_run_error",workflowId:r,ts:Date.now(),durationMs:q,error:d}),j(xe(d),{cause:d})}}if(ye){let l=performance.now();try{let d=await ye(r,se),q=performance.now()-l;if(L({type:"hook_before_start",workflowId:r,ts:Date.now(),durationMs:q,result:d,skipped:!d}),!d){let T=new Error("Workflow skipped by onBeforeStart hook");return j(xe(T),{cause:T})}}catch(d){let q=performance.now()-l;return L({type:"hook_before_start_error",workflowId:r,ts:Date.now(),durationMs:q,error:d}),j(xe(d),{cause:d})}}let R=w?.inputSchema,s=w?.input;if(R){let l=await Rt(R,s);if(!l.ok)return j(l.error);he.input=l.value}else s!==void 0&&(he.input=s);let a=Date.now(),n=performance.now();L({type:"workflow_start",workflowId:r,ts:a});let o=D?.cache??w?.cache,y=D?.streamStore??w?.streamStore;if(Ae&&!o&&(o=new Map),Ae&&o){let l=typeof Ae=="function"?await Ae():Ae;l.steps instanceof Map||(console.warn(`awaitly: resumeState.steps is not a Map (got ${typeof l.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 l.steps=="object"&&l.steps!==null&&(l.steps=new Map(Object.entries(l.steps))));for(let[d,q]of l.steps){let{result:T,meta:f}=q;if(T.ok)o.set(d,T);else{let u=f??{origin:"result",resultCause:T.cause};o.set(d,Se(T.error,u,T.cause))}}}let x=D?.snapshot??w?.snapshot,b=w?.serialization;if(x&&!Ae){o||(o=new Map);let l=x,d=b?.decode;for(let[q,T]of Object.entries(l.steps))if(Object.prototype.hasOwnProperty.call(l.steps,q))try{if(T.ok){let f=d?d(T.value):T.value;o.set(q,Z(f))}else{let f=d?d(T.error):T.error,u=Xe(T.cause),g=T.meta?.origin==="throw"?{origin:"throw",thrown:u}:{origin:"result",resultCause:u};o.set(q,Se(f,g,u))}}catch(f){throw new Le(`Failed to decode step "${q}": ${f instanceof Error?f.message:String(f)}`,q,f instanceof Error?f:void 0)}}let O=!1,I,B,ee=()=>{O=!0,I=typeof i?.reason=="string"?i.reason:i?.reason instanceof Error?i.reason.message:void 0};i&&!i.aborted&&i.addEventListener("abort",ee,{once:!0});let N=()=>{if(O||i?.aborted)throw{type:"WORKFLOW_CANCELLED",reason:I??(typeof i?.reason=="string"?i.reason:i?.reason instanceof Error?i.reason.message:void 0),lastStepKey:B}},H=async(l,d,q)=>{if(!be)return;let T=performance.now();try{await be(l,d,r,se);let f=performance.now()-T;L({type:"hook_after_step",workflowId:r,stepKey:l,ts:Date.now(),durationMs:f})}catch(f){let u=performance.now()-T;throw L({type:"hook_after_step_error",workflowId:r,stepKey:l,ts:Date.now(),durationMs:u,error:f}),f}},K=l=>{let d=async(f,u,g)=>{if(typeof f!="string")throw new Error('[awaitly] step() requires a string ID as the first argument. Example: step("fetchUser", () => fetchUser(id))');let S=f,C=g??{},P=S,E=Object.prototype.hasOwnProperty.call(C,"key")?C.key:S,{ttl:U,out:G}=C;N();let Q=qe(C);if(E&&o&&o.has(E)){L({type:"step_cache_hit",workflowId:r,stepKey:E,name:P,ts:Date.now(),...Q&&{metadata:Q}});let M=o.get(E);if(M.ok)return B=E,G&&(k[G]=M.value),M.value;let V=Ke(M.cause);throw Re(M.error,V)}E&&o&&L({type:"step_cache_miss",workflowId:r,stepKey:E,name:P,ts:Date.now(),...Q&&{metadata:Q}});try{let M=await l(S,u,C);return G&&(k[G]=M),C.compensate&&z.push({stepName:P,value:M,compensate:C.compensate}),E&&(B=E,o&&o.set(E,Z(M),U?{ttl:U}:void 0),await H(E,Z(M))),M}catch(M){if(E&&ge(M)){let V=M,oe=V.meta.origin==="result"?V.meta.resultCause:V.meta.origin==="throw"?V.meta.thrown:void 0,X=Se(V.error,V.meta,oe);o&&o.set(E,X,U?{ttl:U}:void 0),await H(E,X,V.meta)}throw M}};d.try=async(f,u,g)=>{let{ttl:S}=g,C=g.key??f,P=f;if(o&&o.has(C)){L({type:"step_cache_hit",workflowId:r,stepKey:C,name:P,ts:Date.now()});let E=o.get(C);if(E.ok)return E.value;let U=Ke(E.cause);throw Re(E.error,U)}o&&L({type:"step_cache_miss",workflowId:r,stepKey:C,name:P,ts:Date.now()});try{let E=await l.try(f,u,{...g,key:C});return g.compensate&&z.push({stepName:P,value:E,compensate:g.compensate}),o&&o.set(C,Z(E),S?{ttl:S}:void 0),await H(C,Z(E)),E}catch(E){if(ge(E)){let U=E,G=U.meta.origin==="result"?U.meta.resultCause:U.meta.origin==="throw"?U.meta.thrown:void 0,Q=Se(U.error,U.meta,G);o&&o.set(C,Q,S?{ttl:S}:void 0),await H(C,Q,U.meta)}throw E}},d.fromResult=async(f,u,g)=>{let{ttl:S}=g,C=g.key??f,P=f;if(o&&o.has(C)){L({type:"step_cache_hit",workflowId:r,stepKey:C,name:P,ts:Date.now()});let E=o.get(C);if(E.ok)return E.value;let U=Ke(E.cause);throw Re(E.error,U)}o&&L({type:"step_cache_miss",workflowId:r,stepKey:C,name:P,ts:Date.now()});try{let E=await l.fromResult(f,u,{...g,key:C});return o&&o.set(C,Z(E),S?{ttl:S}:void 0),await H(C,Z(E)),E}catch(E){if(ge(E)){let U=E,G=U.meta.origin==="result"?U.meta.resultCause:U.meta.origin==="throw"?U.meta.thrown:void 0,Q=Se(U.error,U.meta,G);o&&o.set(C,Q,S?{ttl:S}:void 0),await H(C,Q,U.meta)}throw E}},d.race=l.race,d.withFallback=async(f,u,g)=>{let S=g.key??f,C=f;if(o&&o.has(S)){L({type:"step_cache_hit",workflowId:r,stepKey:S,name:C,ts:Date.now()});let P=o.get(S);if(P.ok)return P.value;let E=Ke(P.cause);throw Re(P.error,E)}o&&L({type:"step_cache_miss",workflowId:r,stepKey:S,name:C,ts:Date.now()});try{let P=await l.withFallback(f,u,g);return o&&o.set(S,Z(P)),await H(S,Z(P)),P}catch(P){if(ge(P)){let E=P,U=E.meta.origin==="result"?E.meta.resultCause:E.meta.origin==="throw"?E.meta.thrown:void 0,G=Se(E.error,E.meta,U);o&&o.set(S,G),await H(S,G,E.meta)}throw P}},d.withResource=async(f,u)=>{let g=f;try{let S=await l.withResource(f,u);return await H(g,Z(S)),S}catch(S){if(ge(S)){let C=S,P=C.meta.origin==="result"?C.meta.resultCause:C.meta.origin==="throw"?C.meta.thrown:void 0,E=Se(C.error,C.meta,P);await H(g,E,C.meta)}throw S}},d.retry=(f,u,g)=>{let S={key:g.key,retry:{attempts:g.attempts,backoff:g.backoff,initialDelay:g.initialDelay,maxDelay:g.maxDelay,jitter:g.jitter,shouldRetry:g.shouldRetry,onRetry:g.onRetry},timeout:g.timeout,ttl:g.ttl};return d(f,u,S)},d.withTimeout=(f,u,g)=>{let S={key:g.key,timeout:g,ttl:g.ttl};return d(f,u,S)},d.sleep=(f,u,g)=>{if(typeof f!="string"||f.length===0)throw new Error('[awaitly] step.sleep() requires an explicit string ID as the first argument. Example: step.sleep("delay", "5s")');let S=typeof u=="string"?kt(u):u;if(!S)throw new Error(`step.sleep: invalid duration '${u}'`);let C=yt(S),P=g?.signal;return d(f,async()=>{if(i?.aborted||P?.aborted){let U=new Error("Sleep aborted");throw U.name="AbortError",U}return new Promise((U,G)=>{let Q={timeoutId:void 0},M=()=>{Q.timeoutId&&clearTimeout(Q.timeoutId);let V=new Error("Sleep aborted");V.name="AbortError",G(V)};i?.addEventListener("abort",M,{once:!0}),P?.addEventListener("abort",M,{once:!0}),Q.timeoutId=setTimeout(()=>{i?.removeEventListener("abort",M),P?.removeEventListener("abort",M),U(Z(void 0))},C)})},{key:g?.key,ttl:g?.ttl,description:g?.description})};let q=new Map,T=new Map;return d.getWritable=f=>{let u=f?.namespace??"default",g=f?.highWaterMark??16;if(!y)throw new Error("streamStore is required to use getWritable(). Pass a streamStore to createWorkflow options.");let S=`${r}:${u}`,C=q.get(S);if(C&&!C.closed&&!C.aborted)return C.writer;let P=wt({highWaterMark:g,onStateChange:V=>{L({type:"stream_backpressure",workflowId:r,namespace:u,bufferedCount:P.bufferedCount,state:V,ts:Date.now()})}}),E=0,U=!0,G=!1,Q=!1;L({type:"stream_created",workflowId:r,namespace:u,ts:Date.now()});let M={async write(V){if(Q)return j(Be("closed","Stream is closed"));if(G)return j(Be("aborted","Stream was aborted"));P.state==="paused"&&await P.waitForDrain();let oe={value:V,position:E,ts:Date.now()},X=await y.append(r,u,oe);return X.ok?(L({type:"stream_write",workflowId:r,namespace:u,position:E,ts:Date.now()}),E++,P.increment(),Z(void 0)):(L({type:"stream_error",workflowId:r,namespace:u,error:X.error,position:E,ts:Date.now()}),j(Be("store_error",X.error.message,X.error)))},async close(){if(Q)return j(Je("already_closed","Stream is already closed"));let V=await y.closeStream(r,u);return V.ok?(Q=!0,U=!1,L({type:"stream_close",workflowId:r,namespace:u,finalPosition:E,ts:Date.now()}),q.delete(S),Z(void 0)):j(Je("store_error",V.error.message,V.error))},abort(V){G=!0,U=!1,Q=!0,L({type:"stream_error",workflowId:r,namespace:u,error:V,position:E,ts:Date.now()}),q.delete(S)},get writable(){return U},get position(){return E},get namespace(){return u}};return q.set(S,{writer:M,backpressure:P,aborted:G,closed:Q}),M},d.getReadable=f=>{let u=f?.namespace??"default",g=f?.startIndex??0,S=f?.pollInterval??10,C=f?.pollTimeout??3e4;if(!y)throw new Error("streamStore is required to use getReadable(). Pass a streamStore to createWorkflow options.");let P=`${r}:${u}:${g}`,E=T.get(P);if(E&&!E.closed)return E.reader;let U=()=>{let Te=`${r}:${u}`,re=q.get(Te);re&&re.backpressure.decrement()},G=g,Q=!0,M=!1,V=[],oe=0,X={async read(){if(M)return j(ze("closed","Reader is closed"));if(oe<V.length){let ue=V[oe++];return G=ue.position+1,U(),L({type:"stream_read",workflowId:r,namespace:u,position:ue.position,ts:Date.now()}),Z(ue.value)}let Te=`${r}:${u}`,re=Date.now(),ie=q.has(Te),te=await y.getMetadata(r,u),ae=te.ok&&te.value!==void 0;for(;Date.now()-re<C;){let ue=await y.read(r,u,G,100);if(!ue.ok)return j(ze("store_error",ue.error.message,ue.error));let De=ue.value;if(De.length>0){V=De,oe=1;let Ie=De[0];return G=Ie.position+1,U(),L({type:"stream_read",workflowId:r,namespace:u,position:Ie.position,ts:Date.now()}),Z(Ie.value)}let Me=q.has(Te),Ce=await y.getMetadata(r,u),Ze=Ce.ok&&Ce.value!==void 0;if(Me&&(ie=!0),Ze&&(ae=!0),Ce.ok&&Ce.value?.closed)return Q=!1,j(Ve(G));if(ie&&!Me&&!Ze)return Q=!1,j(Ve(G));ae&&!Me&&Ce.ok&&Ce.value?.closed,await new Promise(Ie=>setTimeout(Ie,S))}return Q=!1,j(Ve(G))},close(){M=!0,Q=!1,V=[],T.delete(P)},get readable(){return Q},get position(){return G},get namespace(){return u}};return T.set(P,{reader:X,position:G,closed:M}),X},d.streamForEach=async(f,u,g)=>{let S=g?.checkpointInterval??1,C=g?.concurrency??1,P=[],E=0,U=-1,G=M=>typeof M=="object"&&M!==null&&"read"in M&&typeof M.read=="function",Q=async(M,V,oe,X)=>{let re=S>0&&V%S===0?`stream-foreach:${X}:pos-${oe}`:void 0,ie=re??`stream-item-${oe}`,te=await d(ie,()=>u(M,V),{key:re});return{index:V,position:oe,result:te}};if(G(f))if(C<=1){let M=f.position,V=await f.read();for(;V.ok;){let oe=V.value,{result:X}=await Q(oe,E,M,f.namespace);P.push(X),U=M,E++,M=f.position,V=await f.read()}}else{let M=new Map,V=0,oe=0,X=new Array(C).fill(null),Te=async()=>{for(let ue=0;ue<X.length;ue++)if(X[ue]===null)return ue;let te=X.filter(ue=>ue!==null),ae=await Promise.race(te);return M.set(ae.index,{position:ae.position,result:ae.result}),X[ae.slotIndex]=null,ae.slotIndex},re=f.position,ie=await f.read();for(;ie.ok;){let te=await Te(),ae=V,ue=re,De=ie.value,Me=te;X[te]=Q(De,ae,ue,f.namespace).then(Ce=>({slotIndex:Me,...Ce})),oe++,V++,re=f.position,ie=await f.read()}for(let te=0;te<X.length;te++)if(X[te]!==null){let ae=await X[te];M.set(ae.index,{position:ae.position,result:ae.result})}for(let te=0;te<oe;te++){let ae=M.get(te);ae&&(P.push(ae.result),U=ae.position,E++)}}else if(C<=1){let M=0;for await(let V of f){let{result:oe}=await Q(V,M,M,"async-iterable");P.push(oe),U=M,E++,M++}}else{let M=new Map,V=0,oe=0,X=new Array(C).fill(null),Te=async()=>{for(let te=0;te<X.length;te++)if(X[te]===null)return te;let re=X.filter(te=>te!==null),ie=await Promise.race(re);return M.set(ie.index,ie.result),X[ie.slotIndex]=null,ie.slotIndex};for await(let re of f){let ie=await Te(),te=V,ae=ie;X[ie]=Q(re,te,te,"async-iterable").then(ue=>({slotIndex:ae,...ue})),oe++,V++}for(let re=0;re<X.length;re++)if(X[re]!==null){let ie=await X[re];M.set(ie.index,ie.result)}for(let re=0;re<oe;re++)M.has(re)&&(P.push(M.get(re)),U=re,E++)}return{results:P,processedCount:E,lastPosition:U}},d.if=l.if,d.label=l.label,d.branch=l.branch,d.arm=l.arm,d.forEach=l.forEach,d.item=l.item,d.dep=l.dep,d.workflow=(f,u,g)=>d(f,u,g),d.all=(f,u,g)=>{let S=g!==void 0&&Object.prototype.hasOwnProperty.call(g,"key")?g:{...g,key:void 0};return d(f,async()=>Z(await l.all(f,u)),S)},d.map=(f,u,g,S)=>{let C=S!==void 0&&Object.prototype.hasOwnProperty.call(S,"key")?S:{...S,key:void 0};return d(f,async()=>Z(await l.map(f,u,g,S)),C)},d},$=({step:l})=>{let d=K(l);return W({step:d,steps:We(J??{},d),deps:J,ctx:he})},h;try{h=await Ne($,{onError:me,onEvent:ne,catchUnexpected:xe,workflowId:r,workflowName:e,context:se,_workflowSignal:i})}finally{i&&i.removeEventListener("abort",ee)}if(!h.ok&&z.length>0){let l=[];for(let d=z.length-1;d>=0;d--){let q=z[d];try{await q.compensate(q.value)}catch(T){l.push({stepName:q.stepName,error:T})}}if(l.length>0){let d={type:"SAGA_COMPENSATION_ERROR",originalError:h.error,compensationErrors:l};h=j(d,{cause:h.cause})}}let fe=performance.now()-n;if(!h.ok){let l;if(Ye(h.cause)&&(l=h.cause),!l&&O&&mt(h.error)){let d=h.cause;d!=null&&typeof d=="object"&&"name"in d&&d.name==="AbortError"&&(l={type:"WORKFLOW_CANCELLED",reason:I??(typeof i?.reason=="string"?i.reason:i?.reason instanceof Error?i.reason.message:void 0),lastStepKey:B})}if(l)return L({type:"workflow_cancelled",workflowId:r,ts:Date.now(),durationMs:fe,reason:l.reason,lastStepKey:l.lastStepKey}),l&&!Ye(h.cause)?j(h.error,{cause:l}):h}if(h.ok&&O){let l=I??(typeof i?.reason=="string"?i.reason:i?.reason instanceof Error?i.reason.message:void 0);L({type:"workflow_cancelled",workflowId:r,ts:Date.now(),durationMs:fe,reason:l,lastStepKey:B});let d={type:"WORKFLOW_CANCELLED",reason:l,lastStepKey:B};return j(xe(d),{cause:d})}return h.ok?L({type:"workflow_success",workflowId:r,ts:Date.now(),durationMs:fe}):L({type:"workflow_error",workflowId:r,ts:Date.now(),durationMs:fe,error:h.error}),h}function A(v,W,D){let r,J,z;return typeof v=="string"?(r=v,J=W,z=D):(J=v,z=W),p(r,J,z)}async function F(v,W,D){let r,J,z;typeof v=="string"?(r=v,J=W,z=D):(J=v,z=W);let ce=Tt(),se=z?.onEvent,ne={...z,onEvent:(ye,be)=>{ce.handleEvent(ye);try{se?.(ye,be)}catch{}}},me,pe;try{me=await p(r,J,ne)}catch(ye){let be=w?.catchUnexpected??Fe;me=j(be(ye),{cause:ye})}finally{pe=ce.getResumeState()}return{result:me,resumeState:pe}}let Y={withDeps:v=>Ge(Y,v),run:A,runWithState:F};return Y}function Vt(e){return typeof e=="object"&&e!==null&&e.type==="SAGA_COMPENSATION_ERROR"}function Lt(e,t,c){return xt(e,t,c)}async function $t(e,t){let c=crypto.randomUUID(),_=performance.now(),w=[],p=v=>t?.onEvent?.(v);p({type:"saga_start",sagaId:c,ts:Date.now()});let Y=Object.assign(async(v,W,D)=>{if(typeof v!="string"||v.length===0)throw new TypeError("step(name, operation, options?): first argument must be a string.");let r=await W();if(r.ok)return D?.compensate&&w.push({name:v,value:r.value,compensate:D.compensate}),r.value;throw Re(r.error,{origin:"result",resultCause:r.cause})},{try:async(v,W,D)=>{if(typeof v!="string"||v.length===0)throw new TypeError("step.try(name, operation, options): first argument must be a string.");let r="error"in D?()=>D.error:D.onError;try{let J=await W();return D.compensate&&w.push({name:v,value:J,compensate:D.compensate}),J}catch(J){let z=r(J);throw Re(z,{origin:"throw",thrown:J})}}});try{let v=await e({step:Y});return p({type:"saga_success",sagaId:c,ts:Date.now(),durationMs:performance.now()-_}),Z(v)}catch(v){let W=performance.now()-_,D=ge(v)?v.error:v;p({type:"saga_error",sagaId:c,ts:Date.now(),durationMs:W,error:D}),p({type:"saga_compensation_start",sagaId:c,ts:Date.now(),stepCount:w.length});let r=performance.now(),J=[];for(let z=w.length-1;z>=0;z--){let ce=w[z];try{await ce.compensate(ce.value),p({type:"saga_compensation_step",sagaId:c,stepName:ce.name,ts:Date.now(),success:!0})}catch(se){J.push({stepName:ce.name,error:se}),p({type:"saga_compensation_step",sagaId:c,stepName:ce.name,ts:Date.now(),success:!1,error:se})}}if(p({type:"saga_compensation_end",sagaId:c,ts:Date.now(),durationMs:performance.now()-r,success:J.length===0,failedCount:J.length}),J.length>0){let z={type:"SAGA_COMPENSATION_ERROR",originalError:D,compensationErrors:J};if(t?.onError?.(z),t?.throwOnCompensationFailure)throw z;return j(z)}return t?.onError?.(D),ge(v)?j(D):j(new ve({cause:v}))}}export{Lt as createSagaWorkflow,Vt as isSagaCompensationError,$t as runSaga};
11
- //# sourceMappingURL=saga.js.map