@workflow/world-testing 5.0.0-beta.54 → 5.0.0-beta.56

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.
@@ -21110,7 +21110,30 @@ var init_events2 = __esm({
21110
21110
  tokenRetentionUntil: external_exports2.coerce.date().optional(),
21111
21111
  metadata: SerializedDataSchema2.optional(),
21112
21112
  isWebhook: external_exports2.boolean().optional(),
21113
- isSystem: external_exports2.boolean().optional()
21113
+ isSystem: external_exports2.boolean().optional(),
21114
+ /**
21115
+ * `createHook({ experimental_force: true })`: when the token belongs to
21116
+ * another live run, the World takes it over — journaling
21117
+ * `hook_disposed{forceClaimedBy}` in that run's log and re-pointing the
21118
+ * token — instead of answering `hook_conflict`. Requires the
21119
+ * `hookForceClaim` capability.
21120
+ */
21121
+ force: external_exports2.boolean().optional(),
21122
+ /**
21123
+ * World-written on a forced creation that did take a token over: the
21124
+ * run and hook it was taken from, plus what a queue message to that run
21125
+ * needs (`workflowName`, `deploymentId`, `runSpecVersion`). Absent when
21126
+ * the token was free. The wake-targeting fields are in the LOG, not only
21127
+ * on the hook entity, so a replay can republish the victim's wake from
21128
+ * the row alone; see `publishForceClaimVictimWake` in @workflow/core.
21129
+ */
21130
+ forceClaimedFrom: external_exports2.object({
21131
+ runId: external_exports2.string(),
21132
+ hookId: external_exports2.string(),
21133
+ workflowName: external_exports2.string().optional(),
21134
+ deploymentId: external_exports2.string().optional(),
21135
+ runSpecVersion: external_exports2.number().optional()
21136
+ }).optional()
21114
21137
  })
21115
21138
  }));
