@workflow/world-testing 4.1.0-beta.70 → 4.1.0-beta.71

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.
@@ -49437,6 +49437,19 @@ async function deleteJSON(filePath) {
49437
49437
  }
49438
49438
  }
49439
49439
  __name(deleteJSON, "deleteJSON");
49440
+ async function writeExclusive(filePath, data) {
49441
+ await ensureDir(import_node_path2.default.dirname(filePath));
49442
+ try {
49443
+ await import_node_fs.promises.writeFile(filePath, data, { flag: "wx" });
49444
+ return true;
49445
+ } catch (error48) {
49446
+ if (error48.code === "EEXIST") {
49447
+ return false;
49448
+ }
49449
+ throw error48;
49450
+ }
49451
+ }
49452
+ __name(writeExclusive, "writeExclusive");
49440
49453
  async function listJSONFiles(dirPath) {
49441
49454
  return listFilesByExtension(dirPath, ".json");
49442
49455
  }
@@ -49590,6 +49603,11 @@ function filterHookData(hook, resolveData) {
49590
49603
  __name(filterHookData, "filterHookData");
49591
49604
 
49592
49605
  // ../world-local/dist/storage/helpers.js
49606
+ var import_node_crypto2 = require("node:crypto");
49607
+ function hashToken(token) {
49608
+ return (0, import_node_crypto2.createHash)("sha256").update(token).digest("hex");
49609
+ }
49610
+ __name(hashToken, "hashToken");
49593
49611
  var monotonicUlid = monotonicFactory(() => Math.random());
49594
49612
  var getObjectCreatedAt = /* @__PURE__ */ __name((idPrefix) => (filename) => {
49595
49613
  const replaceRegex = new RegExp(`^${idPrefix}_`, "g");
@@ -49678,6 +49696,8 @@ async function deleteAllHooksForRun(basedir, runId) {
49678
49696
  const hookPath = import_node_path3.default.join(hooksDir, `${file2}.json`);
49679
49697
  const hook = await readJSON(hookPath, HookSchema);
49680
49698
  if (hook && hook.runId === runId) {
49699
+ const constraintPath = import_node_path3.default.join(hooksDir, "tokens", `${hashToken(hook.token)}.json`);
49700
+ await deleteJSON(constraintPath);
49681
49701
  await deleteJSON(hookPath);
49682
49702
  }
49683
49703
  }
@@ -50086,18 +50106,13 @@ function createEventsStorage(basedir) {
50086
50106
  data.eventType === "hook_created" && "eventData" in data
50087
50107
  ) {
50088
50108
  const hookData = data.eventData;
50089
- const hooksDir = import_node_path5.default.join(basedir, "hooks");
50090
- const hookFiles = await listJSONFiles(hooksDir);
50091
- let hasConflict = false;
50092
- for (const file2 of hookFiles) {
50093
- const existingHookPath = import_node_path5.default.join(hooksDir, `${file2}.json`);
50094
- const existingHook = await readJSON(existingHookPath, HookSchema);
50095
- if (existingHook && existingHook.token === hookData.token) {
50096
- hasConflict = true;
50097
- break;
50098
- }
50099
- }
50100
- if (hasConflict) {
50109
+ const constraintPath = import_node_path5.default.join(basedir, "hooks", "tokens", `${hashToken(hookData.token)}.json`);
50110
+ const tokenClaimed = await writeExclusive(constraintPath, JSON.stringify({
50111
+ token: hookData.token,
50112
+ hookId: data.correlationId,
50113
+ runId: effectiveRunId
50114
+ }));
50115
+ if (!tokenClaimed) {
50101
50116
  const conflictEvent = {
50102
50117
  eventType: "hook_conflict",
50103
50118
  correlationId: data.correlationId,
@@ -50138,6 +50153,11 @@ function createEventsStorage(basedir) {
50138
50153
  await writeJSON(hookPath, hook);
50139
50154
  } else if (data.eventType === "hook_disposed") {
50140
50155
  const hookPath = import_node_path5.default.join(basedir, "hooks", `${data.correlationId}.json`);
50156
+ const existingHook = await readJSON(hookPath, HookSchema);
50157
+ if (existingHook) {
50158
+ const disposedConstraintPath = import_node_path5.default.join(basedir, "hooks", "tokens", `${hashToken(existingHook.token)}.json`);
50159
+ await deleteJSON(disposedConstraintPath);
50160
+ }
50141
50161
  await deleteJSON(hookPath);
50142
50162
  } else if (data.eventType === "wait_created" && "eventData" in data) {
50143
50163
  const waitData = data.eventData;
@@ -50602,7 +50622,7 @@ function createLocalWorld(args) {
50602
50622
  __name(createLocalWorld, "createLocalWorld");
50603
50623
 
50604
50624
  // ../world-vercel/dist/encryption.js
50605
- var import_node_crypto2 = require("node:crypto");
50625
+ var import_node_crypto3 = require("node:crypto");
50606
50626
  var import_oidc2 = __toESM(require_dist2(), 1);
50607
50627
 
50608
50628
  // ../world-vercel/dist/http-client.js
@@ -50636,9 +50656,9 @@ async function deriveRunKey(deploymentKey, projectId, runId) {
50636
50656
  if (!projectId || typeof projectId !== "string") {
50637
50657
  throw new Error("projectId must be a non-empty string");
50638
50658
  }
50639
- const baseKey = await import_node_crypto2.webcrypto.subtle.importKey("raw", deploymentKey, "HKDF", false, ["deriveBits"]);
50659
+ const baseKey = await import_node_crypto3.webcrypto.subtle.importKey("raw", deploymentKey, "HKDF", false, ["deriveBits"]);
50640
50660
  const info = new TextEncoder().encode(`${projectId}|${runId}`);
50641
- const derivedBits = await import_node_crypto2.webcrypto.subtle.deriveBits(
50661
+ const derivedBits = await import_node_crypto3.webcrypto.subtle.deriveBits(
50642
50662
  {
50643
50663
  name: "HKDF",
50644
50664
  hash: "SHA-256",
@@ -54381,7 +54401,7 @@ var createWorld = /* @__PURE__ */ __name(() => {
54381
54401
  "WORKFLOW_VERCEL_AUTH_TOKEN",
54382
54402
  "WORKFLOW_VERCEL_ENV"
54383
54403
  ].filter((key) => process.env[key]);
54384
- if (staleEnvVars.length > 0) {
54404
+ if (staleEnvVars.length > 0 && process.env.VERCEL === "1") {
54385
54405
  console.warn(`[workflow] Warning: ${staleEnvVars.join(", ")} env var(s) are set but have no effect at runtime. These are only used by the Workflow CLI. Remove them from your Vercel project environment variables.`);
54386
54406
  }
54387
54407
  return createVercelWorld();
@@ -54552,69 +54572,6 @@ function getQueueOverhead(message) {
54552
54572
  }
54553
54573
  }
54554
54574
  __name(getQueueOverhead, "getQueueOverhead");
54555
- async function withThrottleRetry(fn) {
54556
- try {
54557
- return await fn();
54558
- } catch (err) {
54559
- if (WorkflowAPIError.is(err) && err.status === 429) {
54560
- const retryAfterSeconds = Math.max(
54561
- // If we don't have a retry-after value, 30s seems a reasonable default
54562
- // to avoid re-trying during the unknown rate-limiting period.
54563
- 1,
54564
- typeof err.retryAfter === "number" ? err.retryAfter : 30
54565
- );
54566
- if (retryAfterSeconds < 10) {
54567
- runtimeLogger.warn("Throttled by workflow-server (429), retrying in-process", {
54568
- retryAfterSeconds,
54569
- url: err.url
54570
- });
54571
- await new Promise((resolve3) => setTimeout(resolve3, retryAfterSeconds * 1e3));
54572
- try {
54573
- return await fn();
54574
- } catch (retryErr) {
54575
- if (WorkflowAPIError.is(retryErr) && retryErr.status === 429) {
54576
- const retryRetryAfter = Math.max(1, typeof retryErr.retryAfter === "number" ? retryErr.retryAfter : 1);
54577
- runtimeLogger.warn("Throttled again on retry, deferring to queue", {
54578
- retryAfterSeconds: retryRetryAfter
54579
- });
54580
- return { timeoutSeconds: retryRetryAfter };
54581
- }
54582
- throw retryErr;
54583
- }
54584
- }
54585
- runtimeLogger.warn("Throttled by workflow-server (429), deferring to queue", {
54586
- retryAfterSeconds,
54587
- url: err.url
54588
- });
54589
- return { timeoutSeconds: retryAfterSeconds };
54590
- }
54591
- throw err;
54592
- }
54593
- }
54594
- __name(withThrottleRetry, "withThrottleRetry");
54595
- async function withServerErrorRetry(fn) {
54596
- const delays = [500, 1e3, 2e3];
54597
- for (let attempt = 0; attempt <= delays.length; attempt++) {
54598
- try {
54599
- return await fn();
54600
- } catch (err) {
54601
- if (WorkflowAPIError.is(err) && err.status !== void 0 && err.status >= 500 && attempt < delays.length) {
54602
- runtimeLogger.warn("Server error (5xx) from workflow-server, retrying in-process", {
54603
- status: err.status,
54604
- attempt: attempt + 1,
54605
- maxRetries: delays.length,
54606
- nextDelayMs: delays[attempt],
54607
- url: err.url
54608
- });
54609
- await new Promise((resolve3) => setTimeout(resolve3, delays[attempt]));
54610
- continue;
54611
- }
54612
- throw err;
54613
- }
54614
- }
54615
- throw new Error("withServerErrorRetry: unreachable");
54616
- }
54617
- __name(withServerErrorRetry, "withServerErrorRetry");
54618
54575
 
54619
54576
  // ../core/dist/runtime/suspension-handler.js
54620
54577
  var import_functions = __toESM(require_functions(), 1);
@@ -58257,18 +58214,18 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58257
58214
  });
58258
58215
  let step;
58259
58216
  try {
58260
- const startResult = await withServerErrorRetry(() => world.events.create(workflowRunId, {
58217
+ const startResult = await world.events.create(workflowRunId, {
58261
58218
  eventType: "step_started",
58262
58219
  specVersion: SPEC_VERSION_CURRENT,
58263
58220
  correlationId: stepId
58264
- }));
58221
+ });
58265
58222
  if (!startResult.step) {
58266
58223
  throw new WorkflowRuntimeError(`step_started event for "${stepId}" did not return step entity`);
58267
58224
  }
58268
58225
  step = startResult.step;
58269
58226
  } catch (err) {
58270
58227
  if (WorkflowAPIError.is(err)) {
58271
- if (WorkflowAPIError.is(err) && err.status === 429) {
58228
+ if (err.status === 429) {
58272
58229
  const retryRetryAfter = Math.max(1, typeof err.retryAfter === "number" ? err.retryAfter : 1);
58273
58230
  runtimeLogger.warn("Throttled again on retry, deferring to queue", {
58274
58231
  retryAfterSeconds: retryRetryAfter
@@ -58377,28 +58334,57 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58377
58334
  });
58378
58335
  return;
58379
58336
  }
58380
- try {
58381
- const attempt = step.attempt;
58382
- if (!step.startedAt) {
58383
- throw new WorkflowRuntimeError(`Step "${stepId}" has no "startedAt" timestamp`);
58384
- }
58385
- const stepStartedAt = step.startedAt;
58386
- const ops = [];
58387
- const rawKey = await world.getEncryptionKeyForRun?.(workflowRunId);
58388
- const encryptionKey = rawKey ? await importKey(rawKey) : void 0;
58389
- const hydratedInput = await trace2("step.hydrate", {}, async (hydrateSpan) => {
58390
- const startTime = Date.now();
58391
- const result2 = await hydrateStepArguments(step.input, workflowRunId, encryptionKey, ops);
58392
- const durationMs = Date.now() - startTime;
58393
- hydrateSpan?.setAttributes({
58394
- ...StepArgumentsCount(result2.args.length),
58395
- ...QueueDeserializeTimeMs(durationMs)
58337
+ const attempt = step.attempt;
58338
+ if (!step.startedAt) {
58339
+ const errorMessage = `Step "${stepId}" has no "startedAt" timestamp`;
58340
+ runtimeLogger.error("Fatal runtime error during step setup", {
58341
+ workflowRunId,
58342
+ stepId,
58343
+ error: errorMessage
58344
+ });
58345
+ try {
58346
+ await world.events.create(workflowRunId, {
58347
+ eventType: "step_failed",
58348
+ specVersion: SPEC_VERSION_CURRENT,
58349
+ correlationId: stepId,
58350
+ eventData: {
58351
+ error: errorMessage,
58352
+ stack: new Error(errorMessage).stack ?? ""
58353
+ }
58396
58354
  });
58397
- return result2;
58355
+ } catch (failErr) {
58356
+ if (WorkflowAPIError.is(failErr) && failErr.status === 409) {
58357
+ return;
58358
+ }
58359
+ throw failErr;
58360
+ }
58361
+ await queueMessage(world, getWorkflowQueueName(workflowName), {
58362
+ runId: workflowRunId,
58363
+ traceCarrier: await serializeTraceCarrier(),
58364
+ requestedAt: /* @__PURE__ */ new Date()
58365
+ });
58366
+ return;
58367
+ }
58368
+ const stepStartedAt = step.startedAt;
58369
+ const ops = [];
58370
+ const rawKey = await world.getEncryptionKeyForRun?.(workflowRunId);
58371
+ const encryptionKey = rawKey ? await importKey(rawKey) : void 0;
58372
+ const hydratedInput = await trace2("step.hydrate", {}, async (hydrateSpan) => {
58373
+ const startTime = Date.now();
58374
+ const result2 = await hydrateStepArguments(step.input, workflowRunId, encryptionKey, ops);
58375
+ const durationMs = Date.now() - startTime;
58376
+ hydrateSpan?.setAttributes({
58377
+ ...StepArgumentsCount(result2.args.length),
58378
+ ...QueueDeserializeTimeMs(durationMs)
58398
58379
  });
58399
- const args = hydratedInput.args;
58400
- const thisVal = hydratedInput.thisVal ?? null;
58401
- const executionStartTime = Date.now();
58380
+ return result2;
58381
+ });
58382
+ const args = hydratedInput.args;
58383
+ const thisVal = hydratedInput.thisVal ?? null;
58384
+ let userCodeError;
58385
+ let userCodeFailed = false;
58386
+ const executionStartTime = Date.now();
58387
+ try {
58402
58388
  result = await trace2("step.execute", {}, async () => {
58403
58389
  return await contextStorage.run({
58404
58390
  stepMetadata: {
@@ -58420,63 +58406,29 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58420
58406
  encryptionKey
58421
58407
  }, () => stepFn.apply(thisVal, args));
58422
58408
  });
58423
- const executionTimeMs = Date.now() - executionStartTime;
58424
- span?.setAttributes({
58425
- ...QueueExecutionTimeMs(executionTimeMs)
58426
- });
58427
- result = await trace2("step.dehydrate", {}, async (dehydrateSpan) => {
58428
- const startTime = Date.now();
58429
- const dehydrated = await dehydrateStepReturnValue(result, workflowRunId, encryptionKey, ops);
58430
- const durationMs = Date.now() - startTime;
58431
- dehydrateSpan?.setAttributes({
58432
- ...QueueSerializeTimeMs(durationMs),
58433
- ...StepResultType(typeof dehydrated)
58434
- });
58435
- return dehydrated;
58436
- });
58437
- (0, import_functions5.waitUntil)(Promise.all(ops).catch((err) => {
58438
- const isAbortError = err?.name === "AbortError" || err?.name === "ResponseAborted";
58439
- if (!isAbortError)
58440
- throw err;
58441
- }));
58442
- let stepCompleted409 = false;
58443
- const [, traceCarrier] = await Promise.all([
58444
- withServerErrorRetry(() => world.events.create(workflowRunId, {
58445
- eventType: "step_completed",
58446
- specVersion: SPEC_VERSION_CURRENT,
58447
- correlationId: stepId,
58448
- eventData: {
58449
- result
58450
- }
58451
- })).catch((err) => {
58452
- if (WorkflowAPIError.is(err) && err.status === 409) {
58453
- runtimeLogger.warn("Tried completing step, but step has already finished.", {
58454
- workflowRunId,
58455
- stepId,
58456
- stepName,
58457
- message: err.message
58458
- });
58459
- stepCompleted409 = true;
58460
- return;
58461
- }
58409
+ } catch (err) {
58410
+ userCodeError = err;
58411
+ userCodeFailed = true;
58412
+ }
58413
+ const executionTimeMs = Date.now() - executionStartTime;
58414
+ span?.setAttributes({
58415
+ ...QueueExecutionTimeMs(executionTimeMs)
58416
+ });
58417
+ if (userCodeFailed) {
58418
+ const err = userCodeError;
58419
+ if (WorkflowAPIError.is(err)) {
58420
+ if (err.status === 410) {
58421
+ stepLogger.info("Workflow run already completed, skipping step", {
58422
+ workflowRunId,
58423
+ stepId,
58424
+ message: err.message
58425
+ });
58426
+ return;
58427
+ }
58428
+ if (err.status !== void 0 && err.status >= 500) {
58462
58429
  throw err;
58463
- }),
58464
- serializeTraceCarrier()
58465
- ]);
58466
- if (stepCompleted409) {
58467
- return;
58430
+ }
58468
58431
  }
58469
- span?.setAttributes({
58470
- ...StepStatus("completed"),
58471
- ...StepResultType(typeof result)
58472
- });
58473
- await queueMessage(world, getWorkflowQueueName(workflowName), {
58474
- runId: workflowRunId,
58475
- traceCarrier,
58476
- requestedAt: /* @__PURE__ */ new Date()
58477
- });
58478
- return;
58479
- } catch (err) {
58480
58432
  const normalizedError = await normalizeUnknownError(err);
58481
58433
  const normalizedStack = normalizedError.stack || getErrorStack(err) || "";
58482
58434
  if (err instanceof Error) {
@@ -58492,26 +58444,6 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58492
58444
  ...ErrorCategory(errorCategory),
58493
58445
  ...ErrorRetryable(!isFatal)
58494
58446
  });
58495
- if (WorkflowAPIError.is(err)) {
58496
- if (err.status === 410) {
58497
- stepLogger.info("Workflow run already completed, skipping step", {
58498
- workflowRunId,
58499
- stepId,
58500
- message: err.message
58501
- });
58502
- return;
58503
- }
58504
- if (err.status !== void 0 && err.status >= 500) {
58505
- runtimeLogger.warn("Persistent server error (5xx) during step, deferring to queue retry", {
58506
- status: err.status,
58507
- workflowRunId,
58508
- stepId,
58509
- error: err.message,
58510
- url: err.url
58511
- });
58512
- throw err;
58513
- }
58514
- }
58515
58447
  if (isFatal) {
58516
58448
  stepLogger.error("Encountered FatalError while executing step, bubbling up to parent workflow", {
58517
58449
  workflowRunId,
@@ -58519,7 +58451,7 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58519
58451
  errorStack: normalizedStack
58520
58452
  });
58521
58453
  try {
58522
- await withServerErrorRetry(() => world.events.create(workflowRunId, {
58454
+ await world.events.create(workflowRunId, {
58523
58455
  eventType: "step_failed",
58524
58456
  specVersion: SPEC_VERSION_CURRENT,
58525
58457
  correlationId: stepId,
@@ -58527,7 +58459,7 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58527
58459
  error: normalizedError.message,
58528
58460
  stack: normalizedStack
58529
58461
  }
58530
- }));
58462
+ });
58531
58463
  } catch (stepFailErr) {
58532
58464
  if (WorkflowAPIError.is(stepFailErr) && stepFailErr.status === 409) {
58533
58465
  runtimeLogger.warn("Tried failing step, but step has already finished.", {
@@ -58562,7 +58494,7 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58562
58494
  });
58563
58495
  const errorMessage = `Step "${stepName}" failed after ${maxRetries2} ${pluralize("retry", "retries", maxRetries2)}: ${normalizedError.message}`;
58564
58496
  try {
58565
- await withServerErrorRetry(() => world.events.create(workflowRunId, {
58497
+ await world.events.create(workflowRunId, {
58566
58498
  eventType: "step_failed",
58567
58499
  specVersion: SPEC_VERSION_CURRENT,
58568
58500
  correlationId: stepId,
@@ -58570,7 +58502,7 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58570
58502
  error: errorMessage,
58571
58503
  stack: normalizedStack
58572
58504
  }
58573
- }));
58505
+ });
58574
58506
  } catch (stepFailErr) {
58575
58507
  if (WorkflowAPIError.is(stepFailErr) && stepFailErr.status === 409) {
58576
58508
  runtimeLogger.warn("Tried failing step, but step has already finished.", {
@@ -58604,7 +58536,7 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58604
58536
  });
58605
58537
  }
58606
58538
  try {
58607
- await withServerErrorRetry(() => world.events.create(workflowRunId, {
58539
+ await world.events.create(workflowRunId, {
58608
58540
  eventType: "step_retrying",
58609
58541
  specVersion: SPEC_VERSION_CURRENT,
58610
58542
  correlationId: stepId,
@@ -58615,7 +58547,7 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58615
58547
  retryAfter: err.retryAfter
58616
58548
  }
58617
58549
  }
58618
- }));
58550
+ });
58619
58551
  } catch (stepRetryErr) {
58620
58552
  if (WorkflowAPIError.is(stepRetryErr) && stepRetryErr.status === 409) {
58621
58553
  runtimeLogger.warn("Tried retrying step, but step has already finished.", {
@@ -58641,10 +58573,62 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58641
58573
  return { timeoutSeconds };
58642
58574
  }
58643
58575
  }
58576
+ await queueMessage(world, getWorkflowQueueName(workflowName), {
58577
+ runId: workflowRunId,
58578
+ traceCarrier: await serializeTraceCarrier(),
58579
+ requestedAt: /* @__PURE__ */ new Date()
58580
+ });
58581
+ return;
58582
+ }
58583
+ result = await trace2("step.dehydrate", {}, async (dehydrateSpan) => {
58584
+ const startTime = Date.now();
58585
+ const dehydrated = await dehydrateStepReturnValue(result, workflowRunId, encryptionKey, ops);
58586
+ const durationMs = Date.now() - startTime;
58587
+ dehydrateSpan?.setAttributes({
58588
+ ...QueueSerializeTimeMs(durationMs),
58589
+ ...StepResultType(typeof dehydrated)
58590
+ });
58591
+ return dehydrated;
58592
+ });
58593
+ (0, import_functions5.waitUntil)(Promise.all(ops).catch((err) => {
58594
+ const isAbortError = err?.name === "AbortError" || err?.name === "ResponseAborted";
58595
+ if (!isAbortError)
58596
+ throw err;
58597
+ }));
58598
+ let stepCompleted409 = false;
58599
+ const [, traceCarrier] = await Promise.all([
58600
+ world.events.create(workflowRunId, {
58601
+ eventType: "step_completed",
58602
+ specVersion: SPEC_VERSION_CURRENT,
58603
+ correlationId: stepId,
58604
+ eventData: {
58605
+ result
58606
+ }
58607
+ }).catch((err) => {
58608
+ if (WorkflowAPIError.is(err) && err.status === 409) {
58609
+ runtimeLogger.warn("Tried completing step, but step has already finished.", {
58610
+ workflowRunId,
58611
+ stepId,
58612
+ stepName,
58613
+ message: err.message
58614
+ });
58615
+ stepCompleted409 = true;
58616
+ return;
58617
+ }
58618
+ throw err;
58619
+ }),
58620
+ serializeTraceCarrier()
58621
+ ]);
58622
+ if (stepCompleted409) {
58623
+ return;
58644
58624
  }
58625
+ span?.setAttributes({
58626
+ ...StepStatus("completed"),
58627
+ ...StepResultType(typeof result)
58628
+ });
58645
58629
  await queueMessage(world, getWorkflowQueueName(workflowName), {
58646
58630
  runId: workflowRunId,
58647
- traceCarrier: await serializeTraceCarrier(),
58631
+ traceCarrier,
58648
58632
  requestedAt: /* @__PURE__ */ new Date()
58649
58633
  });
58650
58634
  });
@@ -58659,7 +58643,7 @@ function workflowEntrypoint(workflowCode2) {
58659
58643
  await handleHealthCheckMessage(healthCheck2, "workflow");
58660
58644
  return;
58661
58645
  }
58662
- const { runId, traceCarrier: traceContext, requestedAt, serverErrorRetryCount } = WorkflowInvokePayloadSchema.parse(message_);
58646
+ const { runId, traceCarrier: traceContext, requestedAt } = WorkflowInvokePayloadSchema.parse(message_);
58663
58647
  const workflowName = metadata.queueName.slice("__wkf_workflow_".length);
58664
58648
  const spanLinks = await linkToCurrentContext();
58665
58649
  return await withTraceContext(traceContext, async () => {
@@ -58680,179 +58664,183 @@ function workflowEntrypoint(workflowCode2) {
58680
58664
  ...WorkflowRunId(runId),
58681
58665
  ...WorkflowTracePropagated(!!traceContext)
58682
58666
  });
58683
- return await withThrottleRetry(async () => {
58684
- let workflowStartedAt = -1;
58685
- let workflowRun = await world.runs.get(runId);
58686
- try {
58687
- if (workflowRun.status === "pending") {
58688
- const result2 = await world.events.create(runId, {
58689
- eventType: "run_started",
58690
- specVersion: SPEC_VERSION_CURRENT
58691
- });
58692
- if (!result2.run) {
58693
- throw new WorkflowRuntimeError(`Event creation for 'run_started' did not return the run entity for run "${runId}"`);
58694
- }
58695
- workflowRun = result2.run;
58696
- }
58697
- if (!workflowRun.startedAt) {
58698
- throw new WorkflowRuntimeError(`Workflow run "${runId}" has no "startedAt" timestamp`);
58699
- }
58700
- workflowStartedAt = +workflowRun.startedAt;
58701
- span?.setAttributes({
58702
- ...WorkflowRunStatus(workflowRun.status),
58703
- ...WorkflowStartedAt(workflowStartedAt)
58667
+ let workflowStartedAt = -1;
58668
+ let workflowRun = await world.runs.get(runId);
58669
+ try {
58670
+ if (workflowRun.status === "pending") {
58671
+ const result = await world.events.create(runId, {
58672
+ eventType: "run_started",
58673
+ specVersion: SPEC_VERSION_CURRENT
58704
58674
  });
58705
- if (workflowRun.status !== "running") {
58706
- runtimeLogger.info("Workflow already completed or failed, skipping", {
58707
- workflowRunId: runId,
58708
- status: workflowRun.status
58709
- });
58710
- return;
58711
- }
58712
- const events = await getAllWorkflowRunEvents(workflowRun.runId);
58713
- const now = Date.now();
58714
- const completedWaitIds = new Set(events.filter((e) => e.eventType === "wait_completed").map((e) => e.correlationId));
58715
- const waitsToComplete = events.filter((e) => e.eventType === "wait_created" && e.correlationId !== void 0 && !completedWaitIds.has(e.correlationId) && now >= e.eventData.resumeAt.getTime()).map((e) => ({
58716
- eventType: "wait_completed",
58717
- specVersion: SPEC_VERSION_CURRENT,
58718
- correlationId: e.correlationId
58719
- }));
58720
- for (const waitEvent of waitsToComplete) {
58721
- try {
58722
- const result2 = await world.events.create(runId, waitEvent);
58723
- events.push(result2.event);
58724
- } catch (err) {
58725
- if (WorkflowAPIError.is(err) && err.status === 409) {
58726
- runtimeLogger.info("Wait already completed, skipping", {
58727
- workflowRunId: runId,
58728
- correlationId: waitEvent.correlationId
58729
- });
58730
- continue;
58731
- }
58732
- throw err;
58733
- }
58675
+ if (!result.run) {
58676
+ throw new WorkflowRuntimeError(`Event creation for 'run_started' did not return the run entity for run "${runId}"`);
58734
58677
  }
58735
- const result = await trace2("workflow.replay", {}, async (replaySpan) => {
58736
- replaySpan?.setAttributes({
58737
- ...WorkflowEventsCount(events.length)
58738
- });
58739
- const rawKey = await world.getEncryptionKeyForRun?.(workflowRun);
58740
- const encryptionKey = rawKey ? await importKey(rawKey) : void 0;
58741
- return await runWorkflow(workflowCode2, workflowRun, events, encryptionKey);
58742
- });
58678
+ workflowRun = result.run;
58679
+ }
58680
+ if (!workflowRun.startedAt) {
58681
+ throw new WorkflowRuntimeError(`Workflow run "${runId}" has no "startedAt" timestamp`);
58682
+ }
58683
+ } catch (err) {
58684
+ if (err instanceof WorkflowRuntimeError) {
58685
+ runtimeLogger.error("Fatal runtime error during workflow setup", { workflowRunId: runId, error: err.message });
58743
58686
  try {
58744
58687
  await world.events.create(runId, {
58745
- eventType: "run_completed",
58688
+ eventType: "run_failed",
58746
58689
  specVersion: SPEC_VERSION_CURRENT,
58747
58690
  eventData: {
58748
- output: result
58691
+ error: {
58692
+ message: err.message,
58693
+ stack: err.stack
58694
+ }
58749
58695
  }
58750
58696
  });
58751
- } catch (err) {
58752
- if (WorkflowAPIError.is(err) && (err.status === 409 || err.status === 410)) {
58753
- runtimeLogger.warn("Tried completing workflow run, but run has already finished.", {
58754
- workflowRunId: runId,
58755
- message: err.message
58756
- });
58697
+ } catch (failErr) {
58698
+ if (WorkflowAPIError.is(failErr) && (failErr.status === 409 || failErr.status === 410)) {
58757
58699
  return;
58758
- } else {
58759
- throw err;
58760
58700
  }
58701
+ throw failErr;
58761
58702
  }
58762
- span?.setAttributes({
58763
- ...WorkflowRunStatus("completed"),
58764
- ...WorkflowEventsCount(events.length)
58765
- });
58703
+ return;
58704
+ }
58705
+ throw err;
58706
+ }
58707
+ workflowStartedAt = +workflowRun.startedAt;
58708
+ span?.setAttributes({
58709
+ ...WorkflowRunStatus(workflowRun.status),
58710
+ ...WorkflowStartedAt(workflowStartedAt)
58711
+ });
58712
+ if (workflowRun.status !== "running") {
58713
+ runtimeLogger.info("Workflow already completed or failed, skipping", {
58714
+ workflowRunId: runId,
58715
+ status: workflowRun.status
58716
+ });
58717
+ return;
58718
+ }
58719
+ const events = await getAllWorkflowRunEvents(workflowRun.runId);
58720
+ const now = Date.now();
58721
+ const completedWaitIds = new Set(events.filter((e) => e.eventType === "wait_completed").map((e) => e.correlationId));
58722
+ const waitsToComplete = events.filter((e) => e.eventType === "wait_created" && e.correlationId !== void 0 && !completedWaitIds.has(e.correlationId) && now >= e.eventData.resumeAt.getTime()).map((e) => ({
58723
+ eventType: "wait_completed",
58724
+ specVersion: SPEC_VERSION_CURRENT,
58725
+ correlationId: e.correlationId
58726
+ }));
58727
+ for (const waitEvent of waitsToComplete) {
58728
+ try {
58729
+ const result = await world.events.create(runId, waitEvent);
58730
+ events.push(result.event);
58766
58731
  } catch (err) {
58767
- if (WorkflowSuspension.is(err)) {
58768
- const suspensionMessage = buildWorkflowSuspensionMessage(runId, err.stepCount, err.hookCount, err.waitCount);
58769
- if (suspensionMessage) {
58770
- runtimeLogger.debug(suspensionMessage);
58771
- }
58772
- const result = await handleSuspension({
58773
- suspension: err,
58774
- world,
58775
- run: workflowRun,
58776
- span
58732
+ if (WorkflowAPIError.is(err) && err.status === 409) {
58733
+ runtimeLogger.info("Wait already completed, skipping", {
58734
+ workflowRunId: runId,
58735
+ correlationId: waitEvent.correlationId
58777
58736
  });
58778
- if (result.timeoutSeconds !== void 0) {
58779
- return { timeoutSeconds: result.timeoutSeconds };
58780
- }
58781
- } else {
58782
- if (WorkflowAPIError.is(err) && err.status !== void 0 && err.status >= 500) {
58783
- const retryCount = serverErrorRetryCount ?? 0;
58784
- const delaySecondSteps = [5, 30, 120];
58785
- if (retryCount < delaySecondSteps.length) {
58786
- runtimeLogger.warn("Server error (5xx), re-enqueueing workflow with backoff", {
58787
- workflowRunId: runId,
58788
- retryCount,
58789
- delaySeconds: delaySecondSteps[retryCount],
58790
- error: err.message
58791
- });
58792
- await queueMessage(world, getWorkflowQueueName(workflowName), {
58793
- runId,
58794
- serverErrorRetryCount: retryCount + 1,
58795
- traceCarrier: await serializeTraceCarrier(),
58796
- requestedAt: /* @__PURE__ */ new Date()
58797
- }, { delaySeconds: delaySecondSteps[retryCount] });
58798
- return;
58737
+ continue;
58738
+ }
58739
+ throw err;
58740
+ }
58741
+ }
58742
+ const rawKey = await world.getEncryptionKeyForRun?.(workflowRun);
58743
+ const encryptionKey = rawKey ? await importKey(rawKey) : void 0;
58744
+ let workflowResult;
58745
+ try {
58746
+ workflowResult = await trace2("workflow.replay", {}, async (replaySpan) => {
58747
+ replaySpan?.setAttributes({
58748
+ ...WorkflowEventsCount(events.length)
58749
+ });
58750
+ return await runWorkflow(workflowCode2, workflowRun, events, encryptionKey);
58751
+ });
58752
+ } catch (err) {
58753
+ if (WorkflowSuspension.is(err)) {
58754
+ const suspensionMessage = buildWorkflowSuspensionMessage(runId, err.stepCount, err.hookCount, err.waitCount);
58755
+ if (suspensionMessage) {
58756
+ runtimeLogger.debug(suspensionMessage);
58757
+ }
58758
+ const result = await handleSuspension({
58759
+ suspension: err,
58760
+ world,
58761
+ run: workflowRun,
58762
+ span
58763
+ });
58764
+ if (result.timeoutSeconds !== void 0) {
58765
+ return { timeoutSeconds: result.timeoutSeconds };
58766
+ }
58767
+ return;
58768
+ }
58769
+ if (err instanceof Error) {
58770
+ span?.recordException?.(err);
58771
+ }
58772
+ const normalizedError = await normalizeUnknownError(err);
58773
+ const errorName = normalizedError.name || getErrorName(err);
58774
+ const errorMessage = normalizedError.message;
58775
+ let errorStack = normalizedError.stack || getErrorStack(err);
58776
+ if (errorStack) {
58777
+ const parsedName = parseWorkflowName(workflowName);
58778
+ const filename = parsedName?.moduleSpecifier || workflowName;
58779
+ errorStack = remapErrorStack(errorStack, filename, workflowCode2);
58780
+ }
58781
+ runtimeLogger.error("Error while running workflow", {
58782
+ workflowRunId: runId,
58783
+ errorName,
58784
+ errorStack
58785
+ });
58786
+ try {
58787
+ await world.events.create(runId, {
58788
+ eventType: "run_failed",
58789
+ specVersion: SPEC_VERSION_CURRENT,
58790
+ eventData: {
58791
+ error: {
58792
+ message: errorMessage,
58793
+ stack: errorStack
58799
58794
  }
58800
- } else if (WorkflowAPIError.is(err) && err.status === 429) {
58801
- throw err;
58795
+ // TODO: include error codes when we define them
58802
58796
  }
58803
- if (err instanceof Error) {
58804
- span?.recordException?.(err);
58805
- }
58806
- const normalizedError = await normalizeUnknownError(err);
58807
- const errorName = normalizedError.name || getErrorName(err);
58808
- const errorMessage = normalizedError.message;
58809
- let errorStack = normalizedError.stack || getErrorStack(err);
58810
- if (errorStack) {
58811
- const parsedName = parseWorkflowName(workflowName);
58812
- const filename = parsedName?.moduleSpecifier || workflowName;
58813
- errorStack = remapErrorStack(errorStack, filename, workflowCode2);
58814
- }
58815
- runtimeLogger.error("Error while running workflow", {
58797
+ });
58798
+ } catch (failErr) {
58799
+ if (WorkflowAPIError.is(failErr) && (failErr.status === 409 || failErr.status === 410)) {
58800
+ runtimeLogger.warn("Tried failing workflow run, but run has already finished.", {
58816
58801
  workflowRunId: runId,
58817
- errorName,
58818
- errorStack
58802
+ message: failErr.message
58819
58803
  });
58820
- try {
58821
- await world.events.create(runId, {
58822
- eventType: "run_failed",
58823
- specVersion: SPEC_VERSION_CURRENT,
58824
- eventData: {
58825
- error: {
58826
- message: errorMessage,
58827
- stack: errorStack
58828
- }
58829
- // TODO: include error codes when we define them
58830
- }
58831
- });
58832
- } catch (err2) {
58833
- if (WorkflowAPIError.is(err2) && (err2.status === 409 || err2.status === 410)) {
58834
- runtimeLogger.warn("Tried failing workflow run, but run has already finished.", {
58835
- workflowRunId: runId,
58836
- message: err2.message
58837
- });
58838
- span?.setAttributes({
58839
- ...WorkflowErrorName(errorName),
58840
- ...WorkflowErrorMessage(errorMessage),
58841
- ...ErrorType(errorName)
58842
- });
58843
- return;
58844
- } else {
58845
- throw err2;
58846
- }
58847
- }
58848
58804
  span?.setAttributes({
58849
- ...WorkflowRunStatus("failed"),
58850
58805
  ...WorkflowErrorName(errorName),
58851
58806
  ...WorkflowErrorMessage(errorMessage),
58852
58807
  ...ErrorType(errorName)
58853
58808
  });
58809
+ return;
58810
+ } else {
58811
+ throw failErr;
58812
+ }
58813
+ }
58814
+ span?.setAttributes({
58815
+ ...WorkflowRunStatus("failed"),
58816
+ ...WorkflowErrorName(errorName),
58817
+ ...WorkflowErrorMessage(errorMessage),
58818
+ ...ErrorType(errorName)
58819
+ });
58820
+ return;
58821
+ }
58822
+ try {
58823
+ await world.events.create(runId, {
58824
+ eventType: "run_completed",
58825
+ specVersion: SPEC_VERSION_CURRENT,
58826
+ eventData: {
58827
+ output: workflowResult
58854
58828
  }
58829
+ });
58830
+ } catch (err) {
58831
+ if (WorkflowAPIError.is(err) && (err.status === 409 || err.status === 410)) {
58832
+ runtimeLogger.warn("Tried completing workflow run, but run has already finished.", {
58833
+ workflowRunId: runId,
58834
+ message: err.message
58835
+ });
58836
+ return;
58837
+ } else {
58838
+ throw err;
58855
58839
  }
58840
+ }
58841
+ span?.setAttributes({
58842
+ ...WorkflowRunStatus("completed"),
58843
+ ...WorkflowEventsCount(events.length)
58856
58844
  });
58857
58845
  });
58858
58846
  });
@@ -59090,7 +59078,7 @@ function getWritable(options = {}) {
59090
59078
  __name(getWritable, "getWritable");
59091
59079
 
59092
59080
  // ../workflow/dist/stdlib.js
59093
- var fetch = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//workflow@4.2.0-beta.69//fetch");
59081
+ var fetch = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//workflow@4.2.0-beta.70//fetch");
59094
59082
 
59095
59083
  // ../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/core.js
59096
59084
  var NEVER = Object.freeze({