awaitly 2.0.0 → 3.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 (88) hide show
  1. package/dist/di-Biw_plBn.d.cts +15 -0
  2. package/dist/di-DxyH2N3i.d.ts +15 -0
  3. package/dist/durable.cjs +4670 -0
  4. package/dist/durable.cjs.map +1 -0
  5. package/dist/durable.d.cts +9 -0
  6. package/dist/durable.d.ts +9 -0
  7. package/dist/durable.js +4610 -0
  8. package/dist/durable.js.map +1 -0
  9. package/dist/{di-BbFFfO8y.d.ts → duration-BjVn3QpB.d.cts} +1 -15
  10. package/dist/{di-BDlT7InM.d.cts → duration-BjVn3QpB.d.ts} +1 -15
  11. package/dist/engine.cjs +4501 -0
  12. package/dist/engine.cjs.map +1 -0
  13. package/dist/engine.d.cts +113 -0
  14. package/dist/engine.d.ts +113 -0
  15. package/dist/engine.js +4474 -0
  16. package/dist/engine.js.map +1 -0
  17. package/dist/{errors-DtXvrCiO.d.cts → errors-sDSeaZBO.d.cts} +1 -1
  18. package/dist/{errors-DtXvrCiO.d.ts → errors-sDSeaZBO.d.ts} +1 -1
  19. package/dist/guards-CwQZro1F.d.ts +72 -0
  20. package/dist/guards-DhhOJZda.d.cts +72 -0
  21. package/dist/hitl-BnnnLzh2.d.cts +468 -0
  22. package/dist/hitl-pYfkQMv_.d.ts +468 -0
  23. package/dist/hitl.cjs +646 -0
  24. package/dist/hitl.cjs.map +1 -0
  25. package/dist/hitl.d.cts +440 -0
  26. package/dist/hitl.d.ts +440 -0
  27. package/dist/hitl.js +605 -0
  28. package/dist/hitl.js.map +1 -0
  29. package/dist/index-Bew12SZ8.d.ts +417 -0
  30. package/dist/index-Bwt-iz50.d.cts +417 -0
  31. package/dist/{types-B8NfNRGX.d.ts → index-Cv4K_3sZ.d.ts} +2 -1162
  32. package/dist/{types-BZ2f4MRR.d.cts → index-ICmfQi08.d.cts} +2 -1162
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +11 -1527
  35. package/dist/index.d.ts +11 -1527
  36. package/dist/persistence.cjs +552 -0
  37. package/dist/persistence.cjs.map +1 -0
  38. package/dist/persistence.d.cts +254 -0
  39. package/dist/persistence.d.ts +254 -0
  40. package/dist/persistence.js +499 -0
  41. package/dist/persistence.js.map +1 -0
  42. package/dist/reliability.cjs +1651 -0
  43. package/dist/reliability.cjs.map +1 -0
  44. package/dist/reliability.d.cts +1442 -0
  45. package/dist/reliability.d.ts +1442 -0
  46. package/dist/reliability.js +1589 -0
  47. package/dist/reliability.js.map +1 -0
  48. package/dist/result.d.cts +1 -1
  49. package/dist/result.d.ts +1 -1
  50. package/dist/run.cjs +2283 -0
  51. package/dist/run.cjs.map +1 -0
  52. package/dist/run.d.cts +90 -0
  53. package/dist/run.d.ts +90 -0
  54. package/dist/run.js +2247 -0
  55. package/dist/run.js.map +1 -0
  56. package/dist/saga.cjs +3699 -0
  57. package/dist/saga.cjs.map +1 -0
  58. package/dist/saga.d.cts +162 -0
  59. package/dist/saga.d.ts +162 -0
  60. package/dist/saga.js +3670 -0
  61. package/dist/saga.js.map +1 -0
  62. package/dist/store-contract-BI98VYmX.d.ts +66 -0
  63. package/dist/store-contract-C2HyR_o6.d.cts +66 -0
  64. package/dist/streaming.cjs +895 -0
  65. package/dist/streaming.cjs.map +1 -0
  66. package/dist/streaming.d.cts +594 -0
  67. package/dist/streaming.d.ts +594 -0
  68. package/dist/streaming.js +832 -0
  69. package/dist/streaming.js.map +1 -0
  70. package/dist/testing.d.cts +4 -2
  71. package/dist/testing.d.ts +4 -2
  72. package/dist/types-BDTxgKKc.d.ts +845 -0
  73. package/dist/types-C9Y71dua.d.cts +845 -0
  74. package/dist/types-d8q8iQlk.d.cts +323 -0
  75. package/dist/types-sObbY4mX.d.ts +323 -0
  76. package/dist/webhook.cjs +461 -0
  77. package/dist/webhook.cjs.map +1 -0
  78. package/dist/webhook.d.cts +497 -0
  79. package/dist/webhook.d.ts +497 -0
  80. package/dist/webhook.js +422 -0
  81. package/dist/webhook.js.map +1 -0
  82. package/dist/workflow.cjs +2 -2614
  83. package/dist/workflow.cjs.map +1 -1
  84. package/dist/workflow.d.cts +12 -3023
  85. package/dist/workflow.d.ts +12 -3023
  86. package/dist/workflow.js +2 -2535
  87. package/dist/workflow.js.map +1 -1
  88. package/package.json +46 -1