21116
21139
  HookReceivedEventSchema2 = external_exports2.compile(BaseEventSchema2.extend({
@@ -21125,7 +21148,14 @@ var init_events2 = __esm({
21125
21148
  eventType: external_exports2.literal("hook_disposed"),
21126
21149
  correlationId: external_exports2.string(),
21127
21150
  eventData: external_exports2.object({
21128
- token: external_exports2.string().optional()
21151
+ token: external_exports2.string().optional(),
21152
+ /**
21153
+ * World-written: this disposal was not the run's own. Another run
21154
+ * took the hook's token with `experimental_force`, and this names
21155
+ * it. The hook consumer rejects the hook's awaiters with
21156
+ * `HookForceClaimedError` when it reads this row.
21157
+ */
21158
+ forceClaimedBy: external_exports2.object({ runId: external_exports2.string(), hookId: external_exports2.string() }).optional()
21129
21159
  }).optional()
21130
21160
  }));
21131
21161
  HookConflictEventSchema2 = external_exports2.compile(BaseEventSchema2.extend({
@@ -21135,7 +21165,18 @@ var init_events2 = __esm({
21135
21165
  token: external_exports2.string(),
21136
21166
  // TODO: Make this required once all persisted hook_conflict events and
21137
21167
  // remote World implementations always include the active hook owner's run ID.
21138
- conflictingRunId: external_exports2.string().optional()
21168
+ conflictingRunId: external_exports2.string().optional(),
21169
+ /**
21170
+ * Set when the creation asked for `force` and the World declined to take
21171
+ * the token over. `victim-spec-version`: the run holding the token was
21172
+ * started at a spec version below
21173
+ * `SPEC_VERSION_SUPPORTS_HOOK_FORCE_CLAIM`, so its runtime would not
21174
+ * understand the involuntary disposal — the forced hook gets the
21175
+ * ordinary `HookConflictError` it opted out of instead of stranding
21176
+ * that run. Absent on a conflict answered by a World that does not
21177
+ * implement forcing at all.
21178
+ */
21179
+ forceRefusedReason: external_exports2.literal("victim-spec-version").optional()
21139
21180
  })
21140
21181
  }));
21141
21182
  NoopEventSchema2 = external_exports2.compile(BaseEventSchema2.extend({
@@ -22035,7 +22076,7 @@ var init_queue2 = __esm({
22035
22076
  });
22036
22077
 
22037
22078
  // ../world/dist/hooks.js
22038
- var HookResumeContextSchema2, HOOK_RESUME_INPUT_VERSION2, HOOK_RESUME_DEDUP_VERSION2, HookResumeCapabilitiesSchema2, HookSchema2;
22079
+ var HookResumeContextSchema2, HOOK_RESUME_INPUT_VERSION2, HOOK_RESUME_DEDUP_VERSION2, HookResumeCapabilitiesSchema2, HookClaimedFromSchema2, HookSchema2;
22039
22080
  var init_hooks2 = __esm({
22040
22081
  "../world/dist/hooks.js"() {
22041
22082
  "use strict";
@@ -22076,6 +22117,13 @@ var init_hooks2 = __esm({
22076
22117
  // is engaged.
22077
22118
  hookResumeDedupVersion: external_exports2.number()
22078
22119
  }));
22120
+ HookClaimedFromSchema2 = external_exports2.compile(external_exports2.object({
22121
+ runId: external_exports2.string(),
22122
+ hookId: external_exports2.string(),
22123
+ workflowName: external_exports2.string().optional(),
22124
+ deploymentId: external_exports2.string().optional(),
22125
+ runSpecVersion: external_exports2.number().optional()
22126
+ }));
22079
22127
  HookSchema2 = external_exports2.compile(external_exports2.object({
22080
22128
  runId: external_exports2.string(),
22081
22129
  hookId: external_exports2.string(),
@@ -22103,7 +22151,12 @@ var init_hooks2 = __esm({
22103
22151
  // `resumeHook()` gates its lazy path on this being present and
22104
22152
  // current. Absent against an older/rolled-back server or when the kill switch
22105
22153
  // is active.
22106
- resumeCapabilities: HookResumeCapabilitiesSchema2.optional()
22154
+ resumeCapabilities: HookResumeCapabilitiesSchema2.optional(),
22155
+ // Set when this hook took its token from another run
22156
+ // (`experimental_force`). The wake-targeting fields are the victim run's,
22157
+ // so the claimer's runtime can publish the victim's wake without reading
22158
+ // a run it may not be able to reach; see `HookClaimedFromSchema`.
22159
+ claimedFrom: HookClaimedFromSchema2.optional()
22107
22160
  }));
22108
22161
  }
22109
22162
  });
@@ -22276,7 +22329,7 @@ function requiresNewerWorld(v) {
22276
22329
  return false;
22277
22330
  return v > SPEC_VERSION_MAX_SUPPORTED2;
22278
22331
  }
22279
- var SPEC_VERSION_LEGACY2, SPEC_VERSION_SUPPORTS_EVENT_SOURCING, SPEC_VERSION_SUPPORTS_CBOR_QUEUE_TRANSPORT2, SPEC_VERSION_SUPPORTS_ATTRIBUTES2, SPEC_VERSION_SUPPORTS_COMPRESSION2, SPEC_VERSION_SUPPORTS_SLOT_IDENTITY2, SPEC_VERSION_SUPPORTS_SEALED_LOG2, SPEC_VERSION_CURRENT2, SEALED_LOG_ENV_VAR, SPEC_VERSION_MAX_SUPPORTED2;
22332
+ var SPEC_VERSION_LEGACY2, SPEC_VERSION_SUPPORTS_EVENT_SOURCING, SPEC_VERSION_SUPPORTS_CBOR_QUEUE_TRANSPORT2, SPEC_VERSION_SUPPORTS_ATTRIBUTES2, SPEC_VERSION_SUPPORTS_COMPRESSION2, SPEC_VERSION_SUPPORTS_SLOT_IDENTITY2, SPEC_VERSION_SUPPORTS_SEALED_LOG, SPEC_VERSION_SUPPORTS_HOOK_FORCE_CLAIM2, SPEC_VERSION_CURRENT2, SEALED_LOG_ENV_VAR, SPEC_VERSION_MAX_SUPPORTED2;
22280
22333
  var init_spec_version2 = __esm({
22281
22334
  "../world/dist/spec-version.js"() {
22282
22335
  "use strict";
@@ -22287,11 +22340,12 @@ var init_spec_version2 = __esm({
22287
22340
  SPEC_VERSION_SUPPORTS_ATTRIBUTES2 = 4;
22288
22341
  SPEC_VERSION_SUPPORTS_COMPRESSION2 = 5;
22289
22342
  SPEC_VERSION_SUPPORTS_SLOT_IDENTITY2 = 6;
22290
- SPEC_VERSION_SUPPORTS_SEALED_LOG2 = 7;
22291
- SPEC_VERSION_CURRENT2 = SPEC_VERSION_SUPPORTS_SEALED_LOG2;
22343
+ SPEC_VERSION_SUPPORTS_SEALED_LOG = 7;
22344
+ SPEC_VERSION_SUPPORTS_HOOK_FORCE_CLAIM2 = 8;
22345
+ SPEC_VERSION_CURRENT2 = SPEC_VERSION_SUPPORTS_HOOK_FORCE_CLAIM2;
22292
22346
  SEALED_LOG_ENV_VAR = "WORKFLOW_SEALED_LOG";
22293
22347
  __name(mintedSpecVersion, "mintedSpecVersion");
22294
- SPEC_VERSION_MAX_SUPPORTED2 = SPEC_VERSION_SUPPORTS_SEALED_LOG2;
22348
+ SPEC_VERSION_MAX_SUPPORTED2 = SPEC_VERSION_SUPPORTS_HOOK_FORCE_CLAIM2;
22295
22349
  __name(isLegacySpecVersion2, "isLegacySpecVersion");
22296
22350
  __name(requiresNewerWorld, "requiresNewerWorld");
22297
22351
  }
@@ -22557,6 +22611,7 @@ __export(dist_exports, {
22557
22611
  HOOK_RESUME_DEDUP_VERSION: () => HOOK_RESUME_DEDUP_VERSION2,
22558
22612
  HOOK_RESUME_INPUT_VERSION: () => HOOK_RESUME_INPUT_VERSION2,
22559
22613
  HealthCheckPayloadSchema: () => HealthCheckPayloadSchema2,
22614
+ HookClaimedFromSchema: () => HookClaimedFromSchema2,
22560
22615
  HookCreatedEventSchema: () => HookCreatedEventSchema2,
22561
22616
  HookResumeCapabilitiesSchema: () => HookResumeCapabilitiesSchema2,
22562
22617
  HookSchema: () => HookSchema2,
@@ -22585,7 +22640,8 @@ __export(dist_exports, {
22585
22640
  SPEC_VERSION_SUPPORTS_CBOR_QUEUE_TRANSPORT: () => SPEC_VERSION_SUPPORTS_CBOR_QUEUE_TRANSPORT2,
22586
22641
  SPEC_VERSION_SUPPORTS_COMPRESSION: () => SPEC_VERSION_SUPPORTS_COMPRESSION2,
22587
22642
  SPEC_VERSION_SUPPORTS_EVENT_SOURCING: () => SPEC_VERSION_SUPPORTS_EVENT_SOURCING,
22588
- SPEC_VERSION_SUPPORTS_SEALED_LOG: () => SPEC_VERSION_SUPPORTS_SEALED_LOG2,
22643
+ SPEC_VERSION_SUPPORTS_HOOK_FORCE_CLAIM: () => SPEC_VERSION_SUPPORTS_HOOK_FORCE_CLAIM2,
22644
+ SPEC_VERSION_SUPPORTS_SEALED_LOG: () => SPEC_VERSION_SUPPORTS_SEALED_LOG,
22589
22645
  SPEC_VERSION_SUPPORTS_SLOT_IDENTITY: () => SPEC_VERSION_SUPPORTS_SLOT_IDENTITY2,
22590
22646
  STEP_EVENT_TYPES: () => STEP_EVENT_TYPES2,
22591
22647
  SerializedDataSchema: () => SerializedDataSchema2,
@@ -22730,7 +22786,7 @@ function buildFramedDetails2(hint3, slug) {
22730
22786
  out.push({ label: "docs", value: `${BASE_URL2}/${slug}` });
22731
22787
  return out;
22732
22788
  }
22733
- var BASE_URL2, ERROR_SLUGS2, WorkflowError2, WorkflowWorldError2, WorkflowRunFailedError2, WorkflowRunNotCompletedError2, WorkflowRuntimeError2, CorruptedEventLogError, ReplayDivergenceError, MaxEventsExceededError, RuntimeDecryptionError2, SerializationError2, StepNotRegisteredError2, WorkflowNotRegisteredError2, WorkflowDeploymentMismatchError, WorkflowRunNotFoundError2, HookConflictError2, HookNotFoundError2, EntityConflictError2, RunExpiredError2, StreamError2, StreamExpiredError2, TooEarlyError, ThrottleError2, PreconditionFailedError, WorkflowRunCancelledError2, RunNotSupportedError, FatalError2, RetryableError2, FATAL_ERROR_KEY2, RETRYABLE_ERROR_KEY2, HOOK_CONFLICT_ERROR_KEY2, RUNTIME_DECRYPTION_ERROR_KEY2, STREAM_ERROR_KEY2;
22789
+ var BASE_URL2, ERROR_SLUGS2, WorkflowError2, WorkflowWorldError2, WorkflowRunFailedError2, WorkflowRunNotCompletedError2, WorkflowRuntimeError2, CorruptedEventLogError, ReplayDivergenceError, MaxEventsExceededError, RuntimeDecryptionError2, SerializationError2, StepNotRegisteredError2, WorkflowNotRegisteredError2, WorkflowDeploymentMismatchError, WorkflowRunNotFoundError2, HookConflictError2, HookForceClaimedError2, HookNotFoundError2, EntityConflictError2, RunExpiredError2, StreamError2, StreamExpiredError2, TooEarlyError, ThrottleError2, PreconditionFailedError, WorkflowRunCancelledError2, RunNotSupportedError, FatalError2, RetryableError2, FATAL_ERROR_KEY2, RETRYABLE_ERROR_KEY2, HOOK_CONFLICT_ERROR_KEY2, HOOK_FORCE_CLAIMED_ERROR_KEY2, RUNTIME_DECRYPTION_ERROR_KEY2, STREAM_ERROR_KEY2;
22734
22790
  var init_dist7 = __esm({
22735
22791
  "../errors/dist/index.js"() {
22736
22792
  "use strict";
@@ -22750,6 +22806,7 @@ var init_dist7 = __esm({
22750
22806
  FETCH_IN_WORKFLOW_FUNCTION: "fetch-in-workflow",
22751
22807
  TIMEOUT_FUNCTIONS_IN_WORKFLOW: "timeout-in-workflow",
22752
22808
  HOOK_CONFLICT: "hook-conflict",
22809
+ HOOK_FORCE_CLAIMED: "hook-force-claimed",
22753
22810
  CORRUPTED_EVENT_LOG: "corrupted-event-log",
22754
22811
  REPLAY_DIVERGENCE: "replay-divergence",
22755
22812
  STEP_NOT_REGISTERED: "step-not-registered",
@@ -23043,6 +23100,28 @@ Caused by: ${options.cause.stack}`;
23043
23100
  return isError2(value) && value.name === "HookConflictError";
23044
23101
  }
23045
23102
  };
23103
+ HookForceClaimedError2 = class extends WorkflowError2 {
23104
+ static {
23105
+ __name(this, "HookForceClaimedError");
23106
+ }
23107
+ token;
23108
+ /** The run that took the token. */
23109
+ claimedByRunId;
23110
+ /** The hook (in `claimedByRunId`) the token now belongs to. */
23111
+ claimedByHookId;
23112
+ constructor(token, claimedByRunId, claimedByHookId) {
23113
+ super(`Hook token "${token}" was force-claimed by another workflow (run "${claimedByRunId}")`, { slug: ERROR_SLUGS2.HOOK_FORCE_CLAIMED });
23114
+ this.name = "HookForceClaimedError";
23115
+ this.token = token;
23116
+ this.claimedByRunId = claimedByRunId;
23117
+ if (claimedByHookId !== void 0) {
23118
+ this.claimedByHookId = claimedByHookId;
23119
+ }
23120
+ }
23121
+ static is(value) {
23122
+ return isError2(value) && value.name === "HookForceClaimedError";
23123
+ }
23124
+ };
23046
23125
  HookNotFoundError2 = class extends WorkflowError2 {
23047
23126
  static {
23048
23127
  __name(this, "HookNotFoundError");
@@ -23233,6 +23312,7 @@ Caused by: ${options.cause.stack}`;
23233
23312
  FATAL_ERROR_KEY2 = /* @__PURE__ */ Symbol.for("@workflow/errors//FatalError");
23234
23313
  RETRYABLE_ERROR_KEY2 = /* @__PURE__ */ Symbol.for("@workflow/errors//RetryableError");
23235
23314
  HOOK_CONFLICT_ERROR_KEY2 = /* @__PURE__ */ Symbol.for("@workflow/errors//HookConflictError");
23315
+ HOOK_FORCE_CLAIMED_ERROR_KEY2 = /* @__PURE__ */ Symbol.for("@workflow/errors//HookForceClaimedError");
23236
23316
  RUNTIME_DECRYPTION_ERROR_KEY2 = /* @__PURE__ */ Symbol.for("@workflow/errors//RuntimeDecryptionError");
23237
23317
  STREAM_ERROR_KEY2 = /* @__PURE__ */ Symbol.for("@workflow/errors//StreamError");
23238
23318
  if (typeof globalThis !== "undefined") {
@@ -23260,6 +23340,14 @@ Caused by: ${options.cause.stack}`;
23260
23340
  configurable: false
23261
23341
  });
23262
23342
  }
23343
+ if (!Object.hasOwn(globalThis, HOOK_FORCE_CLAIMED_ERROR_KEY2)) {
23344
+ Object.defineProperty(globalThis, HOOK_FORCE_CLAIMED_ERROR_KEY2, {
23345
+ value: HookForceClaimedError2,
23346
+ writable: false,
23347
+ enumerable: false,
23348
+ configurable: false
23349
+ });
23350
+ }
23263
23351
  if (!Object.hasOwn(globalThis, RUNTIME_DECRYPTION_ERROR_KEY2)) {
23264
23352
  Object.defineProperty(globalThis, RUNTIME_DECRYPTION_ERROR_KEY2, {
23265
23353
  value: RuntimeDecryptionError2,
@@ -54921,6 +55009,35 @@ function hookDisposeLockPath(basedir, hookId, tag) {
54921
55009
  const name = tag ? `${hookId}.disposed.${tag}` : `${hookId}.disposed`;
54922
55010
  return resolveWithinBase(basedir, ".locks", "hooks", name);
54923
55011
  }
55012
+ async function readHookDisposeLock(basedir, hookId, tag) {
55013
+ const candidates = [hookDisposeLockPath(basedir, hookId)];
55014
+ if (tag) {
55015
+ candidates.push(hookDisposeLockPath(basedir, hookId, tag));
55016
+ }
55017
+ for (const lockPath of candidates) {
55018
+ let content;
55019
+ try {
55020
+ content = await fs2.readFile(lockPath, "utf8");
55021
+ } catch {
55022
+ continue;
55023
+ }
55024
+ if (content.trim() === "")
55025
+ return { committed: true };
55026
+ try {
55027
+ const parsed = JSON.parse(content);
55028
+ const by = parsed.forceClaimedBy;
55029
+ if (by && typeof by.runId === "string" && typeof by.hookId === "string") {
55030
+ return {
55031
+ committed: true,
55032
+ forceClaimedBy: { runId: by.runId, hookId: by.hookId }
55033
+ };
55034
+ }
55035
+ } catch {
55036
+ }
55037
+ return { committed: true };
55038
+ }
55039
+ return { committed: false };
55040
+ }
54924
55041
  async function isHookDisposalCommitted(basedir, hookId, tag) {
54925
55042
  const candidates = [hookDisposeLockPath(basedir, hookId)];
54926
55043
  if (tag) {
@@ -55136,6 +55253,7 @@ var init_helpers2 = __esm({
55136
55253
  init_fs();
55137
55254
  __name(hashToken, "hashToken");
55138
55255
  __name(hookDisposeLockPath, "hookDisposeLockPath");
55256
+ __name(readHookDisposeLock, "readHookDisposeLock");
55139
55257
  __name(isHookDisposalCommitted, "isHookDisposalCommitted");
55140
55258
  __name(runTerminalMarkerPath, "runTerminalMarkerPath");
55141
55259
  __name(isRunTerminalCommitted, "isRunTerminalCommitted");
@@ -55153,7 +55271,17 @@ var init_helpers2 = __esm({
55153
55271
  // Legacy claims also omitted eventId. Their recovery marker pins the
55154
55272
  // canonical hook_created event before concurrent retries publish it.
55155
55273
  eventId: external_exports2.string().optional(),
55156
- tokenRetentionUntil: external_exports2.coerce.date().optional()
55274
+ tokenRetentionUntil: external_exports2.coerce.date().optional(),
55275
+ // Set when this claim took the token from another run
55276
+ // (`experimental_force`), so a retry that adopts the claim can still
55277
+ // report — and wake — the run it came from.
55278
+ claimedFrom: external_exports2.object({
55279
+ runId: external_exports2.string(),
55280
+ hookId: external_exports2.string(),
55281
+ workflowName: external_exports2.string().optional(),
55282
+ deploymentId: external_exports2.string().optional(),
55283
+ runSpecVersion: external_exports2.number().optional()
55284
+ }).optional()
55157
55285
  }));
55158
55286
  __name(readHookTokenClaim, "readHookTokenClaim");
55159
55287
  __name(withHookTokenClaimLock, "withHookTokenClaimLock");
@@ -55217,7 +55345,7 @@ async function writeHookCreatedIndexEntries(basedir, token, runId, hookId, event
55217
55345
  assertSafeEntityId("eventId", eventId);
55218
55346
  if (tag !== void 0)
55219
55347
  assertSafeEntityId("tag", tag);
55220
- const fileName = tag ? `${eventId}.${tag}.json` : `${eventId}.json`;
55348
+ const fileName = tag ? `${runId}-${eventId}.${tag}.json` : `${runId}-${eventId}.json`;
55221
55349
  const content = JSON.stringify({ runId });
55222
55350
  await Promise.all([
55223
55351
  writeExclusive(path5.join(tokenIndexDir(basedir, token), fileName), content),
@@ -55324,7 +55452,7 @@ async function ensureHookIndexesImpl(basedir) {
55324
55452
  });
55325
55453
  await writeExclusive(markerPath, "");
55326
55454
  }
55327
- async function findNewestIndexedHookCreatedEvent(basedir, index, matches, tag) {
55455
+ async function findIndexedHookCreatedEvent(basedir, index, accept, tag) {
55328
55456
  await ensureHookIndexes(basedir);
55329
55457
  let dir;
55330
55458
  try {
@@ -55332,6 +55460,10 @@ async function findNewestIndexedHookCreatedEvent(basedir, index, matches, tag) {
55332
55460
  } catch {
55333
55461
  return null;
55334
55462
  }
55463
+ const eventIdOf = /* @__PURE__ */ __name((entryId, runId) => {
55464
+ const stripped = stripTag(entryId);
55465
+ return stripped.startsWith(`${runId}-`) ? stripped.slice(runId.length + 1) : stripped;
55466
+ }, "eventIdOf");
55335
55467
  const entryIds = (await listJSONFiles(dir)).filter((fileId) => isVisibleToTag(fileId, tag)).sort((a, b) => stripTag(b).localeCompare(stripTag(a)));
55336
55468
  for (const entryId of entryIds) {
55337
55469
  let entry = null;
@@ -55344,7 +55476,7 @@ async function findNewestIndexedHookCreatedEvent(basedir, index, matches, tag) {
55344
55476
  }
55345
55477
  if (!entry)
55346
55478
  continue;
55347
- const eventId = stripTag(entryId);
55479
+ const eventId = eventIdOf(entryId, entry.runId);
55348
55480
  let eventPath;
55349
55481
  try {
55350
55482
  eventPath = taggedPath(basedir, "events", `${entry.runId}-${eventId}`, tagOf(entryId));
@@ -55358,7 +55490,7 @@ async function findNewestIndexedHookCreatedEvent(basedir, index, matches, tag) {
55358
55490
  continue;
55359
55491
  if (typeof event.correlationId !== "string")
55360
55492
  continue;
55361
- if (!matches(event))
55493
+ if (!await accept(event))
55362
55494
  continue;
55363
55495
  return event;
55364
55496
  }
@@ -55398,7 +55530,7 @@ var init_hook_index = __esm({
55398
55530
  __name(ensureHookIndexes, "ensureHookIndexes");
55399
55531
  __name(forEachConcurrent, "forEachConcurrent");
55400
55532
  __name(ensureHookIndexesImpl, "ensureHookIndexesImpl");
55401
- __name(findNewestIndexedHookCreatedEvent, "findNewestIndexedHookCreatedEvent");
55533
+ __name(findIndexedHookCreatedEvent, "findIndexedHookCreatedEvent");
55402
55534
  }
55403
55535
  });
55404
55536
 
@@ -55449,11 +55581,14 @@ function getHookCreatedToken(event) {
55449
55581
  return typeof token === "string" ? token : void 0;
55450
55582
  }
55451
55583
  function hookFromCreatedEvent(event) {
55452
- const { token, metadata, isWebhook, isSystem, tokenRetentionUntil } = event.eventData;
55584
+ const { token, metadata, isWebhook, isSystem, tokenRetentionUntil, forceClaimedFrom } = event.eventData;
55453
55585
  return {
55454
55586
  runId: event.runId,
55455
55587
  hookId: event.correlationId,
55456
55588
  token,
55589
+ // The journaled row is the durable record of a takeover; a rebuilt
55590
+ // entity must say where its token came from just as the original did.
55591
+ ...forceClaimedFrom !== void 0 && { claimedFrom: forceClaimedFrom },
55457
55592
  metadata,
55458
55593
  ownerId: "local-owner",
55459
55594
  projectId: "local-project",
@@ -55473,20 +55608,17 @@ async function isTerminalRunCache(basedir, runId, tag) {
55473
55608
  return run3 ? isTerminalWorkflowRunStatus2(run3.status) : false;
55474
55609
  }
55475
55610
  async function findAvailableHookCreatedEvent(basedir, index, matches, tag) {
55476
- const newest = await findNewestIndexedHookCreatedEvent(basedir, index, (event) => isMatchingHookCreatedEvent(event, matches), tag);
55477
- if (!newest || !isMatchingHookCreatedEvent(newest, matches)) {
55478
- return null;
55479
- }
55480
- if (await isTerminalRunCache(basedir, newest.runId, tag)) {
55481
- const retainedUntil = newest.eventData.tokenRetentionUntil;
55482
- if (!retainedUntil || retainedUntil.getTime() <= Date.now()) {
55483
- return null;
55611
+ const isLive = /* @__PURE__ */ __name(async (event) => {
55612
+ if (await isTerminalRunCache(basedir, event.runId, tag)) {
55613
+ const retainedUntil = event.eventData.tokenRetentionUntil;
55614
+ if (!retainedUntil || retainedUntil.getTime() <= Date.now()) {
55615
+ return false;
55616
+ }
55484
55617
  }
55485
- }
55486
- if (await isHookDisposalCommitted(basedir, newest.correlationId, tag)) {
55487
- return null;
55488
- }
55489
- return newest;
55618
+ return !await isHookDisposalCommitted(basedir, event.correlationId, tag);
55619
+ }, "isLive");
55620
+ const found2 = await findIndexedHookCreatedEvent(basedir, index, (event) => isMatchingHookCreatedEvent(event, matches) && isLive(event), tag);
55621
+ return found2 && isMatchingHookCreatedEvent(found2, matches) ? found2 : null;
55490
55622
  }
55491
55623
  async function restoreHookCachesFromEvent(basedir, event, tag) {
55492
55624
  const hook = hookFromCreatedEvent(event);
@@ -55496,7 +55628,8 @@ async function restoreHookCachesFromEvent(basedir, event, tag) {
55496
55628
  hookId: hook.hookId,
55497
55629
  runId: hook.runId,
55498
55630
  eventId: event.eventId,
55499
- tokenRetentionUntil: event.eventData.tokenRetentionUntil
55631
+ tokenRetentionUntil: event.eventData.tokenRetentionUntil,
55632
+ ...hook.claimedFrom && { claimedFrom: hook.claimedFrom }
55500
55633
  }));
55501
55634
  await writeHookByRunMarker(basedir, hook.runId, hook.hookId, tag);
55502
55635
  await writeExclusive(taggedPath(basedir, "hooks", hook.hookId, tag), JSON.stringify(hook, jsonReplacer, 2));
@@ -55521,36 +55654,53 @@ function createHooksStorage(basedir, tag) {
55521
55654
  return !await isTerminalRunCache(basedir, hook.runId, tag);
55522
55655
  }
55523
55656
  __name(isHookAvailable, "isHookAvailable");
55657
+ async function isForceDisposed(hook) {
55658
+ const lock2 = await readHookDisposeLock(basedir, hook.hookId, tag);
55659
+ return lock2.committed && lock2.forceClaimedBy !== void 0;
55660
+ }
55661
+ __name(isForceDisposed, "isForceDisposed");
55524
55662
  async function findHookByToken(token) {
55525
55663
  const claim3 = await readHookTokenClaim(hookTokenClaimPath(basedir, token));
55526
55664
  if (claim3?.hookId) {
55527
55665
  try {
55528
55666
  const hook = await readJSONWithFallback(basedir, "hooks", claim3.hookId, HookSchema2, tag);
55529
55667
  if (hook?.token === token) {
55530
- if (!await isHookAvailable(hook)) {
55668
+ if (await isHookAvailable(hook)) {
55669
+ return { ...hook, isWebhook: hook.isWebhook ?? true };
55670
+ }
55671
+ if (!await isForceDisposed(hook)) {
55531
55672
  throw new HookNotFoundError2(token);
55532
55673
  }
55533
- return { ...hook, isWebhook: hook.isWebhook ?? true };
55674
+ } else if (hook) {
55675
+ return null;
55534
55676
  }
55535
55677
  } catch (error121) {
55536
55678
  if (!UnsafeEntityIdError.is(error121)) {
55537
55679
  throw error121;
55538
55680
  }
55681
+ return null;
55539
55682
  }
55540
- return null;
55541
55683
  }
55542
55684
  const hooksDir = path6.join(basedir, "hooks");
55543
55685
  const files = await listJSONFiles(hooksDir);
55686
+ let disposedMatch = false;
55544
55687
  for (const file3 of files) {
55545
55688
  const hookPath = path6.join(hooksDir, `${file3}.json`);
55546
55689
  const hook = await readJSON(hookPath, HookSchema2);
55547
55690
  if (hook?.token === token) {
55548
- if (!await isHookAvailable(hook)) {
55549
- throw new HookNotFoundError2(token);
55691
+ if (await isHookAvailable(hook)) {
55692
+ return { ...hook, isWebhook: hook.isWebhook ?? true };
55693
+ }
55694
+ if (await isForceDisposed(hook)) {
55695
+ disposedMatch = true;
55696
+ continue;
55550
55697
  }
55551
- return { ...hook, isWebhook: hook.isWebhook ?? true };
55698
+ throw new HookNotFoundError2(token);
55552
55699
  }
55553
55700
  }
55701
+ if (disposedMatch) {
55702
+ throw new HookNotFoundError2(token);
55703
+ }
55554
55704
  return null;
55555
55705
  }
55556
55706
  __name(findHookByToken, "findHookByToken");
@@ -56816,6 +56966,16 @@ function createEventsStorage(basedir, tag) {
56816
56966
  }
56817
56967
  }
56818
56968
  __name(storeEvent, "storeEvent");
56969
+ async function refuseDisposedHookDelivery(hookId, token) {
56970
+ const lock2 = await readHookDisposeLock(basedir, hookId, tag);
56971
+ if (!lock2.committed)
56972
+ return;
56973
+ if (lock2.forceClaimedBy) {
56974
+ throw new HookForceClaimedError2(typeof token === "string" ? token : "", lock2.forceClaimedBy.runId, lock2.forceClaimedBy.hookId);
56975
+ }
56976
+ throw new HookNotFoundError2(hookId);
56977
+ }
56978
+ __name(refuseDisposedHookDelivery, "refuseDisposedHookDelivery");
56819
56979
  const queryRunEvents = /* @__PURE__ */ __name((runId, pagination) => paginatedFileSystemQuery({
56820
56980
  directory: path10.join(basedir, "events"),
56821
56981
  schema: ReadEventSchema,
@@ -57006,8 +57166,8 @@ function createEventsStorage(basedir, tag) {
57006
57166
  }
57007
57167
  }
57008
57168
  }
57009
- if (data.eventType === "hook_received" && await isHookDisposalCommitted(basedir, data.correlationId, tag)) {
57010
- throw new HookNotFoundError2(data.correlationId);
57169
+ if (data.eventType === "hook_received") {
57170
+ await refuseDisposedHookDelivery(data.correlationId, data.eventData?.token);
57011
57171
  }
57012
57172
  const existingHook = await readJSONWithFallback(basedir, "hooks", data.correlationId, HookSchema2, tag);
57013
57173
  if (!existingHook) {
@@ -57066,6 +57226,7 @@ function createEventsStorage(basedir, tag) {
57066
57226
  }
57067
57227
  }
57068
57228
  }
57229
+ let prePublishedEvent;
57069
57230
  let event = {
57070
57231
  ...data,
57071
57232
  runId: effectiveRunId,
@@ -57437,13 +57598,15 @@ function createEventsStorage(basedir, tag) {
57437
57598
  ) {
57438
57599
  const hookData = data.eventData;
57439
57600
  const constraintPath = hookTokenClaimPath(basedir, hookData.token);
57440
- const claimContent = JSON.stringify({
57601
+ let claimedFrom;
57602
+ const claimContent = /* @__PURE__ */ __name(() => JSON.stringify({
57441
57603
  token: hookData.token,
57442
57604
  hookId: data.correlationId,
57443
57605
  runId: effectiveRunId,
57444
57606
  eventId,
57445
- tokenRetentionUntil: hookData.tokenRetentionUntil
57446
- });
57607
+ tokenRetentionUntil: hookData.tokenRetentionUntil,
57608
+ ...claimedFrom && { claimedFrom }
57609
+ }), "claimContent");
57447
57610
  const claimResult = await withHookTokenClaimLock(basedir, hookData.token, async (signal) => {
57448
57611
  let existingClaim = await readHookTokenClaim(constraintPath);
57449
57612
  if (!existingClaim) {
@@ -57454,26 +57617,114 @@ function createEventsStorage(basedir, tag) {
57454
57617
  }
57455
57618
  if (!existingClaim) {
57456
57619
  signal.throwIfAborted();
57457
- assert3(await writeExclusive(constraintPath, claimContent));
57620
+ assert3(await writeExclusive(constraintPath, claimContent()));
57458
57621
  return { status: "claimed" };
57459
57622
  }
57460
57623
  if (existingClaim.runId === effectiveRunId && existingClaim.hookId === data.correlationId) {
57461
57624
  return { status: "owned", claim: existingClaim };
57462
57625
  }
57463
57626
  if (!await isHookTokenClaimReleasable(basedir, existingClaim, tag)) {
57464
- return { status: "conflict", claim: existingClaim };
57627
+ if (hookData.force !== true || !existingClaim.hookId) {
57628
+ return { status: "conflict", claim: existingClaim };
57629
+ }
57630
+ signal.throwIfAborted();
57631
+ const victimRun = await readJSONWithFallback(basedir, "runs", existingClaim.runId, WorkflowRunSchema2, tag);
57632
+ const victimRunning = victimRun !== null && !isTerminalWorkflowRunStatus2(victimRun.status);
57633
+ claimedFrom = {
57634
+ runId: existingClaim.runId,
57635
+ hookId: existingClaim.hookId,
57636
+ ...victimRunning && {
57637
+ workflowName: victimRun.workflowName,
57638
+ deploymentId: victimRun.deploymentId,
57639
+ runSpecVersion: victimRun.specVersion
57640
+ }
57641
+ };
57642
+ if (victimRunning && (victimRun.specVersion ?? SPEC_VERSION_LEGACY2) < SPEC_VERSION_SUPPORTS_HOOK_FORCE_CLAIM2) {
57643
+ return {
57644
+ status: "conflict",
57645
+ claim: existingClaim,
57646
+ forceRefusedReason: "victim-spec-version"
57647
+ };
57648
+ }
57649
+ const journaledEventId = await findExistingHookCreatedEventId(basedir, effectiveRunId, data.correlationId);
57650
+ if (journaledEventId) {
57651
+ eventId = journaledEventId;
57652
+ prePublishedEvent = { ...event, eventId };
57653
+ } else {
57654
+ prePublishedEvent = await storeEvent({
57655
+ ...event,
57656
+ eventData: {
57657
+ ...event.eventData,
57658
+ forceClaimedFrom: claimedFrom
57659
+ }
57660
+ });
57661
+ eventId = prePublishedEvent.eventId;
57662
+ }
57663
+ await writeHookByRunMarker(basedir, effectiveRunId, data.correlationId, tag);
57664
+ await writeJSON(taggedPath(basedir, "hooks", data.correlationId, tag), {
57665
+ runId: effectiveRunId,
57666
+ hookId: data.correlationId,
57667
+ token: hookData.token,
57668
+ metadata: hookData.metadata,
57669
+ ownerId: "local-owner",
57670
+ projectId: "local-project",
57671
+ environment: "local",
57672
+ createdAt: now2,
57673
+ specVersion: effectiveSpecVersion,
57674
+ isWebhook: hookData.isWebhook ?? false,
57675
+ isSystem: hookData.isSystem ?? false,
57676
+ tokenRetentionUntil: hookData.tokenRetentionUntil,
57677
+ claimedFrom
57678
+ }, { overwrite: true });
57679
+ const lockWritten = await writeExclusive(hookDisposeLockPath(basedir, existingClaim.hookId, tag), JSON.stringify({
57680
+ forceClaimedBy: {
57681
+ runId: effectiveRunId,
57682
+ hookId: data.correlationId
57683
+ }
57684
+ }));
57685
+ if (victimRunning) {
57686
+ if (lockWritten) {
57687
+ const disposedEvent = {
57688
+ eventType: "hook_disposed",
57689
+ correlationId: existingClaim.hookId,
57690
+ eventData: {
57691
+ token: hookData.token,
57692
+ forceClaimedBy: {
57693
+ runId: effectiveRunId,
57694
+ hookId: data.correlationId
57695
+ }
57696
+ },
57697
+ runId: existingClaim.runId,
57698
+ eventId: await mintEventId(existingClaim.runId),
57699
+ createdAt: /* @__PURE__ */ new Date(),
57700
+ specVersion: victimRun.specVersion
57701
+ };
57702
+ await storeEvent(disposedEvent);
57703
+ }
57704
+ }
57465
57705
  }
57466
57706
  signal.throwIfAborted();
57467
- await deleteJSON(constraintPath);
57707
+ if (claimedFrom) {
57708
+ await write(constraintPath, claimContent(), {
57709
+ overwrite: true
57710
+ });
57711
+ } else {
57712
+ await deleteJSON(constraintPath);
57713
+ }
57468
57714
  if (existingClaim.hookId) {
57469
57715
  await deleteJSON(taggedPath(basedir, "hooks", existingClaim.hookId, tag));
57470
57716
  await deleteJSON(hookRecoveryMarkerPath(basedir, hookData.token, existingClaim.runId, existingClaim.hookId));
57471
57717
  await deleteHookByRunMarker(basedir, existingClaim.runId, existingClaim.hookId, tag);
57472
57718
  }
57473
57719
  signal.throwIfAborted();
57474
- assert3(await writeExclusive(constraintPath, claimContent));
57720
+ if (!claimedFrom) {
57721
+ assert3(await writeExclusive(constraintPath, claimContent()));
57722
+ }
57475
57723
  return { status: "claimed" };
57476
57724
  });
57725
+ if (claimResult.status === "owned" && claimResult.claim.claimedFrom) {
57726
+ claimedFrom = claimResult.claim.claimedFrom;
57727
+ }
57477
57728
  if (claimResult.status === "owned") {
57478
57729
  const existingClaim = claimResult.claim;
57479
57730
  let canonicalEventId;
@@ -57515,7 +57766,10 @@ function createEventsStorage(basedir, tag) {
57515
57766
  correlationId: data.correlationId,
57516
57767
  eventData: {
57517
57768
  token: hookData.token,
57518
- conflictingRunId: existingClaim.runId
57769
+ conflictingRunId: existingClaim.runId,
57770
+ ...claimResult.forceRefusedReason !== void 0 && {
57771
+ forceRefusedReason: claimResult.forceRefusedReason
57772
+ }
57519
57773
  },
57520
57774
  runId: effectiveRunId,
57521
57775
  eventId,
@@ -57543,6 +57797,18 @@ function createEventsStorage(basedir, tag) {
57543
57797
  hasMore: conflictDelta.hasMore
57544
57798
  };
57545
57799
  }
57800
+ if (claimedFrom) {
57801
+ event = {
57802
+ ...event,
57803
+ eventData: {
57804
+ ...event.eventData,
57805
+ // Wake-targeting fields included: a replay of this run
57806
+ // republishes the victim's wake from this row alone when the
57807
+ // invocation that created the hook died before waking it.
57808
+ forceClaimedFrom: claimedFrom
57809
+ }
57810
+ };
57811
+ }
57546
57812
  const persistedHookData = event.eventData;
57547
57813
  hook = {
57548
57814
  runId: effectiveRunId,
@@ -57557,9 +57823,10 @@ function createEventsStorage(basedir, tag) {
57557
57823
  specVersion: effectiveSpecVersion,
57558
57824
  isWebhook: persistedHookData.isWebhook ?? false,
57559
57825
  isSystem: persistedHookData.isSystem ?? false,
57560
- tokenRetentionUntil: persistedHookData.tokenRetentionUntil
57826
+ tokenRetentionUntil: persistedHookData.tokenRetentionUntil,
57827
+ ...claimedFrom && { claimedFrom }
57561
57828
  };
57562
- hookEntityWriteOptions = claimResult.status === "owned" ? { overwrite: true } : void 0;
57829
+ hookEntityWriteOptions = claimResult.status === "owned" || claimedFrom ? { overwrite: true } : void 0;
57563
57830
  await writeHookCreatedIndexEntries(basedir, hookData.token, effectiveRunId, data.correlationId, eventId, tag);
57564
57831
  } else if (data.eventType === "hook_disposed") {
57565
57832
  const lockPath = hookDisposeLockPath(basedir, data.correlationId, tag);
@@ -57617,8 +57884,14 @@ function createEventsStorage(basedir, tag) {
57617
57884
  };
57618
57885
  await writeJSON(taggedPath(basedir, "waits", waitCompositeKey, tag), wait, { overwrite: true });
57619
57886
  }
57620
- if (data.eventType === "hook_received" && data.correlationId && await isHookDisposalCommitted(basedir, data.correlationId, tag)) {
57621
- throw new HookNotFoundError2(data.correlationId);
57887
+ if (data.eventType === "hook_received" && data.correlationId) {
57888
+ await refuseDisposedHookDelivery(data.correlationId, data.eventData?.token);
57889
+ }
57890
+ if (data.eventType === "hook_created" && data.correlationId) {
57891
+ const own3 = await readHookDisposeLock(basedir, data.correlationId, tag);
57892
+ if (own3.committed && own3.forceClaimedBy) {
57893
+ throw new EntityConflictError2(`Hook "${data.correlationId}" was force-claimed by another run before its creation was journaled`);
57894
+ }
57622
57895
  }
57623
57896
  let eventPath = taggedPath(basedir, "events", `${effectiveRunId}-${eventId}`, tag);
57624
57897
  let serializedEvent = JSON.stringify(event, jsonReplacer, 2);
@@ -57641,7 +57914,13 @@ function createEventsStorage(basedir, tag) {
57641
57914
  return true;
57642
57915
  }, "bumpEventSlot");
57643
57916
  let eventPublished = false;
57644
- for (let attempt = 0; ; attempt++) {
57917
+ if (prePublishedEvent) {
57918
+ event = prePublishedEvent;
57919
+ eventPath = taggedPath(basedir, "events", `${effectiveRunId}-${eventId}`, tag);
57920
+ serializedEvent = JSON.stringify(event, jsonReplacer, 2);
57921
+ eventPublished = true;
57922
+ }
57923
+ for (let attempt = 0; !eventPublished; attempt++) {
57645
57924
  if (data.eventType === "hook_received") {
57646
57925
  const terminalByMarker = await isRunTerminalCommitted(basedir, effectiveRunId, tag);
57647
57926
  const runNow = terminalByMarker ? null : await readJSONWithFallback(basedir, "runs", effectiveRunId, WorkflowRunSchema2, tag);
@@ -58010,7 +58289,11 @@ function createWorld(args) {
58010
58289
  // `(runId, resumeId)` via a filesystem sidecar claim (see
58011
58290
  // events-storage.ts `claimHookResume`), so resumeHook()'s parallel fast
58012
58291
  // path converges on one event in dev exactly as it does on Vercel.
58013
- hookResumeDedup: true
58292
+ hookResumeDedup: true,
58293
+ // The token claim lock serializes the takeover behind
58294
+ // `createHook({ experimental_force: true })`; see the hook_created
58295
+ // branch of storage/events-storage.ts.
58296
+ hookForceClaim: true
58014
58297
  },
58015
58298
  ...queue,
58016
58299
  ...storage,
@@ -61842,7 +62125,7 @@ var version4;
61842
62125
  var init_version3 = __esm({
61843
62126
  "../world-vercel/dist/version.js"() {
61844
62127
  "use strict";
61845
- version4 = "5.0.0-beta.49";
62128
+ version4 = "5.0.0-beta.51";
61846
62129
  }
61847
62130
  });
61848
62131
 
@@ -62424,6 +62707,10 @@ function headersToRecord(headers) {
62424
62707
  }
62425
62708
  function errorForResponse(status, message, opts = {}) {
62426
62709
  const { retryAfter, code: code3, url: url3, mitigated, details } = opts;
62710
+ if (status === 409 && code3 === "hook-force-claimed") {
62711
+ const claimedBy = details && typeof details === "object" ? details.claimedBy : void 0;
62712
+ return new HookForceClaimedError2("", typeof claimedBy?.runId === "string" ? claimedBy.runId : "unknown", typeof claimedBy?.hookId === "string" ? claimedBy.hookId : void 0);
62713
+ }
62427
62714
  if (status === 409)
62428
62715
  return new EntityConflictError2(message);
62429
62716
  if (status === 410) {
@@ -74579,10 +74866,20 @@ function toBatchResult(outcome) {
74579
74866
  messageId: outcome.messageId ? MessageId2.parse(outcome.messageId) : null
74580
74867
  };
74581
74868
  }
74582
- function getHandlerErrorRetryAfterSeconds(deliveryCount) {
74869
+ function getErrorRetryAfterSeconds(error121) {
74870
+ if (typeof error121 !== "object" || error121 === null)
74871
+ return void 0;
74872
+ const retryAfter = error121.retryAfter;
74873
+ if (typeof retryAfter !== "number" || !Number.isFinite(retryAfter) || retryAfter <= 0) {
74874
+ return void 0;
74875
+ }
74876
+ return Math.min(Math.ceil(retryAfter), HANDLER_ERROR_MAX_RETRY_AFTER_SECONDS);
74877
+ }
74878
+ function getHandlerErrorRetryAfterSeconds(error121, deliveryCount) {
74583
74879
  const backoffSeconds = Math.min(Math.max(HANDLER_ERROR_RETRY_AFTER_SECONDS, 2 ** (deliveryCount - 1)), HANDLER_ERROR_MAX_RETRY_AFTER_SECONDS);
74584
74880
  const jitterSeconds = Math.floor(Math.random() * (Math.ceil(backoffSeconds * HANDLER_ERROR_RETRY_JITTER_RATIO) + 1));
74585
- return Math.max(HANDLER_ERROR_RETRY_AFTER_SECONDS, backoffSeconds - jitterSeconds);
74881
+ const jitteredBackoffSeconds = Math.max(HANDLER_ERROR_RETRY_AFTER_SECONDS, backoffSeconds - jitterSeconds);
74882
+ return Math.max(jitteredBackoffSeconds, getErrorRetryAfterSeconds(error121) ?? HANDLER_ERROR_RETRY_AFTER_SECONDS);
74586
74883
  }
74587
74884
  function getRunIdFromPayload(payload) {
74588
74885
  if ("runId" in payload && typeof payload.runId === "string") {
@@ -74800,7 +75097,7 @@ function createQueue2(config4) {
74800
75097
  // redrive in lockstep. Workflow handlers are event-sourced and must
74801
75098
  // remain idempotent because queue retries can happen close together.
74802
75099
  retry: /* @__PURE__ */ __name((error121, { messageId, deliveryCount }) => {
74803
- const afterSeconds = getHandlerErrorRetryAfterSeconds(deliveryCount);
75100
+ const afterSeconds = getHandlerErrorRetryAfterSeconds(error121, deliveryCount);
74804
75101
  console.error(`[workflow] Queue handler failed for message "${messageId}" on delivery attempt ${deliveryCount}; retrying in ${afterSeconds}s:`, error121);
74805
75102
  return { afterSeconds };
74806
75103
  }, "retry")
@@ -74931,6 +75228,7 @@ var init_queue4 = __esm({
74931
75228
  HANDLER_ERROR_RETRY_AFTER_SECONDS = 1;
74932
75229
  HANDLER_ERROR_MAX_RETRY_AFTER_SECONDS = 900;
74933
75230
  HANDLER_ERROR_RETRY_JITTER_RATIO = 0.25;
75231
+ __name(getErrorRetryAfterSeconds, "getErrorRetryAfterSeconds");
74934
75232
  __name(getHandlerErrorRetryAfterSeconds, "getHandlerErrorRetryAfterSeconds");
74935
75233
  FALLBACK_REGION = "iad1";
74936
75234
  __name(getRunIdFromPayload, "getRunIdFromPayload");
@@ -75063,7 +75361,9 @@ function collectErrorMarkers(err, depth = 0) {
75063
75361
  function isRetryableEventPostError(err) {
75064
75362
  if (err instanceof ReplayEventObserverError)
75065
75363
  return false;
75066
- if (EntityConflictError2.is(err) || RunExpiredError2.is(err) || TooEarlyError.is(err) || ThrottleError2.is(err)) {
75364
+ if (EntityConflictError2.is(err) || // A takeover redirect is definitive for THIS target; the runtime's
75365
+ // resume path follows the token instead of re-issuing the write here.
75366
+ HookForceClaimedError2.is(err) || RunExpiredError2.is(err) || TooEarlyError.is(err) || ThrottleError2.is(err)) {
75067
75367
  return false;
75068
75368
  }
75069
75369
  if (WorkflowWorldError2.is(err) || StreamError2.is(err)) {
@@ -75592,6 +75892,8 @@ function buildPostFrameMeta(input3) {
75592
75892
  meta5.hookIsWebhook = input3.hookIsWebhook;
75593
75893
  if (input3.hookIsSystem !== void 0)
75594
75894
  meta5.hookIsSystem = input3.hookIsSystem;
75895
+ if (input3.hookForce !== void 0)
75896
+ meta5.hookForce = input3.hookForce;
75595
75897
  if (input3.resumeId !== void 0)
75596
75898
  meta5.resumeId = input3.resumeId;
75597
75899
  if (input3.errorCode !== void 0)
@@ -75659,8 +75961,13 @@ function errorFromV4Response(statusCode, responseHeaders, errorBody, opName, url
75659
75961
  message = record3.message;
75660
75962
  if (typeof record3.code === "string")
75661
75963
  code3 = record3.code;
75964
+ else if (typeof record3.error === "string")
75965
+ code3 = record3.error;
75662
75966
  if (statusCode === 412)
75663
75967
  details = decodePreconditionDetails(record3);
75968
+ if (statusCode === 409 && code3 === "hook-force-claimed") {
75969
+ details = { claimedBy: record3.claimedBy };
75970
+ }
75664
75971
  } else if (text) {
75665
75972
  message += ` ${text}`;
75666
75973
  }
@@ -76634,6 +76941,9 @@ function splitEventDataForV4(data) {
76634
76941
  if (typeof eventData.isSystem === "boolean") {
76635
76942
  meta5.hookIsSystem = eventData.isSystem;
76636
76943
  }
76944
+ if (eventData.force === true) {
76945
+ meta5.hookForce = true;
76946
+ }
76637
76947
  if (typeof eventData.errorCode === "string") {
76638
76948
  meta5.errorCode = eventData.errorCode;
76639
76949
  }
@@ -76786,6 +77096,10 @@ async function createWorkflowRunEvent(id, data, params, config4) {
76786
77096
  } catch (err) {
76787
77097
  if (err instanceof ReplayEventObserverError)
76788
77098
  throw err.error;
77099
+ if (HookForceClaimedError2.is(err) && data.eventType === "hook_received") {
77100
+ const token = data.eventData?.token;
77101
+ throw new HookForceClaimedError2(typeof token === "string" ? token : err.token, err.claimedByRunId, err.claimedByHookId);
77102
+ }
76789
77103
  if (isHookEventRequiringExistence(data.eventType) && WorkflowWorldError2.is(err) && err.status === 404 && data.correlationId) {
76790
77104
  throw new HookNotFoundError2(data.correlationId);
76791
77105
  }
@@ -78258,7 +78572,15 @@ function createWorld2(config4) {
78258
78572
  maxConcurrency: true,
78259
78573
  // Vercel deployments are atomic and immutable, so a deployment id names
78260
78574
  // one fixed build for its whole lifetime.
78261
- deploymentAffinity: true
78575
+ deploymentAffinity: true,
78576
+ // The server implements the takeover protocol behind
78577
+ // `createHook({ experimental_force: true })` (workflow-server
78578
+ // docs/hook-force-claim.md). Static rather than attested per lookup,
78579
+ // because the decision is made at `createHook()` time, before any
78580
+ // lookup; against a server that has it switched off (or predates it)
78581
+ // a forced creation is answered with `hook_conflict`, which the
78582
+ // runtime reports as an unsupported-World failure rather than a win.
78583
+ hookForceClaim: true
78262
78584
  // NOTE: the backend half of resumeHook()'s lazy path (that
78263
78585
  // the server enforces the `(runId, resumeId)` dedup constraint) is
78264
78586
  // NO LONGER a static world capability here. It is attested per-lookup by
@@ -82220,6 +82542,21 @@ function getCommonReducers2(_global2 = globalThis) {
82220
82542
  }
82221
82543
  return reduced;
82222
82544
  }, "HookConflictError"),
82545
+ HookForceClaimedError: /* @__PURE__ */ __name((value) => {
82546
+ const base = reduceNamedErrorSubclassBase2("HookForceClaimedError", value);
82547
+ if (!base)
82548
+ return false;
82549
+ const reduced = {
82550
+ ...base,
82551
+ token: readProperty2(value, "token"),
82552
+ claimedByRunId: readProperty2(value, "claimedByRunId")
82553
+ };
82554
+ const claimedByHookId = readProperty2(value, "claimedByHookId");
82555
+ if (claimedByHookId !== void 0) {
82556
+ reduced.claimedByHookId = claimedByHookId;
82557
+ }
82558
+ return reduced;
82559
+ }, "HookForceClaimedError"),
82223
82560
  RangeError: makeErrorSubclassReducer2("RangeError"),
82224
82561
  ReferenceError: makeErrorSubclassReducer2("ReferenceError"),
82225
82562
  // RetryableError carries an extra `retryAfter` Date that we serialize as
@@ -82404,6 +82741,16 @@ function getCommonRevivers3(global2 = globalThis) {
82404
82741
  }
82405
82742
  return error121;
82406
82743
  }, "HookConflictError"),
82744
+ HookForceClaimedError: /* @__PURE__ */ __name((value) => {
82745
+ const Ctor = global2[/* @__PURE__ */ Symbol.for("@workflow/errors//HookForceClaimedError")] ?? HookForceClaimedError2;
82746
+ const error121 = new Ctor(value.token, value.claimedByRunId, value.claimedByHookId);
82747
+ if (value.stack !== void 0)
82748
+ error121.stack = value.stack;
82749
+ if ("cause" in value) {
82750
+ error121.cause = value.cause;
82751
+ }
82752
+ return error121;
82753
+ }, "HookForceClaimedError"),
82407
82754
  RangeError: makeErrorSubclassReviver2(global2, "RangeError"),
82408
82755
  ReferenceError: makeErrorSubclassReviver2(global2, "ReferenceError"),
82409
82756
  RetryableError: /* @__PURE__ */ __name((value) => {
@@ -86041,7 +86388,7 @@ var version5;
86041
86388
  var init_version4 = __esm({
86042
86389
  "../core/dist/version.js"() {
86043
86390
  "use strict";
86044
- version5 = "5.0.0-beta.54";
86391
+ version5 = "5.0.0-beta.56";
86045
86392
  }
86046
86393
  });
86047
86394
 
@@ -86512,6 +86859,112 @@ var init_helpers3 = __esm({
86512
86859
  }
86513
86860
  });
86514
86861
 
86862
+ // ../core/dist/runtime/hook-wake.js
86863
+ function isRetryableWakeError2(error121, isDeploymentUnavailableError) {
86864
+ if (isDeploymentUnavailableError?.(error121))
86865
+ return false;
86866
+ const status = error121 ?? {};
86867
+ const code3 = status.status ?? status.statusCode;
86868
+ if (typeof code3 === "number") {
86869
+ return code3 >= 500 || code3 === 408 || code3 === 429;
86870
+ }
86871
+ const name = error121?.name;
86872
+ return name !== "BadRequestError" && name !== "UnauthorizedError" && name !== "ForbiddenError";
86873
+ }
86874
+ async function publishHookWakeWithRetry2(publish, isDeploymentUnavailableError) {
86875
+ let lastError;
86876
+ for (let attempt = 0; attempt <= HOOK_WAKE_RETRY_DELAYS_MS2.length; attempt++) {
86877
+ try {
86878
+ await publish();
86879
+ return;
86880
+ } catch (error121) {
86881
+ lastError = error121;
86882
+ if (!isRetryableWakeError2(error121, isDeploymentUnavailableError))
86883
+ break;
86884
+ const delayMs = HOOK_WAKE_RETRY_DELAYS_MS2[attempt];
86885
+ if (delayMs !== void 0) {
86886
+ await new Promise((resolve3) => setTimeout(resolve3, delayMs));
86887
+ }
86888
+ }
86889
+ }
86890
+ if (HookNotFoundError2.is(lastError)) {
86891
+ throw new WorkflowRuntimeError2("The hook resume was committed, but its workflow wake could not be published", { cause: lastError });
86892
+ }
86893
+ throw lastError;
86894
+ }
86895
+ async function publishForceClaimVictimWake(world, claimerRunId, hook) {
86896
+ const from = hook.claimedFrom;
86897
+ if (!from || from.runId === claimerRunId)
86898
+ return "skipped";
86899
+ if (from.workflowName === void 0) {
86900
+ runtimeLogger2.warn("Force-claimed a hook from a run whose workflow name is unknown; not waking it", { workflowRunId: claimerRunId, victimRunId: from.runId });
86901
+ return "skipped";
86902
+ }
86903
+ try {
86904
+ await publishHookWakeWithRetry2(() => world.queue(getWorkflowQueueName2(from.workflowName), { runId: from.runId }, {
86905
+ ...from.deploymentId !== void 0 && {
86906
+ deploymentId: from.deploymentId
86907
+ },
86908
+ specVersion: from.runSpecVersion ?? SPEC_VERSION_LEGACY2,
86909
+ idempotencyKey: `hook-force-claim-${hook.hookId}`
86910
+ }), world.isDeploymentUnavailableError?.bind(world));
86911
+ return "published";
86912
+ } catch (error121) {
86913
+ runtimeLogger2.error("Force-claimed a hook token but could not wake the run it was taken from; it will read the disposal on its next invocation", {
86914
+ workflowRunId: claimerRunId,
86915
+ victimRunId: from.runId,
86916
+ error: error121 instanceof Error ? error121.message : String(error121)
86917
+ });
86918
+ return "failed";
86919
+ }
86920
+ }
86921
+ function forcedCreationOwingWake(events) {
86922
+ if (!events)
86923
+ return void 0;
86924
+ for (let i = events.length - 1; i >= 0; i--) {
86925
+ const event = events[i];
86926
+ if (event.eventType === "hook_received" || event.eventType === "noop" || event.eventType === "hook_disposed" && event.eventData?.forceClaimedBy !== void 0) {
86927
+ continue;
86928
+ }
86929
+ return event.eventType === "hook_created" && event.eventData.forceClaimedFrom !== void 0 ? event : void 0;
86930
+ }
86931
+ return void 0;
86932
+ }
86933
+ async function republishOwedForceClaimVictimWake(world, runId, events) {
86934
+ const owed = forcedCreationOwingWake(events);
86935
+ if (!owed)
86936
+ return;
86937
+ const claimedFrom = owed.eventData.forceClaimedFrom;
86938
+ const outcome = await publishForceClaimVictimWake(world, runId, {
86939
+ hookId: owed.correlationId,
86940
+ claimedFrom
86941
+ });
86942
+ if (outcome !== "skipped") {
86943
+ runtimeLogger2.info("Republished the wake of a force-claimed hook victim", {
86944
+ workflowRunId: runId,
86945
+ hookId: owed.correlationId,
86946
+ victimRunId: claimedFrom.runId,
86947
+ victimWake: outcome
86948
+ });
86949
+ }
86950
+ }
86951
+ var HOOK_WAKE_RETRY_DELAYS_MS2;
86952
+ var init_hook_wake2 = __esm({
86953
+ "../core/dist/runtime/hook-wake.js"() {
86954
+ "use strict";
86955
+ init_dist7();
86956
+ init_dist6();
86957
+ init_logger2();
86958
+ init_helpers3();
86959
+ HOOK_WAKE_RETRY_DELAYS_MS2 = [25, 100];
86960
+ __name(isRetryableWakeError2, "isRetryableWakeError");
86961
+ __name(publishHookWakeWithRetry2, "publishHookWakeWithRetry");
86962
+ __name(publishForceClaimVictimWake, "publishForceClaimVictimWake");
86963
+ __name(forcedCreationOwingWake, "forcedCreationOwingWake");
86964
+ __name(republishOwedForceClaimVictimWake, "republishOwedForceClaimVictimWake");
86965
+ }
86966
+ });
86967
+
86515
86968
  // ../core/dist/runtime/invocations.js
86516
86969
  async function handleInvocation(world, runId, requestId, payload) {
86517
86970
  const parsed = HookInvocationSchema2.safeParse(payload);
@@ -86730,38 +87183,6 @@ async function computeResumePayloadDigest2(bytes) {
86730
87183
  }
86731
87184
  return hex5;
86732
87185
  }
86733
- function isRetryableWakeError2(error121, isDeploymentUnavailableError) {
86734
- if (isDeploymentUnavailableError?.(error121))
86735
- return false;
86736
- const status = error121 ?? {};
86737
- const code3 = status.status ?? status.statusCode;
86738
- if (typeof code3 === "number") {
86739
- return code3 >= 500 || code3 === 408 || code3 === 429;
86740
- }
86741
- const name = error121?.name;
86742
- return name !== "BadRequestError" && name !== "UnauthorizedError" && name !== "ForbiddenError";
86743
- }
86744
- async function publishHookWakeWithRetry2(publish, isDeploymentUnavailableError) {
86745
- let lastError;
86746
- for (let attempt = 0; attempt <= HOOK_WAKE_RETRY_DELAYS_MS2.length; attempt++) {
86747
- try {
86748
- await publish();
86749
- return;
86750
- } catch (error121) {
86751
- lastError = error121;
86752
- if (!isRetryableWakeError2(error121, isDeploymentUnavailableError))
86753
- break;
86754
- const delayMs = HOOK_WAKE_RETRY_DELAYS_MS2[attempt];
86755
- if (delayMs !== void 0) {
86756
- await new Promise((resolve3) => setTimeout(resolve3, delayMs));
86757
- }
86758
- }
86759
- }
86760
- if (HookNotFoundError2.is(lastError)) {
86761
- throw new WorkflowRuntimeError2("The hook resume was committed, but its workflow wake could not be published", { cause: lastError });
86762
- }
86763
- throw lastError;
86764
- }
86765
87186
  function resumeContextFromRun2(run3) {
86766
87187
  const coreVersion = run3.executionContext?.workflowCoreVersion;
86767
87188
  const traceCarrier = run3.executionContext?.traceCarrier;
@@ -86837,154 +87258,255 @@ async function getHookByToken3(token) {
86837
87258
  async function resumeHook2(tokenOrHook, payload, encryptionKeyOverride) {
86838
87259
  return resumeHookImpl2(tokenOrHook, payload, encryptionKeyOverride, false, Date.now());
86839
87260
  }
86840
- async function resumeHookImpl2(tokenOrHook, payload, encryptionKeyOverride, hookFreshlyLookedUp, resumeRequestedAtMs) {
87261
+ async function resumeHookImpl2(tokenOrHook, payload, encryptionKeyOverride, hookFreshlyLookedUp, resumeRequestedAtMs, webhookOnly = false) {
86841
87262
  return await waitedUntil2(() => {
86842
87263
  return trace5("hook.resume", async (span) => {
86843
87264
  const world = await getWorldLazy2();
86844
- try {
86845
- const suppliedToken = typeof tokenOrHook === "string";
86846
- const hook = suppliedToken ? await world.hooks.getByToken(tokenOrHook) : tokenOrHook;
86847
- const hookResumeCapabilitiesAreFresh = suppliedToken || hookFreshlyLookedUp;
86848
- const info = await resolveHookResumeInfo2(hook);
86849
- const { resumeContext } = info;
86850
- span?.setAttributes({
86851
- ...HookToken2(hook.token),
86852
- ...HookId2(hook.hookId),
86853
- ...WorkflowRunId4(hook.runId),
86854
- "workflow.hook.resume_context_source": info.source
86855
- });
86856
- if (info.run && isTerminalWorkflowRunStatus2(info.run.status)) {
86857
- throw new HookNotFoundError2(hook.token);
86858
- }
86859
- const capabilities = getRunCapabilities2(resumeContext.workflowCoreVersion);
86860
- let payloadKey;
86861
- const runPublicKey = encryptionKeyOverride ? (
86862
- // The caller already holds a key (resumeWebhook resolved one to
86863
- // hydrate hook metadata), so sealing would add an ECDH for no
86864
- // saved round trip. Reuse what it resolved.
86865
- void 0
86866
- ) : decodeRunPublicKey2(resumeContext.encryptionPublicKey);
86867
- if (runPublicKey) {
86868
- payloadKey = sealTo2(runPublicKey);
86869
- } else {
86870
- let encryptionKey = encryptionKeyOverride ?? await resolveHookEncryptionKey2(hook, info);
86871
- if (!capabilities.supportedFormats.has(SerializationFormat2.ENCRYPTED)) {
86872
- encryptionKey = void 0;
86873
- }
86874
- payloadKey = encryptionKey;
86875
- }
86876
- const compression = (resumeContext.runSpecVersion ?? 0) >= SPEC_VERSION_SUPPORTS_COMPRESSION2 && capabilities.supportedFormats.has(SerializationFormat2.GZIP);
86877
- const ops = [];
86878
- const readbackOps = [];
86879
- const v1Compat = isLegacySpecVersion2(hook.specVersion);
86880
- const dehydratedPayload = await dehydrateStepReturnValue2(payload, hook.runId, payloadKey, ops, globalThis, v1Compat, capabilities.framedByteStreams, compression, void 0, readbackOps);
86881
- await Promise.all(ops.map((op) => op.catch((error121) => {
86882
- if (error121 !== void 0)
86883
- throw error121;
86884
- })));
86885
- safeWaitUntil2(Promise.all(readbackOps), (err) => {
86886
- if (err === void 0)
86887
- return;
86888
- runtimeLogger2.warn("Background readback of hook payload failed", {
86889
- workflowRunId: hook.runId,
86890
- hookId: hook.hookId,
86891
- error: err instanceof Error ? err.message : String(err)
87265
+ const token = typeof tokenOrHook === "string" ? tokenOrHook : tokenOrHook.token;
87266
+ let target2 = tokenOrHook;
87267
+ let fresh = hookFreshlyLookedUp;
87268
+ let keyOverride = encryptionKeyOverride;
87269
+ let redirects = 0;
87270
+ let lookupsAfterRedirect = 0;
87271
+ const MAX_LOOKUPS_AFTER_REDIRECT = 5;
87272
+ const resumeId = generateResumeId2();
87273
+ const assertResendable = /* @__PURE__ */ __name((cause) => {
87274
+ if (payload instanceof Request && payload.body !== null && payload.bodyUsed) {
87275
+ span?.setAttributes({
87276
+ "workflow.hook.resume_redirect_unresendable": true
86892
87277
  });
86893
- });
86894
- span?.setAttributes({
86895
- ...WorkflowName2(resumeContext.workflowName)
86896
- });
86897
- const originLink = await linkToTraceCarrier2(resumeContext.traceCarrier);
86898
- if (originLink) {
86899
- span?.addLink?.(originLink);
87278
+ throw new WorkflowRuntimeError2(`Hook token "${token}" changed owner while this webhook request was being delivered; a request body can be sent only once and it was not delivered anywhere \u2014 retry the request, which will reach the token's new owner`, { cause });
86900
87279
  }
86901
- if (world.capabilities?.invoke === true && !v1Compat && dehydratedPayload instanceof Uint8Array) {
86902
- if (!world.invoke) {
86903
- throw new WorkflowRuntimeError2("World advertises invoke without implementing it");
86904
- }
86905
- span?.setAttributes({ "workflow.hook.resume_strategy": "invoke" });
86906
- const result2 = HookInvocationResultSchema2.parse(await world.invoke(hook.runId, {
86907
- type: "hook_resume",
86908
- version: 1,
86909
- hookId: hook.hookId,
86910
- token: hook.token,
86911
- payload: dehydratedPayload
86912
- }, { idempotencyKey: generateResumeId2() }));
86913
- if (result2.status === "rejected") {
86914
- if (result2.code === "HOOK_NOT_FOUND")
86915
- throw new HookNotFoundError2(hook.token);
86916
- throw new WorkflowRuntimeError2("Executor rejected the hook invocation input");
86917
- }
86918
- span?.setAttributes(HookResumeCommitted2(true));
86919
- return asLazyMetadataHook2(hook);
86920
- }
86921
- const queueName = getWorkflowQueueName2(resumeContext.workflowName);
86922
- const queueOptions = {
86923
- deploymentId: resumeContext.deploymentId,
86924
- specVersion: resumeContext.runSpecVersion ?? SPEC_VERSION_LEGACY2
86925
- };
86926
- const backendDedupSupported = (hookResumeCapabilitiesAreFresh ? hook.resumeCapabilities?.hookResumeDedupVersion ?? 0 : 0) >= HOOK_RESUME_DEDUP_VERSION2 || world.capabilities?.hookResumeDedup === true;
86927
- const canClaimResume = backendDedupSupported && !v1Compat && dehydratedPayload instanceof Uint8Array;
86928
- span?.setAttributes({
86929
- "workflow.hook.resume_strategy": "sequential"
86930
- });
86931
- const resumeId = canClaimResume ? generateResumeId2() : void 0;
86932
- const payloadDigest = canClaimResume ? await computeResumePayloadDigest2(dehydratedPayload) : void 0;
86933
- if (resumeId) {
86934
- span?.setAttributes({ "workflow.hook.resume_id": resumeId });
86935
- }
86936
- const isHookGoneError = /* @__PURE__ */ __name((err) => HookNotFoundError2.is(err) || RunExpiredError2.is(err), "isHookGoneError");
87280
+ }, "assertResendable");
87281
+ for (; ; ) {
86937
87282
  try {
86938
- await world.events.create(hook.runId, {
86939
- eventType: "hook_received",
86940
- specVersion: SPEC_VERSION_CURRENT2,
86941
- correlationId: hook.hookId,
86942
- eventData: {
86943
- ...v1Compat ? {} : { token: hook.token },
86944
- payload: dehydratedPayload
86945
- }
86946
- }, {
86947
- v1Compat,
86948
- ...resumeId && payloadDigest ? { resumeId, resumePayloadDigest: payloadDigest } : {}
86949
- });
87283
+ return await resumeHookAttempt2(world, span, target2, payload, keyOverride, fresh, resumeRequestedAtMs, resumeId, webhookOnly);
86950
87284
  } catch (err) {
86951
- if (isHookGoneError(err)) {
86952
- throw new HookNotFoundError2(hook.token);
87285
+ if (err !== null && typeof err === "object" && notFoundReasons2.get(err) === "not-webhook") {
87286
+ throw err;
87287
+ }
87288
+ if (redirects >= MAX_FORCE_CLAIM_REDIRECTS2) {
87289
+ if (HookForceClaimedError2.is(err)) {
87290
+ span?.setAttributes({
87291
+ "workflow.hook.resume_redirects_exhausted": true
87292
+ });
87293
+ throw new WorkflowRuntimeError2(`Hook token "${token}" changed owner ${redirects} times while this resume was in flight; nothing was delivered \u2014 retry the resume`, { cause: err });
87294
+ }
87295
+ throw err;
87296
+ }
87297
+ if (HookForceClaimedError2.is(err)) {
87298
+ assertResendable(err);
87299
+ redirects++;
87300
+ span?.setAttributes({
87301
+ "workflow.hook.resume_redirects": redirects,
87302
+ "workflow.hook.resume_redirect_to_run": err.claimedByRunId
87303
+ });
87304
+ target2 = token;
87305
+ fresh = true;
87306
+ keyOverride = void 0;
87307
+ lookupsAfterRedirect = 0;
87308
+ continue;
87309
+ }
87310
+ if (HookNotFoundError2.is(err) && redirects > 0 && typeof target2 === "string" && lookupsAfterRedirect < MAX_LOOKUPS_AFTER_REDIRECT) {
87311
+ assertResendable(err);
87312
+ lookupsAfterRedirect++;
87313
+ await new Promise((resolve3) => setTimeout(resolve3, 50));
87314
+ continue;
87315
+ }
87316
+ if (HookNotFoundError2.is(err) && notFoundReasons2.get(err) !== "lookup") {
87317
+ const attemptedHookId = typeof target2 === "string" ? void 0 : target2.hookId;
87318
+ let relocated;
87319
+ try {
87320
+ relocated = await world.hooks.getByToken(token);
87321
+ } catch (lookupError) {
87322
+ if (!HookNotFoundError2.is(lookupError)) {
87323
+ runtimeLogger2.warn("Hook resume: re-resolving the token after a not-found failed; surfacing the original error", {
87324
+ token,
87325
+ error: lookupError instanceof Error ? lookupError.message : String(lookupError)
87326
+ });
87327
+ }
87328
+ }
87329
+ if (relocated?.claimedFrom !== void 0 && relocated.hookId !== attemptedHookId && (attemptedHookId === void 0 || relocated.claimedFrom.hookId === attemptedHookId) && !(webhookOnly && relocated.isWebhook === false)) {
87330
+ assertResendable(err);
87331
+ redirects++;
87332
+ span?.setAttributes({
87333
+ "workflow.hook.resume_redirects": redirects,
87334
+ "workflow.hook.resume_redirect_to_run": relocated.runId
87335
+ });
87336
+ target2 = relocated;
87337
+ fresh = true;
87338
+ keyOverride = void 0;
87339
+ continue;
87340
+ }
86953
87341
  }
86954
87342
  throw err;
86955
87343
  }
86956
- span?.setAttributes(HookResumeCommitted2(true));
86957
- const queuePublishRequestedAtMs = Date.now();
86958
- await publishHookWakeWithRetry2(() => world.queue(queueName, {
86959
- runId: hook.runId,
86960
- traceCarrier: resumeContext.traceCarrier ?? void 0,
86961
- hookResumeTiming: {
86962
- resumeRequestedAtMs,
86963
- queuePublishRequestedAtMs,
86964
- strategy: "sequential"
86965
- }
86966
- }, {
86967
- ...queueOptions,
86968
- // Dedup retried publishes whose response was lost: a
86969
- // duplicate wake is harmless for correctness (deterministic
86970
- // replay) but costs a full replay of the run, and the queue
86971
- // accepts a repeated idempotency key by delivering only one
86972
- // of the messages. Claim-less writes have no resumeId and
86973
- // keep the previous behavior.
86974
- ...resumeId ? { idempotencyKey: `hook-${resumeId}` } : {}
86975
- }), world.isDeploymentUnavailableError?.bind(world));
86976
- span?.setAttributes(HookWakePublished2(true));
86977
- return asLazyMetadataHook2(hook);
86978
- } catch (err) {
86979
- span?.setAttributes({
86980
- ...HookToken2(typeof tokenOrHook === "string" ? tokenOrHook : tokenOrHook.token),
86981
- ...HookFound2(false)
86982
- });
86983
- throw err;
86984
87344
  }
86985
87345
  });
86986
87346
  });
86987
87347
  }
87348
+ async function resumeHookAttempt2(world, span, tokenOrHook, payload, encryptionKeyOverride, hookFreshlyLookedUp, resumeRequestedAtMs, logicalResumeId, webhookOnly) {
87349
+ try {
87350
+ const suppliedToken = typeof tokenOrHook === "string";
87351
+ let hook;
87352
+ if (suppliedToken) {
87353
+ try {
87354
+ hook = await world.hooks.getByToken(tokenOrHook);
87355
+ } catch (lookupError) {
87356
+ if (HookNotFoundError2.is(lookupError)) {
87357
+ notFoundReasons2.set(lookupError, "lookup");
87358
+ }
87359
+ throw lookupError;
87360
+ }
87361
+ } else {
87362
+ hook = tokenOrHook;
87363
+ }
87364
+ if (webhookOnly && hook.isWebhook === false) {
87365
+ const notWebhook = new HookNotFoundError2(hook.token);
87366
+ notFoundReasons2.set(notWebhook, "not-webhook");
87367
+ throw notWebhook;
87368
+ }
87369
+ const hookResumeCapabilitiesAreFresh = suppliedToken || hookFreshlyLookedUp;
87370
+ const info = await resolveHookResumeInfo2(hook);
87371
+ const { resumeContext } = info;
87372
+ span?.setAttributes({
87373
+ ...HookToken2(hook.token),
87374
+ ...HookId2(hook.hookId),
87375
+ ...WorkflowRunId4(hook.runId),
87376
+ "workflow.hook.resume_context_source": info.source
87377
+ });
87378
+ if (info.run && isTerminalWorkflowRunStatus2(info.run.status)) {
87379
+ throw new HookNotFoundError2(hook.token);
87380
+ }
87381
+ const capabilities = getRunCapabilities2(resumeContext.workflowCoreVersion);
87382
+ let payloadKey;
87383
+ const runPublicKey = encryptionKeyOverride ? (
87384
+ // The caller already holds a key (resumeWebhook resolved one to
87385
+ // hydrate hook metadata), so sealing would add an ECDH for no
87386
+ // saved round trip. Reuse what it resolved.
87387
+ void 0
87388
+ ) : decodeRunPublicKey2(resumeContext.encryptionPublicKey);
87389
+ if (runPublicKey) {
87390
+ payloadKey = sealTo2(runPublicKey);
87391
+ } else {
87392
+ let encryptionKey = encryptionKeyOverride ?? await resolveHookEncryptionKey2(hook, info);
87393
+ if (!capabilities.supportedFormats.has(SerializationFormat2.ENCRYPTED)) {
87394
+ encryptionKey = void 0;
87395
+ }
87396
+ payloadKey = encryptionKey;
87397
+ }
87398
+ const compression = (resumeContext.runSpecVersion ?? 0) >= SPEC_VERSION_SUPPORTS_COMPRESSION2 && capabilities.supportedFormats.has(SerializationFormat2.GZIP);
87399
+ const ops = [];
87400
+ const readbackOps = [];
87401
+ const v1Compat = isLegacySpecVersion2(hook.specVersion);
87402
+ const dehydratedPayload = await dehydrateStepReturnValue2(payload, hook.runId, payloadKey, ops, globalThis, v1Compat, capabilities.framedByteStreams, compression, void 0, readbackOps);
87403
+ await Promise.all(ops.map((op) => op.catch((error121) => {
87404
+ if (error121 !== void 0)
87405
+ throw error121;
87406
+ })));
87407
+ safeWaitUntil2(Promise.all(readbackOps), (err) => {
87408
+ if (err === void 0)
87409
+ return;
87410
+ runtimeLogger2.warn("Background readback of hook payload failed", {
87411
+ workflowRunId: hook.runId,
87412
+ hookId: hook.hookId,
87413
+ error: err instanceof Error ? err.message : String(err)
87414
+ });
87415
+ });
87416
+ if (world.capabilities?.invoke === true && !v1Compat && dehydratedPayload instanceof Uint8Array) {
87417
+ if (!world.invoke) {
87418
+ throw new WorkflowRuntimeError2("World advertises invoke without implementing it");
87419
+ }
87420
+ span?.setAttributes({ "workflow.hook.resume_strategy": "invoke" });
87421
+ const result2 = HookInvocationResultSchema2.parse(await world.invoke(hook.runId, {
87422
+ type: "hook_resume",
87423
+ version: 1,
87424
+ hookId: hook.hookId,
87425
+ token: hook.token,
87426
+ payload: dehydratedPayload
87427
+ }, { idempotencyKey: logicalResumeId }));
87428
+ if (result2.status === "rejected") {
87429
+ if (result2.code === "HOOK_NOT_FOUND")
87430
+ throw new HookNotFoundError2(hook.token);
87431
+ throw new WorkflowRuntimeError2("Executor rejected the hook invocation input");
87432
+ }
87433
+ span?.setAttributes(HookResumeCommitted2(true));
87434
+ return asLazyMetadataHook2(hook);
87435
+ }
87436
+ span?.setAttributes({
87437
+ ...WorkflowName2(resumeContext.workflowName)
87438
+ });
87439
+ const originLink = await linkToTraceCarrier2(resumeContext.traceCarrier);
87440
+ if (originLink) {
87441
+ span?.addLink?.(originLink);
87442
+ }
87443
+ const queueName = getWorkflowQueueName2(resumeContext.workflowName);
87444
+ const queueOptions = {
87445
+ deploymentId: resumeContext.deploymentId,
87446
+ specVersion: resumeContext.runSpecVersion ?? SPEC_VERSION_LEGACY2
87447
+ };
87448
+ const backendDedupSupported = (hookResumeCapabilitiesAreFresh ? hook.resumeCapabilities?.hookResumeDedupVersion ?? 0 : 0) >= HOOK_RESUME_DEDUP_VERSION2 || world.capabilities?.hookResumeDedup === true;
87449
+ const canClaimResume = backendDedupSupported && !v1Compat && dehydratedPayload instanceof Uint8Array;
87450
+ span?.setAttributes({
87451
+ "workflow.hook.resume_strategy": "sequential"
87452
+ });
87453
+ const resumeId = canClaimResume ? logicalResumeId : void 0;
87454
+ const payloadDigest = canClaimResume ? await computeResumePayloadDigest2(dehydratedPayload) : void 0;
87455
+ if (resumeId) {
87456
+ span?.setAttributes({ "workflow.hook.resume_id": resumeId });
87457
+ }
87458
+ const isHookGoneError = /* @__PURE__ */ __name((err) => HookNotFoundError2.is(err) || RunExpiredError2.is(err), "isHookGoneError");
87459
+ try {
87460
+ await world.events.create(hook.runId, {
87461
+ eventType: "hook_received",
87462
+ specVersion: SPEC_VERSION_CURRENT2,
87463
+ correlationId: hook.hookId,
87464
+ eventData: {
87465
+ ...v1Compat ? {} : { token: hook.token },
87466
+ payload: dehydratedPayload
87467
+ }
87468
+ }, {
87469
+ v1Compat,
87470
+ ...resumeId && payloadDigest ? { resumeId, resumePayloadDigest: payloadDigest } : {}
87471
+ });
87472
+ } catch (err) {
87473
+ if (HookForceClaimedError2.is(err))
87474
+ throw err;
87475
+ if (isHookGoneError(err)) {
87476
+ throw new HookNotFoundError2(hook.token);
87477
+ }
87478
+ throw err;
87479
+ }
87480
+ span?.setAttributes(HookResumeCommitted2(true));
87481
+ const queuePublishRequestedAtMs = Date.now();
87482
+ await publishHookWakeWithRetry2(() => world.queue(queueName, {
87483
+ runId: hook.runId,
87484
+ traceCarrier: resumeContext.traceCarrier ?? void 0,
87485
+ hookResumeTiming: {
87486
+ resumeRequestedAtMs,
87487
+ queuePublishRequestedAtMs,
87488
+ strategy: "sequential"
87489
+ }
87490
+ }, {
87491
+ ...queueOptions,
87492
+ // Dedup retried publishes whose response was lost: a
87493
+ // duplicate wake is harmless for correctness (deterministic
87494
+ // replay) but costs a full replay of the run, and the queue
87495
+ // accepts a repeated idempotency key by delivering only one
87496
+ // of the messages. Claim-less writes have no resumeId and
87497
+ // keep the previous behavior.
87498
+ ...resumeId ? { idempotencyKey: `hook-${resumeId}` } : {}
87499
+ }), world.isDeploymentUnavailableError?.bind(world));
87500
+ span?.setAttributes(HookWakePublished2(true));
87501
+ return asLazyMetadataHook2(hook);
87502
+ } catch (err) {
87503
+ span?.setAttributes({
87504
+ ...HookToken2(typeof tokenOrHook === "string" ? tokenOrHook : tokenOrHook.token),
87505
+ ...HookFound2(false)
87506
+ });
87507
+ throw err;
87508
+ }
87509
+ }
86988
87510
  async function resumeWebhook2(token, request) {
86989
87511
  const resumeRequestedAtMs = Date.now();
86990
87512
  const world = await getWorldLazy2();
@@ -87008,7 +87530,7 @@ async function resumeWebhook2(token, request) {
87008
87530
  } else {
87009
87531
  response = new Response(null, { status: 202 });
87010
87532
  }
87011
- await resumeHookImpl2(hook, request, metadataEncryptionKey(), true, resumeRequestedAtMs);
87533
+ await resumeHookImpl2(hook, request, metadataEncryptionKey(), true, resumeRequestedAtMs, true);
87012
87534
  if (responseReadable) {
87013
87535
  const reader = responseReadable.getReader();
87014
87536
  const chunk = await reader.read();
@@ -87024,7 +87546,7 @@ async function resumeWebhook2(token, request) {
87024
87546
  }
87025
87547
  return response;
87026
87548
  }
87027
- var generateResumeId2, HOOK_WAKE_RETRY_DELAYS_MS2;
87549
+ var generateResumeId2, MAX_FORCE_CLAIM_REDIRECTS2, notFoundReasons2;
87028
87550
  var init_resume_hook2 = __esm({
87029
87551
  "../core/dist/runtime/resume-hook.js"() {
87030
87552
  "use strict";
@@ -87042,13 +87564,11 @@ var init_resume_hook2 = __esm({
87042
87564
  init_telemetry4();
87043
87565
  init_get_world_lazy2();
87044
87566
  init_helpers3();
87567
+ init_hook_wake2();
87045
87568
  init_invocations2();
87046
87569
  init_wait_until2();
87047
87570
  generateResumeId2 = monotonicFactory2();
87048
87571
  __name(computeResumePayloadDigest2, "computeResumePayloadDigest");
87049
- HOOK_WAKE_RETRY_DELAYS_MS2 = [25, 100];
87050
- __name(isRetryableWakeError2, "isRetryableWakeError");
87051
- __name(publishHookWakeWithRetry2, "publishHookWakeWithRetry");
87052
87572
  __name(resumeContextFromRun2, "resumeContextFromRun");
87053
87573
  __name(resolveHookResumeInfo2, "resolveHookResumeInfo");
87054
87574
  __name(resolveHookEncryptionKey2, "resolveHookEncryptionKey");
@@ -87057,7 +87577,10 @@ var init_resume_hook2 = __esm({
87057
87577
  __name(asLazyMetadataHook2, "asLazyMetadataHook");
87058
87578
  __name(getHookByToken3, "getHookByToken");
87059
87579
  __name(resumeHook2, "resumeHook");
87580
+ MAX_FORCE_CLAIM_REDIRECTS2 = 3;
87581
+ notFoundReasons2 = /* @__PURE__ */ new WeakMap();
87060
87582
  __name(resumeHookImpl2, "resumeHookImpl");
87583
+ __name(resumeHookAttempt2, "resumeHookAttempt");
87061
87584
  __name(resumeWebhook2, "resumeWebhook");
87062
87585
  }
87063
87586
  });
@@ -89341,6 +89864,11 @@ function getInlineOwnershipLeaseSeconds() {
89341
89864
  function getReplayDivergenceMaxRetries() {
89342
89865
  return envNumber2("WORKFLOW_REPLAY_DIVERGENCE_MAX_RETRIES", REPLAY_DIVERGENCE_MAX_RETRIES, { integer: true });
89343
89866
  }
89867
+ function getOpenWaitClockSkewMs() {
89868
+ return envNumber2("WORKFLOW_OPEN_WAIT_CLOCK_SKEW_MS", OPEN_WAIT_CLOCK_SKEW_MS, {
89869
+ integer: true
89870
+ });
89871
+ }
89344
89872
  function getPreconditionMaxInProcessRestarts() {
89345
89873
  return envNumber2("WORKFLOW_PRECONDITION_MAX_INPROCESS_RESTARTS", PRECONDITION_MAX_INPROCESS_RESTARTS, { integer: true });
89346
89874
  }
@@ -89353,7 +89881,7 @@ function getPreconditionReinvokeDelaySeconds() {
89353
89881
  function getDeploymentMismatchMaxRetries() {
89354
89882
  return envNumber2("WORKFLOW_DEPLOYMENT_MISMATCH_MAX_RETRIES", DEPLOYMENT_MISMATCH_MAX_RETRIES, { integer: true, min: 0 });
89355
89883
  }
89356
- var MAX_QUEUE_DELIVERIES, REPLAY_TIMEOUT_MS, MIN_REPLAY_TIMEOUT_MS, MAX_REPLAY_TIMEOUT_MS, warned, REPLAY_TIMEOUT_MAX_RETRIES, MAX_INLINE_STEPS, MIN_MAX_INLINE_STEPS, MAX_MAX_INLINE_STEPS, MAX_RESILIENT_STEP_INPUT_BYTES, MAX_BATCH_FANOUT_EVENTS, INLINE_OWNERSHIP_LEASE_SECONDS, MAX_INLINE_OWNERSHIP_LEASE_SECONDS, REPLAY_DIVERGENCE_MAX_RETRIES, PRECONDITION_MAX_INPROCESS_RESTARTS, PRECONDITION_MAX_REINVOCATIONS, PRECONDITION_REINVOKE_DELAY_SECONDS, DEPLOYMENT_MISMATCH_MAX_RETRIES;
89884
+ var MAX_QUEUE_DELIVERIES, REPLAY_TIMEOUT_MS, MIN_REPLAY_TIMEOUT_MS, MAX_REPLAY_TIMEOUT_MS, warned, REPLAY_TIMEOUT_MAX_RETRIES, MAX_INLINE_STEPS, MIN_MAX_INLINE_STEPS, MAX_MAX_INLINE_STEPS, MAX_RESILIENT_STEP_INPUT_BYTES, MAX_BATCH_FANOUT_EVENTS, INLINE_OWNERSHIP_LEASE_SECONDS, MAX_INLINE_OWNERSHIP_LEASE_SECONDS, REPLAY_DIVERGENCE_MAX_RETRIES, OPEN_WAIT_CLOCK_SKEW_MS, PRECONDITION_MAX_INPROCESS_RESTARTS, PRECONDITION_MAX_REINVOCATIONS, PRECONDITION_REINVOKE_DELAY_SECONDS, DEPLOYMENT_MISMATCH_MAX_RETRIES;
89357
89885
  var init_constants3 = __esm({
89358
89886
  "../core/dist/runtime/constants.js"() {
89359
89887
  "use strict";
@@ -89394,6 +89922,8 @@ var init_constants3 = __esm({
89394
89922
  __name(getInlineOwnershipLeaseSeconds, "getInlineOwnershipLeaseSeconds");
89395
89923
  REPLAY_DIVERGENCE_MAX_RETRIES = 3;
89396
89924
  __name(getReplayDivergenceMaxRetries, "getReplayDivergenceMaxRetries");
89925
+ OPEN_WAIT_CLOCK_SKEW_MS = 3e4;
89926
+ __name(getOpenWaitClockSkewMs, "getOpenWaitClockSkewMs");
89397
89927
  PRECONDITION_MAX_INPROCESS_RESTARTS = 3;
89398
89928
  __name(getPreconditionMaxInProcessRestarts, "getPreconditionMaxInProcessRestarts");
89399
89929
  PRECONDITION_MAX_REINVOCATIONS = 5;
@@ -91438,11 +91968,11 @@ var init_step_executor = __esm({
91438
91968
  });
91439
91969
 
91440
91970
  // ../core/dist/runtime/step-single-flight.js
91441
- async function runStepSingleFlight(runId, correlationId, execute) {
91971
+ async function runStepSingleFlight(runId, correlationId, execute, logLevel = "warn") {
91442
91972
  const key = `${runId}:${correlationId}`;
91443
91973
  const existing = singleFlight.inFlight.get(key);
91444
91974
  if (existing) {
91445
- runtimeLogger2.warn("Step execution already in flight in this process; awaiting its settlement instead of executing again", { workflowRunId: runId, stepId: correlationId });
91975
+ runtimeLogger2[logLevel]("Step execution already in flight in this process; awaiting its settlement instead of executing again", { workflowRunId: runId, stepId: correlationId });
91446
91976
  try {
91447
91977
  await existing;
91448
91978
  } catch {
@@ -96634,6 +97164,28 @@ function createQuickJSSerde(vm, capturedRoot) {
96634
97164
  reduced.cause = shape.cause;
96635
97165
  return reduced;
96636
97166
  }, "HookConflictError"),
97167
+ HookForceClaimedError: /* @__PURE__ */ __name((value) => {
97168
+ if (!isHandle(value) || !value.isError)
97169
+ return false;
97170
+ if (chainedString(value, "name") !== "HookForceClaimedError")
97171
+ return false;
97172
+ const shape = reduceErrorShape(value);
97173
+ const reduced = {
97174
+ message: shape.message,
97175
+ stack: shape.stack,
97176
+ token: own3(value, "token"),
97177
+ claimedByRunId: own3(value, "claimedByRunId")
97178
+ };
97179
+ const claimedByHookId = own3(value, "claimedByHookId");
97180
+ if (claimedByHookId && !claimedByHookId.isUndefined) {
97181
+ reduced.claimedByHookId = claimedByHookId;
97182
+ } else {
97183
+ claimedByHookId?.dispose();
97184
+ }
97185
+ if (Object.hasOwn(shape, "cause"))
97186
+ reduced.cause = shape.cause;
97187
+ return reduced;
97188
+ }, "HookForceClaimedError"),
96637
97189
  RangeError: namedErrorSubclassReducer("RangeError"),
96638
97190
  ReferenceError: namedErrorSubclassReducer("ReferenceError"),
96639
97191
  RetryableError: /* @__PURE__ */ __name((value) => {
@@ -97221,6 +97773,42 @@ function createQuickJSSerde(vm, capturedRoot) {
97221
97773
  }
97222
97774
  return error121;
97223
97775
  }, "HookConflictError"),
97776
+ HookForceClaimedError: /* @__PURE__ */ __name((value) => {
97777
+ const cls = registeredErrorClass("@workflow/errors//HookForceClaimedError");
97778
+ let error121;
97779
+ if (cls) {
97780
+ const token = own3(value, "token") ?? vm.undefined;
97781
+ const claimedByRunId = own3(value, "claimedByRunId") ?? vm.undefined;
97782
+ const claimedByHookId = own3(value, "claimedByHookId") ?? vm.undefined;
97783
+ error121 = vm.construct(cls, token, claimedByRunId, claimedByHookId);
97784
+ if (token !== vm.undefined)
97785
+ token.dispose();
97786
+ if (claimedByRunId !== vm.undefined)
97787
+ claimedByRunId.dispose();
97788
+ if (claimedByHookId !== vm.undefined)
97789
+ claimedByHookId.dispose();
97790
+ const stack = own3(value, "stack");
97791
+ if (stack && !stack.isUndefined)
97792
+ define2(error121, "stack", stack);
97793
+ stack?.dispose();
97794
+ if (guestHasOwn(value, "cause")) {
97795
+ const cause = own3(value, "cause") ?? vm.undefined;
97796
+ define2(error121, "cause", cause);
97797
+ if (cause !== vm.undefined)
97798
+ cause.dispose();
97799
+ }
97800
+ cls.dispose();
97801
+ } else {
97802
+ error121 = buildError(i.Error, value, { name: "HookForceClaimedError" });
97803
+ for (const field of ["token", "claimedByRunId", "claimedByHookId"]) {
97804
+ const handle = own3(value, field);
97805
+ if (handle && !handle.isUndefined)
97806
+ define2(error121, field, handle);
97807
+ handle?.dispose();
97808
+ }
97809
+ }
97810
+ return error121;
97811
+ }, "HookForceClaimedError"),
97224
97812
  RangeError: namedErrorSubclassReviver("RangeError"),
97225
97813
  ReferenceError: namedErrorSubclassReviver("ReferenceError"),
97226
97814
  RetryableError: /* @__PURE__ */ __name((value) => {
@@ -97818,6 +98406,7 @@ var init_quickjs_serde = __esm({
97818
98406
  "workflow-class-registry",
97819
98407
  "@workflow/errors//FatalError",
97820
98408
  "@workflow/errors//HookConflictError",
98409
+ "@workflow/errors//HookForceClaimedError",
97821
98410
  "@workflow/errors//RetryableError",
97822
98411
  "@workflow/errors//RuntimeDecryptionError",
97823
98412
  "@workflow/errors//StreamError"
@@ -98509,13 +99098,30 @@ async function processEvents(vm, serde, events, advanceClock, encryptionKey) {
98509
99098
  case "hook_conflict": {
98510
99099
  const conflictToken = eventData?.token ?? "unknown";
98511
99100
  const conflictingRunId = eventData?.conflictingRunId;
99101
+ const forceRefusedReason = eventData?.forceRefusedReason;
98512
99102
  const didSettle = vm.dump(vm.evalCode(`(function(){
98513
99103
  var cid = ${JSON.stringify(cid)};
98514
99104
  var token = ${JSON.stringify(conflictToken)};
98515
99105
  var conflictingRunId = ${JSON.stringify(conflictingRunId ?? null)};
99106
+ var forceRefused = ${JSON.stringify(forceRefusedReason !== void 0)};
98516
99107
  var ErrCls = globalThis[Symbol.for('@workflow/errors//HookConflictError')];
98517
99108
  var err;
98518
- if (typeof ErrCls === 'function') {
99109
+ var hookState = globalThis.__hooks && globalThis.__hooks[cid];
99110
+ // A forced hook asked for a guarantee the World could not give
99111
+ // (older server, kill switch): a misconfiguration, not the
99112
+ // ordinary conflict the caller opted out of. Mirrors hook.ts.
99113
+ var forced = !!(hookState && hookState.force) && !forceRefused;
99114
+ if (forced) {
99115
+ var FatalCls = globalThis[Symbol.for('@workflow/errors//FatalError')];
99116
+ var forcedMessage = 'createHook({ experimental_force: true }) for token "' + token + '" was answered with a hook_conflict: the configured World does not support force-claiming hook tokens' + (conflictingRunId ? ' (run "' + conflictingRunId + '" holds it)' : '') + '.';
99117
+ if (typeof FatalCls === 'function') {
99118
+ err = new FatalCls(forcedMessage);
99119
+ } else {
99120
+ err = new Error(forcedMessage);
99121
+ err.name = 'FatalError';
99122
+ err.fatal = true;
99123
+ }
99124
+ } else if (typeof ErrCls === 'function') {
98519
99125
  err = new ErrCls(token, conflictingRunId || undefined);
98520
99126
  } else {
98521
99127
  err = new Error('Hook token "' + token + '" is already in use by another workflow');
@@ -98524,7 +99130,7 @@ async function processEvents(vm, serde, events, advanceClock, encryptionKey) {
98524
99130
  if (conflictingRunId) err.conflictingRunId = conflictingRunId;
98525
99131
  }
98526
99132
  var run = null;
98527
- if (conflictingRunId) {
99133
+ if (conflictingRunId && !forced) {
98528
99134
  var reg = globalThis[Symbol.for('workflow-class-registry')];
98529
99135
  var RunCls = reg && reg.get('class//workflow//Run');
98530
99136
  var des = RunCls && RunCls[Symbol.for('workflow-deserialize')];
@@ -98588,6 +99194,48 @@ async function processEvents(vm, serde, events, advanceClock, encryptionKey) {
98588
99194
  break;
98589
99195
  }
98590
99196
  case "hook_disposed": {
99197
+ const claimedBy = eventData?.forceClaimedBy;
99198
+ if (claimedBy && typeof claimedBy.runId === "string") {
99199
+ const hookState = vm.dump(vm.evalCode(`(function(){
99200
+ var cid = ${JSON.stringify(cid)};
99201
+ var state = globalThis.__hooks && globalThis.__hooks[cid];
99202
+ var token = state ? state.token : ${JSON.stringify(eventData?.token ?? "")};
99203
+ var claimedByRunId = ${JSON.stringify(claimedBy.runId)};
99204
+ var claimedByHookId = ${JSON.stringify(claimedBy.hookId ?? null)};
99205
+ var ErrCls = globalThis[Symbol.for('@workflow/errors//HookForceClaimedError')];
99206
+ var err;
99207
+ if (typeof ErrCls === 'function') {
99208
+ err = new ErrCls(token, claimedByRunId, claimedByHookId || undefined);
99209
+ } else {
99210
+ err = new Error('Hook token "' + token + '" was force-claimed by another workflow (run "' + claimedByRunId + '")');
99211
+ err.name = 'HookForceClaimedError';
99212
+ err.token = token;
99213
+ err.claimedByRunId = claimedByRunId;
99214
+ if (claimedByHookId) err.claimedByHookId = claimedByHookId;
99215
+ }
99216
+ var settled = false;
99217
+ if (state) {
99218
+ state.forceClaimed = err;
99219
+ var gc = state.getConflictResolvers;
99220
+ state.getConflictResolvers = [];
99221
+ for (var i = 0; i < gc.length; i++) { gc[i].resolve(null); settled = true; }
99222
+ }
99223
+ if (globalThis.__resolvers[cid]) {
99224
+ globalThis.__resolvers[cid].reject(err);
99225
+ delete globalThis.__resolvers[cid];
99226
+ settled = true;
99227
+ }
99228
+ return settled;
99229
+ })()`));
99230
+ if (hookState) {
99231
+ resolved = true;
99232
+ let b;
99233
+ do {
99234
+ b = vm.executePendingJobs();
99235
+ } while (b > 0);
99236
+ }
99237
+ markCreated(vm, cidJs);
99238
+ }
98591
99239
  markCreated(vm, cidJs, "hook_dispose");
98592
99240
  break;
98593
99241
  }
@@ -99346,6 +99994,20 @@ globalThis[Symbol.for("WORKFLOW_CREATE_HOOK")] = function(options) {
99346
99994
  unsupportedRetentionError.fatal = true;
99347
99995
  throw unsupportedRetentionError;
99348
99996
  }
99997
+ if (options.experimental_force === true) {
99998
+ if (options.token === undefined || options.token === null) {
99999
+ throw new Error('\`createHook()\` was called with \`experimental_force: true\` but no \`token\`. Force-claiming only applies to an explicit token another run may hold.');
100000
+ }
100001
+ if (options.isWebhook === true) {
100002
+ throw new Error('Webhook hooks do not support \`experimental_force\`. Use a non-webhook \`createHook()\` with an explicit token.');
100003
+ }
100004
+ if (globalThis.__worldCapabilities?.hookForceClaim !== true) {
100005
+ var unsupportedForceError = new Error('The configured World does not support \`experimental_force\` for Hooks.');
100006
+ unsupportedForceError.name = "FatalError";
100007
+ unsupportedForceError.fatal = true;
100008
+ throw unsupportedForceError;
100009
+ }
100010
+ }
99349
100011
  var token = options.token || globalThis.__generateNanoid();
99350
100012
  var correlationId = "hook_" + globalThis.__generateUlid();
99351
100013
  var isDisposed = false;
@@ -99382,6 +100044,7 @@ globalThis[Symbol.for("WORKFLOW_CREATE_HOOK")] = function(options) {
99382
100044
  token: token,
99383
100045
  tokenRetentionUntil: tokenRetentionUntil,
99384
100046
  isWebhook: !!options.isWebhook,
100047
+ force: options.experimental_force === true,
99385
100048
  metadata: options.metadata,
99386
100049
  hasCreatedEvent: false,
99387
100050
  };
@@ -99397,6 +100060,11 @@ globalThis[Symbol.for("WORKFLOW_CREATE_HOOK")] = function(options) {
99397
100060
  token: token,
99398
100061
  created: false,
99399
100062
  conflict: null,
100063
+ // Set by the host on a hook_disposed{forceClaimedBy}: another run took
100064
+ // the token. Buffered payloads (delivered before the takeover) are still
100065
+ // drained; every await after them rejects with this error.
100066
+ forceClaimed: null,
100067
+ force: options.experimental_force === true,
99400
100068
  getConflictResolvers: [],
99401
100069
  };
99402
100070
 
@@ -99410,6 +100078,10 @@ globalThis[Symbol.for("WORKFLOW_CREATE_HOOK")] = function(options) {
99410
100078
  if (buf && buf.length > 0) {
99411
100079
  return Promise.resolve(buf.shift());
99412
100080
  }
100081
+ var claimedState = globalThis.__hooks[correlationId];
100082
+ if (claimedState && claimedState.forceClaimed) {
100083
+ return Promise.reject(claimedState.forceClaimed);
100084
+ }
99413
100085
  return new Promise(function(resolve, reject) {
99414
100086
  globalThis.__resolvers[correlationId] = { resolve: resolve, reject: reject };
99415
100087
  });
@@ -99425,7 +100097,9 @@ globalThis[Symbol.for("WORKFLOW_CREATE_HOOK")] = function(options) {
99425
100097
  // hook_disposed here would be rejected by the world's
99426
100098
  // hook-existence validation.
99427
100099
  var state = globalThis.__hooks[correlationId];
99428
- if (!state || !state.conflict) {
100100
+ // A force-claimed hook is already disposed \u2014 the takeover journaled
100101
+ // its hook_disposed \u2014 so there is nothing left to dispose either.
100102
+ if (!state || (!state.conflict && !state.forceClaimed)) {
99429
100103
  // Signal to the entrypoint to create a hook_disposed event. The
99430
100104
  // token is carried so the entrypoint can order same-token hook
99431
100105
  // operations sequentially (a dispose must release the token before
@@ -99817,9 +100491,19 @@ async function dispatchPendingOps(params) {
99817
100491
  isWebhook: hook.isWebhook,
99818
100492
  // System hooks (AbortController) are exempt from user
99819
100493
  // token namespace conflict checks.
99820
- ...hook.isSystem ? { isSystem: true } : {}
100494
+ ...hook.isSystem ? { isSystem: true } : {},
100495
+ ...hook.force ? { force: true } : {}
99821
100496
  }
99822
100497
  }, hookDeltaCursor !== void 0 ? { sinceCursor: hookDeltaCursor } : void 0);
100498
+ if (result2.hook?.claimedFrom) {
100499
+ const outcome = await publishForceClaimVictimWake(world, runId, result2.hook);
100500
+ runtimeLogger2.info("Hook token force-claimed from another run", {
100501
+ workflowRunId: runId,
100502
+ hookId: hook.correlationId,
100503
+ victimRunId: result2.hook.claimedFrom.runId,
100504
+ victimWake: outcome
100505
+ });
100506
+ }
99823
100507
  if (result2.event?.eventType === "hook_conflict") {
99824
100508
  await queueMessage(world, getWorkflowQueueName2(workflowRun.workflowName, namespace), {
99825
100509
  runId,
@@ -99908,16 +100592,23 @@ async function dispatchPendingOps(params) {
99908
100592
  hookOpsByToken.set(key, [op]);
99909
100593
  }
99910
100594
  }
99911
- for (const group of hookOpsByToken.values()) {
99912
- opsPromises.push((async () => {
99913
- for (const op of group) {
99914
- if (op.type === "hook") {
99915
- await processHookOp(op);
99916
- } else {
99917
- await processHookDisposeOp(op);
99918
- }
100595
+ const runHookGroup = /* @__PURE__ */ __name(async (group) => {
100596
+ for (const op of group) {
100597
+ if (op.type === "hook") {
100598
+ await processHookOp(op);
100599
+ } else {
100600
+ await processHookDisposeOp(op);
99919
100601
  }
99920
- })());
100602
+ }
100603
+ }, "runHookGroup");
100604
+ const hookGroups = [...hookOpsByToken.values()];
100605
+ const holdsForcedCreation = /* @__PURE__ */ __name((group) => group.some((op) => op.type === "hook" && op.force === true && !op.hasCreatedEvent), "holdsForcedCreation");
100606
+ for (const group of hookGroups.filter(holdsForcedCreation)) {
100607
+ await runHookGroup(group);
100608
+ }
100609
+ for (const group of hookGroups) {
100610
+ if (!holdsForcedCreation(group))
100611
+ opsPromises.push(runHookGroup(group));
99921
100612
  }
99922
100613
  for (const op of pendingOperations) {
99923
100614
  if (op.type === "step" && !op.hasCreatedEvent && !skipStepCreation?.has(op.correlationId)) {
@@ -100149,6 +100840,7 @@ async function runWorkflowWithQuickJS(params) {
100149
100840
  events = allEvents;
100150
100841
  loadedCursor = cursor;
100151
100842
  }
100843
+ await republishOwedForceClaimVictimWake(world, runId, events);
100152
100844
  const logView = new QuickJSLogView(events, loadedCursor);
100153
100845
  const createEvent = /* @__PURE__ */ __name(async (data, eventParams) => {
100154
100846
  const result3 = await world.events.create(runId, data, {
@@ -100558,7 +101250,7 @@ async function runWorkflowWithQuickJS(params) {
100558
101250
  // attempt.
100559
101251
  authoritativeAttempt: 1,
100560
101252
  ...inlineDeltaSinceCursor !== void 0 ? { inlineDeltaSinceCursor } : {}
100561
- }))())));
101253
+ }))(), "debug")));
100562
101254
  } finally {
100563
101255
  budget.resume();
100564
101256
  }
@@ -100893,6 +101585,7 @@ var init_quickjs_entrypoint = __esm({
100893
101585
  init_constants3();
100894
101586
  init_get_port_lazy();
100895
101587
  init_helpers3();
101588
+ init_hook_wake2();
100896
101589
  init_lifecycle_hooks();
100897
101590
  init_quickjs_log_view();
100898
101591
  init_quickjs_runtime();
@@ -101341,6 +102034,7 @@ var StepNotRegisteredError;
101341
102034
  var WorkflowNotRegisteredError;
101342
102035
  var WorkflowRunNotFoundError;
101343
102036
  var HookConflictError;
102037
+ var HookForceClaimedError;
101344
102038
  var HookNotFoundError;
101345
102039
  var EntityConflictError;
101346
102040
  var RunExpiredError;
@@ -101353,6 +102047,7 @@ var RetryableError;
101353
102047
  var FATAL_ERROR_KEY;
101354
102048
  var RETRYABLE_ERROR_KEY;
101355
102049
  var HOOK_CONFLICT_ERROR_KEY;
102050
+ var HOOK_FORCE_CLAIMED_ERROR_KEY;
101356
102051
  var RUNTIME_DECRYPTION_ERROR_KEY;
101357
102052
  var STREAM_ERROR_KEY;
101358
102053
  var init_dist2 = __esm2({
@@ -101374,6 +102069,7 @@ var init_dist2 = __esm2({
101374
102069
  FETCH_IN_WORKFLOW_FUNCTION: "fetch-in-workflow",
101375
102070
  TIMEOUT_FUNCTIONS_IN_WORKFLOW: "timeout-in-workflow",
101376
102071
  HOOK_CONFLICT: "hook-conflict",
102072
+ HOOK_FORCE_CLAIMED: "hook-force-claimed",
101377
102073
  CORRUPTED_EVENT_LOG: "corrupted-event-log",
101378
102074
  REPLAY_DIVERGENCE: "replay-divergence",
101379
102075
  STEP_NOT_REGISTERED: "step-not-registered",
@@ -101633,6 +102329,33 @@ Caused by: ${options.cause.stack}`;
101633
102329
  return isError(value) && value.name === "HookConflictError";
101634
102330
  }
101635
102331
  };
102332
+ HookForceClaimedError = class extends WorkflowError {
102333
+ static {
102334
+ __name(this, "HookForceClaimedError");
102335
+ }
102336
+ static {
102337
+ __name2(this, "HookForceClaimedError");
102338
+ }
102339
+ token;
102340
+ /** The run that took the token. */
102341
+ claimedByRunId;
102342
+ /** The hook (in `claimedByRunId`) the token now belongs to. */
102343
+ claimedByHookId;
102344
+ constructor(token, claimedByRunId, claimedByHookId) {
102345
+ super(`Hook token "${token}" was force-claimed by another workflow (run "${claimedByRunId}")`, {
102346
+ slug: ERROR_SLUGS.HOOK_FORCE_CLAIMED
102347
+ });
102348
+ this.name = "HookForceClaimedError";
102349
+ this.token = token;
102350
+ this.claimedByRunId = claimedByRunId;
102351
+ if (claimedByHookId !== void 0) {
102352
+ this.claimedByHookId = claimedByHookId;
102353
+ }
102354
+ }
102355
+ static is(value) {
102356
+ return isError(value) && value.name === "HookForceClaimedError";
102357
+ }
102358
+ };
101636
102359
  HookNotFoundError = class extends WorkflowError {
101637
102360
  static {
101638
102361
  __name(this, "HookNotFoundError");
@@ -101812,6 +102535,7 @@ Caused by: ${options.cause.stack}`;
101812
102535
  FATAL_ERROR_KEY = /* @__PURE__ */ Symbol.for("@workflow/errors//FatalError");
101813
102536
  RETRYABLE_ERROR_KEY = /* @__PURE__ */ Symbol.for("@workflow/errors//RetryableError");
101814
102537
  HOOK_CONFLICT_ERROR_KEY = /* @__PURE__ */ Symbol.for("@workflow/errors//HookConflictError");
102538
+ HOOK_FORCE_CLAIMED_ERROR_KEY = /* @__PURE__ */ Symbol.for("@workflow/errors//HookForceClaimedError");
101815
102539
  RUNTIME_DECRYPTION_ERROR_KEY = /* @__PURE__ */ Symbol.for("@workflow/errors//RuntimeDecryptionError");
101816
102540
  STREAM_ERROR_KEY = /* @__PURE__ */ Symbol.for("@workflow/errors//StreamError");
101817
102541
  if (typeof globalThis !== "undefined") {
@@ -101839,6 +102563,14 @@ Caused by: ${options.cause.stack}`;
101839
102563
  configurable: false
101840
102564
  });
101841
102565
  }
102566
+ if (!Object.hasOwn(globalThis, HOOK_FORCE_CLAIMED_ERROR_KEY)) {
102567
+ Object.defineProperty(globalThis, HOOK_FORCE_CLAIMED_ERROR_KEY, {
102568
+ value: HookForceClaimedError,
102569
+ writable: false,
102570
+ enumerable: false,
102571
+ configurable: false
102572
+ });
102573
+ }
101842
102574
  if (!Object.hasOwn(globalThis, RUNTIME_DECRYPTION_ERROR_KEY)) {
101843
102575
  Object.defineProperty(globalThis, RUNTIME_DECRYPTION_ERROR_KEY, {
101844
102576
  value: RuntimeDecryptionError,
@@ -101915,7 +102647,7 @@ var SPEC_VERSION_SUPPORTS_CBOR_QUEUE_TRANSPORT;
101915
102647
  var SPEC_VERSION_SUPPORTS_ATTRIBUTES;
101916
102648
  var SPEC_VERSION_SUPPORTS_COMPRESSION;
101917
102649
  var SPEC_VERSION_SUPPORTS_SLOT_IDENTITY;
101918
- var SPEC_VERSION_SUPPORTS_SEALED_LOG;
102650
+ var SPEC_VERSION_SUPPORTS_HOOK_FORCE_CLAIM;
101919
102651
  var SPEC_VERSION_CURRENT;
101920
102652
  var SPEC_VERSION_MAX_SUPPORTED;
101921
102653
  var init_spec_version = __esm2({
@@ -101927,9 +102659,9 @@ var init_spec_version = __esm2({
101927
102659
  SPEC_VERSION_SUPPORTS_ATTRIBUTES = 4;
101928
102660
  SPEC_VERSION_SUPPORTS_COMPRESSION = 5;
101929
102661
  SPEC_VERSION_SUPPORTS_SLOT_IDENTITY = 6;
101930
- SPEC_VERSION_SUPPORTS_SEALED_LOG = 7;
101931
- SPEC_VERSION_CURRENT = SPEC_VERSION_SUPPORTS_SEALED_LOG;
101932
- SPEC_VERSION_MAX_SUPPORTED = SPEC_VERSION_SUPPORTS_SEALED_LOG;
102662
+ SPEC_VERSION_SUPPORTS_HOOK_FORCE_CLAIM = 8;
102663
+ SPEC_VERSION_CURRENT = SPEC_VERSION_SUPPORTS_HOOK_FORCE_CLAIM;
102664
+ SPEC_VERSION_MAX_SUPPORTED = SPEC_VERSION_SUPPORTS_HOOK_FORCE_CLAIM;
101933
102665
  __name2(isLegacySpecVersion, "isLegacySpecVersion");
101934
102666
  }
101935
102667
  });
@@ -126890,7 +127622,30 @@ var init_events = __esm2({
126890
127622
  tokenRetentionUntil: external_exports.coerce.date().optional(),
126891
127623
  metadata: SerializedDataSchema.optional(),
126892
127624
  isWebhook: external_exports.boolean().optional(),
126893
- isSystem: external_exports.boolean().optional()
127625
+ isSystem: external_exports.boolean().optional(),
127626
+ /**
127627
+ * `createHook({ experimental_force: true })`: when the token belongs to
127628
+ * another live run, the World takes it over — journaling
127629
+ * `hook_disposed{forceClaimedBy}` in that run's log and re-pointing the
127630
+ * token — instead of answering `hook_conflict`. Requires the
127631
+ * `hookForceClaim` capability.
127632
+ */
127633
+ force: external_exports.boolean().optional(),
127634
+ /**
127635
+ * World-written on a forced creation that did take a token over: the
127636
+ * run and hook it was taken from, plus what a queue message to that run
127637
+ * needs (`workflowName`, `deploymentId`, `runSpecVersion`). Absent when
127638
+ * the token was free. The wake-targeting fields are in the LOG, not only
127639
+ * on the hook entity, so a replay can republish the victim's wake from
127640
+ * the row alone; see `publishForceClaimVictimWake` in @workflow/core.
127641
+ */
127642
+ forceClaimedFrom: external_exports.object({
127643
+ runId: external_exports.string(),
127644
+ hookId: external_exports.string(),
127645
+ workflowName: external_exports.string().optional(),
127646
+ deploymentId: external_exports.string().optional(),
127647
+ runSpecVersion: external_exports.number().optional()
127648
+ }).optional()
126894
127649
  })
126895
127650
  }));
126896
127651
  HookReceivedEventSchema = external_exports.compile(BaseEventSchema.extend({
@@ -126905,7 +127660,17 @@ var init_events = __esm2({
126905
127660
  eventType: external_exports.literal("hook_disposed"),
126906
127661
  correlationId: external_exports.string(),
126907
127662
  eventData: external_exports.object({
126908
- token: external_exports.string().optional()
127663
+ token: external_exports.string().optional(),
127664
+ /**
127665
+ * World-written: this disposal was not the run's own. Another run
127666
+ * took the hook's token with `experimental_force`, and this names
127667
+ * it. The hook consumer rejects the hook's awaiters with
127668
+ * `HookForceClaimedError` when it reads this row.
127669
+ */
127670
+ forceClaimedBy: external_exports.object({
127671
+ runId: external_exports.string(),
127672
+ hookId: external_exports.string()
127673
+ }).optional()
126909
127674
  }).optional()
126910
127675
  }));
126911
127676
  HookConflictEventSchema = external_exports.compile(BaseEventSchema.extend({
@@ -126915,7 +127680,18 @@ var init_events = __esm2({
126915
127680
  token: external_exports.string(),
126916
127681
  // TODO: Make this required once all persisted hook_conflict events and
126917
127682
  // remote World implementations always include the active hook owner's run ID.
126918
- conflictingRunId: external_exports.string().optional()
127683
+ conflictingRunId: external_exports.string().optional(),
127684
+ /**
127685
+ * Set when the creation asked for `force` and the World declined to take
127686
+ * the token over. `victim-spec-version`: the run holding the token was
127687
+ * started at a spec version below
127688
+ * `SPEC_VERSION_SUPPORTS_HOOK_FORCE_CLAIM`, so its runtime would not
127689
+ * understand the involuntary disposal — the forced hook gets the
127690
+ * ordinary `HookConflictError` it opted out of instead of stranding
127691
+ * that run. Absent on a conflict answered by a World that does not
127692
+ * implement forcing at all.
127693
+ */
127694
+ forceRefusedReason: external_exports.literal("victim-spec-version").optional()
126919
127695
  })
126920
127696
  }));
126921
127697
  NoopEventSchema = external_exports.compile(BaseEventSchema.extend({
@@ -127801,6 +128577,7 @@ var HookResumeContextSchema;
127801
128577
  var HOOK_RESUME_INPUT_VERSION;
127802
128578
  var HOOK_RESUME_DEDUP_VERSION;
127803
128579
  var HookResumeCapabilitiesSchema;
128580
+ var HookClaimedFromSchema;
127804
128581
  var HookSchema;
127805
128582
  var init_hooks = __esm2({
127806
128583
  "../world/dist/hooks.js"() {
@@ -127842,6 +128619,13 @@ var init_hooks = __esm2({
127842
128619
  // is engaged.
127843
128620
  hookResumeDedupVersion: external_exports.number()
127844
128621
  }));
128622
+ HookClaimedFromSchema = external_exports.compile(external_exports.object({
128623
+ runId: external_exports.string(),
128624
+ hookId: external_exports.string(),
128625
+ workflowName: external_exports.string().optional(),
128626
+ deploymentId: external_exports.string().optional(),
128627
+ runSpecVersion: external_exports.number().optional()
128628
+ }));
127845
128629
  HookSchema = external_exports.compile(external_exports.object({
127846
128630
  runId: external_exports.string(),
127847
128631
  hookId: external_exports.string(),
@@ -127869,7 +128653,12 @@ var init_hooks = __esm2({
127869
128653
  // `resumeHook()` gates its lazy path on this being present and
127870
128654
  // current. Absent against an older/rolled-back server or when the kill switch
127871
128655
  // is active.
127872
- resumeCapabilities: HookResumeCapabilitiesSchema.optional()
128656
+ resumeCapabilities: HookResumeCapabilitiesSchema.optional(),
128657
+ // Set when this hook took its token from another run
128658
+ // (`experimental_force`). The wake-targeting fields are the victim run's,
128659
+ // so the claimer's runtime can publish the victim's wake without reading
128660
+ // a run it may not be able to reach; see `HookClaimedFromSchema`.
128661
+ claimedFrom: HookClaimedFromSchema.optional()
127873
128662
  }));
127874
128663
  }
127875
128664
  });
@@ -128607,6 +129396,20 @@ function getCommonReducers(_global2 = globalThis) {
128607
129396
  }
128608
129397
  return reduced;
128609
129398
  }, "HookConflictError"),
129399
+ HookForceClaimedError: /* @__PURE__ */ __name2((value) => {
129400
+ const base = reduceNamedErrorSubclassBase("HookForceClaimedError", value);
129401
+ if (!base) return false;
129402
+ const reduced = {
129403
+ ...base,
129404
+ token: readProperty(value, "token"),
129405
+ claimedByRunId: readProperty(value, "claimedByRunId")
129406
+ };
129407
+ const claimedByHookId = readProperty(value, "claimedByHookId");
129408
+ if (claimedByHookId !== void 0) {
129409
+ reduced.claimedByHookId = claimedByHookId;
129410
+ }
129411
+ return reduced;
129412
+ }, "HookForceClaimedError"),
128610
129413
  RangeError: makeErrorSubclassReducer("RangeError"),
128611
129414
  ReferenceError: makeErrorSubclassReducer("ReferenceError"),
128612
129415
  // RetryableError carries an extra `retryAfter` Date that we serialize as
@@ -128782,6 +129585,15 @@ function getCommonRevivers(global2 = globalThis) {
128782
129585
  }
128783
129586
  return error612;
128784
129587
  }, "HookConflictError"),
129588
+ HookForceClaimedError: /* @__PURE__ */ __name2((value) => {
129589
+ const Ctor = global2[/* @__PURE__ */ Symbol.for("@workflow/errors//HookForceClaimedError")] ?? HookForceClaimedError;
129590
+ const error612 = new Ctor(value.token, value.claimedByRunId, value.claimedByHookId);
129591
+ if (value.stack !== void 0) error612.stack = value.stack;
129592
+ if ("cause" in value) {
129593
+ error612.cause = value.cause;
129594
+ }
129595
+ return error612;
129596
+ }, "HookForceClaimedError"),
128785
129597
  RangeError: makeErrorSubclassReviver(global2, "RangeError"),
128786
129598
  ReferenceError: makeErrorSubclassReviver(global2, "ReferenceError"),
128787
129599
  RetryableError: /* @__PURE__ */ __name2((value) => {
@@ -134364,7 +135176,7 @@ var version2;
134364
135176
  var init_version = __esm2({
134365
135177
  "../core/dist/version.js"() {
134366
135178
  "use strict";
134367
- version2 = "5.0.0-beta.54";
135179
+ version2 = "5.0.0-beta.56";
134368
135180
  }
134369
135181
  });
134370
135182
  function getWorkflowQueueName(workflowName, namespace) {
@@ -134551,6 +135363,56 @@ var init_helpers = __esm2({
134551
135363
  __name2(healthCheck, "healthCheck");
134552
135364
  }
134553
135365
  });
135366
+ function isRetryableWakeError(error612, isDeploymentUnavailableError) {
135367
+ if (isDeploymentUnavailableError?.(error612)) return false;
135368
+ const status = error612 ?? {};
135369
+ const code22 = status.status ?? status.statusCode;
135370
+ if (typeof code22 === "number") {
135371
+ return code22 >= 500 || code22 === 408 || code22 === 429;
135372
+ }
135373
+ const name = error612?.name;
135374
+ return name !== "BadRequestError" && name !== "UnauthorizedError" && name !== "ForbiddenError";
135375
+ }
135376
+ __name(isRetryableWakeError, "isRetryableWakeError");
135377
+ async function publishHookWakeWithRetry(publish, isDeploymentUnavailableError) {
135378
+ let lastError;
135379
+ for (let attempt = 0; attempt <= HOOK_WAKE_RETRY_DELAYS_MS.length; attempt++) {
135380
+ try {
135381
+ await publish();
135382
+ return;
135383
+ } catch (error612) {
135384
+ lastError = error612;
135385
+ if (!isRetryableWakeError(error612, isDeploymentUnavailableError)) break;
135386
+ const delayMs = HOOK_WAKE_RETRY_DELAYS_MS[attempt];
135387
+ if (delayMs !== void 0) {
135388
+ await new Promise((resolve3) => setTimeout(resolve3, delayMs));
135389
+ }
135390
+ }
135391
+ }
135392
+ if (HookNotFoundError.is(lastError)) {
135393
+ throw new WorkflowRuntimeError("The hook resume was committed, but its workflow wake could not be published", {
135394
+ cause: lastError
135395
+ });
135396
+ }
135397
+ throw lastError;
135398
+ }
135399
+ __name(publishHookWakeWithRetry, "publishHookWakeWithRetry");
135400
+ var HOOK_WAKE_RETRY_DELAYS_MS;
135401
+ var init_hook_wake = __esm2({
135402
+ "../core/dist/runtime/hook-wake.js"() {
135403
+ "use strict";
135404
+ init_dist2();
135405
+ init_dist4();
135406
+ init_logger();
135407
+ init_helpers();
135408
+ HOOK_WAKE_RETRY_DELAYS_MS = [
135409
+ 25,
135410
+ 100
135411
+ ];
135412
+ __name2(isRetryableWakeError, "isRetryableWakeError");
135413
+ __name2(publishHookWakeWithRetry, "publishHookWakeWithRetry");
135414
+ }
135415
+ });
134554
135416
  var HookInvocationSchema;
134555
135417
  var HookInvocationResultSchema;
134556
135418
  var init_invocations = __esm2({
@@ -139600,40 +140462,6 @@ async function computeResumePayloadDigest(bytes) {
139600
140462
  return hex32;
139601
140463
  }
139602
140464
  __name(computeResumePayloadDigest, "computeResumePayloadDigest");
139603
- function isRetryableWakeError(error612, isDeploymentUnavailableError) {
139604
- if (isDeploymentUnavailableError?.(error612)) return false;
139605
- const status = error612 ?? {};
139606
- const code22 = status.status ?? status.statusCode;
139607
- if (typeof code22 === "number") {
139608
- return code22 >= 500 || code22 === 408 || code22 === 429;
139609
- }
139610
- const name = error612?.name;
139611
- return name !== "BadRequestError" && name !== "UnauthorizedError" && name !== "ForbiddenError";
139612
- }
139613
- __name(isRetryableWakeError, "isRetryableWakeError");
139614
- async function publishHookWakeWithRetry(publish, isDeploymentUnavailableError) {
139615
- let lastError;
139616
- for (let attempt = 0; attempt <= HOOK_WAKE_RETRY_DELAYS_MS.length; attempt++) {
139617
- try {
139618
- await publish();
139619
- return;
139620
- } catch (error612) {
139621
- lastError = error612;
139622
- if (!isRetryableWakeError(error612, isDeploymentUnavailableError)) break;
139623
- const delayMs = HOOK_WAKE_RETRY_DELAYS_MS[attempt];
139624
- if (delayMs !== void 0) {
139625
- await new Promise((resolve3) => setTimeout(resolve3, delayMs));
139626
- }
139627
- }
139628
- }
139629
- if (HookNotFoundError.is(lastError)) {
139630
- throw new WorkflowRuntimeError("The hook resume was committed, but its workflow wake could not be published", {
139631
- cause: lastError
139632
- });
139633
- }
139634
- throw lastError;
139635
- }
139636
- __name(publishHookWakeWithRetry, "publishHookWakeWithRetry");
139637
140465
  function resumeContextFromRun(run22) {
139638
140466
  const coreVersion = run22.executionContext?.workflowCoreVersion;
139639
140467
  const traceCarrier = run22.executionContext?.traceCarrier;
@@ -139723,164 +140551,269 @@ async function resumeHook(tokenOrHook, payload, encryptionKeyOverride) {
139723
140551
  return resumeHookImpl(tokenOrHook, payload, encryptionKeyOverride, false, Date.now());
139724
140552
  }
139725
140553
  __name(resumeHook, "resumeHook");
139726
- async function resumeHookImpl(tokenOrHook, payload, encryptionKeyOverride, hookFreshlyLookedUp, resumeRequestedAtMs) {
140554
+ async function resumeHookImpl(tokenOrHook, payload, encryptionKeyOverride, hookFreshlyLookedUp, resumeRequestedAtMs, webhookOnly = false) {
139727
140555
  return await waitedUntil(() => {
139728
140556
  return trace("hook.resume", async (span) => {
139729
140557
  const world = await getWorldLazy();
139730
- try {
139731
- const suppliedToken = typeof tokenOrHook === "string";
139732
- const hook = suppliedToken ? await world.hooks.getByToken(tokenOrHook) : tokenOrHook;
139733
- const hookResumeCapabilitiesAreFresh = suppliedToken || hookFreshlyLookedUp;
139734
- const info = await resolveHookResumeInfo(hook);
139735
- const { resumeContext } = info;
139736
- span?.setAttributes({
139737
- ...HookToken(hook.token),
139738
- ...HookId(hook.hookId),
139739
- ...WorkflowRunId(hook.runId),
139740
- "workflow.hook.resume_context_source": info.source
139741
- });
139742
- if (info.run && isTerminalWorkflowRunStatus(info.run.status)) {
139743
- throw new HookNotFoundError(hook.token);
139744
- }
139745
- const capabilities = getRunCapabilities(resumeContext.workflowCoreVersion);
139746
- let payloadKey;
139747
- const runPublicKey = encryptionKeyOverride ? (
139748
- // hydrate hook metadata), so sealing would add an ECDH for no
139749
- // saved round trip. Reuse what it resolved.
139750
- void 0
139751
- ) : decodeRunPublicKey(resumeContext.encryptionPublicKey);
139752
- if (runPublicKey) {
139753
- payloadKey = sealTo(runPublicKey);
139754
- } else {
139755
- let encryptionKey = encryptionKeyOverride ?? await resolveHookEncryptionKey(hook, info);
139756
- if (!capabilities.supportedFormats.has(SerializationFormat.ENCRYPTED)) {
139757
- encryptionKey = void 0;
139758
- }
139759
- payloadKey = encryptionKey;
139760
- }
139761
- const compression = (resumeContext.runSpecVersion ?? 0) >= SPEC_VERSION_SUPPORTS_COMPRESSION && capabilities.supportedFormats.has(SerializationFormat.GZIP);
139762
- const ops = [];
139763
- const readbackOps = [];
139764
- const v1Compat = isLegacySpecVersion(hook.specVersion);
139765
- const dehydratedPayload = await dehydrateStepReturnValue(payload, hook.runId, payloadKey, ops, globalThis, v1Compat, capabilities.framedByteStreams, compression, void 0, readbackOps);
139766
- await Promise.all(ops.map((op) => op.catch((error612) => {
139767
- if (error612 !== void 0) throw error612;
139768
- })));
139769
- safeWaitUntil(Promise.all(readbackOps), (err) => {
139770
- if (err === void 0) return;
139771
- runtimeLogger.warn("Background readback of hook payload failed", {
139772
- workflowRunId: hook.runId,
139773
- hookId: hook.hookId,
139774
- error: err instanceof Error ? err.message : String(err)
139775
- });
139776
- });
139777
- span?.setAttributes({
139778
- ...WorkflowName(resumeContext.workflowName)
139779
- });
139780
- const originLink = await linkToTraceCarrier(resumeContext.traceCarrier);
139781
- if (originLink) {
139782
- span?.addLink?.(originLink);
139783
- }
139784
- if (world.capabilities?.invoke === true && !v1Compat && dehydratedPayload instanceof Uint8Array) {
139785
- if (!world.invoke) {
139786
- throw new WorkflowRuntimeError("World advertises invoke without implementing it");
139787
- }
140558
+ const token = typeof tokenOrHook === "string" ? tokenOrHook : tokenOrHook.token;
140559
+ let target2 = tokenOrHook;
140560
+ let fresh = hookFreshlyLookedUp;
140561
+ let keyOverride = encryptionKeyOverride;
140562
+ let redirects = 0;
140563
+ let lookupsAfterRedirect = 0;
140564
+ const MAX_LOOKUPS_AFTER_REDIRECT = 5;
140565
+ const resumeId = generateResumeId();
140566
+ const assertResendable = /* @__PURE__ */ __name2((cause) => {
140567
+ if (payload instanceof Request && payload.body !== null && payload.bodyUsed) {
139788
140568
  span?.setAttributes({
139789
- "workflow.hook.resume_strategy": "invoke"
140569
+ "workflow.hook.resume_redirect_unresendable": true
139790
140570
  });
139791
- const result2 = HookInvocationResultSchema.parse(await world.invoke(hook.runId, {
139792
- type: "hook_resume",
139793
- version: 1,
139794
- hookId: hook.hookId,
139795
- token: hook.token,
139796
- payload: dehydratedPayload
139797
- }, {
139798
- idempotencyKey: generateResumeId()
139799
- }));
139800
- if (result2.status === "rejected") {
139801
- if (result2.code === "HOOK_NOT_FOUND") throw new HookNotFoundError(hook.token);
139802
- throw new WorkflowRuntimeError("Executor rejected the hook invocation input");
139803
- }
139804
- span?.setAttributes(HookResumeCommitted(true));
139805
- return asLazyMetadataHook(hook);
139806
- }
139807
- const queueName = getWorkflowQueueName(resumeContext.workflowName);
139808
- const queueOptions = {
139809
- deploymentId: resumeContext.deploymentId,
139810
- specVersion: resumeContext.runSpecVersion ?? SPEC_VERSION_LEGACY
139811
- };
139812
- const backendDedupSupported = (hookResumeCapabilitiesAreFresh ? hook.resumeCapabilities?.hookResumeDedupVersion ?? 0 : 0) >= HOOK_RESUME_DEDUP_VERSION || world.capabilities?.hookResumeDedup === true;
139813
- const canClaimResume = backendDedupSupported && !v1Compat && dehydratedPayload instanceof Uint8Array;
139814
- span?.setAttributes({
139815
- "workflow.hook.resume_strategy": "sequential"
139816
- });
139817
- const resumeId = canClaimResume ? generateResumeId() : void 0;
139818
- const payloadDigest = canClaimResume ? await computeResumePayloadDigest(dehydratedPayload) : void 0;
139819
- if (resumeId) {
139820
- span?.setAttributes({
139821
- "workflow.hook.resume_id": resumeId
140571
+ throw new WorkflowRuntimeError(`Hook token "${token}" changed owner while this webhook request was being delivered; a request body can be sent only once and it was not delivered anywhere \u2014 retry the request, which will reach the token's new owner`, {
140572
+ cause
139822
140573
  });
139823
140574
  }
139824
- const isHookGoneError = /* @__PURE__ */ __name2((err) => HookNotFoundError.is(err) || RunExpiredError.is(err), "isHookGoneError");
140575
+ }, "assertResendable");
140576
+ for (; ; ) {
139825
140577
  try {
139826
- await world.events.create(hook.runId, {
139827
- eventType: "hook_received",
139828
- specVersion: SPEC_VERSION_CURRENT,
139829
- correlationId: hook.hookId,
139830
- eventData: {
139831
- ...v1Compat ? {} : {
139832
- token: hook.token
139833
- },
139834
- payload: dehydratedPayload
139835
- }
139836
- }, {
139837
- v1Compat,
139838
- ...resumeId && payloadDigest ? {
139839
- resumeId,
139840
- resumePayloadDigest: payloadDigest
139841
- } : {}
139842
- });
140578
+ return await resumeHookAttempt(world, span, target2, payload, keyOverride, fresh, resumeRequestedAtMs, resumeId, webhookOnly);
139843
140579
  } catch (err) {
139844
- if (isHookGoneError(err)) {
139845
- throw new HookNotFoundError(hook.token);
140580
+ if (err !== null && typeof err === "object" && notFoundReasons.get(err) === "not-webhook") {
140581
+ throw err;
140582
+ }
140583
+ if (redirects >= MAX_FORCE_CLAIM_REDIRECTS) {
140584
+ if (HookForceClaimedError.is(err)) {
140585
+ span?.setAttributes({
140586
+ "workflow.hook.resume_redirects_exhausted": true
140587
+ });
140588
+ throw new WorkflowRuntimeError(`Hook token "${token}" changed owner ${redirects} times while this resume was in flight; nothing was delivered \u2014 retry the resume`, {
140589
+ cause: err
140590
+ });
140591
+ }
140592
+ throw err;
140593
+ }
140594
+ if (HookForceClaimedError.is(err)) {
140595
+ assertResendable(err);
140596
+ redirects++;
140597
+ span?.setAttributes({
140598
+ "workflow.hook.resume_redirects": redirects,
140599
+ "workflow.hook.resume_redirect_to_run": err.claimedByRunId
140600
+ });
140601
+ target2 = token;
140602
+ fresh = true;
140603
+ keyOverride = void 0;
140604
+ lookupsAfterRedirect = 0;
140605
+ continue;
140606
+ }
140607
+ if (HookNotFoundError.is(err) && redirects > 0 && typeof target2 === "string" && lookupsAfterRedirect < MAX_LOOKUPS_AFTER_REDIRECT) {
140608
+ assertResendable(err);
140609
+ lookupsAfterRedirect++;
140610
+ await new Promise((resolve3) => setTimeout(resolve3, 50));
140611
+ continue;
140612
+ }
140613
+ if (HookNotFoundError.is(err) && notFoundReasons.get(err) !== "lookup") {
140614
+ const attemptedHookId = typeof target2 === "string" ? void 0 : target2.hookId;
140615
+ let relocated;
140616
+ try {
140617
+ relocated = await world.hooks.getByToken(token);
140618
+ } catch (lookupError) {
140619
+ if (!HookNotFoundError.is(lookupError)) {
140620
+ runtimeLogger.warn("Hook resume: re-resolving the token after a not-found failed; surfacing the original error", {
140621
+ token,
140622
+ error: lookupError instanceof Error ? lookupError.message : String(lookupError)
140623
+ });
140624
+ }
140625
+ }
140626
+ if (relocated?.claimedFrom !== void 0 && relocated.hookId !== attemptedHookId && (attemptedHookId === void 0 || relocated.claimedFrom.hookId === attemptedHookId) && !(webhookOnly && relocated.isWebhook === false)) {
140627
+ assertResendable(err);
140628
+ redirects++;
140629
+ span?.setAttributes({
140630
+ "workflow.hook.resume_redirects": redirects,
140631
+ "workflow.hook.resume_redirect_to_run": relocated.runId
140632
+ });
140633
+ target2 = relocated;
140634
+ fresh = true;
140635
+ keyOverride = void 0;
140636
+ continue;
140637
+ }
139846
140638
  }
139847
140639
  throw err;
139848
140640
  }
139849
- span?.setAttributes(HookResumeCommitted(true));
139850
- const queuePublishRequestedAtMs = Date.now();
139851
- await publishHookWakeWithRetry(() => world.queue(queueName, {
139852
- runId: hook.runId,
139853
- traceCarrier: resumeContext.traceCarrier ?? void 0,
139854
- hookResumeTiming: {
139855
- resumeRequestedAtMs,
139856
- queuePublishRequestedAtMs,
139857
- strategy: "sequential"
139858
- }
139859
- }, {
139860
- ...queueOptions,
139861
- // Dedup retried publishes whose response was lost: a
139862
- // duplicate wake is harmless for correctness (deterministic
139863
- // replay) but costs a full replay of the run, and the queue
139864
- // accepts a repeated idempotency key by delivering only one
139865
- // of the messages. Claim-less writes have no resumeId and
139866
- // keep the previous behavior.
139867
- ...resumeId ? {
139868
- idempotencyKey: `hook-${resumeId}`
139869
- } : {}
139870
- }), world.isDeploymentUnavailableError?.bind(world));
139871
- span?.setAttributes(HookWakePublished(true));
139872
- return asLazyMetadataHook(hook);
139873
- } catch (err) {
139874
- span?.setAttributes({
139875
- ...HookToken(typeof tokenOrHook === "string" ? tokenOrHook : tokenOrHook.token),
139876
- ...HookFound(false)
139877
- });
139878
- throw err;
139879
140641
  }
139880
140642
  });
139881
140643
  });
139882
140644
  }
139883
140645
  __name(resumeHookImpl, "resumeHookImpl");
140646
+ async function resumeHookAttempt(world, span, tokenOrHook, payload, encryptionKeyOverride, hookFreshlyLookedUp, resumeRequestedAtMs, logicalResumeId, webhookOnly) {
140647
+ try {
140648
+ const suppliedToken = typeof tokenOrHook === "string";
140649
+ let hook;
140650
+ if (suppliedToken) {
140651
+ try {
140652
+ hook = await world.hooks.getByToken(tokenOrHook);
140653
+ } catch (lookupError) {
140654
+ if (HookNotFoundError.is(lookupError)) {
140655
+ notFoundReasons.set(lookupError, "lookup");
140656
+ }
140657
+ throw lookupError;
140658
+ }
140659
+ } else {
140660
+ hook = tokenOrHook;
140661
+ }
140662
+ if (webhookOnly && hook.isWebhook === false) {
140663
+ const notWebhook = new HookNotFoundError(hook.token);
140664
+ notFoundReasons.set(notWebhook, "not-webhook");
140665
+ throw notWebhook;
140666
+ }
140667
+ const hookResumeCapabilitiesAreFresh = suppliedToken || hookFreshlyLookedUp;
140668
+ const info = await resolveHookResumeInfo(hook);
140669
+ const { resumeContext } = info;
140670
+ span?.setAttributes({
140671
+ ...HookToken(hook.token),
140672
+ ...HookId(hook.hookId),
140673
+ ...WorkflowRunId(hook.runId),
140674
+ "workflow.hook.resume_context_source": info.source
140675
+ });
140676
+ if (info.run && isTerminalWorkflowRunStatus(info.run.status)) {
140677
+ throw new HookNotFoundError(hook.token);
140678
+ }
140679
+ const capabilities = getRunCapabilities(resumeContext.workflowCoreVersion);
140680
+ let payloadKey;
140681
+ const runPublicKey = encryptionKeyOverride ? (
140682
+ // hydrate hook metadata), so sealing would add an ECDH for no
140683
+ // saved round trip. Reuse what it resolved.
140684
+ void 0
140685
+ ) : decodeRunPublicKey(resumeContext.encryptionPublicKey);
140686
+ if (runPublicKey) {
140687
+ payloadKey = sealTo(runPublicKey);
140688
+ } else {
140689
+ let encryptionKey = encryptionKeyOverride ?? await resolveHookEncryptionKey(hook, info);
140690
+ if (!capabilities.supportedFormats.has(SerializationFormat.ENCRYPTED)) {
140691
+ encryptionKey = void 0;
140692
+ }
140693
+ payloadKey = encryptionKey;
140694
+ }
140695
+ const compression = (resumeContext.runSpecVersion ?? 0) >= SPEC_VERSION_SUPPORTS_COMPRESSION && capabilities.supportedFormats.has(SerializationFormat.GZIP);
140696
+ const ops = [];
140697
+ const readbackOps = [];
140698
+ const v1Compat = isLegacySpecVersion(hook.specVersion);
140699
+ const dehydratedPayload = await dehydrateStepReturnValue(payload, hook.runId, payloadKey, ops, globalThis, v1Compat, capabilities.framedByteStreams, compression, void 0, readbackOps);
140700
+ await Promise.all(ops.map((op) => op.catch((error612) => {
140701
+ if (error612 !== void 0) throw error612;
140702
+ })));
140703
+ safeWaitUntil(Promise.all(readbackOps), (err) => {
140704
+ if (err === void 0) return;
140705
+ runtimeLogger.warn("Background readback of hook payload failed", {
140706
+ workflowRunId: hook.runId,
140707
+ hookId: hook.hookId,
140708
+ error: err instanceof Error ? err.message : String(err)
140709
+ });
140710
+ });
140711
+ if (world.capabilities?.invoke === true && !v1Compat && dehydratedPayload instanceof Uint8Array) {
140712
+ if (!world.invoke) {
140713
+ throw new WorkflowRuntimeError("World advertises invoke without implementing it");
140714
+ }
140715
+ span?.setAttributes({
140716
+ "workflow.hook.resume_strategy": "invoke"
140717
+ });
140718
+ const result2 = HookInvocationResultSchema.parse(await world.invoke(hook.runId, {
140719
+ type: "hook_resume",
140720
+ version: 1,
140721
+ hookId: hook.hookId,
140722
+ token: hook.token,
140723
+ payload: dehydratedPayload
140724
+ }, {
140725
+ idempotencyKey: logicalResumeId
140726
+ }));
140727
+ if (result2.status === "rejected") {
140728
+ if (result2.code === "HOOK_NOT_FOUND") throw new HookNotFoundError(hook.token);
140729
+ throw new WorkflowRuntimeError("Executor rejected the hook invocation input");
140730
+ }
140731
+ span?.setAttributes(HookResumeCommitted(true));
140732
+ return asLazyMetadataHook(hook);
140733
+ }
140734
+ span?.setAttributes({
140735
+ ...WorkflowName(resumeContext.workflowName)
140736
+ });
140737
+ const originLink = await linkToTraceCarrier(resumeContext.traceCarrier);
140738
+ if (originLink) {
140739
+ span?.addLink?.(originLink);
140740
+ }
140741
+ const queueName = getWorkflowQueueName(resumeContext.workflowName);
140742
+ const queueOptions = {
140743
+ deploymentId: resumeContext.deploymentId,
140744
+ specVersion: resumeContext.runSpecVersion ?? SPEC_VERSION_LEGACY
140745
+ };
140746
+ const backendDedupSupported = (hookResumeCapabilitiesAreFresh ? hook.resumeCapabilities?.hookResumeDedupVersion ?? 0 : 0) >= HOOK_RESUME_DEDUP_VERSION || world.capabilities?.hookResumeDedup === true;
140747
+ const canClaimResume = backendDedupSupported && !v1Compat && dehydratedPayload instanceof Uint8Array;
140748
+ span?.setAttributes({
140749
+ "workflow.hook.resume_strategy": "sequential"
140750
+ });
140751
+ const resumeId = canClaimResume ? logicalResumeId : void 0;
140752
+ const payloadDigest = canClaimResume ? await computeResumePayloadDigest(dehydratedPayload) : void 0;
140753
+ if (resumeId) {
140754
+ span?.setAttributes({
140755
+ "workflow.hook.resume_id": resumeId
140756
+ });
140757
+ }
140758
+ const isHookGoneError = /* @__PURE__ */ __name2((err) => HookNotFoundError.is(err) || RunExpiredError.is(err), "isHookGoneError");
140759
+ try {
140760
+ await world.events.create(hook.runId, {
140761
+ eventType: "hook_received",
140762
+ specVersion: SPEC_VERSION_CURRENT,
140763
+ correlationId: hook.hookId,
140764
+ eventData: {
140765
+ ...v1Compat ? {} : {
140766
+ token: hook.token
140767
+ },
140768
+ payload: dehydratedPayload
140769
+ }
140770
+ }, {
140771
+ v1Compat,
140772
+ ...resumeId && payloadDigest ? {
140773
+ resumeId,
140774
+ resumePayloadDigest: payloadDigest
140775
+ } : {}
140776
+ });
140777
+ } catch (err) {
140778
+ if (HookForceClaimedError.is(err)) throw err;
140779
+ if (isHookGoneError(err)) {
140780
+ throw new HookNotFoundError(hook.token);
140781
+ }
140782
+ throw err;
140783
+ }
140784
+ span?.setAttributes(HookResumeCommitted(true));
140785
+ const queuePublishRequestedAtMs = Date.now();
140786
+ await publishHookWakeWithRetry(() => world.queue(queueName, {
140787
+ runId: hook.runId,
140788
+ traceCarrier: resumeContext.traceCarrier ?? void 0,
140789
+ hookResumeTiming: {
140790
+ resumeRequestedAtMs,
140791
+ queuePublishRequestedAtMs,
140792
+ strategy: "sequential"
140793
+ }
140794
+ }, {
140795
+ ...queueOptions,
140796
+ // Dedup retried publishes whose response was lost: a
140797
+ // duplicate wake is harmless for correctness (deterministic
140798
+ // replay) but costs a full replay of the run, and the queue
140799
+ // accepts a repeated idempotency key by delivering only one
140800
+ // of the messages. Claim-less writes have no resumeId and
140801
+ // keep the previous behavior.
140802
+ ...resumeId ? {
140803
+ idempotencyKey: `hook-${resumeId}`
140804
+ } : {}
140805
+ }), world.isDeploymentUnavailableError?.bind(world));
140806
+ span?.setAttributes(HookWakePublished(true));
140807
+ return asLazyMetadataHook(hook);
140808
+ } catch (err) {
140809
+ span?.setAttributes({
140810
+ ...HookToken(typeof tokenOrHook === "string" ? tokenOrHook : tokenOrHook.token),
140811
+ ...HookFound(false)
140812
+ });
140813
+ throw err;
140814
+ }
140815
+ }
140816
+ __name(resumeHookAttempt, "resumeHookAttempt");
139884
140817
  async function resumeWebhook(token, request) {
139885
140818
  const resumeRequestedAtMs = Date.now();
139886
140819
  const world = await getWorldLazy();
@@ -139908,7 +140841,7 @@ async function resumeWebhook(token, request) {
139908
140841
  status: 202
139909
140842
  });
139910
140843
  }
139911
- await resumeHookImpl(hook, request, metadataEncryptionKey(), true, resumeRequestedAtMs);
140844
+ await resumeHookImpl(hook, request, metadataEncryptionKey(), true, resumeRequestedAtMs, true);
139912
140845
  if (responseReadable) {
139913
140846
  const reader = responseReadable.getReader();
139914
140847
  const chunk = await reader.read();
@@ -139926,7 +140859,8 @@ async function resumeWebhook(token, request) {
139926
140859
  }
139927
140860
  __name(resumeWebhook, "resumeWebhook");
139928
140861
  var generateResumeId;
139929
- var HOOK_WAKE_RETRY_DELAYS_MS;
140862
+ var MAX_FORCE_CLAIM_REDIRECTS;
140863
+ var notFoundReasons;
139930
140864
  var init_resume_hook = __esm2({
139931
140865
  "../core/dist/runtime/resume-hook.js"() {
139932
140866
  "use strict";
@@ -139944,16 +140878,11 @@ var init_resume_hook = __esm2({
139944
140878
  init_telemetry();
139945
140879
  init_get_world_lazy();
139946
140880
  init_helpers();
140881
+ init_hook_wake();
139947
140882
  init_invocations();
139948
140883
  init_wait_until();
139949
140884
  generateResumeId = monotonicFactory();
139950
140885
  __name2(computeResumePayloadDigest, "computeResumePayloadDigest");
139951
- HOOK_WAKE_RETRY_DELAYS_MS = [
139952
- 25,
139953
- 100
139954
- ];
139955
- __name2(isRetryableWakeError, "isRetryableWakeError");
139956
- __name2(publishHookWakeWithRetry, "publishHookWakeWithRetry");
139957
140886
  __name2(resumeContextFromRun, "resumeContextFromRun");
139958
140887
  __name2(resolveHookResumeInfo, "resolveHookResumeInfo");
139959
140888
  __name2(resolveHookEncryptionKey, "resolveHookEncryptionKey");
@@ -139962,7 +140891,10 @@ var init_resume_hook = __esm2({
139962
140891
  __name2(asLazyMetadataHook, "asLazyMetadataHook");
139963
140892
  __name2(getHookByToken, "getHookByToken");
139964
140893
  __name2(resumeHook, "resumeHook");
140894
+ MAX_FORCE_CLAIM_REDIRECTS = 3;
140895
+ notFoundReasons = /* @__PURE__ */ new WeakMap();
139965
140896
  __name2(resumeHookImpl, "resumeHookImpl");
140897
+ __name2(resumeHookAttempt, "resumeHookAttempt");
139966
140898
  __name2(resumeWebhook, "resumeWebhook");
139967
140899
  }
139968
140900
  });
@@ -142401,7 +143333,7 @@ __name2(start, "start");
142401
143333
  value: "start",
142402
143334
  configurable: true
142403
143335
  });
142404
- })(start, "step//@workflow/core/runtime/start@5.0.0-beta.54//start");
143336
+ })(start, "step//@workflow/core/runtime/start@5.0.0-beta.56//start");
142405
143337
  async function wakeUpRun(world, runId, options) {
142406
143338
  try {
142407
143339
  const run22 = await world.runs.get(runId, {
@@ -142876,7 +143808,7 @@ var Run = class _Run {
142876
143808
  value: "wakeUp",
142877
143809
  configurable: true
142878
143810
  });
142879
- })(Run.prototype["wakeUp"], "step//@workflow/core/runtime/run@5.0.0-beta.54//Run#wakeUp");
143811
+ })(Run.prototype["wakeUp"], "step//@workflow/core/runtime/run@5.0.0-beta.56//Run#wakeUp");
142880
143812
  (function(__wf_fn, __wf_id) {
142881
143813
  var __wf_sym = /* @__PURE__ */ Symbol.for("@workflow/core//registeredSteps"), __wf_reg = globalThis[__wf_sym] || (globalThis[__wf_sym] = /* @__PURE__ */ new Map());
142882
143814
  __wf_reg.set(__wf_id, __wf_fn);
@@ -142885,7 +143817,7 @@ var Run = class _Run {
142885
143817
  value: "cancel",
142886
143818
  configurable: true
142887
143819
  });
142888
- })(Run.prototype["cancel"], "step//@workflow/core/runtime/run@5.0.0-beta.54//Run#cancel");
143820
+ })(Run.prototype["cancel"], "step//@workflow/core/runtime/run@5.0.0-beta.56//Run#cancel");
142889
143821
  (function(__wf_fn, __wf_id) {
142890
143822
  var __wf_sym = /* @__PURE__ */ Symbol.for("@workflow/core//registeredSteps"), __wf_reg = globalThis[__wf_sym] || (globalThis[__wf_sym] = /* @__PURE__ */ new Map());
142891
143823
  __wf_reg.set(__wf_id, __wf_fn);
@@ -142894,7 +143826,7 @@ var Run = class _Run {
142894
143826
  value: "getReadable",
142895
143827
  configurable: true
142896
143828
  });
142897
- })(Run.prototype["getReadable"], "step//@workflow/core/runtime/run@5.0.0-beta.54//Run#getReadable");
143829
+ })(Run.prototype["getReadable"], "step//@workflow/core/runtime/run@5.0.0-beta.56//Run#getReadable");
142898
143830
  (function(__wf_fn, __wf_id) {
142899
143831
  var __wf_sym = /* @__PURE__ */ Symbol.for("@workflow/core//registeredSteps"), __wf_reg = globalThis[__wf_sym] || (globalThis[__wf_sym] = /* @__PURE__ */ new Map());
142900
143832
  __wf_reg.set(__wf_id, __wf_fn);
@@ -142903,7 +143835,7 @@ var Run = class _Run {
142903
143835
  value: "getWritable",
142904
143836
  configurable: true
142905
143837
  });
142906
- })(Run.prototype["getWritable"], "step//@workflow/core/runtime/run@5.0.0-beta.54//Run#getWritable");
143838
+ })(Run.prototype["getWritable"], "step//@workflow/core/runtime/run@5.0.0-beta.56//Run#getWritable");
142907
143839
  (function(__wf_fn, __wf_id) {
142908
143840
  var __wf_sym = /* @__PURE__ */ Symbol.for("@workflow/core//registeredSteps"), __wf_reg = globalThis[__wf_sym] || (globalThis[__wf_sym] = /* @__PURE__ */ new Map());
142909
143841
  __wf_reg.set(__wf_id, __wf_fn);
@@ -142912,7 +143844,7 @@ var Run = class _Run {
142912
143844
  value: "exists",
142913
143845
  configurable: true
142914
143846
  });
142915
- })(Object.getOwnPropertyDescriptor(Run.prototype, "exists").get, "step//@workflow/core/runtime/run@5.0.0-beta.54//Run#exists");
143847
+ })(Object.getOwnPropertyDescriptor(Run.prototype, "exists").get, "step//@workflow/core/runtime/run@5.0.0-beta.56//Run#exists");
142916
143848
  (function(__wf_fn, __wf_id) {
142917
143849
  var __wf_sym = /* @__PURE__ */ Symbol.for("@workflow/core//registeredSteps"), __wf_reg = globalThis[__wf_sym] || (globalThis[__wf_sym] = /* @__PURE__ */ new Map());
142918
143850
  __wf_reg.set(__wf_id, __wf_fn);
@@ -142921,7 +143853,7 @@ var Run = class _Run {
142921
143853
  value: "status",
142922
143854
  configurable: true
142923
143855
  });
142924
- })(Object.getOwnPropertyDescriptor(Run.prototype, "status").get, "step//@workflow/core/runtime/run@5.0.0-beta.54//Run#status");
143856
+ })(Object.getOwnPropertyDescriptor(Run.prototype, "status").get, "step//@workflow/core/runtime/run@5.0.0-beta.56//Run#status");
142925
143857
  (function(__wf_fn, __wf_id) {
142926
143858
  var __wf_sym = /* @__PURE__ */ Symbol.for("@workflow/core//registeredSteps"), __wf_reg = globalThis[__wf_sym] || (globalThis[__wf_sym] = /* @__PURE__ */ new Map());
142927
143859
  __wf_reg.set(__wf_id, __wf_fn);
@@ -142930,7 +143862,7 @@ var Run = class _Run {
142930
143862
  value: "returnValue",
142931
143863
  configurable: true
142932
143864
  });
142933
- })(Object.getOwnPropertyDescriptor(Run.prototype, "returnValue").get, "step//@workflow/core/runtime/run@5.0.0-beta.54//Run#returnValue");
143865
+ })(Object.getOwnPropertyDescriptor(Run.prototype, "returnValue").get, "step//@workflow/core/runtime/run@5.0.0-beta.56//Run#returnValue");
142934
143866
  (function(__wf_fn, __wf_id) {
142935
143867
  var __wf_sym = /* @__PURE__ */ Symbol.for("@workflow/core//registeredSteps"), __wf_reg = globalThis[__wf_sym] || (globalThis[__wf_sym] = /* @__PURE__ */ new Map());
142936
143868
  __wf_reg.set(__wf_id, __wf_fn);
@@ -142939,7 +143871,7 @@ var Run = class _Run {
142939
143871
  value: "workflowName",
142940
143872
  configurable: true
142941
143873
  });
142942
- })(Object.getOwnPropertyDescriptor(Run.prototype, "workflowName").get, "step//@workflow/core/runtime/run@5.0.0-beta.54//Run#workflowName");
143874
+ })(Object.getOwnPropertyDescriptor(Run.prototype, "workflowName").get, "step//@workflow/core/runtime/run@5.0.0-beta.56//Run#workflowName");
142943
143875
  (function(__wf_fn, __wf_id) {
142944
143876
  var __wf_sym = /* @__PURE__ */ Symbol.for("@workflow/core//registeredSteps"), __wf_reg = globalThis[__wf_sym] || (globalThis[__wf_sym] = /* @__PURE__ */ new Map());
142945
143877
  __wf_reg.set(__wf_id, __wf_fn);
@@ -142948,7 +143880,7 @@ var Run = class _Run {
142948
143880
  value: "createdAt",
142949
143881
  configurable: true
142950
143882
  });
142951
- })(Object.getOwnPropertyDescriptor(Run.prototype, "createdAt").get, "step//@workflow/core/runtime/run@5.0.0-beta.54//Run#createdAt");
143883
+ })(Object.getOwnPropertyDescriptor(Run.prototype, "createdAt").get, "step//@workflow/core/runtime/run@5.0.0-beta.56//Run#createdAt");
142952
143884
  (function(__wf_fn, __wf_id) {
142953
143885
  var __wf_sym = /* @__PURE__ */ Symbol.for("@workflow/core//registeredSteps"), __wf_reg = globalThis[__wf_sym] || (globalThis[__wf_sym] = /* @__PURE__ */ new Map());
142954
143886
  __wf_reg.set(__wf_id, __wf_fn);
@@ -142957,7 +143889,7 @@ var Run = class _Run {
142957
143889
  value: "startedAt",
142958
143890
  configurable: true
142959
143891
  });
142960
- })(Object.getOwnPropertyDescriptor(Run.prototype, "startedAt").get, "step//@workflow/core/runtime/run@5.0.0-beta.54//Run#startedAt");
143892
+ })(Object.getOwnPropertyDescriptor(Run.prototype, "startedAt").get, "step//@workflow/core/runtime/run@5.0.0-beta.56//Run#startedAt");
142961
143893
  (function(__wf_fn, __wf_id) {
142962
143894
  var __wf_sym = /* @__PURE__ */ Symbol.for("@workflow/core//registeredSteps"), __wf_reg = globalThis[__wf_sym] || (globalThis[__wf_sym] = /* @__PURE__ */ new Map());
142963
143895
  __wf_reg.set(__wf_id, __wf_fn);
@@ -142966,7 +143898,7 @@ var Run = class _Run {
142966
143898
  value: "completedAt",
142967
143899
  configurable: true
142968
143900
  });
142969
- })(Object.getOwnPropertyDescriptor(Run.prototype, "completedAt").get, "step//@workflow/core/runtime/run@5.0.0-beta.54//Run#completedAt");
143901
+ })(Object.getOwnPropertyDescriptor(Run.prototype, "completedAt").get, "step//@workflow/core/runtime/run@5.0.0-beta.56//Run#completedAt");
142970
143902
  (function(__wf_cls, __wf_id) {
142971
143903
  var __wf_sym = /* @__PURE__ */ Symbol.for("workflow-class-registry"), __wf_reg = globalThis[__wf_sym] || (globalThis[__wf_sym] = /* @__PURE__ */ new Map());
142972
143904
  __wf_reg.set(__wf_id, __wf_cls);
@@ -142976,7 +143908,7 @@ var Run = class _Run {
142976
143908
  enumerable: false,
142977
143909
  configurable: false
142978
143910
  });
142979
- })(Run, "class//@workflow/core/runtime/run@5.0.0-beta.54//Run");
143911
+ })(Run, "class//@workflow/core/runtime/run@5.0.0-beta.56//Run");
142980
143912
  async function fetch2(...args) {
142981
143913
  return globalThis.fetch(...args);
142982
143914
  }
@@ -143816,6 +144748,60 @@ __name(guardDeploymentAffinity, "guardDeploymentAffinity");
143816
144748
  init_helpers3();
143817
144749
  init_invocations2();
143818
144750
  init_lifecycle_hooks();
144751
+
144752
+ // ../core/dist/runtime/open-hook-wait-state.js
144753
+ function openHookAndWaitState(events) {
144754
+ const hooks = /* @__PURE__ */ new Set();
144755
+ const waits = /* @__PURE__ */ new Map();
144756
+ for (const event of events) {
144757
+ switch (event.eventType) {
144758
+ case "hook_created":
144759
+ hooks.add(event.correlationId);
144760
+ break;
144761
+ case "hook_disposed":
144762
+ hooks.delete(event.correlationId);
144763
+ break;
144764
+ case "wait_created":
144765
+ waits.set(event.correlationId, resumeAtMs(event.eventData?.resumeAt));
144766
+ break;
144767
+ case "wait_completed":
144768
+ waits.delete(event.correlationId);
144769
+ break;
144770
+ }
144771
+ }
144772
+ let earliestOpenWaitResumeAtMs;
144773
+ for (const at of waits.values()) {
144774
+ if (earliestOpenWaitResumeAtMs === void 0 || at < earliestOpenWaitResumeAtMs) {
144775
+ earliestOpenWaitResumeAtMs = at;
144776
+ }
144777
+ }
144778
+ return {
144779
+ openHook: hooks.size > 0,
144780
+ openWait: waits.size > 0,
144781
+ earliestOpenWaitResumeAtMs
144782
+ };
144783
+ }
144784
+ __name(openHookAndWaitState, "openHookAndWaitState");
144785
+ function resumeAtMs(resumeAt) {
144786
+ let ms3;
144787
+ if (resumeAt instanceof Date) {
144788
+ ms3 = resumeAt.getTime();
144789
+ } else if (typeof resumeAt === "number") {
144790
+ ms3 = resumeAt;
144791
+ } else if (typeof resumeAt === "string") {
144792
+ ms3 = new Date(resumeAt).getTime();
144793
+ } else {
144794
+ return -Infinity;
144795
+ }
144796
+ return Number.isFinite(ms3) ? ms3 : -Infinity;
144797
+ }
144798
+ __name(resumeAtMs, "resumeAtMs");
144799
+ function hasOpenWaitDueBy(state, deadlineMs) {
144800
+ return state.earliestOpenWaitResumeAtMs !== void 0 && state.earliestOpenWaitResumeAtMs <= deadlineMs;
144801
+ }
144802
+ __name(hasOpenWaitDueBy, "hasOpenWaitDueBy");
144803
+
144804
+ // ../core/dist/runtime.js
143819
144805
  init_replay_budget();
143820
144806
  init_replay_recovery_reporter();
143821
144807
  init_resume_latency();
@@ -143879,9 +144865,10 @@ init_util5();
143879
144865
  init_compute_instance();
143880
144866
  init_constants3();
143881
144867
  init_helpers3();
144868
+ init_hook_wake2();
143882
144869
  init_replay_recovery_reporter();
143883
144870
  init_unserializable_step();
143884
- async function createHookEvent({ runId, hookEvent, queueItem, requestId, sinceCursor, createEvent }) {
144871
+ async function createHookEvent({ runId, hookEvent, queueItem, requestId, sinceCursor, createEvent, world }) {
143885
144872
  try {
143886
144873
  const result2 = await createEvent(hookEvent, {
143887
144874
  requestId,
@@ -143893,6 +144880,15 @@ async function createHookEvent({ runId, hookEvent, queueItem, requestId, sinceCu
143893
144880
  hasAwaitedHookCreation: false
143894
144881
  };
143895
144882
  }
144883
+ if (result2.hook?.claimedFrom) {
144884
+ const outcome = await publishForceClaimVictimWake(world, runId, result2.hook);
144885
+ runtimeLogger2.info("Hook token force-claimed from another run", {
144886
+ workflowRunId: runId,
144887
+ hookId: queueItem.correlationId,
144888
+ victimRunId: result2.hook.claimedFrom.runId,
144889
+ victimWake: outcome
144890
+ });
144891
+ }
143896
144892
  return {
143897
144893
  hasHookConflict: false,
143898
144894
  hasAwaitedHookCreation: queueItem.hasConflictAwaiter === true
@@ -143929,6 +144925,7 @@ async function createHookEvent({ runId, hookEvent, queueItem, requestId, sinceCu
143929
144925
  __name(createHookEvent, "createHookEvent");
143930
144926
  async function handleSuspension({ suspension, world, run: run3, span, requestId, eventLog, runReadyBarrier, replayRecoveryReporter, stepDispatch, ownerMessageId, allowDeferredBatchWork }) {
143931
144927
  const runId = run3.runId;
144928
+ await republishOwedForceClaimVictimWake(world, runId, eventLog?.events);
143932
144929
  const ensureRunReady = /* @__PURE__ */ __name(async () => {
143933
144930
  if (runReadyBarrier) {
143934
144931
  try {
@@ -144059,7 +145056,7 @@ async function handleSuspension({ suspension, world, run: run3, span, requestId,
144059
145056
  if (hookItemsByToken.size > 0) {
144060
145057
  const hookPhaseStart = Date.now();
144061
145058
  await ensureRunReady();
144062
- await settlePhase([...hookItemsByToken.values()].map(async (items) => {
145059
+ const processHookGroup = /* @__PURE__ */ __name(async (items) => {
144063
145060
  for (const queueItem of items) {
144064
145061
  let creationConflicted = false;
144065
145062
  if (!queueItem.hasCreatedEvent) {
@@ -144076,7 +145073,8 @@ async function handleSuspension({ suspension, world, run: run3, span, requestId,
144076
145073
  tokenRetentionUntil: queueItem.tokenRetentionUntil,
144077
145074
  metadata: hookMetadata,
144078
145075
  isWebhook: queueItem.isWebhook ?? false,
144079
- ...queueItem.isSystem && { isSystem: true }
145076
+ ...queueItem.isSystem && { isSystem: true },
145077
+ ...queueItem.force && { force: true }
144080
145078
  }
144081
145079
  };
144082
145080
  const result2 = await createHookEvent({
@@ -144085,7 +145083,8 @@ async function handleSuspension({ suspension, world, run: run3, span, requestId,
144085
145083
  queueItem,
144086
145084
  requestId,
144087
145085
  sinceCursor: hookDeltaCursor,
144088
- createEvent: createGuarded
145086
+ createEvent: createGuarded,
145087
+ world
144089
145088
  });
144090
145089
  if (result2.hasHookConflict) {
144091
145090
  hookConflictCorrelationIds.push(queueItem.correlationId);
@@ -144099,7 +145098,13 @@ async function handleSuspension({ suspension, world, run: run3, span, requestId,
144099
145098
  await disposeHook(queueItem);
144100
145099
  }
144101
145100
  }
144102
- }));
145101
+ }, "processHookGroup");
145102
+ const groups = [...hookItemsByToken.values()];
145103
+ const holdsForcedCreation = /* @__PURE__ */ __name((items) => items.some((item) => item.force === true && !item.hasCreatedEvent), "holdsForcedCreation");
145104
+ for (const items of groups.filter(holdsForcedCreation)) {
145105
+ await settlePhase([processHookGroup(items)]);
145106
+ }
145107
+ await settlePhase(groups.filter((items) => !holdsForcedCreation(items)).map(processHookGroup));
144103
145108
  hookCreationMs = Date.now() - hookPhaseStart;
144104
145109
  }
144105
145110
  const hooksNeedingAbort = allHookItems.filter((item) => item.abortRequested && !item.disposed);
@@ -144693,13 +145698,14 @@ async function handleSuspension({ suspension, world, run: run3, span, requestId,
144693
145698
  const now2 = Date.now();
144694
145699
  let soonestWait;
144695
145700
  for (const queueItem of waitItems) {
144696
- const resumeAtMs = queueItem.resumeAt.getTime();
144697
- const delayMs = Math.max(1e3, resumeAtMs - now2);
145701
+ const resumeAtMs2 = queueItem.resumeAt.getTime();
145702
+ const delayMs = Math.max(1e3, resumeAtMs2 - now2);
144698
145703
  const timeoutSeconds = Math.ceil(delayMs / 1e3);
144699
145704
  if (!soonestWait || timeoutSeconds < soonestWait.seconds) {
144700
145705
  soonestWait = {
144701
145706
  seconds: timeoutSeconds,
144702
- correlationId: queueItem.correlationId
145707
+ correlationId: queueItem.correlationId,
145708
+ resumeAtMs: resumeAtMs2
144703
145709
  };
144704
145710
  }
144705
145711
  }
@@ -145694,6 +146700,17 @@ function createCreateHook(ctx) {
145694
146700
  if (options.experimental_minRetention !== void 0 && ctx.worldCapabilities?.hookRetention?.active !== true) {
145695
146701
  throw new FatalError2("The configured World does not support `experimental_minRetention` for Hooks.");
145696
146702
  }
146703
+ if (options.experimental_force === true) {
146704
+ if (options.token === void 0 || options.token === null) {
146705
+ throw new Error("`createHook()` was called with `experimental_force: true` but no `token`. Force-claiming only applies to an explicit token another run may hold.");
146706
+ }
146707
+ if (options.isWebhook === true) {
146708
+ throw new Error("Webhook hooks do not support `experimental_force`. Use a non-webhook `createHook()` with an explicit token.");
146709
+ }
146710
+ if (ctx.worldCapabilities?.hookForceClaim !== true) {
146711
+ throw new FatalError2("The configured World does not support `experimental_force` for Hooks.");
146712
+ }
146713
+ }
145697
146714
  const correlationId = `hook_${ctx.generateUlid()}`;
145698
146715
  const token = options.token ?? ctx.generateNanoid();
145699
146716
  const tokenRetentionUntil = options.experimental_minRetention === void 0 ? void 0 : parseDurationToDate2(options.experimental_minRetention);
@@ -145703,6 +146720,7 @@ function createCreateHook(ctx) {
145703
146720
  correlationId,
145704
146721
  token,
145705
146722
  tokenRetentionUntil,
146723
+ ...options.experimental_force === true && { force: true },
145706
146724
  metadata: options.metadata,
145707
146725
  isWebhook
145708
146726
  });
@@ -145714,6 +146732,7 @@ function createCreateHook(ctx) {
145714
146732
  let hasDisposedEvent = false;
145715
146733
  let hasConflict = false;
145716
146734
  let conflictErrorRef = null;
146735
+ let forceClaimedErrorRef = null;
145717
146736
  let conflictRunRef = null;
145718
146737
  let registrationDelivered = Promise.resolve();
145719
146738
  function deliverRegistration(deliveredAt, settle) {
@@ -145774,10 +146793,11 @@ function createCreateHook(ctx) {
145774
146793
  if (event.eventType === "hook_conflict") {
145775
146794
  ctx.invocationsQueue.delete(correlationId);
145776
146795
  const conflictEvent = event;
145777
- const conflictError = new HookConflictError2(conflictEvent.eventData.token, conflictEvent.eventData.conflictingRunId);
146796
+ const forced = options.experimental_force === true && conflictEvent.eventData.forceRefusedReason === void 0;
146797
+ const conflictError = forced ? new FatalError2(`createHook({ experimental_force: true }) for token "${conflictEvent.eventData.token}" was answered with a hook_conflict: the configured World does not support force-claiming hook tokens${conflictEvent.eventData.conflictingRunId ? ` (run "${conflictEvent.eventData.conflictingRunId}" holds it)` : ""}.`) : new HookConflictError2(conflictEvent.eventData.token, conflictEvent.eventData.conflictingRunId);
145778
146798
  hasConflict = true;
145779
146799
  conflictErrorRef = conflictError;
145780
- conflictRunRef = createConflictingRun(ctx, conflictEvent.eventData.conflictingRunId);
146800
+ conflictRunRef = forced ? null : createConflictingRun(ctx, conflictEvent.eventData.conflictingRunId);
145781
146801
  const pendingPromises = promises.slice();
145782
146802
  promises.length = 0;
145783
146803
  const pendingGetConflictPromises = getConflictPromises.slice();
@@ -145869,6 +146889,28 @@ function createCreateHook(ctx) {
145869
146889
  if (event.eventType === "hook_disposed") {
145870
146890
  ctx.invocationsQueue.delete(correlationId);
145871
146891
  hasDisposedEvent = true;
146892
+ const claimedBy = event.eventData?.forceClaimedBy;
146893
+ if (claimedBy) {
146894
+ const error121 = new HookForceClaimedError2(token, claimedBy.runId, claimedBy.hookId);
146895
+ forceClaimedErrorRef = error121;
146896
+ const pendingPromises = promises.slice();
146897
+ promises.length = 0;
146898
+ const pendingGetConflictPromises = getConflictPromises.slice();
146899
+ getConflictPromises.length = 0;
146900
+ ctx.promiseQueue = ctx.promiseQueue.then(() => {
146901
+ for (const resolver2 of pendingPromises) {
146902
+ resolver2.reject(error121);
146903
+ }
146904
+ for (const resolver2 of pendingGetConflictPromises) {
146905
+ resolver2.resolve(null);
146906
+ }
146907
+ });
146908
+ webhookLogger2.debug("Hook force-claimed by another run", {
146909
+ correlationId,
146910
+ token,
146911
+ claimedByRunId: claimedBy.runId
146912
+ });
146913
+ }
145872
146914
  return EventConsumerResult2.Finished;
145873
146915
  }
145874
146916
  ctx.promiseQueue = ctx.promiseQueue.then(() => {
@@ -145891,6 +146933,13 @@ function createCreateHook(ctx) {
145891
146933
  return nextDelivery.claim();
145892
146934
  }
145893
146935
  }
146936
+ if (forceClaimedErrorRef) {
146937
+ const error121 = forceClaimedErrorRef;
146938
+ ctx.promiseQueue = ctx.promiseQueue.then(() => {
146939
+ resolvers.reject(error121);
146940
+ });
146941
+ return resolvers.promise;
146942
+ }
145894
146943
  if (eventLogEmpty) {
145895
146944
  scheduleWorkflowSuspension(ctx);
145896
146945
  }
@@ -146917,28 +147966,6 @@ function countMissingIds(ids, present) {
146917
147966
  return missing;
146918
147967
  }
146919
147968
  __name(countMissingIds, "countMissingIds");
146920
- function openHookAndWaitState(events) {
146921
- const hooks = /* @__PURE__ */ new Set();
146922
- const waits = /* @__PURE__ */ new Set();
146923
- for (const event of events) {
146924
- switch (event.eventType) {
146925
- case "hook_created":
146926
- hooks.add(event.correlationId);
146927
- break;
146928
- case "hook_disposed":
146929
- hooks.delete(event.correlationId);
146930
- break;
146931
- case "wait_created":
146932
- waits.add(event.correlationId);
146933
- break;
146934
- case "wait_completed":
146935
- waits.delete(event.correlationId);
146936
- break;
146937
- }
146938
- }
146939
- return { openHook: hooks.size > 0, openWait: waits.size > 0 };
146940
- }
146941
- __name(openHookAndWaitState, "openHookAndWaitState");
146942
147969
  function getRetentionDecision({ suspension, serializationBlockerCount, hookContinuation = false, invocationContinuation = false }) {
146943
147970
  if (!isVmRetentionEnabled()) {
146944
147971
  return { retain: false, reason: "disabled" };
@@ -147104,6 +148131,8 @@ function workflowEntrypoint(workflowCode2, options) {
147104
148131
  });
147105
148132
  const invocationStartTime = Date.now();
147106
148133
  const noInlineReplayAfterMs = await getMaxInlineDurationMs(world, invocationStartTime);
148134
+ const openWaitDueDeadlineMs = invocationStartTime + noInlineReplayAfterMs + getOpenWaitClockSkewMs();
148135
+ let eventLogFromInlineDelta = false;
147107
148136
  let loopIteration = 0;
147108
148137
  const replayRecoveryReporter = replayDivergence ? new ReplayRecoveryReporter(replayDivergence.count) : ReplayRecoveryReporter.inert();
147109
148138
  let compiledWorkflowScripts;
@@ -147982,6 +149011,7 @@ function workflowEntrypoint(workflowCode2, options) {
147982
149011
  return;
147983
149012
  }
147984
149013
  if (eventLog.type !== "ready") {
149014
+ eventLogFromInlineDelta = false;
147985
149015
  const page = await loadWorkflowRunEvents(runId, eventLog.type === "loadAfter" ? eventLog.cursor : void 0);
147986
149016
  if (eventLog.type === "loadAfter") {
147987
149017
  appendEventLog(eventLog, page);
@@ -148029,6 +149059,7 @@ function workflowEntrypoint(workflowCode2, options) {
148029
149059
  const completedWaitIdsAfterWrites = new Set(eventLog.events.filter((e) => e.eventType === "wait_completed").map((e) => e.correlationId));
148030
149060
  const missingWaitCompletions = waitsToComplete.filter((waitEvent) => !completedWaitIdsAfterWrites.has(waitEvent.correlationId));
148031
149061
  if (missingWaitCompletions.length > 0) {
149062
+ eventLogFromInlineDelta = false;
148032
149063
  if (eventLog.cursor) {
148033
149064
  const page = await loadWorkflowRunEvents(runId, eventLog.cursor);
148034
149065
  const completedWaitIdsAfterCursor = new Set(page.events.filter((e) => e.eventType === "wait_completed").map((e) => e.correlationId));
@@ -148329,6 +149360,18 @@ function workflowEntrypoint(workflowCode2, options) {
148329
149360
  continue;
148330
149361
  }
148331
149362
  const pendingSteps = suspensionResult.pendingSteps;
149363
+ if (eventLogFromInlineDelta && suspensionResult.waitTimeout !== void 0 && pendingSteps.length === 0 && !suspensionResult.hasAwaitedHookCreation && openHookWait.value.openWait) {
149364
+ runtimeLogger2.debug("Re-reading the event log before parking on a wait over an inline delta", {
149365
+ workflowRunId: runId,
149366
+ loopIteration,
149367
+ waitCorrelationId: suspensionResult.waitTimeout.correlationId
149368
+ });
149369
+ span?.setAttributes({
149370
+ "workflow.wait_park_reread": true
149371
+ });
149372
+ eventLog = nextEventLogLoad(eventLog);
149373
+ continue;
149374
+ }
148332
149375
  const lazyInlineSteps = suspensionResult.lazyInlineSteps;
148333
149376
  const inlineCorrelationIds = new Set(lazyInlineSteps.map((s) => s.correlationId));
148334
149377
  const traceCarrier = await nextTraceCarrier();
@@ -148476,7 +149519,13 @@ function workflowEntrypoint(workflowCode2, options) {
148476
149519
  return;
148477
149520
  }
148478
149521
  const openHookWaitState = openHookWait.value;
148479
- const requestInlineDelta = typeof eventLog.cursor === "string" && err.stepCount === 1 && err.waitCount === 0 && pendingSteps.length === 1 && lazyInlineSteps.length === 1 && ownedRecoverySteps.length === 0 && !suspensionResult.waitTimeout && !openHookWaitState.openWait;
149522
+ const waitDueThisInvocation = hasOpenWaitDueBy(openHookWaitState, openWaitDueDeadlineMs) || suspensionResult.waitTimeout !== void 0 && !(suspensionResult.waitTimeout.resumeAtMs > openWaitDueDeadlineMs);
149523
+ const requestInlineDelta = typeof eventLog.cursor === "string" && err.stepCount === 1 && pendingSteps.length === 1 && lazyInlineSteps.length === 1 && ownedRecoverySteps.length === 0 && !waitDueThisInvocation;
149524
+ if (requestInlineDelta && (openHookWaitState.openWait || suspensionResult.waitTimeout !== void 0)) {
149525
+ span?.setAttributes({
149526
+ "workflow.inline_delta_over_pending_wait": true
149527
+ });
149528
+ }
148480
149529
  const suppressOptimisticStart = openHookWaitState.openHook || err.hookCount > 0 || suspensionResult.hasHookEvents;
148481
149530
  const forceOptimisticStart = turbo && !suspensionResult.hasAttributeEvents && !suspensionResult.waitTimeout && !suspensionResult.hasHookEvents && !suspensionResult.hasAwaitedHookCreation && !openHookWaitState.openHook && !openHookWaitState.openWait;
148482
149531
  const latencyTracking = computeStepLatencyTracking({
@@ -148687,6 +149736,7 @@ function workflowEntrypoint(workflowCode2, options) {
148687
149736
  const only = stepResults[0];
148688
149737
  if (only.type === "completed" && only.inlineDelta) {
148689
149738
  appendEventLog(eventLog, only.inlineDelta);
149739
+ eventLogFromInlineDelta = !only.inlineDelta.hasMore;
148690
149740
  eventLog = only.inlineDelta.hasMore ? nextEventLogLoad(eventLog) : { ...eventLog, type: "ready" };
148691
149741
  continue;
148692
149742
  }
@@ -149436,6 +150486,7 @@ var ERROR_SLUGS = {
149436
150486
  FETCH_IN_WORKFLOW_FUNCTION: "fetch-in-workflow",
149437
150487
  TIMEOUT_FUNCTIONS_IN_WORKFLOW: "timeout-in-workflow",
149438
150488
  HOOK_CONFLICT: "hook-conflict",
150489
+ HOOK_FORCE_CLAIMED: "hook-force-claimed",
149439
150490
  CORRUPTED_EVENT_LOG: "corrupted-event-log",
149440
150491
  REPLAY_DIVERGENCE: "replay-divergence",
149441
150492
  STEP_NOT_REGISTERED: "step-not-registered",
@@ -149549,6 +150600,30 @@ var HookConflictError = class extends WorkflowError {
149549
150600
  return isError(value) && value.name === "HookConflictError";
149550
150601
  }
149551
150602
  };
150603
+ var HookForceClaimedError = class extends WorkflowError {
150604
+ static {
150605
+ __name(this, "HookForceClaimedError");
150606
+ }
150607
+ token;
150608
+ /** The run that took the token. */
150609
+ claimedByRunId;
150610
+ /** The hook (in \`claimedByRunId\`) the token now belongs to. */
150611
+ claimedByHookId;
150612
+ constructor(token, claimedByRunId, claimedByHookId) {
150613
+ super(\`Hook token "\${token}" was force-claimed by another workflow (run "\${claimedByRunId}")\`, {
150614
+ slug: ERROR_SLUGS.HOOK_FORCE_CLAIMED
150615
+ });
150616
+ this.name = "HookForceClaimedError";
150617
+ this.token = token;
150618
+ this.claimedByRunId = claimedByRunId;
150619
+ if (claimedByHookId !== void 0) {
150620
+ this.claimedByHookId = claimedByHookId;
150621
+ }
150622
+ }
150623
+ static is(value) {
150624
+ return isError(value) && value.name === "HookForceClaimedError";
150625
+ }
150626
+ };
149552
150627
  var StreamError = class extends WorkflowWorldError {
149553
150628
  static {
149554
150629
  __name(this, "StreamError");
@@ -149605,6 +150680,7 @@ var RetryableError = class extends Error {
149605
150680
  var FATAL_ERROR_KEY = /* @__PURE__ */ Symbol.for("@workflow/errors//FatalError");
149606
150681
  var RETRYABLE_ERROR_KEY = /* @__PURE__ */ Symbol.for("@workflow/errors//RetryableError");
149607
150682
  var HOOK_CONFLICT_ERROR_KEY = /* @__PURE__ */ Symbol.for("@workflow/errors//HookConflictError");
150683
+ var HOOK_FORCE_CLAIMED_ERROR_KEY = /* @__PURE__ */ Symbol.for("@workflow/errors//HookForceClaimedError");
149608
150684
  var RUNTIME_DECRYPTION_ERROR_KEY = /* @__PURE__ */ Symbol.for("@workflow/errors//RuntimeDecryptionError");
149609
150685
  var STREAM_ERROR_KEY = /* @__PURE__ */ Symbol.for("@workflow/errors//StreamError");
149610
150686
  if (typeof globalThis !== "undefined") {
@@ -149632,6 +150708,14 @@ if (typeof globalThis !== "undefined") {
149632
150708
  configurable: false
149633
150709
  });
149634
150710
  }
150711
+ if (!Object.hasOwn(globalThis, HOOK_FORCE_CLAIMED_ERROR_KEY)) {
150712
+ Object.defineProperty(globalThis, HOOK_FORCE_CLAIMED_ERROR_KEY, {
150713
+ value: HookForceClaimedError,
150714
+ writable: false,
150715
+ enumerable: false,
150716
+ configurable: false
150717
+ });
150718
+ }
149635
150719
  if (!Object.hasOwn(globalThis, RUNTIME_DECRYPTION_ERROR_KEY)) {
149636
150720
  Object.defineProperty(globalThis, RUNTIME_DECRYPTION_ERROR_KEY, {
149637
150721
  value: RuntimeDecryptionError,
@@ -149736,11 +150820,11 @@ var Run = class _Run {
149736
150820
  return this.getWritable();
149737
150821
  }
149738
150822
  };
149739
- Run.prototype["wakeUp"] = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.54//Run#wakeUp");
149740
- Run.prototype["cancel"] = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.54//Run#cancel");
149741
- Run.prototype["getReadable"] = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.54//Run#getReadable");
149742
- Run.prototype["getWritable"] = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.54//Run#getWritable");
149743
- var __step_Run$exists = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.54//Run#exists");
150823
+ Run.prototype["wakeUp"] = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.56//Run#wakeUp");
150824
+ Run.prototype["cancel"] = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.56//Run#cancel");
150825
+ Run.prototype["getReadable"] = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.56//Run#getReadable");
150826
+ Run.prototype["getWritable"] = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.56//Run#getWritable");
150827
+ var __step_Run$exists = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.56//Run#exists");
149744
150828
  Object.defineProperty(Run.prototype, "exists", {
149745
150829
  get() {
149746
150830
  return __step_Run$exists.call(this);
@@ -149748,7 +150832,7 @@ Object.defineProperty(Run.prototype, "exists", {
149748
150832
  configurable: true,
149749
150833
  enumerable: false
149750
150834
  });
149751
- var __step_Run$status = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.54//Run#status");
150835
+ var __step_Run$status = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.56//Run#status");
149752
150836
  Object.defineProperty(Run.prototype, "status", {
149753
150837
  get() {
149754
150838
  return __step_Run$status.call(this);
@@ -149756,7 +150840,7 @@ Object.defineProperty(Run.prototype, "status", {
149756
150840
  configurable: true,
149757
150841
  enumerable: false
149758
150842
  });
149759
- var __step_Run$returnValue = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.54//Run#returnValue");
150843
+ var __step_Run$returnValue = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.56//Run#returnValue");
149760
150844
  Object.defineProperty(Run.prototype, "returnValue", {
149761
150845
  get() {
149762
150846
  return __step_Run$returnValue.call(this);
@@ -149764,7 +150848,7 @@ Object.defineProperty(Run.prototype, "returnValue", {
149764
150848
  configurable: true,
149765
150849
  enumerable: false
149766
150850
  });
149767
- var __step_Run$workflowName = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.54//Run#workflowName");
150851
+ var __step_Run$workflowName = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.56//Run#workflowName");
149768
150852
  Object.defineProperty(Run.prototype, "workflowName", {
149769
150853
  get() {
149770
150854
  return __step_Run$workflowName.call(this);
@@ -149772,7 +150856,7 @@ Object.defineProperty(Run.prototype, "workflowName", {
149772
150856
  configurable: true,
149773
150857
  enumerable: false
149774
150858
  });
149775
- var __step_Run$createdAt = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.54//Run#createdAt");
150859
+ var __step_Run$createdAt = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.56//Run#createdAt");
149776
150860
  Object.defineProperty(Run.prototype, "createdAt", {
149777
150861
  get() {
149778
150862
  return __step_Run$createdAt.call(this);
@@ -149780,7 +150864,7 @@ Object.defineProperty(Run.prototype, "createdAt", {
149780
150864
  configurable: true,
149781
150865
  enumerable: false
149782
150866
  });
149783
- var __step_Run$startedAt = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.54//Run#startedAt");
150867
+ var __step_Run$startedAt = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.56//Run#startedAt");
149784
150868
  Object.defineProperty(Run.prototype, "startedAt", {
149785
150869
  get() {
149786
150870
  return __step_Run$startedAt.call(this);
@@ -149788,7 +150872,7 @@ Object.defineProperty(Run.prototype, "startedAt", {
149788
150872
  configurable: true,
149789
150873
  enumerable: false
149790
150874
  });
149791
- var __step_Run$completedAt = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.54//Run#completedAt");
150875
+ var __step_Run$completedAt = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/run@5.0.0-beta.56//Run#completedAt");
149792
150876
  Object.defineProperty(Run.prototype, "completedAt", {
149793
150877
  get() {
149794
150878
  return __step_Run$completedAt.call(this);
@@ -149805,7 +150889,7 @@ Object.defineProperty(Run.prototype, "completedAt", {
149805
150889
  enumerable: false,
149806
150890
  configurable: false
149807
150891
  });
149808
- })(Run, "class//@workflow/core/runtime/run@5.0.0-beta.54//Run");
150892
+ })(Run, "class//@workflow/core/runtime/run@5.0.0-beta.56//Run");
149809
150893
 
149810
150894
  // ../core/dist/workflow/create-hook.js
149811
150895
  aliasSerializationClass(RUN_CLASS_ID, Run);
@@ -157401,7 +158485,7 @@ globalThis.__private_workflows.set("workflow//./workflows/inline-execution//hook
157401
158485
  var latestNoOpWarning = globalSingleton("@workflow/core//latestNoOpWarning", 1, () => ({
157402
158486
  warned: false
157403
158487
  }));
157404
- var start = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/start@5.0.0-beta.54//start");
158488
+ var start = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//@workflow/core/runtime/start@5.0.0-beta.56//start");
157405
158489
 
157406
158490
  // workflows/lineage.ts
157407
158491
  var noop = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//./workflows/lineage//noop");