@workflow/world-testing 4.1.0-beta.69 → 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.
@@ -2730,7 +2730,7 @@ var require_token_util = __commonJS({
2730
2730
  getTokenPayload: /* @__PURE__ */ __name(() => getTokenPayload, "getTokenPayload"),
2731
2731
  getVercelCliToken: /* @__PURE__ */ __name(() => getVercelCliToken, "getVercelCliToken"),
2732
2732
  getVercelDataDir: /* @__PURE__ */ __name(() => getVercelDataDir, "getVercelDataDir"),
2733
- getVercelOidcToken: /* @__PURE__ */ __name(() => getVercelOidcToken5, "getVercelOidcToken"),
2733
+ getVercelOidcToken: /* @__PURE__ */ __name(() => getVercelOidcToken6, "getVercelOidcToken"),
2734
2734
  isExpired: /* @__PURE__ */ __name(() => isExpired, "isExpired"),
2735
2735
  loadToken: /* @__PURE__ */ __name(() => loadToken, "loadToken"),
2736
2736
  saveToken: /* @__PURE__ */ __name(() => saveToken, "saveToken")
@@ -2765,7 +2765,7 @@ var require_token_util = __commonJS({
2765
2765
  return JSON.parse(token).token;
2766
2766
  }
2767
2767
  __name(getVercelCliToken, "getVercelCliToken");
2768
- async function getVercelOidcToken5(authToken, projectId, teamId) {
2768
+ async function getVercelOidcToken6(authToken, projectId, teamId) {
2769
2769
  try {
2770
2770
  const url2 = `https://api.vercel.com/v1/projects/${projectId}/token?source=vercel-oidc-refresh${teamId ? `&teamId=${teamId}` : ""}`;
2771
2771
  const res = await fetch(url2, {
@@ -2786,7 +2786,7 @@ var require_token_util = __commonJS({
2786
2786
  throw new import_token_error.VercelOidcTokenError(`Failed to refresh OIDC token`, e);
2787
2787
  }
2788
2788
  }
2789
- __name(getVercelOidcToken5, "getVercelOidcToken");
2789
+ __name(getVercelOidcToken6, "getVercelOidcToken");
2790
2790
  function assertVercelOidcTokenResponse(res) {
2791
2791
  if (!res || typeof res !== "object") {
2792
2792
  throw new TypeError("Expected an object");
@@ -2950,13 +2950,13 @@ var require_get_vercel_oidc_token = __commonJS({
2950
2950
  var __toCommonJS2 = /* @__PURE__ */ __name((mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod), "__toCommonJS");
2951
2951
  var get_vercel_oidc_token_exports = {};
2952
2952
  __export2(get_vercel_oidc_token_exports, {
2953
- getVercelOidcToken: /* @__PURE__ */ __name(() => getVercelOidcToken5, "getVercelOidcToken"),
2953
+ getVercelOidcToken: /* @__PURE__ */ __name(() => getVercelOidcToken6, "getVercelOidcToken"),
2954
2954
  getVercelOidcTokenSync: /* @__PURE__ */ __name(() => getVercelOidcTokenSync2, "getVercelOidcTokenSync")
2955
2955
  });
2956
2956
  module2.exports = __toCommonJS2(get_vercel_oidc_token_exports);
2957
2957
  var import_get_context = require_get_context();
2958
2958
  var import_token_error = require_token_error();
2959
- async function getVercelOidcToken5() {
2959
+ async function getVercelOidcToken6() {
2960
2960
  let token = "";
2961
2961
  let err;
2962
2962
  try {
@@ -2982,7 +2982,7 @@ ${error48.message}`;
2982
2982
  }
2983
2983
  return token;
2984
2984
  }
2985
- __name(getVercelOidcToken5, "getVercelOidcToken");
2985
+ __name(getVercelOidcToken6, "getVercelOidcToken");
2986
2986
  function getVercelOidcTokenSync2() {
2987
2987
  const token = (0, import_get_context.getContext)().headers?.["x-vercel-oidc-token"] ?? process.env.VERCEL_OIDC_TOKEN;
2988
2988
  if (!token) {
@@ -28043,7 +28043,7 @@ var require_token_util2 = __commonJS({
28043
28043
  findProjectInfo: /* @__PURE__ */ __name(() => findProjectInfo, "findProjectInfo"),
28044
28044
  getTokenPayload: /* @__PURE__ */ __name(() => getTokenPayload, "getTokenPayload"),
28045
28045
  getVercelDataDir: /* @__PURE__ */ __name(() => getVercelDataDir, "getVercelDataDir"),
28046
- getVercelOidcToken: /* @__PURE__ */ __name(() => getVercelOidcToken5, "getVercelOidcToken"),
28046
+ getVercelOidcToken: /* @__PURE__ */ __name(() => getVercelOidcToken6, "getVercelOidcToken"),
28047
28047
  getVercelToken: /* @__PURE__ */ __name(() => getVercelToken2, "getVercelToken"),
28048
28048
  isExpired: /* @__PURE__ */ __name(() => isExpired, "isExpired"),
28049
28049
  loadToken: /* @__PURE__ */ __name(() => loadToken, "loadToken"),
@@ -28105,7 +28105,7 @@ var require_token_util2 = __commonJS({
28105
28105
  }
28106
28106
  }
28107
28107
  __name(getVercelToken2, "getVercelToken");
28108
- async function getVercelOidcToken5(authToken, projectId, teamId) {
28108
+ async function getVercelOidcToken6(authToken, projectId, teamId) {
28109
28109
  const url2 = `https://api.vercel.com/v1/projects/${projectId}/token?source=vercel-oidc-refresh${teamId ? `&teamId=${teamId}` : ""}`;
28110
28110
  const res = await fetch(url2, {
28111
28111
  method: "POST",
@@ -28122,7 +28122,7 @@ var require_token_util2 = __commonJS({
28122
28122
  assertVercelOidcTokenResponse(tokenRes);
28123
28123
  return tokenRes;
28124
28124
  }
28125
- __name(getVercelOidcToken5, "getVercelOidcToken");
28125
+ __name(getVercelOidcToken6, "getVercelOidcToken");
28126
28126
  function assertVercelOidcTokenResponse(res) {
28127
28127
  if (!res || typeof res !== "object") {
28128
28128
  throw new TypeError(
@@ -28297,13 +28297,13 @@ var require_get_vercel_oidc_token2 = __commonJS({
28297
28297
  var __toCommonJS2 = /* @__PURE__ */ __name((mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod), "__toCommonJS");
28298
28298
  var get_vercel_oidc_token_exports = {};
28299
28299
  __export2(get_vercel_oidc_token_exports, {
28300
- getVercelOidcToken: /* @__PURE__ */ __name(() => getVercelOidcToken5, "getVercelOidcToken"),
28300
+ getVercelOidcToken: /* @__PURE__ */ __name(() => getVercelOidcToken6, "getVercelOidcToken"),
28301
28301
  getVercelOidcTokenSync: /* @__PURE__ */ __name(() => getVercelOidcTokenSync2, "getVercelOidcTokenSync")
28302
28302
  });
28303
28303
  module2.exports = __toCommonJS2(get_vercel_oidc_token_exports);
28304
28304
  var import_get_context = require_get_context2();
28305
28305
  var import_token_error = require_token_error2();
28306
- async function getVercelOidcToken5(options) {
28306
+ async function getVercelOidcToken6(options) {
28307
28307
  let token = "";
28308
28308
  let err;
28309
28309
  try {
@@ -28333,7 +28333,7 @@ ${error48.message}`;
28333
28333
  }
28334
28334
  return token;
28335
28335
  }
28336
- __name(getVercelOidcToken5, "getVercelOidcToken");
28336
+ __name(getVercelOidcToken6, "getVercelOidcToken");
28337
28337
  function getVercelOidcTokenSync2() {
28338
28338
  const token = (0, import_get_context.getContext)().headers?.["x-vercel-oidc-token"] ?? process.env.VERCEL_OIDC_TOKEN;
28339
28339
  if (!token) {
@@ -49017,17 +49017,86 @@ var LOCAL_QUEUE_MAX_VISIBILITY = parseInt(process.env.WORKFLOW_LOCAL_QUEUE_MAX_V
49017
49017
  var MAX_SAFE_TIMEOUT_MS = 2147483647;
49018
49018
  var DEFAULT_CONCURRENCY_LIMIT = 1e3;
49019
49019
  var WORKFLOW_LOCAL_QUEUE_CONCURRENCY = parseInt(process.env.WORKFLOW_LOCAL_QUEUE_CONCURRENCY ?? "0", 10) || DEFAULT_CONCURRENCY_LIMIT;
49020
- function createQueue(config3) {
49020
+ function getQueueRoute(queueName) {
49021
+ if (queueName.startsWith("__wkf_step_")) {
49022
+ return { pathname: "step", prefix: "__wkf_step_" };
49023
+ }
49024
+ if (queueName.startsWith("__wkf_workflow_")) {
49025
+ return { pathname: "flow", prefix: "__wkf_workflow_" };
49026
+ }
49027
+ throw new Error("Unknown queue name prefix");
49028
+ }
49029
+ __name(getQueueRoute, "getQueueRoute");
49030
+ function createQueueExecutor(config3) {
49021
49031
  const httpAgent = new import_undici.Agent({
49022
49032
  headersTimeout: 0,
49023
49033
  connections: 1e3,
49024
49034
  keepAliveTimeout: 3e4
49025
49035
  });
49036
+ const directHandlers = /* @__PURE__ */ new Map();
49037
+ const executeMessage = /* @__PURE__ */ __name(async ({ queueName, messageId, attempt, body, headers: extraHeaders }) => {
49038
+ const { pathname, prefix } = getQueueRoute(queueName);
49039
+ const headers = {
49040
+ ...extraHeaders,
49041
+ "content-type": "application/json",
49042
+ "x-vqs-queue-name": queueName,
49043
+ "x-vqs-message-id": messageId,
49044
+ "x-vqs-message-attempt": String(attempt)
49045
+ };
49046
+ const directHandler = directHandlers.get(prefix);
49047
+ let response;
49048
+ if (directHandler) {
49049
+ const req = new Request("http://localhost/.well-known/workflow/v1/" + pathname, {
49050
+ method: "POST",
49051
+ headers,
49052
+ body
49053
+ });
49054
+ response = await directHandler(req);
49055
+ } else {
49056
+ const baseUrl = await resolveBaseUrl(config3);
49057
+ response = await fetch(`${baseUrl}/.well-known/workflow/v1/${pathname}`, {
49058
+ method: "POST",
49059
+ duplex: "half",
49060
+ dispatcher: httpAgent,
49061
+ headers,
49062
+ body
49063
+ });
49064
+ }
49065
+ const text = await response.text();
49066
+ if (!response.ok) {
49067
+ return {
49068
+ type: "error",
49069
+ status: response.status,
49070
+ text,
49071
+ headers: Object.fromEntries(response.headers.entries())
49072
+ };
49073
+ }
49074
+ try {
49075
+ const timeoutSeconds = Number(JSON.parse(text).timeoutSeconds);
49076
+ if (Number.isFinite(timeoutSeconds) && timeoutSeconds >= 0) {
49077
+ return { type: "reschedule", timeoutSeconds };
49078
+ }
49079
+ } catch {
49080
+ }
49081
+ return { type: "completed" };
49082
+ }, "executeMessage");
49083
+ return {
49084
+ executeMessage,
49085
+ registerHandler(prefix, handler) {
49086
+ directHandlers.set(prefix, handler);
49087
+ },
49088
+ async close() {
49089
+ await httpAgent.close();
49090
+ }
49091
+ };
49092
+ }
49093
+ __name(createQueueExecutor, "createQueueExecutor");
49094
+ function createQueue(config3) {
49095
+ const executor = createQueueExecutor(config3);
49026
49096
  const transport = new JsonTransport();
49027
49097
  const generateId2 = monotonicFactory();
49028
49098
  const semaphore = new import_async_sema.Sema(WORKFLOW_LOCAL_QUEUE_CONCURRENCY);
49029
49099
  const inflightMessages = /* @__PURE__ */ new Map();
49030
- const directHandlers = /* @__PURE__ */ new Map();
49031
49100
  const queue = /* @__PURE__ */ __name(async (queueName, message, opts) => {
49032
49101
  const cleanup = [];
49033
49102
  if (opts?.idempotencyKey) {
@@ -49037,17 +49106,7 @@ function createQueue(config3) {
49037
49106
  }
49038
49107
  }
49039
49108
  const body = transport.serialize(message);
49040
- let pathname;
49041
- let prefix;
49042
- if (queueName.startsWith("__wkf_step_")) {
49043
- pathname = `step`;
49044
- prefix = "__wkf_step_";
49045
- } else if (queueName.startsWith("__wkf_workflow_")) {
49046
- pathname = `flow`;
49047
- prefix = "__wkf_workflow_";
49048
- } else {
49049
- throw new Error("Unknown queue name prefix");
49050
- }
49109
+ getQueueRoute(queueName);
49051
49110
  const messageId = MessageId.parse(`msg_${generateId2()}`);
49052
49111
  if (opts?.idempotencyKey) {
49053
49112
  const key = opts.idempotencyKey;
@@ -49064,55 +49123,31 @@ function createQueue(config3) {
49064
49123
  }
49065
49124
  try {
49066
49125
  let defaultRetriesLeft = 3;
49067
- const directHandler = directHandlers.get(prefix);
49068
49126
  for (let attempt = 0; defaultRetriesLeft > 0; attempt++) {
49069
49127
  defaultRetriesLeft--;
49070
- let response;
49071
- const headers = {
49072
- ...opts?.headers,
49073
- "content-type": "application/json",
49074
- "x-vqs-queue-name": queueName,
49075
- "x-vqs-message-id": messageId,
49076
- "x-vqs-message-attempt": String(attempt + 1)
49077
- };
49078
- if (directHandler) {
49079
- const req = new Request("http://localhost/.well-known/workflow/v1/" + pathname, {
49080
- method: "POST",
49081
- headers,
49082
- body
49083
- });
49084
- response = await directHandler(req);
49085
- } else {
49086
- const baseUrl = await resolveBaseUrl(config3);
49087
- response = await fetch(`${baseUrl}/.well-known/workflow/v1/${pathname}`, {
49088
- method: "POST",
49089
- duplex: "half",
49090
- dispatcher: httpAgent,
49091
- headers,
49092
- body
49093
- });
49128
+ const result = await executor.executeMessage({
49129
+ queueName,
49130
+ messageId,
49131
+ attempt: attempt + 1,
49132
+ body,
49133
+ headers: opts?.headers
49134
+ });
49135
+ if (result.type === "completed") {
49136
+ return;
49094
49137
  }
49095
- const text = await response.text();
49096
- if (response.ok) {
49097
- try {
49098
- const timeoutSeconds = Number(JSON.parse(text).timeoutSeconds);
49099
- if (Number.isFinite(timeoutSeconds) && timeoutSeconds >= 0) {
49100
- if (timeoutSeconds > 0) {
49101
- const timeoutMs = Math.min(timeoutSeconds * 1e3, MAX_SAFE_TIMEOUT_MS);
49102
- await (0, import_promises3.setTimeout)(timeoutMs);
49103
- }
49104
- defaultRetriesLeft++;
49105
- continue;
49106
- }
49107
- } catch {
49138
+ if (result.type === "reschedule") {
49139
+ if (result.timeoutSeconds > 0) {
49140
+ const timeoutMs = Math.min(result.timeoutSeconds * 1e3, MAX_SAFE_TIMEOUT_MS);
49141
+ await (0, import_promises3.setTimeout)(timeoutMs);
49108
49142
  }
49109
- return;
49143
+ defaultRetriesLeft++;
49144
+ continue;
49110
49145
  }
49111
49146
  console.error(`[local world] Failed to queue message`, {
49112
49147
  queueName,
49113
- text,
49114
- status: response.status,
49115
- headers: Object.fromEntries(response.headers.entries()),
49148
+ text: result.text,
49149
+ status: result.status,
49150
+ headers: result.headers,
49116
49151
  body: body.toString()
49117
49152
  });
49118
49153
  }
@@ -49175,11 +49210,9 @@ function createQueue(config3) {
49175
49210
  queue,
49176
49211
  createQueueHandler,
49177
49212
  getDeploymentId,
49178
- registerHandler(prefix, handler) {
49179
- directHandlers.set(prefix, handler);
49180
- },
49213
+ registerHandler: executor.registerHandler,
49181
49214
  async close() {
49182
- await httpAgent.close();
49215
+ await executor.close();
49183
49216
  }
49184
49217
  };
49185
49218
  }
@@ -49404,6 +49437,19 @@ async function deleteJSON(filePath) {
49404
49437
  }
49405
49438
  }
49406
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");
49407
49453
  async function listJSONFiles(dirPath) {
49408
49454
  return listFilesByExtension(dirPath, ".json");
49409
49455
  }
@@ -49557,6 +49603,11 @@ function filterHookData(hook, resolveData) {
49557
49603
  __name(filterHookData, "filterHookData");
49558
49604
 
49559
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");
49560
49611
  var monotonicUlid = monotonicFactory(() => Math.random());
49561
49612
  var getObjectCreatedAt = /* @__PURE__ */ __name((idPrefix) => (filename) => {
49562
49613
  const replaceRegex = new RegExp(`^${idPrefix}_`, "g");
@@ -49645,6 +49696,8 @@ async function deleteAllHooksForRun(basedir, runId) {
49645
49696
  const hookPath = import_node_path3.default.join(hooksDir, `${file2}.json`);
49646
49697
  const hook = await readJSON(hookPath, HookSchema);
49647
49698
  if (hook && hook.runId === runId) {
49699
+ const constraintPath = import_node_path3.default.join(hooksDir, "tokens", `${hashToken(hook.token)}.json`);
49700
+ await deleteJSON(constraintPath);
49648
49701
  await deleteJSON(hookPath);
49649
49702
  }
49650
49703
  }
@@ -50053,18 +50106,13 @@ function createEventsStorage(basedir) {
50053
50106
  data.eventType === "hook_created" && "eventData" in data
50054
50107
  ) {
50055
50108
  const hookData = data.eventData;
50056
- const hooksDir = import_node_path5.default.join(basedir, "hooks");
50057
- const hookFiles = await listJSONFiles(hooksDir);
50058
- let hasConflict = false;
50059
- for (const file2 of hookFiles) {
50060
- const existingHookPath = import_node_path5.default.join(hooksDir, `${file2}.json`);
50061
- const existingHook = await readJSON(existingHookPath, HookSchema);
50062
- if (existingHook && existingHook.token === hookData.token) {
50063
- hasConflict = true;
50064
- break;
50065
- }
50066
- }
50067
- 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) {
50068
50116
  const conflictEvent = {
50069
50117
  eventType: "hook_conflict",
50070
50118
  correlationId: data.correlationId,
@@ -50105,6 +50153,11 @@ function createEventsStorage(basedir) {
50105
50153
  await writeJSON(hookPath, hook);
50106
50154
  } else if (data.eventType === "hook_disposed") {
50107
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
+ }
50108
50161
  await deleteJSON(hookPath);
50109
50162
  } else if (data.eventType === "wait_created" && "eventData" in data) {
50110
50163
  const waitData = data.eventData;
@@ -50569,7 +50622,7 @@ function createLocalWorld(args) {
50569
50622
  __name(createLocalWorld, "createLocalWorld");
50570
50623
 
50571
50624
  // ../world-vercel/dist/encryption.js
50572
- var import_node_crypto2 = require("node:crypto");
50625
+ var import_node_crypto3 = require("node:crypto");
50573
50626
  var import_oidc2 = __toESM(require_dist2(), 1);
50574
50627
 
50575
50628
  // ../world-vercel/dist/http-client.js
@@ -50603,9 +50656,9 @@ async function deriveRunKey(deploymentKey, projectId, runId) {
50603
50656
  if (!projectId || typeof projectId !== "string") {
50604
50657
  throw new Error("projectId must be a non-empty string");
50605
50658
  }
50606
- 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"]);
50607
50660
  const info = new TextEncoder().encode(`${projectId}|${runId}`);
50608
- const derivedBits = await import_node_crypto2.webcrypto.subtle.deriveBits(
50661
+ const derivedBits = await import_node_crypto3.webcrypto.subtle.deriveBits(
50609
50662
  {
50610
50663
  name: "HKDF",
50611
50664
  hash: "SHA-256",
@@ -53112,7 +53165,7 @@ var RpcService3 = SemanticConvention3("rpc.service");
53112
53165
  var RpcMethod3 = SemanticConvention3("rpc.method");
53113
53166
 
53114
53167
  // ../world-vercel/dist/version.js
53115
- var version2 = "4.1.0-beta.42";
53168
+ var version2 = "4.1.0-beta.43";
53116
53169
 
53117
53170
  // ../world-vercel/dist/utils.js
53118
53171
  var WORKFLOW_SERVER_URL_OVERRIDE = "";
@@ -53440,6 +53493,50 @@ function createQueue2(config3) {
53440
53493
  }
53441
53494
  __name(createQueue2, "createQueue");
53442
53495
 
53496
+ // ../world-vercel/dist/resolve-latest-deployment.js
53497
+ var import_oidc4 = __toESM(require_dist2(), 1);
53498
+ var ResolveLatestDeploymentResponseSchema = object({
53499
+ id: string2()
53500
+ });
53501
+ function createResolveLatestDeploymentId(config3) {
53502
+ return /* @__PURE__ */ __name(async function resolveLatestDeploymentId() {
53503
+ const currentDeploymentId = process.env.VERCEL_DEPLOYMENT_ID;
53504
+ if (!currentDeploymentId) {
53505
+ throw new Error("Cannot resolve latest deployment: VERCEL_DEPLOYMENT_ID environment variable is not set");
53506
+ }
53507
+ const oidcToken = await (0, import_oidc4.getVercelOidcToken)().catch(() => null);
53508
+ const token = config3?.token ?? oidcToken ?? process.env.VERCEL_TOKEN;
53509
+ if (!token) {
53510
+ throw new Error("Cannot resolve latest deployment: no OIDC token or VERCEL_TOKEN available");
53511
+ }
53512
+ const url2 = `https://api.vercel.com/v1/workflow/resolve-latest-deployment/${encodeURIComponent(currentDeploymentId)}`;
53513
+ const response = await fetch(url2, {
53514
+ method: "GET",
53515
+ headers: {
53516
+ authorization: `Bearer ${token}`
53517
+ },
53518
+ // @ts-expect-error -- undici dispatcher is accepted by Node.js fetch but not in @types/node's RequestInit
53519
+ dispatcher: getDispatcher()
53520
+ });
53521
+ if (!response.ok) {
53522
+ let body;
53523
+ try {
53524
+ body = await response.text();
53525
+ } catch {
53526
+ body = "<unable to read response body>";
53527
+ }
53528
+ throw new Error(`Failed to resolve latest deployment for ${currentDeploymentId}: HTTP ${response.status} ${response.statusText}${body ? ` \u2014 ${body}` : ""}`);
53529
+ }
53530
+ const data = await response.json();
53531
+ const result = ResolveLatestDeploymentResponseSchema.safeParse(data);
53532
+ if (!result.success) {
53533
+ throw new Error(`Invalid response from Vercel API: expected { id: string }. Zod error: ${result.error.message}`);
53534
+ }
53535
+ return result.data.id;
53536
+ }, "resolveLatestDeploymentId");
53537
+ }
53538
+ __name(createResolveLatestDeploymentId, "createResolveLatestDeploymentId");
53539
+
53443
53540
  // ../world-vercel/dist/refs.js
53444
53541
  function isRefDescriptor(value) {
53445
53542
  return typeof value === "object" && value !== null && "_type" in value && "_ref" in value && typeof value._ref === "string" && value._type === "RemoteRef";
@@ -53605,7 +53702,7 @@ async function getWorkflowRun(id, params, config3) {
53605
53702
  const searchParams = new URLSearchParams();
53606
53703
  searchParams.set("remoteRefBehavior", remoteRefBehavior);
53607
53704
  const queryString = searchParams.toString();
53608
- const endpoint = `/v2/runs/${id}${queryString ? `?${queryString}` : ""}`;
53705
+ const endpoint = `/v2/runs/${encodeURIComponent(id)}${queryString ? `?${queryString}` : ""}`;
53609
53706
  try {
53610
53707
  const run = await makeRequest({
53611
53708
  endpoint,
@@ -53628,7 +53725,7 @@ async function cancelWorkflowRunV1(id, params, config3) {
53628
53725
  const searchParams = new URLSearchParams();
53629
53726
  searchParams.set("remoteRefBehavior", remoteRefBehavior);
53630
53727
  const queryString = searchParams.toString();
53631
- const endpoint = `/v1/runs/${id}/cancel${queryString ? `?${queryString}` : ""}`;
53728
+ const endpoint = `/v1/runs/${encodeURIComponent(id)}/cancel${queryString ? `?${queryString}` : ""}`;
53632
53729
  try {
53633
53730
  const run = await makeRequest({
53634
53731
  endpoint,
@@ -53732,7 +53829,7 @@ async function listWorkflowRunSteps(params, config3) {
53732
53829
  const remoteRefBehavior = resolveData === "none" ? "lazy" : "resolve";
53733
53830
  searchParams.set("remoteRefBehavior", remoteRefBehavior);
53734
53831
  const queryString = searchParams.toString();
53735
- const endpoint = `/v2/runs/${runId}/steps${queryString ? `?${queryString}` : ""}`;
53832
+ const endpoint = `/v2/runs/${encodeURIComponent(runId)}/steps${queryString ? `?${queryString}` : ""}`;
53736
53833
  const response = await makeRequest({
53737
53834
  endpoint,
53738
53835
  options: { method: "GET" },
@@ -53751,7 +53848,7 @@ async function getStep(runId, stepId, params, config3) {
53751
53848
  const searchParams = new URLSearchParams();
53752
53849
  searchParams.set("remoteRefBehavior", remoteRefBehavior);
53753
53850
  const queryString = searchParams.toString();
53754
- const endpoint = runId ? `/v2/runs/${runId}/steps/${stepId}${queryString ? `?${queryString}` : ""}` : `/v2/steps/${stepId}${queryString ? `?${queryString}` : ""}`;
53851
+ const endpoint = runId ? `/v2/runs/${encodeURIComponent(runId)}/steps/${encodeURIComponent(stepId)}${queryString ? `?${queryString}` : ""}` : `/v2/steps/${encodeURIComponent(stepId)}${queryString ? `?${queryString}` : ""}`;
53755
53852
  const step = await makeRequest({
53756
53853
  endpoint,
53757
53854
  options: { method: "GET" },
@@ -53894,7 +53991,7 @@ async function getEvent(runId, eventId, params, config3) {
53894
53991
  const searchParams = new URLSearchParams();
53895
53992
  searchParams.set("remoteRefBehavior", remoteRefBehavior);
53896
53993
  const queryString = searchParams.toString();
53897
- const endpoint = `/v2/runs/${runId}/events/${eventId}${queryString ? `?${queryString}` : ""}`;
53994
+ const endpoint = `/v2/runs/${encodeURIComponent(runId)}/events/${encodeURIComponent(eventId)}${queryString ? `?${queryString}` : ""}`;
53898
53995
  const event = await makeRequest({
53899
53996
  endpoint,
53900
53997
  options: { method: "GET" },
@@ -53928,7 +54025,7 @@ async function getWorkflowRunEvents(params, config3) {
53928
54025
  searchParams.set("remoteRefBehavior", "lazy");
53929
54026
  const queryString = searchParams.toString();
53930
54027
  const query = queryString ? `?${queryString}` : "";
53931
- const endpoint = correlationId ? `/v2/events${query}` : `/v2/runs/${runId}/events${query}`;
54028
+ const endpoint = correlationId ? `/v2/events${query}` : `/v2/runs/${encodeURIComponent(runId)}/events${query}`;
53932
54029
  let refResolveConcurrency;
53933
54030
  const response = await makeRequest({
53934
54031
  endpoint,
@@ -53980,7 +54077,7 @@ async function createWorkflowRunEvent(id, data, params, config3) {
53980
54077
  return { run };
53981
54078
  }
53982
54079
  const wireResult2 = await makeRequest({
53983
- endpoint: `/v1/runs/${id}/events`,
54080
+ endpoint: `/v1/runs/${encodeURIComponent(id)}/events`,
53984
54081
  options: { method: "POST" },
53985
54082
  data,
53986
54083
  config: config3,
@@ -53994,7 +54091,7 @@ async function createWorkflowRunEvent(id, data, params, config3) {
53994
54091
  throw new WorkflowAPIError(validationError, { status: 400 });
53995
54092
  }
53996
54093
  }
53997
- const runIdPath = id === null ? "null" : id;
54094
+ const runIdPath = id === null ? "null" : encodeURIComponent(id);
53998
54095
  const remoteRefBehavior = eventsNeedingResolve.has(data.eventType) ? "resolve" : "lazy";
53999
54096
  if (remoteRefBehavior === "resolve") {
54000
54097
  const wireResult2 = await makeRequest({
@@ -54070,7 +54167,7 @@ async function listHooks(params, config3) {
54070
54167
  __name(listHooks, "listHooks");
54071
54168
  async function getHook(hookId, params, config3) {
54072
54169
  const resolveData = params?.resolveData || "all";
54073
- const endpoint = `/v2/hooks/${hookId}`;
54170
+ const endpoint = `/v2/hooks/${encodeURIComponent(hookId)}`;
54074
54171
  const hook = await makeRequest({
54075
54172
  endpoint,
54076
54173
  options: { method: "GET" },
@@ -54183,7 +54280,7 @@ __name(createStorage2, "createStorage");
54183
54280
  // ../world-vercel/dist/streamer.js
54184
54281
  function getStreamUrl(name, runId, httpConfig) {
54185
54282
  if (runId) {
54186
- return new URL(`${httpConfig.baseUrl}/v2/runs/${runId}/stream/${encodeURIComponent(name)}`);
54283
+ return new URL(`${httpConfig.baseUrl}/v2/runs/${encodeURIComponent(runId)}/stream/${encodeURIComponent(name)}`);
54187
54284
  }
54188
54285
  return new URL(`${httpConfig.baseUrl}/v2/stream/${encodeURIComponent(name)}`);
54189
54286
  }
@@ -54264,7 +54361,7 @@ function createStreamer2(config3) {
54264
54361
  },
54265
54362
  async listStreamsByRunId(runId) {
54266
54363
  const httpConfig = await getHttpConfig(config3);
54267
- const url2 = new URL(`${httpConfig.baseUrl}/v2/runs/${runId}/streams`);
54364
+ const url2 = new URL(`${httpConfig.baseUrl}/v2/runs/${encodeURIComponent(runId)}/streams`);
54268
54365
  const response = await fetch(url2, {
54269
54366
  headers: httpConfig.headers
54270
54367
  });
@@ -54284,7 +54381,8 @@ function createVercelWorld(config3) {
54284
54381
  ...createQueue2(config3),
54285
54382
  ...createStorage2(config3),
54286
54383
  ...createStreamer2(config3),
54287
- getEncryptionKeyForRun: createGetEncryptionKeyForRun(projectId, config3?.projectConfig?.teamId, config3?.token)
54384
+ getEncryptionKeyForRun: createGetEncryptionKeyForRun(projectId, config3?.projectConfig?.teamId, config3?.token),
54385
+ resolveLatestDeploymentId: createResolveLatestDeploymentId(config3)
54288
54386
  };
54289
54387
  }
54290
54388
  __name(createVercelWorld, "createVercelWorld");
@@ -54303,7 +54401,7 @@ var createWorld = /* @__PURE__ */ __name(() => {
54303
54401
  "WORKFLOW_VERCEL_AUTH_TOKEN",
54304
54402
  "WORKFLOW_VERCEL_ENV"
54305
54403
  ].filter((key) => process.env[key]);
54306
- if (staleEnvVars.length > 0) {
54404
+ if (staleEnvVars.length > 0 && process.env.VERCEL === "1") {
54307
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.`);
54308
54406
  }
54309
54407
  return createVercelWorld();
@@ -54474,69 +54572,6 @@ function getQueueOverhead(message) {
54474
54572
  }
54475
54573
  }
54476
54574
  __name(getQueueOverhead, "getQueueOverhead");
54477
- async function withThrottleRetry(fn) {
54478
- try {
54479
- return await fn();
54480
- } catch (err) {
54481
- if (WorkflowAPIError.is(err) && err.status === 429) {
54482
- const retryAfterSeconds = Math.max(
54483
- // If we don't have a retry-after value, 30s seems a reasonable default
54484
- // to avoid re-trying during the unknown rate-limiting period.
54485
- 1,
54486
- typeof err.retryAfter === "number" ? err.retryAfter : 30
54487
- );
54488
- if (retryAfterSeconds < 10) {
54489
- runtimeLogger.warn("Throttled by workflow-server (429), retrying in-process", {
54490
- retryAfterSeconds,
54491
- url: err.url
54492
- });
54493
- await new Promise((resolve3) => setTimeout(resolve3, retryAfterSeconds * 1e3));
54494
- try {
54495
- return await fn();
54496
- } catch (retryErr) {
54497
- if (WorkflowAPIError.is(retryErr) && retryErr.status === 429) {
54498
- const retryRetryAfter = Math.max(1, typeof retryErr.retryAfter === "number" ? retryErr.retryAfter : 1);
54499
- runtimeLogger.warn("Throttled again on retry, deferring to queue", {
54500
- retryAfterSeconds: retryRetryAfter
54501
- });
54502
- return { timeoutSeconds: retryRetryAfter };
54503
- }
54504
- throw retryErr;
54505
- }
54506
- }
54507
- runtimeLogger.warn("Throttled by workflow-server (429), deferring to queue", {
54508
- retryAfterSeconds,
54509
- url: err.url
54510
- });
54511
- return { timeoutSeconds: retryAfterSeconds };
54512
- }
54513
- throw err;
54514
- }
54515
- }
54516
- __name(withThrottleRetry, "withThrottleRetry");
54517
- async function withServerErrorRetry(fn) {
54518
- const delays = [500, 1e3, 2e3];
54519
- for (let attempt = 0; attempt <= delays.length; attempt++) {
54520
- try {
54521
- return await fn();
54522
- } catch (err) {
54523
- if (WorkflowAPIError.is(err) && err.status !== void 0 && err.status >= 500 && attempt < delays.length) {
54524
- runtimeLogger.warn("Server error (5xx) from workflow-server, retrying in-process", {
54525
- status: err.status,
54526
- attempt: attempt + 1,
54527
- maxRetries: delays.length,
54528
- nextDelayMs: delays[attempt],
54529
- url: err.url
54530
- });
54531
- await new Promise((resolve3) => setTimeout(resolve3, delays[attempt]));
54532
- continue;
54533
- }
54534
- throw err;
54535
- }
54536
- }
54537
- throw new Error("withServerErrorRetry: unreachable");
54538
- }
54539
- __name(withServerErrorRetry, "withServerErrorRetry");
54540
54575
 
54541
54576
  // ../core/dist/runtime/suspension-handler.js
54542
54577
  var import_functions = __toESM(require_functions(), 1);
@@ -58179,18 +58214,18 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58179
58214
  });
58180
58215
  let step;
58181
58216
  try {
58182
- const startResult = await withServerErrorRetry(() => world.events.create(workflowRunId, {
58217
+ const startResult = await world.events.create(workflowRunId, {
58183
58218
  eventType: "step_started",
58184
58219
  specVersion: SPEC_VERSION_CURRENT,
58185
58220
  correlationId: stepId
58186
- }));
58221
+ });
58187
58222
  if (!startResult.step) {
58188
58223
  throw new WorkflowRuntimeError(`step_started event for "${stepId}" did not return step entity`);
58189
58224
  }
58190
58225
  step = startResult.step;
58191
58226
  } catch (err) {
58192
58227
  if (WorkflowAPIError.is(err)) {
58193
- if (WorkflowAPIError.is(err) && err.status === 429) {
58228
+ if (err.status === 429) {
58194
58229
  const retryRetryAfter = Math.max(1, typeof err.retryAfter === "number" ? err.retryAfter : 1);
58195
58230
  runtimeLogger.warn("Throttled again on retry, deferring to queue", {
58196
58231
  retryAfterSeconds: retryRetryAfter
@@ -58299,28 +58334,57 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58299
58334
  });
58300
58335
  return;
58301
58336
  }
58302
- try {
58303
- const attempt = step.attempt;
58304
- if (!step.startedAt) {
58305
- throw new WorkflowRuntimeError(`Step "${stepId}" has no "startedAt" timestamp`);
58306
- }
58307
- const stepStartedAt = step.startedAt;
58308
- const ops = [];
58309
- const rawKey = await world.getEncryptionKeyForRun?.(workflowRunId);
58310
- const encryptionKey = rawKey ? await importKey(rawKey) : void 0;
58311
- const hydratedInput = await trace2("step.hydrate", {}, async (hydrateSpan) => {
58312
- const startTime = Date.now();
58313
- const result2 = await hydrateStepArguments(step.input, workflowRunId, encryptionKey, ops);
58314
- const durationMs = Date.now() - startTime;
58315
- hydrateSpan?.setAttributes({
58316
- ...StepArgumentsCount(result2.args.length),
58317
- ...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
+ }
58318
58354
  });
58319
- 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)
58320
58379
  });
58321
- const args = hydratedInput.args;
58322
- const thisVal = hydratedInput.thisVal ?? null;
58323
- 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 {
58324
58388
  result = await trace2("step.execute", {}, async () => {
58325
58389
  return await contextStorage.run({
58326
58390
  stepMetadata: {
@@ -58342,63 +58406,29 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58342
58406
  encryptionKey
58343
58407
  }, () => stepFn.apply(thisVal, args));
58344
58408
  });
58345
- const executionTimeMs = Date.now() - executionStartTime;
58346
- span?.setAttributes({
58347
- ...QueueExecutionTimeMs(executionTimeMs)
58348
- });
58349
- result = await trace2("step.dehydrate", {}, async (dehydrateSpan) => {
58350
- const startTime = Date.now();
58351
- const dehydrated = await dehydrateStepReturnValue(result, workflowRunId, encryptionKey, ops);
58352
- const durationMs = Date.now() - startTime;
58353
- dehydrateSpan?.setAttributes({
58354
- ...QueueSerializeTimeMs(durationMs),
58355
- ...StepResultType(typeof dehydrated)
58356
- });
58357
- return dehydrated;
58358
- });
58359
- (0, import_functions5.waitUntil)(Promise.all(ops).catch((err) => {
58360
- const isAbortError = err?.name === "AbortError" || err?.name === "ResponseAborted";
58361
- if (!isAbortError)
58362
- throw err;
58363
- }));
58364
- let stepCompleted409 = false;
58365
- const [, traceCarrier] = await Promise.all([
58366
- withServerErrorRetry(() => world.events.create(workflowRunId, {
58367
- eventType: "step_completed",
58368
- specVersion: SPEC_VERSION_CURRENT,
58369
- correlationId: stepId,
58370
- eventData: {
58371
- result
58372
- }
58373
- })).catch((err) => {
58374
- if (WorkflowAPIError.is(err) && err.status === 409) {
58375
- runtimeLogger.warn("Tried completing step, but step has already finished.", {
58376
- workflowRunId,
58377
- stepId,
58378
- stepName,
58379
- message: err.message
58380
- });
58381
- stepCompleted409 = true;
58382
- return;
58383
- }
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) {
58384
58429
  throw err;
58385
- }),
58386
- serializeTraceCarrier()
58387
- ]);
58388
- if (stepCompleted409) {
58389
- return;
58430
+ }
58390
58431
  }
58391
- span?.setAttributes({
58392
- ...StepStatus("completed"),
58393
- ...StepResultType(typeof result)
58394
- });
58395
- await queueMessage(world, getWorkflowQueueName(workflowName), {
58396
- runId: workflowRunId,
58397
- traceCarrier,
58398
- requestedAt: /* @__PURE__ */ new Date()
58399
- });
58400
- return;
58401
- } catch (err) {
58402
58432
  const normalizedError = await normalizeUnknownError(err);
58403
58433
  const normalizedStack = normalizedError.stack || getErrorStack(err) || "";
58404
58434
  if (err instanceof Error) {
@@ -58414,26 +58444,6 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58414
58444
  ...ErrorCategory(errorCategory),
58415
58445
  ...ErrorRetryable(!isFatal)
58416
58446
  });
58417
- if (WorkflowAPIError.is(err)) {
58418
- if (err.status === 410) {
58419
- stepLogger.info("Workflow run already completed, skipping step", {
58420
- workflowRunId,
58421
- stepId,
58422
- message: err.message
58423
- });
58424
- return;
58425
- }
58426
- if (err.status !== void 0 && err.status >= 500) {
58427
- runtimeLogger.warn("Persistent server error (5xx) during step, deferring to queue retry", {
58428
- status: err.status,
58429
- workflowRunId,
58430
- stepId,
58431
- error: err.message,
58432
- url: err.url
58433
- });
58434
- throw err;
58435
- }
58436
- }
58437
58447
  if (isFatal) {
58438
58448
  stepLogger.error("Encountered FatalError while executing step, bubbling up to parent workflow", {
58439
58449
  workflowRunId,
@@ -58441,7 +58451,7 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58441
58451
  errorStack: normalizedStack
58442
58452
  });
58443
58453
  try {
58444
- await withServerErrorRetry(() => world.events.create(workflowRunId, {
58454
+ await world.events.create(workflowRunId, {
58445
58455
  eventType: "step_failed",
58446
58456
  specVersion: SPEC_VERSION_CURRENT,
58447
58457
  correlationId: stepId,
@@ -58449,7 +58459,7 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58449
58459
  error: normalizedError.message,
58450
58460
  stack: normalizedStack
58451
58461
  }
58452
- }));
58462
+ });
58453
58463
  } catch (stepFailErr) {
58454
58464
  if (WorkflowAPIError.is(stepFailErr) && stepFailErr.status === 409) {
58455
58465
  runtimeLogger.warn("Tried failing step, but step has already finished.", {
@@ -58484,7 +58494,7 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58484
58494
  });
58485
58495
  const errorMessage = `Step "${stepName}" failed after ${maxRetries2} ${pluralize("retry", "retries", maxRetries2)}: ${normalizedError.message}`;
58486
58496
  try {
58487
- await withServerErrorRetry(() => world.events.create(workflowRunId, {
58497
+ await world.events.create(workflowRunId, {
58488
58498
  eventType: "step_failed",
58489
58499
  specVersion: SPEC_VERSION_CURRENT,
58490
58500
  correlationId: stepId,
@@ -58492,7 +58502,7 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58492
58502
  error: errorMessage,
58493
58503
  stack: normalizedStack
58494
58504
  }
58495
- }));
58505
+ });
58496
58506
  } catch (stepFailErr) {
58497
58507
  if (WorkflowAPIError.is(stepFailErr) && stepFailErr.status === 409) {
58498
58508
  runtimeLogger.warn("Tried failing step, but step has already finished.", {
@@ -58526,7 +58536,7 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58526
58536
  });
58527
58537
  }
58528
58538
  try {
58529
- await withServerErrorRetry(() => world.events.create(workflowRunId, {
58539
+ await world.events.create(workflowRunId, {
58530
58540
  eventType: "step_retrying",
58531
58541
  specVersion: SPEC_VERSION_CURRENT,
58532
58542
  correlationId: stepId,
@@ -58537,7 +58547,7 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58537
58547
  retryAfter: err.retryAfter
58538
58548
  }
58539
58549
  }
58540
- }));
58550
+ });
58541
58551
  } catch (stepRetryErr) {
58542
58552
  if (WorkflowAPIError.is(stepRetryErr) && stepRetryErr.status === 409) {
58543
58553
  runtimeLogger.warn("Tried retrying step, but step has already finished.", {
@@ -58563,10 +58573,62 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
58563
58573
  return { timeoutSeconds };
58564
58574
  }
58565
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;
58566
58624
  }
58625
+ span?.setAttributes({
58626
+ ...StepStatus("completed"),
58627
+ ...StepResultType(typeof result)
58628
+ });
58567
58629
  await queueMessage(world, getWorkflowQueueName(workflowName), {
58568
58630
  runId: workflowRunId,
58569
- traceCarrier: await serializeTraceCarrier(),
58631
+ traceCarrier,
58570
58632
  requestedAt: /* @__PURE__ */ new Date()
58571
58633
  });
58572
58634
  });
@@ -58581,7 +58643,7 @@ function workflowEntrypoint(workflowCode2) {
58581
58643
  await handleHealthCheckMessage(healthCheck2, "workflow");
58582
58644
  return;
58583
58645
  }
58584
- const { runId, traceCarrier: traceContext, requestedAt, serverErrorRetryCount } = WorkflowInvokePayloadSchema.parse(message_);
58646
+ const { runId, traceCarrier: traceContext, requestedAt } = WorkflowInvokePayloadSchema.parse(message_);
58585
58647
  const workflowName = metadata.queueName.slice("__wkf_workflow_".length);
58586
58648
  const spanLinks = await linkToCurrentContext();
58587
58649
  return await withTraceContext(traceContext, async () => {
@@ -58602,179 +58664,183 @@ function workflowEntrypoint(workflowCode2) {
58602
58664
  ...WorkflowRunId(runId),
58603
58665
  ...WorkflowTracePropagated(!!traceContext)
58604
58666
  });
58605
- return await withThrottleRetry(async () => {
58606
- let workflowStartedAt = -1;
58607
- let workflowRun = await world.runs.get(runId);
58608
- try {
58609
- if (workflowRun.status === "pending") {
58610
- const result2 = await world.events.create(runId, {
58611
- eventType: "run_started",
58612
- specVersion: SPEC_VERSION_CURRENT
58613
- });
58614
- if (!result2.run) {
58615
- throw new WorkflowRuntimeError(`Event creation for 'run_started' did not return the run entity for run "${runId}"`);
58616
- }
58617
- workflowRun = result2.run;
58618
- }
58619
- if (!workflowRun.startedAt) {
58620
- throw new WorkflowRuntimeError(`Workflow run "${runId}" has no "startedAt" timestamp`);
58621
- }
58622
- workflowStartedAt = +workflowRun.startedAt;
58623
- span?.setAttributes({
58624
- ...WorkflowRunStatus(workflowRun.status),
58625
- ...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
58626
58674
  });
58627
- if (workflowRun.status !== "running") {
58628
- runtimeLogger.info("Workflow already completed or failed, skipping", {
58629
- workflowRunId: runId,
58630
- status: workflowRun.status
58631
- });
58632
- return;
58633
- }
58634
- const events = await getAllWorkflowRunEvents(workflowRun.runId);
58635
- const now = Date.now();
58636
- const completedWaitIds = new Set(events.filter((e) => e.eventType === "wait_completed").map((e) => e.correlationId));
58637
- const waitsToComplete = events.filter((e) => e.eventType === "wait_created" && e.correlationId !== void 0 && !completedWaitIds.has(e.correlationId) && now >= e.eventData.resumeAt.getTime()).map((e) => ({
58638
- eventType: "wait_completed",
58639
- specVersion: SPEC_VERSION_CURRENT,
58640
- correlationId: e.correlationId
58641
- }));
58642
- for (const waitEvent of waitsToComplete) {
58643
- try {
58644
- const result2 = await world.events.create(runId, waitEvent);
58645
- events.push(result2.event);
58646
- } catch (err) {
58647
- if (WorkflowAPIError.is(err) && err.status === 409) {
58648
- runtimeLogger.info("Wait already completed, skipping", {
58649
- workflowRunId: runId,
58650
- correlationId: waitEvent.correlationId
58651
- });
58652
- continue;
58653
- }
58654
- throw err;
58655
- }
58675
+ if (!result.run) {
58676
+ throw new WorkflowRuntimeError(`Event creation for 'run_started' did not return the run entity for run "${runId}"`);
58656
58677
  }
58657
- const result = await trace2("workflow.replay", {}, async (replaySpan) => {
58658
- replaySpan?.setAttributes({
58659
- ...WorkflowEventsCount(events.length)
58660
- });
58661
- const rawKey = await world.getEncryptionKeyForRun?.(workflowRun);
58662
- const encryptionKey = rawKey ? await importKey(rawKey) : void 0;
58663
- return await runWorkflow(workflowCode2, workflowRun, events, encryptionKey);
58664
- });
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 });
58665
58686
  try {
58666
58687
  await world.events.create(runId, {
58667
- eventType: "run_completed",
58688
+ eventType: "run_failed",
58668
58689
  specVersion: SPEC_VERSION_CURRENT,
58669
58690
  eventData: {
58670
- output: result
58691
+ error: {
58692
+ message: err.message,
58693
+ stack: err.stack
58694
+ }
58671
58695
  }
58672
58696
  });
58673
- } catch (err) {
58674
- if (WorkflowAPIError.is(err) && (err.status === 409 || err.status === 410)) {
58675
- runtimeLogger.warn("Tried completing workflow run, but run has already finished.", {
58676
- workflowRunId: runId,
58677
- message: err.message
58678
- });
58697
+ } catch (failErr) {
58698
+ if (WorkflowAPIError.is(failErr) && (failErr.status === 409 || failErr.status === 410)) {
58679
58699
  return;
58680
- } else {
58681
- throw err;
58682
58700
  }
58701
+ throw failErr;
58683
58702
  }
58684
- span?.setAttributes({
58685
- ...WorkflowRunStatus("completed"),
58686
- ...WorkflowEventsCount(events.length)
58687
- });
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);
58688
58731
  } catch (err) {
58689
- if (WorkflowSuspension.is(err)) {
58690
- const suspensionMessage = buildWorkflowSuspensionMessage(runId, err.stepCount, err.hookCount, err.waitCount);
58691
- if (suspensionMessage) {
58692
- runtimeLogger.debug(suspensionMessage);
58693
- }
58694
- const result = await handleSuspension({
58695
- suspension: err,
58696
- world,
58697
- run: workflowRun,
58698
- span
58732
+ if (WorkflowAPIError.is(err) && err.status === 409) {
58733
+ runtimeLogger.info("Wait already completed, skipping", {
58734
+ workflowRunId: runId,
58735
+ correlationId: waitEvent.correlationId
58699
58736
  });
58700
- if (result.timeoutSeconds !== void 0) {
58701
- return { timeoutSeconds: result.timeoutSeconds };
58702
- }
58703
- } else {
58704
- if (WorkflowAPIError.is(err) && err.status !== void 0 && err.status >= 500) {
58705
- const retryCount = serverErrorRetryCount ?? 0;
58706
- const delaySecondSteps = [5, 30, 120];
58707
- if (retryCount < delaySecondSteps.length) {
58708
- runtimeLogger.warn("Server error (5xx), re-enqueueing workflow with backoff", {
58709
- workflowRunId: runId,
58710
- retryCount,
58711
- delaySeconds: delaySecondSteps[retryCount],
58712
- error: err.message
58713
- });
58714
- await queueMessage(world, getWorkflowQueueName(workflowName), {
58715
- runId,
58716
- serverErrorRetryCount: retryCount + 1,
58717
- traceCarrier: await serializeTraceCarrier(),
58718
- requestedAt: /* @__PURE__ */ new Date()
58719
- }, { delaySeconds: delaySecondSteps[retryCount] });
58720
- 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
58721
58794
  }
58722
- } else if (WorkflowAPIError.is(err) && err.status === 429) {
58723
- throw err;
58724
- }
58725
- if (err instanceof Error) {
58726
- span?.recordException?.(err);
58795
+ // TODO: include error codes when we define them
58727
58796
  }
58728
- const normalizedError = await normalizeUnknownError(err);
58729
- const errorName = normalizedError.name || getErrorName(err);
58730
- const errorMessage = normalizedError.message;
58731
- let errorStack = normalizedError.stack || getErrorStack(err);
58732
- if (errorStack) {
58733
- const parsedName = parseWorkflowName(workflowName);
58734
- const filename = parsedName?.moduleSpecifier || workflowName;
58735
- errorStack = remapErrorStack(errorStack, filename, workflowCode2);
58736
- }
58737
- 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.", {
58738
58801
  workflowRunId: runId,
58739
- errorName,
58740
- errorStack
58802
+ message: failErr.message
58741
58803
  });
58742
- try {
58743
- await world.events.create(runId, {
58744
- eventType: "run_failed",
58745
- specVersion: SPEC_VERSION_CURRENT,
58746
- eventData: {
58747
- error: {
58748
- message: errorMessage,
58749
- stack: errorStack
58750
- }
58751
- // TODO: include error codes when we define them
58752
- }
58753
- });
58754
- } catch (err2) {
58755
- if (WorkflowAPIError.is(err2) && (err2.status === 409 || err2.status === 410)) {
58756
- runtimeLogger.warn("Tried failing workflow run, but run has already finished.", {
58757
- workflowRunId: runId,
58758
- message: err2.message
58759
- });
58760
- span?.setAttributes({
58761
- ...WorkflowErrorName(errorName),
58762
- ...WorkflowErrorMessage(errorMessage),
58763
- ...ErrorType(errorName)
58764
- });
58765
- return;
58766
- } else {
58767
- throw err2;
58768
- }
58769
- }
58770
58804
  span?.setAttributes({
58771
- ...WorkflowRunStatus("failed"),
58772
58805
  ...WorkflowErrorName(errorName),
58773
58806
  ...WorkflowErrorMessage(errorMessage),
58774
58807
  ...ErrorType(errorName)
58775
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
58776
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;
58777
58839
  }
58840
+ }
58841
+ span?.setAttributes({
58842
+ ...WorkflowRunStatus("completed"),
58843
+ ...WorkflowEventsCount(events.length)
58778
58844
  });
58779
58845
  });
58780
58846
  });
@@ -59012,7 +59078,7 @@ function getWritable(options = {}) {
59012
59078
  __name(getWritable, "getWritable");
59013
59079
 
59014
59080
  // ../workflow/dist/stdlib.js
59015
- var fetch = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//workflow@4.2.0-beta.68//fetch");
59081
+ var fetch = globalThis[/* @__PURE__ */ Symbol.for("WORKFLOW_USE_STEP")]("step//workflow@4.2.0-beta.70//fetch");
59016
59082
 
59017
59083
  // ../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/core.js
59018
59084
  var NEVER = Object.freeze({