@workflow/world-testing 4.1.15 → 4.1.17

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.
@@ -50439,7 +50439,7 @@ init_dist();
50439
50439
  init_node();
50440
50440
 
50441
50441
  // ../core/dist/version.js
50442
- var version2 = "4.8.0";
50442
+ var version2 = "4.8.2";
50443
50443
 
50444
50444
  // ../core/dist/runtime/world.js
50445
50445
  var import_node_module = require("node:module");
@@ -53391,7 +53391,6 @@ init_zod();
53391
53391
  // ../world-vercel/dist/http-client.js
53392
53392
  var import_undici2 = __toESM(require_undici(), 1);
53393
53393
  var _dispatcher;
53394
- var _eventsDispatcher;
53395
53394
  var _streamDispatcher;
53396
53395
  var _streamCloseDispatcher;
53397
53396
  var DEFAULT_HEADERS_TIMEOUT_MS = 3e4;
@@ -53450,6 +53449,14 @@ function getEventsAgentOptions() {
53450
53449
  };
53451
53450
  }
53452
53451
  __name(getEventsAgentOptions, "getEventsAgentOptions");
53452
+ function getEventsAgentOptionsNoH2() {
53453
+ return {
53454
+ ...getBaseAgentOptions(),
53455
+ allowH2: false,
53456
+ pipelining: 1
53457
+ };
53458
+ }
53459
+ __name(getEventsAgentOptionsNoH2, "getEventsAgentOptionsNoH2");
53453
53460
  function getStreamAgentOptions() {
53454
53461
  return {
53455
53462
  ...getBaseAgentOptions(),
@@ -53488,10 +53495,10 @@ var STREAM_CLOSE_RETRY_OPTIONS = {
53488
53495
  statusCodes: [429, 500, 502, 503, 504]
53489
53496
  };
53490
53497
  var H2_REBUFFER_MAX_BYTES = 1 << 20;
53491
- function h2MultiplexEnabled() {
53498
+ function h2EventsEnabled() {
53492
53499
  return process.env.WORKFLOW_H2_MULTIPLEX !== "0";
53493
53500
  }
53494
- __name(h2MultiplexEnabled, "h2MultiplexEnabled");
53501
+ __name(h2EventsEnabled, "h2EventsEnabled");
53495
53502
  function contentLength(headers) {
53496
53503
  if (!headers || typeof headers !== "object" || Array.isArray(headers)) {
53497
53504
  return Number.NaN;
@@ -53524,12 +53531,86 @@ function h2MultiplexInterceptor(dispatch) {
53524
53531
  };
53525
53532
  }
53526
53533
  __name(h2MultiplexInterceptor, "h2MultiplexInterceptor");
53534
+ var EVENTS_RECYCLE_AFTER_CONSECUTIVE_FAILURES = 3;
53535
+ var RECYCLE_MIN_INTERVAL_MS = 5e3;
53536
+ var RETIRED_CLOSE_DELAY_MS = 5e3;
53537
+ var RETIRED_DESTROY_DELAY_MS = 6e4;
53538
+ var RECYCLABLE_ERROR_CODES = /* @__PURE__ */ new Set([
53539
+ // Covers H2 stream timeout, frameError and GOAWAY (undici InformationalError).
53540
+ "UND_ERR_INFO",
53541
+ "UND_ERR_HEADERS_TIMEOUT",
53542
+ "UND_ERR_BODY_TIMEOUT"
53543
+ ]);
53544
+ var MAX_CAUSE_DEPTH = 8;
53545
+ function isRecyclableTransportError(error48) {
53546
+ let current = error48;
53547
+ for (let depth = 0; current && depth < MAX_CAUSE_DEPTH; depth++) {
53548
+ const code = current.code;
53549
+ if (typeof code === "string" && RECYCLABLE_ERROR_CODES.has(code)) {
53550
+ return true;
53551
+ }
53552
+ current = current.cause;
53553
+ }
53554
+ return false;
53555
+ }
53556
+ __name(isRecyclableTransportError, "isRecyclableTransportError");
53557
+ function createDispatcherRecycler(factory, label) {
53558
+ let current;
53559
+ let consecutiveFailures = 0;
53560
+ let lastRecycledAt = 0;
53561
+ function retire(stale) {
53562
+ const closeTimer = setTimeout(() => {
53563
+ void Promise.resolve(stale.close?.()).catch(() => void 0);
53564
+ }, RETIRED_CLOSE_DELAY_MS);
53565
+ const destroyTimer = setTimeout(() => {
53566
+ void Promise.resolve(stale.destroy?.()).catch(() => void 0);
53567
+ }, RETIRED_DESTROY_DELAY_MS);
53568
+ closeTimer.unref?.();
53569
+ destroyTimer.unref?.();
53570
+ }
53571
+ __name(retire, "retire");
53572
+ return {
53573
+ get() {
53574
+ current ??= factory();
53575
+ return current;
53576
+ },
53577
+ note(dispatcher, error48) {
53578
+ if (!current || dispatcher !== current)
53579
+ return;
53580
+ if (error48 === void 0) {
53581
+ consecutiveFailures = 0;
53582
+ return;
53583
+ }
53584
+ if (!isRecyclableTransportError(error48))
53585
+ return;
53586
+ consecutiveFailures++;
53587
+ if (consecutiveFailures < EVENTS_RECYCLE_AFTER_CONSECUTIVE_FAILURES) {
53588
+ return;
53589
+ }
53590
+ const now = Date.now();
53591
+ if (now - lastRecycledAt < RECYCLE_MIN_INTERVAL_MS)
53592
+ return;
53593
+ lastRecycledAt = now;
53594
+ consecutiveFailures = 0;
53595
+ const stale = current;
53596
+ current = void 0;
53597
+ console.warn(`[workflow] ${label}: rebuilding connection pool after ${EVENTS_RECYCLE_AFTER_CONSECUTIVE_FAILURES} consecutive transport failures`);
53598
+ retire(stale);
53599
+ }
53600
+ };
53601
+ }
53602
+ __name(createDispatcherRecycler, "createDispatcherRecycler");
53603
+ var eventsRecycler = createDispatcherRecycler(() => createEventsDispatcher(), "events transport");
53604
+ function noteEventsTransportOutcome(dispatcher, error48) {
53605
+ eventsRecycler.note(dispatcher, error48);
53606
+ }
53607
+ __name(noteEventsTransportOutcome, "noteEventsTransportOutcome");
53527
53608
  function getDispatcher(config3) {
53528
53609
  return config3?.dispatcher ?? getDefaultDispatcher();
53529
53610
  }
53530
53611
  __name(getDispatcher, "getDispatcher");
53531
53612
  function getEventsDispatcher(config3) {
53532
- return config3?.dispatcher ?? getDefaultEventsDispatcher();
53613
+ return config3?.dispatcher ?? eventsRecycler.get();
53533
53614
  }
53534
53615
  __name(getEventsDispatcher, "getEventsDispatcher");
53535
53616
  function getStreamDispatcher(config3) {
@@ -53541,8 +53622,12 @@ function getStreamCloseDispatcher(config3) {
53541
53622
  }
53542
53623
  __name(getStreamCloseDispatcher, "getStreamCloseDispatcher");
53543
53624
  function createEventsDispatcher(agentOverrides) {
53544
- const agent = new import_undici2.RetryAgent(new import_undici2.Agent({ ...getEventsAgentOptions(), ...agentOverrides }), getRetryAgentOptions());
53545
- if (!h2MultiplexEnabled()) {
53625
+ const h2 = h2EventsEnabled();
53626
+ const agent = new import_undici2.RetryAgent(new import_undici2.Agent({
53627
+ ...h2 ? getEventsAgentOptions() : getEventsAgentOptionsNoH2(),
53628
+ ...agentOverrides
53629
+ }), getRetryAgentOptions());
53630
+ if (!h2) {
53546
53631
  return agent;
53547
53632
  }
53548
53633
  return withBoundLifecycle(agent, agent.compose(h2MultiplexInterceptor));
@@ -53563,11 +53648,6 @@ function getDefaultDispatcher() {
53563
53648
  return _dispatcher;
53564
53649
  }
53565
53650
  __name(getDefaultDispatcher, "getDefaultDispatcher");
53566
- function getDefaultEventsDispatcher() {
53567
- _eventsDispatcher ??= createEventsDispatcher();
53568
- return _eventsDispatcher;
53569
- }
53570
- __name(getDefaultEventsDispatcher, "getDefaultEventsDispatcher");
53571
53651
  function getDefaultStreamDispatcher() {
53572
53652
  _streamDispatcher ??= createStreamDispatcher(STREAM_RETRY_OPTIONS);
53573
53653
  return _streamDispatcher;
@@ -53762,7 +53842,7 @@ function httpClientSpanAttributes(args) {
53762
53842
  }
53763
53843
  __name(httpClientSpanAttributes, "httpClientSpanAttributes");
53764
53844
  async function instrumentedFetch(opts) {
53765
- const { method, url: url2, headers, body, dispatcher, peerService = "workflow-server", timeoutMs = REQUEST_TIMEOUT_MS, signal: callerSignal, injectTraceContext = true, cacheBust = true, logLabel, buildError } = opts;
53845
+ const { method, url: url2, headers, body, dispatcher, peerService = "workflow-server", timeoutMs = REQUEST_TIMEOUT_MS, signal: callerSignal, injectTraceContext = true, cacheBust = true, logLabel, buildError, onTransportOutcome } = opts;
53766
53846
  const label = logLabel ?? url2;
53767
53847
  return trace4(`http ${method}`, { kind: await getSpanKind3("CLIENT") }, async (span) => {
53768
53848
  span?.setAttributes(httpClientSpanAttributes({ method, url: url2, peerService }));
@@ -53785,6 +53865,7 @@ async function instrumentedFetch(opts) {
53785
53865
  });
53786
53866
  } catch (error48) {
53787
53867
  const elapsed = Date.now() - start2;
53868
+ onTransportOutcome?.(error48);
53788
53869
  if (error48 instanceof Error && (error48.name === "TimeoutError" || error48.name === "AbortError")) {
53789
53870
  const timeoutError = new WorkflowWorldError(`${method} ${label} timed out after ${elapsed}ms`, { url: url2, cause: error48 });
53790
53871
  span?.setAttributes({ ...ErrorType2("TIMEOUT") });
@@ -53794,6 +53875,7 @@ async function instrumentedFetch(opts) {
53794
53875
  throw error48;
53795
53876
  }
53796
53877
  const ms2 = Date.now() - start2;
53878
+ onTransportOutcome?.();
53797
53879
  httpLog(method, label, response, ms2);
53798
53880
  span?.setAttributes({ ...HttpResponseStatusCode2(response.status) });
53799
53881
  if (!response.ok) {
@@ -60949,7 +61031,7 @@ var import_oidc3 = __toESM(require_dist(), 1);
60949
61031
  init_dist();
60950
61032
 
60951
61033
  // ../world-vercel/dist/version.js
60952
- var version3 = "4.6.1";
61034
+ var version3 = "4.6.2";
60953
61035
 
60954
61036
  // ../world-vercel/dist/utils.js
60955
61037
  var WORKFLOW_SERVER_URL_OVERRIDE = "";
@@ -61767,12 +61849,18 @@ __name(readerToIterator, "readerToIterator");
61767
61849
 
61768
61850
  // ../world-vercel/dist/events-v4.js
61769
61851
  async function fetchV4(url2, init, config3, opName) {
61852
+ const dispatcher = getEventsDispatcher(config3);
61770
61853
  return instrumentedFetch({
61771
61854
  method: init.method,
61772
61855
  url: url2,
61773
61856
  headers: init.headers,
61774
61857
  body: init.body,
61775
- dispatcher: getEventsDispatcher(config3),
61858
+ dispatcher,
61859
+ // Repeated transport failures retire the shared events pool and the next
61860
+ // request builds a fresh one. undici keeps a black-holed HTTP/2 session in
61861
+ // service indefinitely, so without this every request routed onto it fails
61862
+ // until the compute instance is recycled — see noteEventsTransportOutcome.
61863
+ onTransportOutcome: /* @__PURE__ */ __name((error48) => noteEventsTransportOutcome(dispatcher, error48), "onTransportOutcome"),
61776
61864
  timeoutMs: null,
61777
61865
  logLabel: opName,
61778
61866
  buildError: /* @__PURE__ */ __name(async (response) => errorFromV4Response(response.status, headersToRecord(response.headers), await response.text(), opName, url2), "buildError")
@@ -63947,30 +64035,74 @@ function getStepFunction(stepId) {
63947
64035
  return void 0;
63948
64036
  }
63949
64037
  __name(getStepFunction, "getStepFunction");
63950
- async function awaitEarlierDeliveries(ctx, eventIndex, deferBehindKinds) {
64038
+ var DEFER_BEHIND = {
64039
+ hook: ["wait", "step"],
64040
+ wait: ["hook", "step"],
64041
+ step: ["wait", "hook", "step"]
64042
+ };
64043
+ function resolvesOnItsOwn(barriers, index, entry, memo) {
64044
+ const cached2 = memo.get(index);
64045
+ if (cached2 !== void 0) {
64046
+ return cached2;
64047
+ }
64048
+ const result = computeResolvesOnItsOwn(barriers, index, entry, memo);
64049
+ memo.set(index, result);
64050
+ return result;
64051
+ }
64052
+ __name(resolvesOnItsOwn, "resolvesOnItsOwn");
64053
+ function computeResolvesOnItsOwn(barriers, index, entry, memo) {
64054
+ if (!entry.armed) {
64055
+ return false;
64056
+ }
64057
+ if (entry.kind === "step") {
64058
+ return true;
64059
+ }
64060
+ const deferBehind = DEFER_BEHIND[entry.kind];
64061
+ for (const [otherIndex, other] of barriers) {
64062
+ if (otherIndex < index && deferBehind.includes(other.kind) && !resolvesOnItsOwn(barriers, otherIndex, other, memo)) {
64063
+ return false;
64064
+ }
64065
+ }
64066
+ return true;
64067
+ }
64068
+ __name(computeResolvesOnItsOwn, "computeResolvesOnItsOwn");
64069
+ async function awaitEarlierDeliveries(ctx, eventIndex, kind) {
63951
64070
  if (eventIndex === void 0 || !ctx.pendingDeliveryBarriers || ctx.pendingDeliveryBarriers.size === 0) {
63952
64071
  return;
63953
64072
  }
64073
+ const barriers = ctx.pendingDeliveryBarriers;
64074
+ const deferBehind = DEFER_BEHIND[kind];
63954
64075
  const earlier = [];
63955
- for (const [index, entry] of ctx.pendingDeliveryBarriers) {
63956
- if (index < eventIndex && deferBehindKinds.includes(entry.kind)) {
63957
- earlier.push(entry.delivered);
64076
+ const selfResolving = /* @__PURE__ */ new Map();
64077
+ for (const [index, entry] of barriers) {
64078
+ if (index >= eventIndex || !deferBehind.includes(entry.kind)) {
64079
+ continue;
64080
+ }
64081
+ if (kind === "step" && !resolvesOnItsOwn(barriers, index, entry, selfResolving)) {
64082
+ continue;
63958
64083
  }
64084
+ earlier.push(entry.delivered);
63959
64085
  }
63960
64086
  if (earlier.length > 0) {
63961
64087
  await Promise.all(earlier);
64088
+ await new Promise((resolve3) => setTimeout(resolve3, 0));
63962
64089
  }
63963
64090
  }
63964
64091
  __name(awaitEarlierDeliveries, "awaitEarlierDeliveries");
63965
- function registerDeliveryBarrier(ctx, eventIndex, kind) {
64092
+ function registerDeliveryBarrier(ctx, eventIndex, kind, options = {}) {
63966
64093
  const barriers = ctx.pendingDeliveryBarriers;
63967
64094
  if (!barriers || eventIndex === void 0) {
63968
64095
  return { markDelivered: /* @__PURE__ */ __name(() => {
63969
- }, "markDelivered") };
64096
+ }, "markDelivered"), arm: /* @__PURE__ */ __name(() => {
64097
+ }, "arm") };
63970
64098
  }
63971
64099
  let done = false;
63972
64100
  const { promise: promise2, resolve: resolve3 } = withResolvers();
63973
- const entry = { kind, delivered: promise2 };
64101
+ const entry = {
64102
+ kind,
64103
+ delivered: promise2,
64104
+ armed: options.armed ?? true
64105
+ };
63974
64106
  barriers.set(eventIndex, entry);
63975
64107
  const finish = /* @__PURE__ */ __name(() => {
63976
64108
  if (done) {
@@ -63983,12 +64115,35 @@ function registerDeliveryBarrier(ctx, eventIndex, kind) {
63983
64115
  resolve3();
63984
64116
  }, "finish");
63985
64117
  scheduleWhenIdle(ctx, finish);
63986
- return { markDelivered: finish };
64118
+ return {
64119
+ markDelivered: finish,
64120
+ arm: /* @__PURE__ */ __name(() => {
64121
+ entry.armed = true;
64122
+ }, "arm")
64123
+ };
63987
64124
  }
63988
64125
  __name(registerDeliveryBarrier, "registerDeliveryBarrier");
64126
+ function hasParkedCommittedDelivery(ctx) {
64127
+ const barriers = ctx.pendingDeliveryBarriers;
64128
+ if (!barriers || barriers.size === 0) {
64129
+ return false;
64130
+ }
64131
+ const selfResolving = /* @__PURE__ */ new Map();
64132
+ for (const [index, entry] of barriers) {
64133
+ if (resolvesOnItsOwn(barriers, index, entry, selfResolving)) {
64134
+ return true;
64135
+ }
64136
+ }
64137
+ return false;
64138
+ }
64139
+ __name(hasParkedCommittedDelivery, "hasParkedCommittedDelivery");
64140
+ function isDeliveryIdle(ctx) {
64141
+ return ctx.pendingDeliveries === 0 && !hasParkedCommittedDelivery(ctx);
64142
+ }
64143
+ __name(isDeliveryIdle, "isDeliveryIdle");
63989
64144
  function scheduleWhenIdle(ctx, fn) {
63990
64145
  const check2 = /* @__PURE__ */ __name(() => {
63991
- if (ctx.pendingDeliveries > 0) {
64146
+ if (!isDeliveryIdle(ctx)) {
63992
64147
  ctx.promiseQueue.then(() => {
63993
64148
  setTimeout(check2, 0);
63994
64149
  });
@@ -66079,6 +66234,7 @@ __name(customRandom, "customRandom");
66079
66234
  init_node();
66080
66235
 
66081
66236
  // ../core/dist/events-consumer.js
66237
+ var DEFERRED_CHECK_DELAY_MS = 100;
66082
66238
  var EventConsumerResult;
66083
66239
  (function(EventConsumerResult2) {
66084
66240
  EventConsumerResult2[EventConsumerResult2["Consumed"] = 0] = "Consumed";
@@ -66095,6 +66251,7 @@ var EventsConsumer = class {
66095
66251
  onConsumedEvent;
66096
66252
  onUnconsumedEvent;
66097
66253
  getPromiseQueue;
66254
+ isDeliveryIdle;
66098
66255
  pendingUnconsumedCheck = null;
66099
66256
  pendingUnconsumedTimeout = null;
66100
66257
  unconsumedCheckVersion = 0;
@@ -66104,6 +66261,7 @@ var EventsConsumer = class {
66104
66261
  this.onConsumedEvent = options.onConsumedEvent;
66105
66262
  this.onUnconsumedEvent = options.onUnconsumedEvent;
66106
66263
  this.getPromiseQueue = options.getPromiseQueue;
66264
+ this.isDeliveryIdle = options.isDeliveryIdle ?? (() => true);
66107
66265
  }
66108
66266
  /**
66109
66267
  * Registers a callback function to be called after an event has been consumed
@@ -66187,16 +66345,58 @@ var EventsConsumer = class {
66187
66345
  // resumes -> the next hook payload starts hydrating).
66188
66346
  () => new Promise((resolve3) => setTimeout(resolve3, 0))
66189
66347
  ).then(() => this.getPromiseQueue()).then(() => {
66190
- this.pendingUnconsumedTimeout = setTimeout(() => {
66191
- this.pendingUnconsumedTimeout = null;
66192
- if (this.unconsumedCheckVersion === checkVersion) {
66193
- this.pendingUnconsumedCheck = null;
66194
- this.onUnconsumedEvent(currentEvent);
66195
- }
66196
- }, 100);
66348
+ this.whenDeliveryIdle(checkVersion, () => {
66349
+ this.pendingUnconsumedTimeout = setTimeout(() => {
66350
+ this.pendingUnconsumedTimeout = null;
66351
+ if (this.unconsumedCheckVersion === checkVersion) {
66352
+ this.pendingUnconsumedCheck = null;
66353
+ this.onUnconsumedEvent(currentEvent);
66354
+ }
66355
+ }, DEFERRED_CHECK_DELAY_MS);
66356
+ });
66197
66357
  });
66198
66358
  }
66199
66359
  }
66360
+ /**
66361
+ * Run `fn` once no data delivery is in flight, polling the way
66362
+ * `scheduleWhenIdle` does: let the promise queue drain, re-check a timer
66363
+ * tick later, repeat.
66364
+ *
66365
+ * Without this the check is a bet that every delivery the walk is running
66366
+ * ahead of lands inside a fixed window. Consumption is synchronous while the
66367
+ * resolution it triggers is not: a step result hydrates in the host, resolves
66368
+ * from a detached continuation behind `awaitEarlierDeliveries`, and only then
66369
+ * does VM code run far enough to subscribe the next consumer. Replaying a
66370
+ * batch of N parallel step results leaves N-1 of them on that detached path
66371
+ * with the queue already drained, so the walk sits on the ordered event the
66372
+ * VM is about to draw and the window is the only thing standing between a
66373
+ * healthy run and `ReplayDivergenceError`. On a backend whose deliveries take
66374
+ * longer than the window, that bet loses.
66375
+ *
66376
+ * Termination is `hasParkedCommittedDelivery`'s: it counts only deliveries
66377
+ * that resolve on their own, so nothing here can gate its own retirement. A
66378
+ * genuinely orphaned event has no delivery to wait on and reaches `fn` on the
66379
+ * first poll.
66380
+ */
66381
+ whenDeliveryIdle(checkVersion, fn) {
66382
+ const poll = /* @__PURE__ */ __name(() => {
66383
+ this.pendingUnconsumedTimeout = null;
66384
+ if (this.unconsumedCheckVersion !== checkVersion) {
66385
+ return;
66386
+ }
66387
+ if (this.isDeliveryIdle()) {
66388
+ fn();
66389
+ return;
66390
+ }
66391
+ this.getPromiseQueue().then(() => {
66392
+ if (this.unconsumedCheckVersion !== checkVersion) {
66393
+ return;
66394
+ }
66395
+ this.pendingUnconsumedTimeout = setTimeout(poll, 0);
66396
+ });
66397
+ }, "poll");
66398
+ poll();
66399
+ }
66200
66400
  };
66201
66401
 
66202
66402
  // ../core/dist/runtime/get-port-lazy.js
@@ -66323,6 +66523,9 @@ function createUseStep(ctx) {
66323
66523
  }
66324
66524
  if (event.eventType === "step_failed") {
66325
66525
  ctx.invocationsQueue.delete(event.correlationId);
66526
+ const eventIndex = ctx.eventsConsumer.eventIndex;
66527
+ const barrier = registerDeliveryBarrier(ctx, eventIndex, "step");
66528
+ const earlierDelivered = awaitEarlierDeliveries(ctx, eventIndex, "step");
66326
66529
  ctx.promiseQueue = ctx.promiseQueue.then(() => {
66327
66530
  const errorData = event.eventData.error;
66328
66531
  const isErrorObject = typeof errorData === "object" && errorData !== null;
@@ -66332,7 +66535,10 @@ function createUseStep(ctx) {
66332
66535
  if (errorStack) {
66333
66536
  error48.stack = errorStack;
66334
66537
  }
66335
- reject(error48);
66538
+ void earlierDelivered.then(() => {
66539
+ barrier.markDelivered();
66540
+ reject(error48);
66541
+ });
66336
66542
  });
66337
66543
  return EventConsumerResult.Finished;
66338
66544
  }
@@ -66340,16 +66546,28 @@ function createUseStep(ctx) {
66340
66546
  ctx.invocationsQueue.delete(event.correlationId);
66341
66547
  const completedEventId = event.eventId;
66342
66548
  const serializedResult = event.eventData.result;
66549
+ const eventIndex = ctx.eventsConsumer.eventIndex;
66550
+ const barrier = registerDeliveryBarrier(ctx, eventIndex, "step");
66551
+ let outcome;
66552
+ const earlierDelivered = awaitEarlierDeliveries(ctx, eventIndex, "step");
66343
66553
  ctx.pendingDeliveries++;
66344
66554
  ctx.promiseQueue = ctx.promiseQueue.then(async () => {
66345
66555
  try {
66346
66556
  const hydratedResult = await getOrHydrateStepReturnValue(ctx.stepHydrationCache, completedEventId, () => hydrateStepReturnValue(serializedResult, ctx.runId, ctx.encryptionKey, ctx.globalThis));
66347
- resolve3(hydratedResult);
66557
+ outcome = { ok: true, value: hydratedResult };
66348
66558
  } catch (error48) {
66349
- reject(error48);
66559
+ outcome = { ok: false, error: error48 };
66350
66560
  } finally {
66351
66561
  ctx.pendingDeliveries--;
66352
66562
  }
66563
+ void earlierDelivered.then(() => {
66564
+ barrier.markDelivered();
66565
+ if (outcome.ok) {
66566
+ resolve3(outcome.value);
66567
+ } else {
66568
+ reject(outcome.error);
66569
+ }
66570
+ });
66353
66571
  });
66354
66572
  return EventConsumerResult.Finished;
66355
66573
  }
@@ -66823,10 +67041,10 @@ function createContext(options) {
66823
67041
  g.Math.random = rng;
66824
67042
  const Date_ = g.Date;
66825
67043
  g.Date = /* @__PURE__ */ __name(function Date2(...args) {
66826
- if (args.length === 0) {
66827
- return new Date_(fixedTimestamp);
67044
+ if (new.target === void 0) {
67045
+ return new Date_(fixedTimestamp).toString();
66828
67046
  }
66829
- return new Date_(...args);
67047
+ return Reflect.construct(Date_, args.length === 0 ? [fixedTimestamp] : args, new.target);
66830
67048
  }, "Date");
66831
67049
  g.Date.prototype = Date_.prototype;
66832
67050
  Object.setPrototypeOf(g.Date, Date_);
@@ -67030,8 +67248,12 @@ function createCreateHook(ctx) {
67030
67248
  }
67031
67249
  if (event.eventType === "hook_received") {
67032
67250
  const eventIndex = ctx.eventsConsumer.eventIndex;
67033
- const barrier = registerDeliveryBarrier(ctx, eventIndex, "hook");
67034
- if (promises.length > 0) {
67251
+ const hasWaitingConsumer = promises.length > 0;
67252
+ const barrier = registerDeliveryBarrier(ctx, eventIndex, "hook", {
67253
+ armed: hasWaitingConsumer
67254
+ });
67255
+ if (hasWaitingConsumer) {
67256
+ const earlierDelivered = awaitEarlierDeliveries(ctx, eventIndex, "hook");
67035
67257
  const next2 = promises.shift();
67036
67258
  if (next2) {
67037
67259
  ctx.pendingDeliveries++;
@@ -67045,7 +67267,7 @@ function createCreateHook(ctx) {
67045
67267
  } finally {
67046
67268
  ctx.pendingDeliveries--;
67047
67269
  }
67048
- void awaitEarlierDeliveries(ctx, eventIndex, ["wait"]).then(() => {
67270
+ void earlierDelivered.then(() => {
67049
67271
  barrier.markDelivered();
67050
67272
  if (hydrateOutcome.ok) {
67051
67273
  next2.resolve(hydrateOutcome.value);
@@ -67058,13 +67280,16 @@ function createCreateHook(ctx) {
67058
67280
  } else {
67059
67281
  let outcome;
67060
67282
  const hydrated = withResolvers();
67061
- const claim = /* @__PURE__ */ __name(() => hydrated.promise.then(() => awaitEarlierDeliveries(ctx, eventIndex, ["wait"])).then(() => {
67062
- barrier.markDelivered();
67063
- if (outcome && !outcome.ok) {
67064
- throw outcome.error;
67065
- }
67066
- return outcome.value;
67067
- }), "claim");
67283
+ const claim = /* @__PURE__ */ __name(() => {
67284
+ barrier.arm();
67285
+ return hydrated.promise.then(() => awaitEarlierDeliveries(ctx, eventIndex, "hook")).then(() => {
67286
+ barrier.markDelivered();
67287
+ if (outcome && !outcome.ok) {
67288
+ throw outcome.error;
67289
+ }
67290
+ return outcome.value;
67291
+ });
67292
+ }, "claim");
67068
67293
  ctx.pendingDeliveries++;
67069
67294
  ctx.promiseQueue = ctx.promiseQueue.then(async () => {
67070
67295
  try {
@@ -67243,8 +67468,9 @@ function createSleep(ctx) {
67243
67468
  ctx.invocationsQueue.delete(correlationId);
67244
67469
  const eventIndex = ctx.eventsConsumer.eventIndex;
67245
67470
  const barrier = registerDeliveryBarrier(ctx, eventIndex, "wait");
67471
+ const earlierDelivered = awaitEarlierDeliveries(ctx, eventIndex, "wait");
67246
67472
  const queueAtCompletion = ctx.promiseQueue;
67247
- void queueAtCompletion.then(() => awaitEarlierDeliveries(ctx, eventIndex, ["hook"])).then(() => {
67473
+ void queueAtCompletion.then(() => earlierDelivered).then(() => {
67248
67474
  barrier.markDelivered();
67249
67475
  resolve3();
67250
67476
  });
@@ -67302,6 +67528,7 @@ async function runWorkflow(workflowCode2, workflowRun, events, encryptionKey, st
67302
67528
  const ulid5 = monotonicFactory(() => vmGlobalThis.Math.random());
67303
67529
  const generateNanoid = customRandom(urlAlphabet, 21, (size) => new Uint8Array(size).map(() => 256 * vmGlobalThis.Math.random()));
67304
67530
  const promiseQueueHolder = { current: Promise.resolve() };
67531
+ const deliveryIdleHolder = { current: /* @__PURE__ */ __name(() => true, "current") };
67305
67532
  const eventsConsumer = new EventsConsumer(events, {
67306
67533
  onConsumedEvent: /* @__PURE__ */ __name((event) => {
67307
67534
  updateTimestamp(+event.createdAt);
@@ -67309,7 +67536,8 @@ async function runWorkflow(workflowCode2, workflowRun, events, encryptionKey, st
67309
67536
  onUnconsumedEvent: /* @__PURE__ */ __name((event) => {
67310
67537
  workflowDiscontinuation.reject(new ReplayDivergenceError(`Replay could not consume event: eventType=${event.eventType}, correlationId=${event.correlationId}, eventId=${event.eventId}.`, { eventId: event.eventId }));
67311
67538
  }, "onUnconsumedEvent"),
67312
- getPromiseQueue: /* @__PURE__ */ __name(() => promiseQueueHolder.current, "getPromiseQueue")
67539
+ getPromiseQueue: /* @__PURE__ */ __name(() => promiseQueueHolder.current, "getPromiseQueue"),
67540
+ isDeliveryIdle: /* @__PURE__ */ __name(() => deliveryIdleHolder.current(), "isDeliveryIdle")
67313
67541
  });
67314
67542
  const workflowContext = {
67315
67543
  runId: workflowRun.runId,
@@ -67332,6 +67560,7 @@ async function runWorkflow(workflowCode2, workflowRun, events, encryptionKey, st
67332
67560
  pendingDeliveryBarriers: /* @__PURE__ */ new Map(),
67333
67561
  stepHydrationCache
67334
67562
  };
67563
+ deliveryIdleHolder.current = () => isDeliveryIdle(workflowContext);
67335
67564
  workflowContext.eventsConsumer.subscribe((event) => {
67336
67565
  if (!event) {
67337
67566
  return EventConsumerResult.NotConsumed;