package/dist/run.cjs ADDED
@@ -0,0 +1,2283 @@
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/run-entry.ts
21
+ var run_entry_exports = {};
22
+ __export(run_entry_exports, {
23
+ EARLY_EXIT_SYMBOL: () => EARLY_EXIT_SYMBOL,
24
+ STEP_TIMEOUT_MARKER: () => STEP_TIMEOUT_MARKER,
25
+ createEarlyExit: () => createEarlyExit,
26
+ fallback: () => fallback,
27
+ getStepTimeoutMeta: () => getStepTimeoutMeta,
28
+ isEarlyExit: () => isEarlyExit,
29
+ isStepTimeoutError: () => isStepTimeoutError,
30
+ retry: () => retry,
31
+ run: () => run,
32
+ timeout: () => timeout
33
+ });
34
+ module.exports = __toCommonJS(run_entry_exports);
35
+
36
+ // src/slugs.ts
37
+ var AWAITLY_SLUGS = {
38
+ // --- step-* ---
39
+ "step-require-id": "step-require-id",
40
+ "step-no-immediate-execution": "step-no-immediate-execution",
41
+ "step-require-thunk-for-key": "step-require-thunk-for-key",
42
+ "step-no-bare-await": "step-no-bare-await",
43
+ "step-no-try-catch-wrap": "step-no-try-catch-wrap",
44
+ "step-stable-cache-keys": "step-stable-cache-keys",
45
+ // --- workflow-* ---
46
+ "workflow-no-floating": "workflow-no-floating",
47
+ "workflow-options-position": "workflow-options-position",
48
+ "workflow-callback-shape": "workflow-callback-shape",
49
+ "workflow-no-callable-form": "workflow-no-callable-form",
50
+ "workflow-no-dynamic-import": "workflow-no-dynamic-import",
51
+ "workflow-prefer-step-if": "workflow-prefer-step-if",
52
+ "workflow-prefer-step-foreach": "workflow-prefer-step-foreach",
53
+ // --- result-* ---
54
+ "result-no-floating": "result-no-floating",
55
+ "result-require-handling": "result-require-handling",
56
+ "result-no-double-wrap": "result-no-double-wrap",
57
+ "result-no-manual-propagation": "result-no-manual-propagation",
58
+ "result-no-direct-ok-err": "result-no-direct-ok-err",
59
+ // --- error-* ---
60
+ "error-check-unexpected-first": "error-check-unexpected-first",
61
+ "error-access-cause": "error-access-cause",
62
+ "error-normalize": "error-normalize",
63
+ "error-no-throw-in-deps": "error-no-throw-in-deps",
64
+ // --- concurrency-* ---
65
+ "concurrency-no-promise-all": "concurrency-no-promise-all",
66
+ "concurrency-no-promise-race": "concurrency-no-promise-race",
67
+ "concurrency-no-promise-allsettled": "concurrency-no-promise-allsettled",
68
+ // --- runtime-* ---
69
+ "runtime-step-timeout": "runtime-step-timeout",
70
+ "runtime-step-aborted": "runtime-step-aborted",
71
+ "runtime-retry-exhausted": "runtime-retry-exhausted",
72
+ "runtime-rate-limit": "runtime-rate-limit",
73
+ "runtime-circuit-open": "runtime-circuit-open",
74
+ "runtime-unexpected": "runtime-unexpected",
75
+ "runtime-resolver-not-found": "runtime-resolver-not-found",
76
+ "runtime-saga-compensation": "runtime-saga-compensation"
77
+ };
78
+ function slugDocsUrl(slug) {
79
+ return `https://jagreehal.github.io/awaitly/rules/#${slug}`;
80
+ }
81
+ var ALL_SLUGS = Object.keys(
82
+ AWAITLY_SLUGS
83
+ );
84
+
85
+ // src/tagged-error.ts
86
+ var InternalTaggedErrorBase = class extends Error {
87
+ type;
88
+ /** @deprecated Use `type`. */
89
+ _tag;
90
+ };
91
+ function TaggedError(tag, options) {
92
+ return class extends InternalTaggedErrorBase {
93
+ type = tag;
94
+ /** @deprecated Use `type`. */
95
+ _tag = tag;
96
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
97
+ constructor(props, errorOptions) {
98
+ const message = options?.message ? options.message(props ?? {}) : tag;
99
+ super(message);
100
+ this.name = tag;
101
+ if (options?.slug !== void 0) {
102
+ if (!options.hint) {
103
+ throw new TypeError(
104
+ `TaggedError: 'hint' is required when 'slug' is set (slug: "${options.slug}")`
105
+ );
106
+ }
107
+ Object.defineProperty(this, "code", {
108
+ value: options.slug,
109
+ enumerable: true,
110
+ writable: false,
111
+ configurable: false
112
+ });
113
+ Object.defineProperty(this, "hint", {
114
+ value: options.hint,
115
+ enumerable: true,
116
+ writable: false,
117
+ configurable: false
118
+ });
119
+ Object.defineProperty(this, "docsUrl", {
120
+ value: slugDocsUrl(options.slug),
121
+ enumerable: true,
122
+ writable: false,
123
+ configurable: false
124
+ });
125
+ }
126
+ Object.setPrototypeOf(this, new.target.prototype);
127
+ if (props && typeof props === "object") {
128
+ let safeProps;
129
+ if (options?.slug !== void 0) {
130
+ const {
131
+ _tag: _,
132
+ type: _t,
133
+ name: _n,
134
+ message: _m,
135
+ stack: _s,
136
+ code: _c,
137
+ hint: _h,
138
+ docsUrl: _d,
139
+ ...rest
140
+ } = props;
141
+ safeProps = rest;
142
+ } else {
143
+ const {
144
+ _tag: _,
145
+ type: _t,
146
+ name: _n,
147
+ message: _m,
148
+ stack: _s,
149
+ ...rest
150
+ } = props;
151
+ safeProps = rest;
152
+ }
153
+ const hasUserCause = Object.prototype.hasOwnProperty.call(
154
+ safeProps,
155
+ "cause"
156
+ );
157
+ const userCause = hasUserCause ? safeProps.cause : void 0;
158
+ if (hasUserCause) {
159
+ delete safeProps.cause;
160
+ }
161
+ const hasOptionsCause = errorOptions?.cause !== void 0;
162
+ if (hasUserCause && hasOptionsCause) {
163
+ throw new TypeError(
164
+ "TaggedError: cannot provide 'cause' in props when also setting ErrorOptions.cause"
165
+ );
166
+ }
167
+ Object.assign(this, safeProps);
168
+ if (hasUserCause) {
169
+ this.cause = userCause;
170
+ }
171
+ if (hasOptionsCause) {
172
+ this.cause = errorOptions?.cause;
173
+ }
174
+ } else if (errorOptions?.cause !== void 0) {
175
+ this.cause = errorOptions.cause;
176
+ }
177
+ }
178
+ };
179
+ }
180
+ Object.defineProperty(TaggedError, Symbol.hasInstance, {
181
+ value: (instance) => instance instanceof InternalTaggedErrorBase
182
+ });
183
+ ((TaggedError2) => {
184
+ function isError(value) {
185
+ return value instanceof Error;
186
+ }
187
+ TaggedError2.isError = isError;
188
+ function isTaggedError(value) {
189
+ return value instanceof InternalTaggedErrorBase;
190
+ }
191
+ TaggedError2.isTaggedError = isTaggedError;
192
+ function match(error, handlers) {
193
+ const tag = error._tag;
194
+ const handler = handlers[tag];
195
+ return handler(
196
+ error
197
+ );
198
+ }
199
+ TaggedError2.match = match;
200
+ function matchPartial(error, handlers, otherwise) {
201
+ const tag = error._tag;
202
+ const handler = handlers[tag];
203
+ if (handler) {
204
+ return handler(
205
+ error
206
+ );
207
+ }
208
+ return otherwise(error);
209
+ }
210
+ TaggedError2.matchPartial = matchPartial;
211
+ })(TaggedError || (TaggedError = {}));
212
+
213
+ // src/errors.ts
214
+ var TimeoutError = class extends (/* @__PURE__ */ TaggedError("TimeoutError", {
215
+ slug: "runtime-step-timeout",
216
+ hint: "Increase the step's timeout option, or check why the upstream operation is slow.",
217
+ message: (p) => p.operation ? `TimeoutError: ${p.operation} timed out after ${p.ms}ms` : `TimeoutError: Operation timed out after ${p.ms}ms`
218
+ })) {
219
+ };
220
+ var UnexpectedError = class extends (/* @__PURE__ */ TaggedError("UnexpectedError", {
221
+ slug: "runtime-unexpected",
222
+ hint: "An unexpected exception escaped a step. Inspect cause; consider returning a typed Result instead of throwing.",
223
+ message: (p) => `UnexpectedError: ${p.cause instanceof Error ? p.cause.message : String(p.cause ?? "unknown")}`
224
+ })) {
225
+ };
226
+
227
+ // src/result/index.ts
228
+ function ok(value) {
229
+ return { ok: true, value };
230
+ }
231
+ function err(error, options) {
232
+ const cause = options?.cause;
233
+ return { ok: false, error, ...cause !== void 0 ? { cause } : {} };
234
+ }
235
+
236
+ // src/core/bound-steps.ts
237
+ var isDepResultShaped = (value) => typeof value === "object" && value !== null && "ok" in value && typeof value.ok === "boolean" && (value.ok ? "value" in value : "error" in value);
238
+ var bindSteps = (deps, step) => {
239
+ const steps = {};
240
+ const invocationCounts = /* @__PURE__ */ new Map();
241
+ for (const key of Object.keys(deps)) {
242
+ const dep = deps[key];
243
+ if (typeof dep !== "function") continue;
244
+ steps[key] = (...args) => {
245
+ const count = (invocationCounts.get(key) ?? 0) + 1;
246
+ invocationCounts.set(key, count);
247
+ const stepKey = count === 1 ? key : `${key}#${count}`;
248
+ return step(stepKey, async () => {
249
+ const value = await dep(...args);
250
+ return isDepResultShaped(value) ? value : ok(value);
251
+ });
252
+ };
253
+ }
254
+ return steps;
255
+ };
256
+
257
+ // src/duration.ts
258
+ function toMillis(duration) {
259
+ return duration.millis;
260
+ }
261
+
262
+ // src/core/policies.ts
263
+ var toMs = (d) => typeof d === "number" ? d : toMillis(d);
264
+ var attemptCall = async (fn, args) => {
265
+ try {
266
+ const value = await fn(...args);
267
+ if (isDepResultShaped(value)) {
268
+ return value.ok ? { kind: "ok", value: value.value } : { kind: "err", error: value.error, result: value };
269
+ }
270
+ return { kind: "ok", value };
271
+ } catch (thrown) {
272
+ return { kind: "threw", thrown };
273
+ }
274
+ };
275
+ var named = (wrapped, source) => {
276
+ const name = source.name;
277
+ if (name) {
278
+ Object.defineProperty(wrapped, "name", { value: name, configurable: true });
279
+ }
280
+ return wrapped;
281
+ };
282
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
283
+ function retry(fn, options) {
284
+ const attempts = Math.max(1, Math.trunc(options.attempts));
285
+ const baseDelay = options.delay === void 0 ? 0 : toMs(options.delay);
286
+ const maxDelay = options.maxDelay === void 0 ? Infinity : toMs(options.maxDelay);
287
+ const backoff = options.backoff ?? "fixed";
288
+ const delayFor = (attempt) => {
289
+ const raw = backoff === "exponential" ? baseDelay * 2 ** (attempt - 1) : backoff === "linear" ? baseDelay * attempt : baseDelay;
290
+ return Math.min(raw, maxDelay);
291
+ };
292
+ const wrapped = async (...args) => {
293
+ let last = { kind: "threw", thrown: void 0 };
294
+ for (let attempt = 1; attempt <= attempts; attempt++) {
295
+ last = await attemptCall(fn, args);
296
+ if (last.kind === "ok") return ok(last.value);
297
+ const failure = last.kind === "err" ? last.error : last.thrown;
298
+ if (options.retryIf && !options.retryIf(failure)) break;
299
+ if (attempt < attempts) {
300
+ options.onRetry?.({ attempt, failure });
301
+ const ms = delayFor(attempt);
302
+ if (ms > 0) await sleep(ms);
303
+ }
304
+ }
305
+ if (last.kind === "err") return last.result;
306
+ throw last.thrown;
307
+ };
308
+ return named(wrapped, fn);
309
+ }
310
+ function timeout(fn, after) {
311
+ const ms = toMs(after);
312
+ const TIMED_OUT = /* @__PURE__ */ Symbol("timed-out");
313
+ const wrapped = async (...args) => {
314
+ let timer;
315
+ try {
316
+ const outcome = await Promise.race([
317
+ attemptCall(fn, args),
318
+ new Promise((resolve) => {
319
+ timer = setTimeout(() => resolve(TIMED_OUT), ms);
320
+ })
321
+ ]);
322
+ if (outcome === TIMED_OUT) {
323
+ return err(new TimeoutError({ operation: fn.name || void 0, ms }));
324
+ }
325
+ if (outcome.kind === "ok") return ok(outcome.value);
326
+ if (outcome.kind === "err") return outcome.result;
327
+ throw outcome.thrown;
328
+ } finally {
329
+ if (timer !== void 0) clearTimeout(timer);
330
+ }
331
+ };
332
+ return named(wrapped, fn);
333
+ }
334
+ function fallback(fn, onFailure) {
335
+ const wrapped = async (...args) => {
336
+ const outcome = await attemptCall(fn, args);
337
+ if (outcome.kind === "ok") return ok(outcome.value);
338
+ const failure = outcome.kind === "err" ? outcome.error : new UnexpectedError({ cause: outcome.thrown });
339
+ const recovered = await attemptCall(onFailure, [failure, ...args]);
340
+ if (recovered.kind === "ok") return ok(recovered.value);
341
+ if (recovered.kind === "err") return recovered.result;
342
+ throw recovered.thrown;
343
+ };
344
+ return named(wrapped, fn);
345
+ }
346
+
347
+ // src/core/index.ts
348
+ function parseDurationString(input) {
349
+ const match = input.trim().match(/^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)$/i);
350
+ if (!match) return void 0;
351
+ const value = parseFloat(match[1]);
352
+ const unit = match[2].toLowerCase();
353
+ const multipliers = { ms: 1, s: 1e3, m: 6e4, h: 36e5, d: 864e5 };
354
+ return { _tag: "Duration", millis: value * (multipliers[unit] ?? 1) };
355
+ }
356
+ function defaultCatchUnexpected(cause) {
357
+ return new UnexpectedError({ cause });
358
+ }
359
+ function ok2(value) {
360
+ return { ok: true, value };
361
+ }
362
+ function err2(error, options) {
363
+ const cause = options?.cause;
364
+ return { ok: false, error, ...cause !== void 0 ? { cause } : {} };
365
+ }
366
+ function extractErrorTag(error) {
367
+ if (error == null) return "unknown";
368
+ if (typeof error === "string") return error.trim() || "unknown";
369
+ if (typeof error === "object") {
370
+ const tagged = error;
371
+ if (typeof tagged._tag === "string") {
372
+ const trimmed = tagged._tag.trim();
373
+ if (trimmed) return trimmed;
374
+ }
375
+ if (typeof tagged.tag === "string") {
376
+ const trimmed = tagged.tag.trim();
377
+ if (trimmed) return trimmed;
378
+ }
379
+ if (typeof tagged.code === "string") {
380
+ const trimmed = tagged.code.trim();
381
+ if (trimmed) return trimmed;
382
+ } else if (typeof tagged.code === "number") {
383
+ return String(tagged.code);
384
+ }
385
+ if (error instanceof Error && error.name) {
386
+ const trimmed = error.name.trim();
387
+ if (trimmed) return trimmed;
388
+ }
389
+ }
390
+ return "unknown";
391
+ }
392
+ function lookupErrorClassification(tag, errorMeta) {
393
+ if (!errorMeta || !tag) return void 0;
394
+ return errorMeta[tag];
395
+ }
396
+ function extractStepMetadata(options) {
397
+ const { intent, domain, owner, tags, stateChanges, emits, calls } = options;
398
+ if (!intent && !domain && !owner && !tags?.length && !stateChanges?.length && !emits?.length && !calls?.length) {
399
+ return void 0;
400
+ }
401
+ const metadata = {};
402
+ if (intent) metadata.intent = intent;
403
+ if (domain) metadata.domain = domain;
404
+ if (owner) metadata.owner = owner;
405
+ if (tags?.length) metadata.tags = tags;
406
+ if (stateChanges?.length) metadata.stateChanges = stateChanges;
407
+ if (emits?.length) metadata.emits = emits;
408
+ if (calls?.length) metadata.calls = calls;
409
+ return metadata;
410
+ }
411
+ function buildStepErrorPayload(error, errorMeta, origin, attempt, cumulativeDurationMs) {
412
+ const tag = extractErrorTag(error);
413
+ const classification = lookupErrorClassification(tag, errorMeta);
414
+ const diagnostics = { tag, origin };
415
+ if (classification !== void 0) diagnostics.classification = classification;
416
+ if (attempt !== void 0) diagnostics.attempt = attempt;
417
+ if (cumulativeDurationMs !== void 0) diagnostics.cumulativeDurationMs = cumulativeDurationMs;
418
+ return diagnostics;
419
+ }
420
+ var STEP_TIMEOUT_MARKER = /* @__PURE__ */ Symbol.for("step_timeout_marker");
421
+ function isStepTimeoutError(e) {
422
+ if (typeof e !== "object" || e === null) {
423
+ return false;
424
+ }
425
+ if (e.type === "STEP_TIMEOUT") {
426
+ return true;
427
+ }
428
+ return STEP_TIMEOUT_MARKER in e;
429
+ }
430
+ function getStepTimeoutMeta(e) {
431
+ if (typeof e !== "object" || e === null) {
432
+ return void 0;
433
+ }
434
+ if (e.type === "STEP_TIMEOUT") {
435
+ const err3 = e;
436
+ return {
437
+ timeoutMs: err3.timeoutMs,
438
+ stepName: err3.stepName,
439
+ stepKey: err3.stepKey,
440
+ attempt: err3.attempt
441
+ };
442
+ }
443
+ if (STEP_TIMEOUT_MARKER in e) {
444
+ return e[STEP_TIMEOUT_MARKER];
445
+ }
446
+ return void 0;
447
+ }
448
+ var EARLY_EXIT_SYMBOL = /* @__PURE__ */ Symbol("early-exit");
449
+ function createEarlyExit(error, meta) {
450
+ return {
451
+ [EARLY_EXIT_SYMBOL]: true,
452
+ error,
453
+ meta
454
+ };
455
+ }
456
+ function isEarlyExit(e) {
457
+ return typeof e === "object" && e !== null && e[EARLY_EXIT_SYMBOL] === true;
458
+ }
459
+ var MAPPER_EXCEPTION_SYMBOL = /* @__PURE__ */ Symbol("mapper-exception");
460
+ function createMapperException(thrown) {
461
+ return { [MAPPER_EXCEPTION_SYMBOL]: true, thrown };
462
+ }
463
+ function isMapperException(e) {
464
+ return typeof e === "object" && e !== null && e[MAPPER_EXCEPTION_SYMBOL] === true;
465
+ }
466
+ function calculateRetryDelay(attempt, options) {
467
+ const { backoff, initialDelay, maxDelay, jitter } = options;
468
+ let delay;
469
+ switch (backoff) {
470
+ case "fixed":
471
+ delay = initialDelay;
472
+ break;
473
+ case "linear":
474
+ delay = initialDelay * attempt;
475
+ break;
476
+ case "exponential":
477
+ delay = initialDelay * Math.pow(2, attempt - 1);
478
+ break;
479
+ }
480
+ delay = Math.min(delay, maxDelay);
481
+ if (jitter) {
482
+ const jitterAmount = delay * 0.25 * Math.random();
483
+ delay = delay + jitterAmount;
484
+ }
485
+ return Math.floor(delay);
486
+ }
487
+ function sleep2(ms) {
488
+ return new Promise((resolve) => setTimeout(resolve, ms));
489
+ }
490
+ var TIMEOUT_SYMBOL = /* @__PURE__ */ Symbol("timeout");
491
+ var TIMEOUT_OPTION_SYMBOL = /* @__PURE__ */ Symbol("timeout-option");
492
+ function isTimeoutOptionMarker(value) {
493
+ return typeof value === "object" && value !== null && value[TIMEOUT_OPTION_SYMBOL] === true;
494
+ }
495
+ async function executeWithTimeout(operation, options, stepInfo, externalSignal) {
496
+ const controller = new AbortController();
497
+ const behavior = options.onTimeout ?? "error";
498
+ const createTimeoutError = () => {
499
+ if (typeof behavior === "function") {
500
+ return behavior({
501
+ name: stepInfo.name,
502
+ key: stepInfo.key,
503
+ ms: options.ms
504
+ });
505
+ }
506
+ return options.error ?? {
507
+ type: "STEP_TIMEOUT",
508
+ stepName: stepInfo.name,
509
+ stepKey: stepInfo.key,
510
+ timeoutMs: options.ms,
511
+ attempt: stepInfo.attempt
512
+ };
513
+ };
514
+ let timeoutId;
515
+ if (externalSignal?.aborted) {
516
+ controller.abort(externalSignal.reason);
517
+ }
518
+ let externalAbortHandler;
519
+ if (externalSignal && !externalSignal.aborted) {
520
+ externalAbortHandler = () => controller.abort(externalSignal.reason);
521
+ externalSignal.addEventListener("abort", externalAbortHandler, { once: true });
522
+ }
523
+ const timeoutPromise = new Promise((_, reject) => {
524
+ timeoutId = setTimeout(() => {
525
+ if (behavior !== "disconnect") {
526
+ controller.abort();
527
+ }
528
+ if (behavior === "option") {
529
+ reject({ [TIMEOUT_OPTION_SYMBOL]: true, ms: options.ms });
530
+ return;
531
+ }
532
+ reject({ [TIMEOUT_SYMBOL]: true, error: createTimeoutError() });
533
+ }, options.ms);
534
+ });
535
+ let operationPromise;
536
+ if (options.signal) {
537
+ operationPromise = Promise.resolve(
538
+ operation(controller.signal)
539
+ );
540
+ } else {
541
+ operationPromise = Promise.resolve(operation());
542
+ }
543
+ try {
544
+ const result = await Promise.race([operationPromise, timeoutPromise]);
545
+ return result;
546
+ } catch (error) {
547
+ if (typeof error === "object" && error !== null && error[TIMEOUT_OPTION_SYMBOL] === true) {
548
+ throw { [TIMEOUT_OPTION_SYMBOL]: true, ms: options.ms };
549
+ }
550
+ if (typeof error === "object" && error !== null && error[TIMEOUT_SYMBOL] === true) {
551
+ if (behavior === "disconnect") {
552
+ operationPromise.catch(() => {
553
+ });
554
+ }
555
+ const errorToThrow = error.error;
556
+ if (typeof errorToThrow === "object" && errorToThrow !== null && errorToThrow.type !== "STEP_TIMEOUT") {
557
+ const meta = {
558
+ timeoutMs: options.ms,
559
+ stepName: stepInfo.name,
560
+ stepKey: stepInfo.key,
561
+ attempt: stepInfo.attempt
562
+ };
563
+ if (STEP_TIMEOUT_MARKER in errorToThrow) {
564
+ errorToThrow[STEP_TIMEOUT_MARKER] = meta;
565
+ } else {
566
+ Object.defineProperty(errorToThrow, STEP_TIMEOUT_MARKER, {
567
+ value: meta,
568
+ enumerable: false,
569
+ writable: true,
570
+ configurable: false
571
+ });
572
+ }
573
+ }
574
+ throw errorToThrow;
575
+ }
576
+ throw error;
577
+ } finally {
578
+ clearTimeout(timeoutId);
579
+ if (externalAbortHandler && externalSignal) {
580
+ externalSignal.removeEventListener("abort", externalAbortHandler);
581
+ }
582
+ }
583
+ }
584
+ var DEFAULT_RETRY_CONFIG = {
585
+ backoff: "exponential",
586
+ initialDelay: 100,
587
+ maxDelay: 3e4,
588
+ jitter: true,
589
+ shouldRetry: () => true,
590
+ onRetry: () => {
591
+ }
592
+ };
593
+ async function runFn(fnOrDeps, optionsOrFn, maybeOptions) {
594
+ if (typeof fnOrDeps !== "function") {
595
+ const deps = fnOrDeps;
596
+ const boundFn = optionsOrFn;
597
+ if (typeof boundFn !== "function") {
598
+ throw new TypeError(
599
+ "[awaitly] run(deps, fn) requires a callback as the second argument. Example: run({ getUser }, async (s) => s.getUser(id))"
600
+ );
601
+ }
602
+ const classicRun = runFn;
603
+ return classicRun(
604
+ ({ step }) => boundFn(bindSteps(deps, step), { step }),
605
+ maybeOptions
606
+ );
607
+ }
608
+ const fn = fnOrDeps;
609
+ const options = optionsOrFn;
610
+ const {
611
+ onError,
612
+ onEvent,
613
+ catchUnexpected,
614
+ workflowId: providedWorkflowId,
615
+ workflowName,
616
+ context,
617
+ graph,
618
+ _workflowSignal
619
+ } = options && typeof options === "object" ? options : {};
620
+ const workflowId = providedWorkflowId ?? crypto.randomUUID();
621
+ const declaredIds = graph ? new Set(
622
+ Array.isArray(graph) ? graph : graph.states.map((state) => state.semanticId ?? state.id)
623
+ ) : void 0;
624
+ const declaredPatterns = declaredIds ? [...declaredIds].filter((id) => id.includes("{")).map(
625
+ (id) => new RegExp(
626
+ `^${id.replaceAll(/[.*+?^$()[\]\\|]/g, String.raw`\$&`).replaceAll(/\{[^}]*\}/g, ".+")}$`
627
+ )
628
+ ) : void 0;
629
+ const assertDeclared = (id, kind) => {
630
+ if (!declaredIds || declaredIds.has(id)) return;
631
+ if (declaredPatterns?.some((re) => re.test(id))) return;
632
+ throw new Error(
633
+ `[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.`
634
+ );
635
+ };
636
+ const effectiveCatchUnexpected = catchUnexpected ?? defaultCatchUnexpected;
637
+ const activeScopeStack = [];
638
+ let stepIdCounter = 0;
639
+ const generateStepId = (stepKey) => {
640
+ return stepKey ?? `step_${++stepIdCounter}`;
641
+ };
642
+ const emitEvent = (event) => {
643
+ const eventWithContext = event.context !== void 0 || context === void 0 ? event : { ...event, context };
644
+ const eventWithName = workflowName !== void 0 && eventWithContext.workflowName === void 0 ? { ...eventWithContext, workflowName } : eventWithContext;
645
+ if (eventWithName.type === "step_success") {
646
+ const stepId = eventWithName.stepId;
647
+ for (let i = activeScopeStack.length - 1; i >= 0; i--) {
648
+ const scope = activeScopeStack[i];
649
+ if (scope.type === "race" && !scope.winnerId) {
650
+ scope.winnerId = stepId;
651
+ break;
652
+ }
653
+ }
654
+ }
655
+ onEvent?.(eventWithName, context);
656
+ };
657
+ const earlyExit = createEarlyExit;
658
+ const isEarlyExitE = (e) => isEarlyExit(e);
659
+ const wrapForStep = (error, _meta) => {
660
+ return error;
661
+ };
662
+ const isResultLike = (value) => {
663
+ if (typeof value === "function") return false;
664
+ if (value && typeof value === "object" && "ok" in value) return true;
665
+ if (value && typeof value === "object" && "then" in value && typeof value.then === "function") return true;
666
+ return false;
667
+ };
668
+ try {
669
+ let normalizeParallelOperations2 = function(rawOperations) {
670
+ const out = {};
671
+ for (const [key, value2] of Object.entries(rawOperations)) {
672
+ if (typeof value2 === "function") {
673
+ out[key] = value2;
674
+ } else if (value2 && typeof value2 === "object" && "fn" in value2) {
675
+ out[key] = value2.fn;
676
+ } else {
677
+ throw new TypeError(`step.all: operation "${key}" must be a function or { fn, errors? } object`);
678
+ }
679
+ }
680
+ return out;
681
+ }, executeParallelArray2 = function(name, operation) {
682
+ const scopeId = `scope_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
683
+ return (async () => {
684
+ const startTime = performance.now();
685
+ let scopeEnded = false;
686
+ activeScopeStack.push({ scopeId, type: "parallel" });
687
+ const emitScopeEnd = () => {
688
+ if (scopeEnded) return;
689
+ scopeEnded = true;
690
+ const idx = activeScopeStack.findIndex((s) => s.scopeId === scopeId);
691
+ if (idx !== -1) activeScopeStack.splice(idx, 1);
692
+ emitEvent({
693
+ type: "scope_end",
694
+ workflowId,
695
+ scopeId,
696
+ ts: Date.now(),
697
+ durationMs: performance.now() - startTime
698
+ });
699
+ };
700
+ emitEvent({
701
+ type: "scope_start",
702
+ workflowId,
703
+ scopeId,
704
+ scopeType: "parallel",
705
+ name,
706
+ ts: Date.now()
707
+ });
708
+ try {
709
+ const result = await operation();
710
+ emitScopeEnd();
711
+ if (!result.ok) {
712
+ onError?.(result.error, name, context);
713
+ throw earlyExit(result.error, {
714
+ origin: "result",
715
+ resultCause: result.cause
716
+ });
717
+ }
718
+ return result.value;
719
+ } catch (error) {
720
+ emitScopeEnd();
721
+ throw error;
722
+ }
723
+ })();
724
+ }, executeParallelNamed2 = function(operations, options2) {
725
+ const keys = Object.keys(operations);
726
+ const name = options2.name ?? `Parallel(${keys.join(", ")})`;
727
+ const scopeId = `scope_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
728
+ return (async () => {
729
+ const startTime = performance.now();
730
+ let scopeEnded = false;
731
+ activeScopeStack.push({ scopeId, type: "parallel" });
732
+ const emitScopeEnd = () => {
733
+ if (scopeEnded) return;
734
+ scopeEnded = true;
735
+ const idx = activeScopeStack.findIndex((s) => s.scopeId === scopeId);
736
+ if (idx !== -1) activeScopeStack.splice(idx, 1);
737
+ emitEvent({
738
+ type: "scope_end",
739
+ workflowId,
740
+ scopeId,
741
+ ts: Date.now(),
742
+ durationMs: performance.now() - startTime
743
+ });
744
+ };
745
+ emitEvent({
746
+ type: "scope_start",
747
+ workflowId,
748
+ scopeId,
749
+ scopeType: "parallel",
750
+ name,
751
+ ts: Date.now()
752
+ });
753
+ try {
754
+ const results = await new Promise((resolve) => {
755
+ if (keys.length === 0) {
756
+ resolve([]);
757
+ return;
758
+ }
759
+ let settled = false;
760
+ let pendingCount = keys.length;
761
+ const resultArray = new Array(keys.length);
762
+ for (let i = 0; i < keys.length; i++) {
763
+ const key = keys[i];
764
+ const index = i;
765
+ Promise.resolve(operations[key]()).catch((reason) => err2(
766
+ { type: "PROMISE_REJECTED", cause: reason },
767
+ { cause: { type: "PROMISE_REJECTION", reason } }
768
+ )).then((result) => {
769
+ if (settled) return;
770
+ if (!result.ok) {
771
+ settled = true;
772
+ resolve([{ key, result }]);
773
+ return;
774
+ }
775
+ resultArray[index] = { key, result };
776
+ pendingCount--;
777
+ if (pendingCount === 0) {
778
+ resolve(resultArray);
779
+ }
780
+ });
781
+ }
782
+ });
783
+ emitScopeEnd();
784
+ const output = {};
785
+ for (const { key, result } of results) {
786
+ if (!result.ok) {
787
+ onError?.(result.error, key, context);
788
+ throw earlyExit(result.error, {
789
+ origin: "result",
790
+ resultCause: result.cause
791
+ });
792
+ }
793
+ output[key] = result.value;
794
+ }
795
+ return output;
796
+ } catch (error) {
797
+ emitScopeEnd();
798
+ throw error;
799
+ }
800
+ })();
801
+ };
802
+ var normalizeParallelOperations = normalizeParallelOperations2, executeParallelArray = executeParallelArray2, executeParallelNamed = executeParallelNamed2;
803
+ const stepFn = (id, operationOrResult, stepOptions) => {
804
+ return (async () => {
805
+ if (typeof id !== "string" || id.length === 0) {
806
+ throw new Error(
807
+ '[awaitly] step() requires an explicit string ID as the first argument. Example: step("fetchUser", () => fetchUser(id))'
808
+ );
809
+ }
810
+ assertDeclared(id, "step");
811
+ const parsedOptions = stepOptions ?? {};
812
+ const stepMetadata = extractStepMetadata(parsedOptions);
813
+ const stepName = id;
814
+ const stepKey = parsedOptions.key ?? id;
815
+ const explicitKey = parsedOptions.key ?? id;
816
+ const { description: stepDescription, retry: retryConfig, timeout: timeoutConfig } = parsedOptions;
817
+ const stepId = generateStepId(stepKey);
818
+ const hasEventListeners = onEvent;
819
+ const overallStartTime = hasEventListeners ? performance.now() : 0;
820
+ const isDirectResult = isResultLike(operationOrResult);
821
+ const operation = isDirectResult ? () => operationOrResult : operationOrResult;
822
+ const maxAttempts = Math.max(1, retryConfig?.attempts ?? 1);
823
+ const effectiveRetry = {
824
+ attempts: maxAttempts,
825
+ backoff: retryConfig?.backoff ?? DEFAULT_RETRY_CONFIG.backoff,
826
+ initialDelay: retryConfig?.initialDelay ?? DEFAULT_RETRY_CONFIG.initialDelay,
827
+ maxDelay: retryConfig?.maxDelay ?? DEFAULT_RETRY_CONFIG.maxDelay,
828
+ jitter: retryConfig?.jitter ?? DEFAULT_RETRY_CONFIG.jitter,
829
+ shouldRetry: retryConfig?.shouldRetry ?? DEFAULT_RETRY_CONFIG.shouldRetry,
830
+ onRetry: retryConfig?.onRetry ?? DEFAULT_RETRY_CONFIG.onRetry
831
+ };
832
+ if (onEvent) {
833
+ emitEvent({
834
+ type: "step_start",
835
+ workflowId,
836
+ stepId,
837
+ stepKey,
838
+ name: stepName,
839
+ description: stepDescription,
840
+ ts: Date.now(),
841
+ ...stepMetadata && { metadata: stepMetadata }
842
+ });
843
+ }
844
+ let lastResult;
845
+ for (let attempt = 1; attempt <= effectiveRetry.attempts; attempt++) {
846
+ const attemptStartTime = hasEventListeners ? performance.now() : 0;
847
+ try {
848
+ let result;
849
+ if (timeoutConfig) {
850
+ result = await executeWithTimeout(
851
+ operation,
852
+ timeoutConfig,
853
+ { name: stepName, key: stepKey, attempt },
854
+ _workflowSignal
855
+ );
856
+ } else {
857
+ result = await operation();
858
+ }
859
+ if (result.ok) {
860
+ const durationMs = performance.now() - overallStartTime;
861
+ emitEvent({
862
+ type: "step_success",
863
+ workflowId,
864
+ stepId,
865
+ stepKey,
866
+ name: stepName,
867
+ description: stepDescription,
868
+ ts: Date.now(),
869
+ durationMs,
870
+ ...stepMetadata && { metadata: stepMetadata }
871
+ });
872
+ if (explicitKey) {
873
+ emitEvent({
874
+ type: "step_complete",
875
+ workflowId,
876
+ stepKey: explicitKey,
877
+ name: stepName,
878
+ description: stepDescription,
879
+ ts: Date.now(),
880
+ durationMs,
881
+ result,
882
+ ...stepMetadata && { metadata: stepMetadata }
883
+ });
884
+ }
885
+ return result.value;
886
+ }
887
+ lastResult = result;
888
+ if (attempt < effectiveRetry.attempts && effectiveRetry.shouldRetry(result.error, attempt)) {
889
+ const delay = calculateRetryDelay(attempt, effectiveRetry);
890
+ emitEvent({
891
+ type: "step_retry",
892
+ workflowId,
893
+ stepId,
894
+ stepKey,
895
+ name: stepName,
896
+ ts: Date.now(),
897
+ attempt: attempt + 1,
898
+ maxAttempts: effectiveRetry.attempts,
899
+ delayMs: delay,
900
+ error: result.error,
901
+ ...stepMetadata && { metadata: stepMetadata },
902
+ diagnostics: buildStepErrorPayload(result.error, parsedOptions.errorMeta, "result", attempt, performance.now() - overallStartTime)
903
+ });
904
+ effectiveRetry.onRetry(result.error, attempt, delay);
905
+ await sleep2(delay);
906
+ continue;
907
+ }
908
+ if (effectiveRetry.attempts > 1) {
909
+ emitEvent({
910
+ type: "step_retries_exhausted",
911
+ workflowId,
912
+ stepId,
913
+ stepKey,
914
+ name: stepName,
915
+ ts: Date.now(),
916
+ durationMs: performance.now() - overallStartTime,
917
+ attempts: attempt,
918
+ lastError: result.error,
919
+ ...stepMetadata && { metadata: stepMetadata },
920
+ diagnostics: buildStepErrorPayload(result.error, parsedOptions.errorMeta, "result", attempt, performance.now() - overallStartTime)
921
+ });
922
+ }
923
+ break;
924
+ } catch (thrown) {
925
+ const durationMs = performance.now() - attemptStartTime;
926
+ if (isTimeoutOptionMarker(thrown)) {
927
+ const timeoutMs = thrown.ms;
928
+ emitEvent({
929
+ type: "step_timeout",
930
+ workflowId,
931
+ stepId,
932
+ stepKey,
933
+ name: stepName,
934
+ ts: Date.now(),
935
+ timeoutMs,
936
+ attempt,
937
+ ...stepMetadata && { metadata: stepMetadata },
938
+ diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, "timeout", attempt)
939
+ });
940
+ emitEvent({
941
+ type: "step_success",
942
+ workflowId,
943
+ stepId,
944
+ stepKey,
945
+ name: stepName,
946
+ description: stepDescription,
947
+ ts: Date.now(),
948
+ durationMs: performance.now() - overallStartTime,
949
+ ...stepMetadata && { metadata: stepMetadata }
950
+ });
951
+ if (explicitKey) {
952
+ emitEvent({
953
+ type: "step_complete",
954
+ workflowId,
955
+ stepKey: explicitKey,
956
+ name: stepName,
957
+ description: stepDescription,
958
+ ts: Date.now(),
959
+ durationMs: performance.now() - overallStartTime,
960
+ result: ok2(void 0),
961
+ ...stepMetadata && { metadata: stepMetadata }
962
+ });
963
+ }
964
+ return void 0;
965
+ }
966
+ if (isEarlyExitE(thrown)) {
967
+ emitEvent({
968
+ type: "step_aborted",
969
+ workflowId,
970
+ stepId,
971
+ stepKey,
972
+ name: stepName,
973
+ description: stepDescription,
974
+ ts: Date.now(),
975
+ durationMs,
976
+ ...stepMetadata && { metadata: stepMetadata }
977
+ });
978
+ throw thrown;
979
+ }
980
+ if (isStepTimeoutError(thrown)) {
981
+ const timeoutMeta = getStepTimeoutMeta(thrown);
982
+ const timeoutMs = timeoutConfig?.ms ?? timeoutMeta?.timeoutMs ?? 0;
983
+ emitEvent({
984
+ type: "step_timeout",
985
+ workflowId,
986
+ stepId,
987
+ stepKey,
988
+ name: stepName,
989
+ ts: Date.now(),
990
+ timeoutMs,
991
+ attempt,
992
+ ...stepMetadata && { metadata: stepMetadata },
993
+ diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, "timeout", attempt)
994
+ });
995
+ if (attempt < effectiveRetry.attempts && effectiveRetry.shouldRetry(thrown, attempt)) {
996
+ const delay = calculateRetryDelay(attempt, effectiveRetry);
997
+ emitEvent({
998
+ type: "step_retry",
999
+ workflowId,
1000
+ stepId,
1001
+ stepKey,
1002
+ name: stepName,
1003
+ ts: Date.now(),
1004
+ attempt: attempt + 1,
1005
+ maxAttempts: effectiveRetry.attempts,
1006
+ delayMs: delay,
1007
+ error: thrown,
1008
+ ...stepMetadata && { metadata: stepMetadata },
1009
+ diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, "timeout", attempt, performance.now() - overallStartTime)
1010
+ });
1011
+ effectiveRetry.onRetry(thrown, attempt, delay);
1012
+ await sleep2(delay);
1013
+ continue;
1014
+ }
1015
+ if (effectiveRetry.attempts > 1) {
1016
+ emitEvent({
1017
+ type: "step_retries_exhausted",
1018
+ workflowId,
1019
+ stepId,
1020
+ stepKey,
1021
+ name: stepName,
1022
+ ts: Date.now(),
1023
+ durationMs: performance.now() - overallStartTime,
1024
+ attempts: attempt,
1025
+ lastError: thrown,
1026
+ ...stepMetadata && { metadata: stepMetadata },
1027
+ diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, "timeout", attempt, performance.now() - overallStartTime)
1028
+ });
1029
+ }
1030
+ const totalDurationMs3 = performance.now() - overallStartTime;
1031
+ emitEvent({
1032
+ type: "step_error",
1033
+ workflowId,
1034
+ stepId,
1035
+ stepKey,
1036
+ name: stepName,
1037
+ description: stepDescription,
1038
+ ts: Date.now(),
1039
+ durationMs: totalDurationMs3,
1040
+ error: thrown,
1041
+ ...stepMetadata && { metadata: stepMetadata },
1042
+ diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, "timeout", attempt, totalDurationMs3)
1043
+ });
1044
+ if (explicitKey) {
1045
+ emitEvent({
1046
+ type: "step_complete",
1047
+ workflowId,
1048
+ stepKey: explicitKey,
1049
+ name: stepName,
1050
+ description: stepDescription,
1051
+ ts: Date.now(),
1052
+ durationMs: totalDurationMs3,
1053
+ result: err2(thrown, { cause: thrown }),
1054
+ meta: { origin: "throw", thrown },
1055
+ ...stepMetadata && { metadata: stepMetadata }
1056
+ });
1057
+ }
1058
+ onError?.(thrown, stepName, context);
1059
+ throw earlyExit(thrown, { origin: "throw", thrown });
1060
+ }
1061
+ if (attempt < effectiveRetry.attempts && effectiveRetry.shouldRetry(thrown, attempt)) {
1062
+ const delay = calculateRetryDelay(attempt, effectiveRetry);
1063
+ emitEvent({
1064
+ type: "step_retry",
1065
+ workflowId,
1066
+ stepId,
1067
+ stepKey,
1068
+ name: stepName,
1069
+ ts: Date.now(),
1070
+ attempt: attempt + 1,
1071
+ maxAttempts: effectiveRetry.attempts,
1072
+ delayMs: delay,
1073
+ error: thrown,
1074
+ ...stepMetadata && { metadata: stepMetadata },
1075
+ diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, "throw", attempt, performance.now() - overallStartTime)
1076
+ });
1077
+ effectiveRetry.onRetry(thrown, attempt, delay);
1078
+ await sleep2(delay);
1079
+ continue;
1080
+ }
1081
+ if (effectiveRetry.attempts > 1 && !isStepTimeoutError(thrown)) {
1082
+ emitEvent({
1083
+ type: "step_retries_exhausted",
1084
+ workflowId,
1085
+ stepId,
1086
+ stepKey,
1087
+ name: stepName,
1088
+ ts: Date.now(),
1089
+ durationMs: performance.now() - overallStartTime,
1090
+ attempts: attempt,
1091
+ lastError: thrown,
1092
+ ...stepMetadata && { metadata: stepMetadata },
1093
+ diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, "throw", attempt, performance.now() - overallStartTime)
1094
+ });
1095
+ }
1096
+ const totalDurationMs2 = performance.now() - overallStartTime;
1097
+ let mappedError;
1098
+ try {
1099
+ mappedError = effectiveCatchUnexpected(thrown);
1100
+ } catch (mapperError) {
1101
+ throw createMapperException(mapperError);
1102
+ }
1103
+ emitEvent({
1104
+ type: "step_error",
1105
+ workflowId,
1106
+ stepId,
1107
+ stepKey,
1108
+ name: stepName,
1109
+ description: stepDescription,
1110
+ ts: Date.now(),
1111
+ durationMs: totalDurationMs2,
1112
+ error: mappedError,
1113
+ ...stepMetadata && { metadata: stepMetadata },
1114
+ diagnostics: buildStepErrorPayload(thrown, parsedOptions.errorMeta, "throw", attempt, totalDurationMs2)
1115
+ });
1116
+ if (explicitKey) {
1117
+ emitEvent({
1118
+ type: "step_complete",
1119
+ workflowId,
1120
+ stepKey: explicitKey,
1121
+ name: stepName,
1122
+ description: stepDescription,
1123
+ ts: Date.now(),
1124
+ durationMs: totalDurationMs2,
1125
+ result: err2(mappedError, { cause: thrown }),
1126
+ meta: { origin: "throw", thrown },
1127
+ ...stepMetadata && { metadata: stepMetadata }
1128
+ });
1129
+ }
1130
+ onError?.(mappedError, stepName, context);
1131
+ throw earlyExit(mappedError, { origin: "throw", thrown });
1132
+ }
1133
+ }
1134
+ const errorResult = lastResult;
1135
+ const totalDurationMs = performance.now() - overallStartTime;
1136
+ const wrappedError = wrapForStep(errorResult.error, {
1137
+ origin: "result",
1138
+ resultCause: errorResult.cause
1139
+ });
1140
+ emitEvent({
1141
+ type: "step_error",
1142
+ workflowId,
1143
+ stepId,
1144
+ stepKey,
1145
+ name: stepName,
1146
+ description: stepDescription,
1147
+ ts: Date.now(),
1148
+ durationMs: totalDurationMs,
1149
+ error: wrappedError,
1150
+ ...stepMetadata && { metadata: stepMetadata },
1151
+ diagnostics: buildStepErrorPayload(errorResult.error, parsedOptions.errorMeta, "result", effectiveRetry.attempts, totalDurationMs)
1152
+ });
1153
+ if (explicitKey) {
1154
+ emitEvent({
1155
+ type: "step_complete",
1156
+ workflowId,
1157
+ stepKey: explicitKey,
1158
+ name: stepName,
1159
+ description: stepDescription,
1160
+ ts: Date.now(),
1161
+ durationMs: totalDurationMs,
1162
+ result: errorResult,
1163
+ meta: { origin: "result", resultCause: errorResult.cause },
1164
+ ...stepMetadata && { metadata: stepMetadata }
1165
+ });
1166
+ }
1167
+ onError?.(wrappedError, stepName, context);
1168
+ throw earlyExit(wrappedError, {
1169
+ origin: "result",
1170
+ resultCause: errorResult.cause
1171
+ });
1172
+ })();
1173
+ };
1174
+ stepFn.try = (id, operation, opts) => {
1175
+ if (typeof id !== "string" || id.length === 0) {
1176
+ throw new Error(
1177
+ '[awaitly] step.try() requires an explicit string ID as the first argument. Example: step.try("parse", () => JSON.parse(str), { error: "PARSE_ERROR" })'
1178
+ );
1179
+ }
1180
+ assertDeclared(id, "step");
1181
+ const mapToError = "error" in opts ? () => opts.error : opts.onError;
1182
+ if (opts.retry || opts.timeout) {
1183
+ return stepFn.retry(
1184
+ id,
1185
+ async () => {
1186
+ try {
1187
+ return ok2(await operation());
1188
+ } catch (cause) {
1189
+ return err2(mapToError(cause), { cause });
1190
+ }
1191
+ },
1192
+ {
1193
+ attempts: opts.retry?.attempts ?? 1,
1194
+ ...opts.retry ?? {},
1195
+ key: opts.key,
1196
+ timeout: opts.timeout
1197
+ }
1198
+ );
1199
+ }
1200
+ const stepKey = opts.key ?? id;
1201
+ const stepName = id;
1202
+ const stepId = id;
1203
+ const hasEventListeners = onEvent;
1204
+ return (async () => {
1205
+ const startTime = hasEventListeners ? performance.now() : 0;
1206
+ if (onEvent) {
1207
+ emitEvent({
1208
+ type: "step_start",
1209
+ workflowId,
1210
+ stepId,
1211
+ stepKey,
1212
+ name: stepName,
1213
+ ts: Date.now()
1214
+ });
1215
+ }
1216
+ try {
1217
+ const value2 = await operation();
1218
+ const durationMs = performance.now() - startTime;
1219
+ emitEvent({
1220
+ type: "step_success",
1221
+ workflowId,
1222
+ stepId,
1223
+ stepKey,
1224
+ name: stepName,
1225
+ ts: Date.now(),
1226
+ durationMs
1227
+ });
1228
+ if (stepKey) {
1229
+ emitEvent({
1230
+ type: "step_complete",
1231
+ workflowId,
1232
+ stepKey,
1233
+ name: stepName,
1234
+ ts: Date.now(),
1235
+ durationMs,
1236
+ result: ok2(value2)
1237
+ });
1238
+ }
1239
+ return value2;
1240
+ } catch (error) {
1241
+ const mapped = mapToError(error);
1242
+ const durationMs = performance.now() - startTime;
1243
+ const wrappedError = wrapForStep(mapped, { origin: "throw", thrown: error });
1244
+ emitEvent({
1245
+ type: "step_error",
1246
+ workflowId,
1247
+ stepId,
1248
+ stepKey,
1249
+ name: stepName,
1250
+ ts: Date.now(),
1251
+ durationMs,
1252
+ error: wrappedError
1253
+ });
1254
+ if (stepKey) {
1255
+ emitEvent({
1256
+ type: "step_complete",
1257
+ workflowId,
1258
+ stepKey,
1259
+ name: stepName,
1260
+ ts: Date.now(),
1261
+ durationMs,
1262
+ result: err2(mapped, { cause: error }),
1263
+ meta: { origin: "throw", thrown: error }
1264
+ });
1265
+ }
1266
+ onError?.(wrappedError, stepName, context);
1267
+ throw earlyExit(wrappedError, { origin: "throw", thrown: error });
1268
+ }
1269
+ })();
1270
+ };
1271
+ stepFn.fromResult = (id, operation, opts) => {
1272
+ if (typeof id !== "string" || id.length === 0) {
1273
+ throw new Error(
1274
+ '[awaitly] step.fromResult() requires an explicit string ID as the first argument. Example: step.fromResult("callProvider", () => callProvider(input), { onError: (e) => ({ type: "FAILED" }) })'
1275
+ );
1276
+ }
1277
+ assertDeclared(id, "step");
1278
+ const stepKey = opts.key ?? id;
1279
+ const stepName = id;
1280
+ const stepId = id;
1281
+ const mapToError = "error" in opts ? () => opts.error : opts.onError;
1282
+ const hasEventListeners = onEvent;
1283
+ return (async () => {
1284
+ const startTime = hasEventListeners ? performance.now() : 0;
1285
+ if (onEvent) {
1286
+ emitEvent({
1287
+ type: "step_start",
1288
+ workflowId,
1289
+ stepId,
1290
+ stepKey,
1291
+ name: stepName,
1292
+ ts: Date.now()
1293
+ });
1294
+ }
1295
+ const result = await operation();
1296
+ if (result.ok) {
1297
+ const durationMs = performance.now() - startTime;
1298
+ emitEvent({
1299
+ type: "step_success",
1300
+ workflowId,
1301
+ stepId,
1302
+ stepKey,
1303
+ name: stepName,
1304
+ ts: Date.now(),
1305
+ durationMs
1306
+ });
1307
+ if (stepKey) {
1308
+ emitEvent({
1309
+ type: "step_complete",
1310
+ workflowId,
1311
+ stepKey,
1312
+ name: stepName,
1313
+ ts: Date.now(),
1314
+ durationMs,
1315
+ result: ok2(result.value)
1316
+ });
1317
+ }
1318
+ return result.value;
1319
+ } else {
1320
+ const mapped = mapToError(result.error);
1321
+ const durationMs = performance.now() - startTime;
1322
+ const wrappedError = wrapForStep(mapped, {
1323
+ origin: "result",
1324
+ resultCause: result.error
1325
+ });
1326
+ emitEvent({
1327
+ type: "step_error",
1328
+ workflowId,
1329
+ stepId,
1330
+ stepKey,
1331
+ name: stepName,
1332
+ ts: Date.now(),
1333
+ durationMs,
1334
+ error: wrappedError
1335
+ });
1336
+ if (stepKey) {
1337
+ emitEvent({
1338
+ type: "step_complete",
1339
+ workflowId,
1340
+ stepKey,
1341
+ name: stepName,
1342
+ ts: Date.now(),
1343
+ durationMs,
1344
+ result: err2(mapped, { cause: result.error }),
1345
+ meta: { origin: "result", resultCause: result.error }
1346
+ });
1347
+ }
1348
+ onError?.(wrappedError, stepName, context);
1349
+ throw earlyExit(wrappedError, {
1350
+ origin: "result",
1351
+ resultCause: result.error
1352
+ });
1353
+ }
1354
+ })();
1355
+ };
1356
+ stepFn.fromNullable = (id, operation, onNull, options2) => {
1357
+ if (typeof id !== "string" || id.length === 0) {
1358
+ throw new Error(
1359
+ '[awaitly] step.fromNullable() requires an explicit string ID as the first argument. Example: step.fromNullable("getUser", () => db.find(id), () => ({ type: "NOT_FOUND" }))'
1360
+ );
1361
+ }
1362
+ return stepFn(
1363
+ id,
1364
+ async () => {
1365
+ const value2 = await operation();
1366
+ return value2 != null ? ok2(value2) : err2(onNull());
1367
+ },
1368
+ options2
1369
+ );
1370
+ };
1371
+ stepFn.retry = (id, operation, options2) => {
1372
+ if (typeof id !== "string" || id.length === 0) {
1373
+ throw new Error(
1374
+ '[awaitly] step.retry() requires an explicit string ID as the first argument. Example: step.retry("fetchData", () => fetchData(), { attempts: 3 })'
1375
+ );
1376
+ }
1377
+ return stepFn(id, operation, {
1378
+ key: options2.key ?? id,
1379
+ retry: {
1380
+ attempts: options2.attempts,
1381
+ backoff: options2.backoff,
1382
+ initialDelay: options2.initialDelay,
1383
+ maxDelay: options2.maxDelay,
1384
+ jitter: options2.jitter,
1385
+ shouldRetry: options2.shouldRetry,
1386
+ onRetry: options2.onRetry
1387
+ },
1388
+ timeout: options2.timeout
1389
+ });
1390
+ };
1391
+ stepFn.withTimeout = (id, operation, options2) => {
1392
+ if (typeof id !== "string" || id.length === 0) {
1393
+ throw new Error(
1394
+ '[awaitly] step.withTimeout() requires an explicit string ID as the first argument. Example: step.withTimeout("slowOp", () => slowOp(), { ms: 5000 })'
1395
+ );
1396
+ }
1397
+ return stepFn(
1398
+ id,
1399
+ operation,
1400
+ {
1401
+ key: options2.key ?? id,
1402
+ timeout: options2
1403
+ }
1404
+ );
1405
+ };
1406
+ stepFn.sleep = (id, duration, options2) => {
1407
+ if (typeof id !== "string" || id.length === 0) {
1408
+ throw new Error(
1409
+ '[awaitly] step.sleep() requires an explicit string ID as the first argument. Example: step.sleep("delay", "5s")'
1410
+ );
1411
+ }
1412
+ const d = typeof duration === "string" ? parseDurationString(duration) : duration;
1413
+ if (!d) {
1414
+ throw new Error(`step.sleep: invalid duration '${duration}'`);
1415
+ }
1416
+ const ms = d.millis;
1417
+ const userSignal = options2?.signal;
1418
+ return stepFn(
1419
+ id,
1420
+ async () => {
1421
+ if (_workflowSignal?.aborted || userSignal?.aborted) {
1422
+ const e = new Error("Sleep aborted");
1423
+ e.name = "AbortError";
1424
+ throw e;
1425
+ }
1426
+ return new Promise((resolve, reject) => {
1427
+ const state = { timeoutId: void 0 };
1428
+ const onAbort = () => {
1429
+ if (state.timeoutId) clearTimeout(state.timeoutId);
1430
+ const e = new Error("Sleep aborted");
1431
+ e.name = "AbortError";
1432
+ reject(e);
1433
+ };
1434
+ _workflowSignal?.addEventListener("abort", onAbort, { once: true });
1435
+ userSignal?.addEventListener("abort", onAbort, { once: true });
1436
+ state.timeoutId = setTimeout(() => {
1437
+ _workflowSignal?.removeEventListener("abort", onAbort);
1438
+ userSignal?.removeEventListener("abort", onAbort);
1439
+ resolve(ok2(void 0));
1440
+ }, ms);
1441
+ });
1442
+ },
1443
+ {
1444
+ key: options2?.key ?? id,
1445
+ description: options2?.description
1446
+ }
1447
+ );
1448
+ };
1449
+ stepFn.all = ((...args) => {
1450
+ if (typeof args[0] !== "string") {
1451
+ throw new TypeError(
1452
+ "step.all(name, ...): first argument must be a string (step name). Example: step.all('Fetch data', { user: () => fetchUser(), posts: () => fetchPosts() })"
1453
+ );
1454
+ }
1455
+ const name = args[0];
1456
+ const second = args[1];
1457
+ if (typeof second === "function") {
1458
+ return executeParallelArray2(name, second);
1459
+ }
1460
+ if (second && typeof second === "object" && !Array.isArray(second)) {
1461
+ const rawOperations = second;
1462
+ const normalizedOperations = normalizeParallelOperations2(rawOperations);
1463
+ return executeParallelNamed2(normalizedOperations, { name });
1464
+ }
1465
+ throw new TypeError(
1466
+ "step.all(name, ...): second argument must be a function (array form) or an object of operations (object form)."
1467
+ );
1468
+ });
1469
+ stepFn.race = (name, operation) => {
1470
+ const scopeId = `scope_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
1471
+ return (async () => {
1472
+ const startTime = performance.now();
1473
+ let scopeEnded = false;
1474
+ const scopeEntry = { scopeId, type: "race", winnerId: void 0 };
1475
+ activeScopeStack.push(scopeEntry);
1476
+ const emitScopeEnd = () => {
1477
+ if (scopeEnded) return;
1478
+ scopeEnded = true;
1479
+ const idx = activeScopeStack.findIndex((s) => s.scopeId === scopeId);
1480
+ if (idx !== -1) activeScopeStack.splice(idx, 1);
1481
+ emitEvent({
1482
+ type: "scope_end",
1483
+ workflowId,
1484
+ scopeId,
1485
+ ts: Date.now(),
1486
+ durationMs: performance.now() - startTime,
1487
+ winnerId: scopeEntry.winnerId
1488
+ });
1489
+ };
1490
+ emitEvent({
1491
+ type: "scope_start",
1492
+ workflowId,
1493
+ scopeId,
1494
+ scopeType: "race",
1495
+ name,
1496
+ ts: Date.now()
1497
+ });
1498
+ try {
1499
+ const result = await operation();
1500
+ emitScopeEnd();
1501
+ if (!result.ok) {
1502
+ onError?.(result.error, name, context);
1503
+ throw earlyExit(result.error, {
1504
+ origin: "result",
1505
+ resultCause: result.cause
1506
+ });
1507
+ }
1508
+ return result.value;
1509
+ } catch (error) {
1510
+ emitScopeEnd();
1511
+ throw error;
1512
+ }
1513
+ })();
1514
+ };
1515
+ stepFn.if = (id, conditionLabel, condition) => {
1516
+ assertDeclared(id, "decision");
1517
+ const value2 = condition();
1518
+ emitEvent({
1519
+ type: "decision",
1520
+ workflowId,
1521
+ decisionId: id,
1522
+ label: conditionLabel,
1523
+ branch: value2 ? "then" : "else",
1524
+ value: value2,
1525
+ ts: Date.now()
1526
+ });
1527
+ return value2;
1528
+ };
1529
+ stepFn.label = stepFn.if;
1530
+ stepFn.branch = async (id, options2) => {
1531
+ const { condition, then: thenFn, else: elseFn } = options2;
1532
+ assertDeclared(id, "decision");
1533
+ const conditionResult = condition();
1534
+ const branch = conditionResult ? "then" : "else";
1535
+ const startTime = performance.now();
1536
+ emitEvent({
1537
+ type: "decision",
1538
+ workflowId,
1539
+ decisionId: id,
1540
+ label: options2.conditionLabel,
1541
+ branch,
1542
+ value: conditionResult,
1543
+ phase: "start",
1544
+ ts: Date.now()
1545
+ });
1546
+ const emitEnd = () => {
1547
+ emitEvent({
1548
+ type: "decision",
1549
+ workflowId,
1550
+ decisionId: id,
1551
+ label: options2.conditionLabel,
1552
+ branch,
1553
+ value: conditionResult,
1554
+ phase: "end",
1555
+ durationMs: performance.now() - startTime,
1556
+ ts: Date.now()
1557
+ });
1558
+ };
1559
+ try {
1560
+ if (conditionResult) {
1561
+ return await thenFn();
1562
+ } else if (elseFn) {
1563
+ return await elseFn();
1564
+ }
1565
+ return void 0;
1566
+ } finally {
1567
+ emitEnd();
1568
+ }
1569
+ };
1570
+ stepFn.arm = (fn2, errors) => {
1571
+ return { fn: fn2, errors };
1572
+ };
1573
+ stepFn.forEach = async (_id, items, options2) => {
1574
+ const results = [];
1575
+ const maxIterations = options2.maxIterations;
1576
+ let index = 0;
1577
+ const isRunForm = "run" in options2;
1578
+ const asyncItems = Symbol.asyncIterator in items ? items : (async function* () {
1579
+ yield* items;
1580
+ })();
1581
+ for await (const item of asyncItems) {
1582
+ if (maxIterations !== void 0 && index >= maxIterations) {
1583
+ break;
1584
+ }
1585
+ let result;
1586
+ if (isRunForm) {
1587
+ const runOptions = options2;
1588
+ result = await runOptions.run(item, index);
1589
+ } else {
1590
+ const itemOptions = options2;
1591
+ result = await itemOptions.item.handler(item, index, stepFn);
1592
+ }
1593
+ results.push(result);
1594
+ index++;
1595
+ }
1596
+ return results;
1597
+ };
1598
+ stepFn.item = (handler) => {
1599
+ return {
1600
+ __forEachItemHandler: true,
1601
+ handler
1602
+ };
1603
+ };
1604
+ stepFn.dep = (_name, fn2) => {
1605
+ return fn2;
1606
+ };
1607
+ stepFn.workflow = (id, getter, options2) => {
1608
+ return stepFn(id, getter, options2);
1609
+ };
1610
+ stepFn.map = async (id, items, mapper, options2) => {
1611
+ const concurrency = options2?.concurrency ?? items.length;
1612
+ return stepFn(
1613
+ id,
1614
+ () => {
1615
+ if (concurrency >= items.length) {
1616
+ return allAsync(items.map((item, index) => mapper(item, index)));
1617
+ } else {
1618
+ return (async () => {
1619
+ const results = [];
1620
+ for (let i = 0; i < items.length; i += concurrency) {
1621
+ const batch = items.slice(i, i + concurrency);
1622
+ const batchResult = await allAsync(
1623
+ batch.map((item, batchIndex) => mapper(item, i + batchIndex))
1624
+ );
1625
+ if (!batchResult.ok) {
1626
+ return batchResult;
1627
+ }
1628
+ results.push(...batchResult.value);
1629
+ }
1630
+ return ok2(results);
1631
+ })();
1632
+ }
1633
+ },
1634
+ { key: options2?.key }
1635
+ );
1636
+ };
1637
+ stepFn.withFallback = (id, operation, options2) => {
1638
+ if (typeof id !== "string" || id.length === 0) {
1639
+ throw new Error(
1640
+ '[awaitly] step.withFallback() requires an explicit string ID as the first argument. Example: step.withFallback("getUser", () => fetchUser(id), { fallback: () => fetchFromCache(id) })'
1641
+ );
1642
+ }
1643
+ assertDeclared(id, "step");
1644
+ const stepKey = options2.key ?? id;
1645
+ const stepName = id;
1646
+ const stepId = generateStepId(stepKey);
1647
+ const hasEventListeners = onEvent;
1648
+ return (async () => {
1649
+ const startTime = hasEventListeners ? performance.now() : 0;
1650
+ if (onEvent) {
1651
+ emitEvent({
1652
+ type: "step_start",
1653
+ workflowId,
1654
+ stepId,
1655
+ stepKey,
1656
+ name: stepName,
1657
+ ts: Date.now()
1658
+ });
1659
+ }
1660
+ let primaryResult;
1661
+ try {
1662
+ primaryResult = await operation();
1663
+ } catch (thrown) {
1664
+ if (isEarlyExitE(thrown)) {
1665
+ emitEvent({
1666
+ type: "step_aborted",
1667
+ workflowId,
1668
+ stepId,
1669
+ stepKey,
1670
+ name: stepName,
1671
+ ts: Date.now(),
1672
+ durationMs: performance.now() - startTime
1673
+ });
1674
+ throw thrown;
1675
+ }
1676
+ let mappedError;
1677
+ try {
1678
+ mappedError = effectiveCatchUnexpected(thrown);
1679
+ } catch (mapperError) {
1680
+ throw createMapperException(mapperError);
1681
+ }
1682
+ if (options2.on !== void 0 && options2.on !== mappedError) {
1683
+ const durationMs2 = performance.now() - startTime;
1684
+ emitEvent({
1685
+ type: "step_error",
1686
+ workflowId,
1687
+ stepId,
1688
+ stepKey,
1689
+ name: stepName,
1690
+ ts: Date.now(),
1691
+ durationMs: durationMs2,
1692
+ error: mappedError
1693
+ });
1694
+ if (stepKey) {
1695
+ emitEvent({
1696
+ type: "step_complete",
1697
+ workflowId,
1698
+ stepKey,
1699
+ name: stepName,
1700
+ ts: Date.now(),
1701
+ durationMs: durationMs2,
1702
+ result: err2(mappedError, { cause: thrown }),
1703
+ meta: { origin: "throw", thrown }
1704
+ });
1705
+ }
1706
+ onError?.(mappedError, stepName, context);
1707
+ throw earlyExit(mappedError, { origin: "throw", thrown });
1708
+ }
1709
+ let fallbackResultFromThrow;
1710
+ try {
1711
+ fallbackResultFromThrow = await options2.fallback();
1712
+ } catch (fallbackThrown) {
1713
+ if (isEarlyExitE(fallbackThrown)) {
1714
+ emitEvent({
1715
+ type: "step_aborted",
1716
+ workflowId,
1717
+ stepId,
1718
+ stepKey,
1719
+ name: stepName,
1720
+ ts: Date.now(),
1721
+ durationMs: performance.now() - startTime
1722
+ });
1723
+ throw fallbackThrown;
1724
+ }
1725
+ let fallbackMappedError;
1726
+ try {
1727
+ fallbackMappedError = effectiveCatchUnexpected(fallbackThrown);
1728
+ } catch (mapperError) {
1729
+ throw createMapperException(mapperError);
1730
+ }
1731
+ const durationMs2 = performance.now() - startTime;
1732
+ emitEvent({
1733
+ type: "step_error",
1734
+ workflowId,
1735
+ stepId,
1736
+ stepKey,
1737
+ name: stepName,
1738
+ ts: Date.now(),
1739
+ durationMs: durationMs2,
1740
+ error: fallbackMappedError
1741
+ });
1742
+ if (stepKey) {
1743
+ emitEvent({
1744
+ type: "step_complete",
1745
+ workflowId,
1746
+ stepKey,
1747
+ name: stepName,
1748
+ ts: Date.now(),
1749
+ durationMs: durationMs2,
1750
+ result: err2(fallbackMappedError, { cause: fallbackThrown }),
1751
+ meta: { origin: "throw", thrown: fallbackThrown }
1752
+ });
1753
+ }
1754
+ onError?.(fallbackMappedError, stepName, context);
1755
+ throw earlyExit(fallbackMappedError, { origin: "throw", thrown: fallbackThrown });
1756
+ }
1757
+ if (fallbackResultFromThrow.ok) {
1758
+ const durationMs2 = performance.now() - startTime;
1759
+ emitEvent({
1760
+ type: "step_success",
1761
+ workflowId,
1762
+ stepId,
1763
+ stepKey,
1764
+ name: stepName,
1765
+ ts: Date.now(),
1766
+ durationMs: durationMs2
1767
+ });
1768
+ if (stepKey) {
1769
+ emitEvent({
1770
+ type: "step_complete",
1771
+ workflowId,
1772
+ stepKey,
1773
+ name: stepName,
1774
+ ts: Date.now(),
1775
+ durationMs: durationMs2,
1776
+ result: fallbackResultFromThrow,
1777
+ meta: { origin: "fallback", fallbackUsed: true, fallbackReason: String(mappedError) }
1778
+ });
1779
+ }
1780
+ return fallbackResultFromThrow.value;
1781
+ } else {
1782
+ const durationMs2 = performance.now() - startTime;
1783
+ const wrappedError2 = wrapForStep(fallbackResultFromThrow.error, {
1784
+ origin: "result",
1785
+ resultCause: fallbackResultFromThrow.cause
1786
+ });
1787
+ emitEvent({
1788
+ type: "step_error",
1789
+ workflowId,
1790
+ stepId,
1791
+ stepKey,
1792
+ name: stepName,
1793
+ ts: Date.now(),
1794
+ durationMs: durationMs2,
1795
+ error: wrappedError2
1796
+ });
1797
+ if (stepKey) {
1798
+ emitEvent({
1799
+ type: "step_complete",
1800
+ workflowId,
1801
+ stepKey,
1802
+ name: stepName,
1803
+ ts: Date.now(),
1804
+ durationMs: durationMs2,
1805
+ result: fallbackResultFromThrow,
1806
+ meta: { origin: "result", resultCause: fallbackResultFromThrow.cause }
1807
+ });
1808
+ }
1809
+ onError?.(wrappedError2, stepName, context);
1810
+ throw earlyExit(wrappedError2, {
1811
+ origin: "result",
1812
+ resultCause: fallbackResultFromThrow.cause
1813
+ });
1814
+ }
1815
+ }
1816
+ if (primaryResult.ok) {
1817
+ const durationMs2 = performance.now() - startTime;
1818
+ emitEvent({
1819
+ type: "step_success",
1820
+ workflowId,
1821
+ stepId,
1822
+ stepKey,
1823
+ name: stepName,
1824
+ ts: Date.now(),
1825
+ durationMs: durationMs2
1826
+ });
1827
+ if (stepKey) {
1828
+ emitEvent({
1829
+ type: "step_complete",
1830
+ workflowId,
1831
+ stepKey,
1832
+ name: stepName,
1833
+ ts: Date.now(),
1834
+ durationMs: durationMs2,
1835
+ result: primaryResult
1836
+ });
1837
+ }
1838
+ return primaryResult.value;
1839
+ }
1840
+ const primaryError = primaryResult.error;
1841
+ if (options2.on !== void 0 && options2.on !== primaryError) {
1842
+ const durationMs2 = performance.now() - startTime;
1843
+ const wrappedError2 = wrapForStep(primaryError, {
1844
+ origin: "result",
1845
+ resultCause: primaryResult.cause
1846
+ });
1847
+ emitEvent({
1848
+ type: "step_error",
1849
+ workflowId,
1850
+ stepId,
1851
+ stepKey,
1852
+ name: stepName,
1853
+ ts: Date.now(),
1854
+ durationMs: durationMs2,
1855
+ error: wrappedError2
1856
+ });
1857
+ if (stepKey) {
1858
+ emitEvent({
1859
+ type: "step_complete",
1860
+ workflowId,
1861
+ stepKey,
1862
+ name: stepName,
1863
+ ts: Date.now(),
1864
+ durationMs: durationMs2,
1865
+ result: primaryResult,
1866
+ meta: { origin: "result", resultCause: primaryResult.cause }
1867
+ });
1868
+ }
1869
+ onError?.(wrappedError2, stepName, context);
1870
+ throw earlyExit(wrappedError2, {
1871
+ origin: "result",
1872
+ resultCause: primaryResult.cause
1873
+ });
1874
+ }
1875
+ let fallbackResult;
1876
+ try {
1877
+ fallbackResult = await options2.fallback();
1878
+ } catch (thrown) {
1879
+ if (isEarlyExitE(thrown)) {
1880
+ emitEvent({
1881
+ type: "step_aborted",
1882
+ workflowId,
1883
+ stepId,
1884
+ stepKey,
1885
+ name: stepName,
1886
+ ts: Date.now(),
1887
+ durationMs: performance.now() - startTime
1888
+ });
1889
+ throw thrown;
1890
+ }
1891
+ let mappedError;
1892
+ try {
1893
+ mappedError = effectiveCatchUnexpected(thrown);
1894
+ } catch (mapperError) {
1895
+ throw createMapperException(mapperError);
1896
+ }
1897
+ const durationMs2 = performance.now() - startTime;
1898
+ emitEvent({
1899
+ type: "step_error",
1900
+ workflowId,
1901
+ stepId,
1902
+ stepKey,
1903
+ name: stepName,
1904
+ ts: Date.now(),
1905
+ durationMs: durationMs2,
1906
+ error: mappedError
1907
+ });
1908
+ if (stepKey) {
1909
+ emitEvent({
1910
+ type: "step_complete",
1911
+ workflowId,
1912
+ stepKey,
1913
+ name: stepName,
1914
+ ts: Date.now(),
1915
+ durationMs: durationMs2,
1916
+ result: err2(mappedError, { cause: thrown }),
1917
+ meta: { origin: "throw", thrown }
1918
+ });
1919
+ }
1920
+ onError?.(mappedError, stepName, context);
1921
+ throw earlyExit(mappedError, { origin: "throw", thrown });
1922
+ }
1923
+ if (fallbackResult.ok) {
1924
+ const durationMs2 = performance.now() - startTime;
1925
+ emitEvent({
1926
+ type: "step_success",
1927
+ workflowId,
1928
+ stepId,
1929
+ stepKey,
1930
+ name: stepName,
1931
+ ts: Date.now(),
1932
+ durationMs: durationMs2
1933
+ });
1934
+ if (stepKey) {
1935
+ emitEvent({
1936
+ type: "step_complete",
1937
+ workflowId,
1938
+ stepKey,
1939
+ name: stepName,
1940
+ ts: Date.now(),
1941
+ durationMs: durationMs2,
1942
+ result: fallbackResult,
1943
+ meta: { origin: "fallback", fallbackUsed: true, fallbackReason: String(primaryError) }
1944
+ });
1945
+ }
1946
+ return fallbackResult.value;
1947
+ }
1948
+ const durationMs = performance.now() - startTime;
1949
+ const wrappedError = wrapForStep(fallbackResult.error, {
1950
+ origin: "result",
1951
+ resultCause: fallbackResult.cause
1952
+ });
1953
+ emitEvent({
1954
+ type: "step_error",
1955
+ workflowId,
1956
+ stepId,
1957
+ stepKey,
1958
+ name: stepName,
1959
+ ts: Date.now(),
1960
+ durationMs,
1961
+ error: wrappedError
1962
+ });
1963
+ if (stepKey) {
1964
+ emitEvent({
1965
+ type: "step_complete",
1966
+ workflowId,
1967
+ stepKey,
1968
+ name: stepName,
1969
+ ts: Date.now(),
1970
+ durationMs,
1971
+ result: fallbackResult,
1972
+ meta: { origin: "result", resultCause: fallbackResult.cause }
1973
+ });
1974
+ }
1975
+ onError?.(wrappedError, stepName, context);
1976
+ throw earlyExit(wrappedError, {
1977
+ origin: "result",
1978
+ resultCause: fallbackResult.cause
1979
+ });
1980
+ })();
1981
+ };
1982
+ stepFn.withResource = (id, options2) => {
1983
+ if (typeof id !== "string" || id.length === 0) {
1984
+ throw new Error(
1985
+ '[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() })'
1986
+ );
1987
+ }
1988
+ assertDeclared(id, "step");
1989
+ const stepKey = id;
1990
+ const stepName = id;
1991
+ const stepId = generateStepId(stepKey);
1992
+ const hasEventListeners = onEvent;
1993
+ return (async () => {
1994
+ const startTime = hasEventListeners ? performance.now() : 0;
1995
+ if (onEvent) {
1996
+ emitEvent({
1997
+ type: "step_start",
1998
+ workflowId,
1999
+ stepId,
2000
+ stepKey,
2001
+ name: stepName,
2002
+ ts: Date.now()
2003
+ });
2004
+ }
2005
+ let acquireResult;
2006
+ try {
2007
+ acquireResult = await options2.acquire();
2008
+ } catch (thrown) {
2009
+ if (isEarlyExitE(thrown)) {
2010
+ emitEvent({
2011
+ type: "step_aborted",
2012
+ workflowId,
2013
+ stepId,
2014
+ stepKey,
2015
+ name: stepName,
2016
+ ts: Date.now(),
2017
+ durationMs: performance.now() - startTime
2018
+ });
2019
+ throw thrown;
2020
+ }
2021
+ let mappedError;
2022
+ try {
2023
+ mappedError = effectiveCatchUnexpected(thrown);
2024
+ } catch (mapperError) {
2025
+ throw createMapperException(mapperError);
2026
+ }
2027
+ const durationMs2 = performance.now() - startTime;
2028
+ emitEvent({
2029
+ type: "step_error",
2030
+ workflowId,
2031
+ stepId,
2032
+ stepKey,
2033
+ name: stepName,
2034
+ ts: Date.now(),
2035
+ durationMs: durationMs2,
2036
+ error: mappedError
2037
+ });
2038
+ if (stepKey) {
2039
+ emitEvent({
2040
+ type: "step_complete",
2041
+ workflowId,
2042
+ stepKey,
2043
+ name: stepName,
2044
+ ts: Date.now(),
2045
+ durationMs: durationMs2,
2046
+ result: err2(mappedError, { cause: thrown }),
2047
+ meta: { origin: "throw", thrown }
2048
+ });
2049
+ }
2050
+ onError?.(mappedError, stepName, context);
2051
+ throw earlyExit(mappedError, { origin: "throw", thrown });
2052
+ }
2053
+ if (!acquireResult.ok) {
2054
+ const durationMs2 = performance.now() - startTime;
2055
+ const wrappedError2 = wrapForStep(acquireResult.error, {
2056
+ origin: "result",
2057
+ resultCause: acquireResult.cause
2058
+ });
2059
+ emitEvent({
2060
+ type: "step_error",
2061
+ workflowId,
2062
+ stepId,
2063
+ stepKey,
2064
+ name: stepName,
2065
+ ts: Date.now(),
2066
+ durationMs: durationMs2,
2067
+ error: wrappedError2
2068
+ });
2069
+ if (stepKey) {
2070
+ emitEvent({
2071
+ type: "step_complete",
2072
+ workflowId,
2073
+ stepKey,
2074
+ name: stepName,
2075
+ ts: Date.now(),
2076
+ durationMs: durationMs2,
2077
+ result: acquireResult,
2078
+ meta: { origin: "result", resultCause: acquireResult.cause }
2079
+ });
2080
+ }
2081
+ onError?.(wrappedError2, stepName, context);
2082
+ throw earlyExit(wrappedError2, {
2083
+ origin: "result",
2084
+ resultCause: acquireResult.cause
2085
+ });
2086
+ }
2087
+ const resource = acquireResult.value;
2088
+ let useResult;
2089
+ let useThrown;
2090
+ let useThrewNonResult = false;
2091
+ try {
2092
+ useResult = await options2.use(resource);
2093
+ } catch (thrown) {
2094
+ if (isEarlyExitE(thrown)) {
2095
+ try {
2096
+ await options2.release(resource);
2097
+ } catch (releaseErr) {
2098
+ console.warn(
2099
+ `[awaitly] step.withResource("${id}"): release threw after earlyExit:`,
2100
+ releaseErr
2101
+ );
2102
+ }
2103
+ throw thrown;
2104
+ }
2105
+ useThrown = thrown;
2106
+ useThrewNonResult = true;
2107
+ }
2108
+ try {
2109
+ await options2.release(resource);
2110
+ } catch (releaseErr) {
2111
+ console.warn(
2112
+ `[awaitly] step.withResource("${id}"): release threw:`,
2113
+ releaseErr
2114
+ );
2115
+ }
2116
+ if (useThrewNonResult) {
2117
+ let mappedError;
2118
+ try {
2119
+ mappedError = effectiveCatchUnexpected(useThrown);
2120
+ } catch (mapperError) {
2121
+ throw createMapperException(mapperError);
2122
+ }
2123
+ const durationMs2 = performance.now() - startTime;
2124
+ emitEvent({
2125
+ type: "step_error",
2126
+ workflowId,
2127
+ stepId,
2128
+ stepKey,
2129
+ name: stepName,
2130
+ ts: Date.now(),
2131
+ durationMs: durationMs2,
2132
+ error: mappedError
2133
+ });
2134
+ if (stepKey) {
2135
+ emitEvent({
2136
+ type: "step_complete",
2137
+ workflowId,
2138
+ stepKey,
2139
+ name: stepName,
2140
+ ts: Date.now(),
2141
+ durationMs: durationMs2,
2142
+ result: err2(mappedError, { cause: useThrown }),
2143
+ meta: { origin: "throw", thrown: useThrown }
2144
+ });
2145
+ }
2146
+ onError?.(mappedError, stepName, context);
2147
+ throw earlyExit(mappedError, { origin: "throw", thrown: useThrown });
2148
+ }
2149
+ const result = useResult;
2150
+ if (result.ok) {
2151
+ const durationMs2 = performance.now() - startTime;
2152
+ emitEvent({
2153
+ type: "step_success",
2154
+ workflowId,
2155
+ stepId,
2156
+ stepKey,
2157
+ name: stepName,
2158
+ ts: Date.now(),
2159
+ durationMs: durationMs2
2160
+ });
2161
+ if (stepKey) {
2162
+ emitEvent({
2163
+ type: "step_complete",
2164
+ workflowId,
2165
+ stepKey,
2166
+ name: stepName,
2167
+ ts: Date.now(),
2168
+ durationMs: durationMs2,
2169
+ result
2170
+ });
2171
+ }
2172
+ return result.value;
2173
+ }
2174
+ const durationMs = performance.now() - startTime;
2175
+ const wrappedError = wrapForStep(result.error, {
2176
+ origin: "result",
2177
+ resultCause: result.cause
2178
+ });
2179
+ emitEvent({
2180
+ type: "step_error",
2181
+ workflowId,
2182
+ stepId,
2183
+ stepKey,
2184
+ name: stepName,
2185
+ ts: Date.now(),
2186
+ durationMs,
2187
+ error: wrappedError
2188
+ });
2189
+ if (stepKey) {
2190
+ emitEvent({
2191
+ type: "step_complete",
2192
+ workflowId,
2193
+ stepKey,
2194
+ name: stepName,
2195
+ ts: Date.now(),
2196
+ durationMs,
2197
+ result,
2198
+ meta: { origin: "result", resultCause: result.cause }
2199
+ });
2200
+ }
2201
+ onError?.(wrappedError, stepName, context);
2202
+ throw earlyExit(wrappedError, {
2203
+ origin: "result",
2204
+ resultCause: result.cause
2205
+ });
2206
+ })();
2207
+ };
2208
+ const step = stepFn;
2209
+ const value = await fn({ step });
2210
+ if (process.env.NODE_ENV !== "production" && value !== null && typeof value === "object" && "ok" in value && typeof value.ok === "boolean") {
2211
+ const maybeResult = value;
2212
+ if (maybeResult.ok === true && "value" in maybeResult || maybeResult.ok === false && "error" in maybeResult) {
2213
+ console.warn(
2214
+ `awaitly: Workflow executor returned a Result-like object. Return raw values, not ok() or err().
2215
+
2216
+ Incorrect: return ok({ data });
2217
+ Correct: return { data };
2218
+
2219
+ See: https://jagreehal.github.io/awaitly/guides/troubleshooting/#returning-ok-from-workflow-executor-double-wrapping`
2220
+ );
2221
+ }
2222
+ }
2223
+ return ok2(value);
2224
+ } catch (error) {
2225
+ if (isMapperException(error)) {
2226
+ throw error.thrown;
2227
+ }
2228
+ if (isEarlyExitE(error)) {
2229
+ const originalCause = error.meta.origin === "throw" ? error.meta.thrown : error.meta.origin === "result" ? error.meta.resultCause : void 0;
2230
+ return err2(error.error, { cause: originalCause });
2231
+ }
2232
+ const mapped = effectiveCatchUnexpected(error);
2233
+ onError?.(mapped, "unexpected", context);
2234
+ return err2(mapped, { cause: error });
2235
+ }
2236
+ }
2237
+ var runStrict = (fn, options) => {
2238
+ return runFn(fn, options);
2239
+ };
2240
+ var run = /* @__PURE__ */ Object.assign(runFn, { strict: runStrict });
2241
+ async function allAsync(results) {
2242
+ if (results.length === 0) {
2243
+ return ok2([]);
2244
+ }
2245
+ return new Promise((resolve) => {
2246
+ let settled = false;
2247
+ let pendingCount = results.length;
2248
+ const values = new Array(results.length);
2249
+ for (let i = 0; i < results.length; i++) {
2250
+ const index = i;
2251
+ Promise.resolve(results[index]).catch((reason) => err2(
2252
+ { type: "PROMISE_REJECTED", cause: reason },
2253
+ { cause: { type: "PROMISE_REJECTION", reason } }
2254
+ )).then((result) => {
2255
+ if (settled) return;
2256
+ if (!result.ok) {
2257
+ settled = true;
2258
+ resolve(result);
2259
+ return;
2260
+ }
2261
+ values[index] = result.value;
2262
+ pendingCount--;
2263
+ if (pendingCount === 0) {
2264
+ resolve(ok2(values));
2265
+ }
2266
+ });
2267
+ }
2268
+ });
2269
+ }
2270
+ // Annotate the CommonJS export names for ESM import in node:
2271
+ 0 && (module.exports = {
2272
+ EARLY_EXIT_SYMBOL,
2273
+ STEP_TIMEOUT_MARKER,
2274
+ createEarlyExit,
2275
+ fallback,
2276
+ getStepTimeoutMeta,
2277
+ isEarlyExit,
2278
+ isStepTimeoutError,
2279
+ retry,
2280
+ run,
2281
+ timeout
2282
+ });
2283
+ //# sourceMappingURL=run.cjs.map