@workflow/web 5.0.0-beta.25 → 5.0.0-beta.26

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.
@@ -18,7 +18,7 @@ import { createRequire as __wkfCreateRequire } from "node:module";
18
18
  if (typeof require === "undefined") {
19
19
  globalThis.require = __wkfCreateRequire(import.meta.url);
20
20
  }
21
- import { a as requireReact, S as ServerRouter, c as createReadableStreamFromReadable, r as reactExports, g as getDefaultExportFromCjs, R as React, b as ReactExports, w as withComponentProps, d as withErrorBoundaryProps, M as Meta, L as Links, e as ScrollRestoration, f as Scripts, O as Outlet, u as useNavigate, h as useSearchParams, i as Link$1, j as useRouteError, k as isRouteErrorResponse, l as useLocation, m as useParams } from "./app-e2FYIgWU.js";
21
+ import { a as requireReact, S as ServerRouter, c as createReadableStreamFromReadable, r as reactExports, g as getDefaultExportFromCjs, R as React, b as ReactExports, w as withComponentProps, d as withErrorBoundaryProps, M as Meta, L as Links, e as ScrollRestoration, f as Scripts, O as Outlet, u as useNavigate, h as useSearchParams, i as Link$1, j as useRouteError, k as isRouteErrorResponse, l as useLocation, m as useParams } from "./app-DQ35jFT1.js";
22
22
  import require$$0$4, { PassThrough } from "node:stream";
23
23
  import require$$0 from "util";
24
24
  import require$$1 from "crypto";
@@ -49912,7 +49912,7 @@ function replaceEncryptedAndExpiredWithMarkers(resource) {
49912
49912
  async function hydrateResourceIOWithKey(resource, key) {
49913
49913
  const { hydrateDataWithKey: hydrateDataWithKey2 } = await Promise.resolve().then(() => serializationFormat);
49914
49914
  const { importKey: importKey2 } = await Promise.resolve().then(() => encryption);
49915
- const { ensureZstdDecoderRegistered } = await import("./zstd-browser-decoder-CcinVfMP.js");
49915
+ const { ensureZstdDecoderRegistered } = await import("./zstd-browser-decoder-pCjqxVHM.js");
49916
49916
  ensureZstdDecoderRegistered();
49917
49917
  const cryptoKey = await importKey2(key);
49918
49918
  const revivers = getRevivers();
@@ -82803,7 +82803,7 @@ var tn = f("block", "before:content-[counter(line)]", "before:inline-block", "be
82803
82803
  var et = ({ className: e, language: t, style: o, isIncomplete: n, ...s2 }) => jsxRuntimeExports.jsx("div", { className: f("my-4 flex w-full flex-col gap-2 rounded-xl border border-border bg-sidebar p-2", e), "data-incomplete": n || void 0, "data-language": t, "data-streamdown": "code-block", style: { contentVisibility: "auto", containIntrinsicSize: "auto 200px", ...o }, ...s2 });
82804
82804
  var Se = reactExports.createContext({ code: "" }), de = () => reactExports.useContext(Se);
82805
82805
  var ot = ({ language: e }) => jsxRuntimeExports.jsx("div", { className: "flex h-8 items-center text-muted-foreground text-xs", "data-language": e, "data-streamdown": "code-block-header", children: jsxRuntimeExports.jsx("span", { className: "ml-1 font-mono lowercase", children: e }) });
82806
- var cn$1 = /\n+$/, dn = reactExports.lazy(() => import("./highlighted-body-B3W2YXNL-B7xcG7gl.js").then((e) => ({ default: e.HighlightedCodeBlockBody }))), rt = ({ code: e, language: t, className: o, children: n, isIncomplete: s2 = false, ...r2 }) => {
82806
+ var cn$1 = /\n+$/, dn = reactExports.lazy(() => import("./highlighted-body-B3W2YXNL-DUlvgLoF.js").then((e) => ({ default: e.HighlightedCodeBlockBody }))), rt = ({ code: e, language: t, className: o, children: n, isIncomplete: s2 = false, ...r2 }) => {
82807
82807
  let i = reactExports.useMemo(() => e.replace(cn$1, ""), [e]), c = reactExports.useMemo(() => ({ bg: "transparent", fg: "inherit", tokens: i.split(`
82808
82808
  `).map((a2) => [{ content: a2, color: "inherit", bgColor: "transparent", htmlStyle: {}, offset: 0 }]) }), [i]);
82809
82809
  return jsxRuntimeExports.jsx(Se.Provider, { value: { code: e }, children: jsxRuntimeExports.jsxs(et, { isIncomplete: s2, language: t, children: [jsxRuntimeExports.jsx(ot, { language: t }), n ? jsxRuntimeExports.jsx("div", { className: "pointer-events-none sticky top-2 z-10 -mt-10 flex h-8 items-center justify-end", children: jsxRuntimeExports.jsx("div", { className: "pointer-events-auto flex shrink-0 items-center gap-2 rounded-md border border-sidebar bg-sidebar/80 px-1.5 py-1 supports-[backdrop-filter]:bg-sidebar/70 supports-[backdrop-filter]:backdrop-blur", "data-streamdown": "code-block-actions", children: n }) }) : null, jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: jsxRuntimeExports.jsx(Qe, { className: o, language: t, result: c, ...r2 }), children: jsxRuntimeExports.jsx(dn, { className: o, code: i, language: t, raw: c, ...r2 }) })] }) });
@@ -83125,7 +83125,7 @@ var Dt = ({ children: e, className: t, onDownload: o, onError: n }) => {
83125
83125
  }, []), jsxRuntimeExports.jsxs("div", { className: "relative", ref: i, children: [jsxRuntimeExports.jsx("button", { className: f("cursor-pointer p-1 text-muted-foreground transition-all hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50", t), disabled: c, onClick: () => r2(!s2), title: "Download table", type: "button", children: e != null ? e : jsxRuntimeExports.jsx(Z, { size: 14 }) }), s2 ? jsxRuntimeExports.jsxs("div", { className: "absolute top-full right-0 z-10 mt-1 min-w-[120px] overflow-hidden rounded-md border border-border bg-background shadow-lg", children: [jsxRuntimeExports.jsx("button", { className: "w-full px-3 py-2 text-left text-sm transition-colors hover:bg-muted/40", onClick: () => a2("csv"), title: "Download table as CSV", type: "button", children: "CSV" }), jsxRuntimeExports.jsx("button", { className: "w-full px-3 py-2 text-left text-sm transition-colors hover:bg-muted/40", onClick: () => a2("markdown"), title: "Download table as Markdown", type: "button", children: "Markdown" })] }) : null] });
83126
83126
  };
83127
83127
  var Vt = ({ children: e, className: t, showControls: o, ...n }) => jsxRuntimeExports.jsxs("div", { className: "my-4 flex flex-col gap-2 rounded-lg border border-border bg-sidebar p-2", "data-streamdown": "table-wrapper", children: [o ? jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-end gap-1", children: [jsxRuntimeExports.jsx(Ht, {}), jsxRuntimeExports.jsx(Dt, {})] }) : null, jsxRuntimeExports.jsx("div", { className: "border-collapse overflow-x-auto overscroll-y-auto rounded-md border border-border bg-background", children: jsxRuntimeExports.jsx("table", { className: f("w-full divide-y divide-border", t), "data-streamdown": "table", ...n, children: e }) })] });
83128
- var Jn = reactExports.lazy(() => import("./mermaid-3ZIDBTTL-DQqBhQ9Y.js").then((e) => ({ default: e.Mermaid }))), Kn = /language-([^\s]+)/;
83128
+ var Jn = reactExports.lazy(() => import("./mermaid-3ZIDBTTL-BdnRYE9a.js").then((e) => ({ default: e.Mermaid }))), Kn = /language-([^\s]+)/;
83129
83129
  function ke(e, t) {
83130
83130
  if (!(e != null && e.position || t != null && t.position)) return true;
83131
83131
  if (!(e != null && e.position && (t != null && t.position))) return false;
@@ -90698,6 +90698,19 @@ if (typeof globalThis !== "undefined") {
90698
90698
  });
90699
90699
  }
90700
90700
  }
90701
+ const RETRYABLE_WORLD_ERROR_CODES = /* @__PURE__ */ new Set(["TRANSPORT", "TIMEOUT"]);
90702
+ function isRetryableWorldError(err) {
90703
+ if (ThrottleError.is(err)) {
90704
+ return true;
90705
+ }
90706
+ if (!WorkflowWorldError.is(err)) {
90707
+ return false;
90708
+ }
90709
+ if (err.status !== void 0 && err.status >= 500) {
90710
+ return true;
90711
+ }
90712
+ return err.code !== void 0 && RETRYABLE_WORLD_ERROR_CODES.has(err.code);
90713
+ }
90701
90714
  const colorEnabled = (() => {
90702
90715
  var _a3;
90703
90716
  const p2 = globalThis.process;
@@ -91238,7 +91251,7 @@ const encryption = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
91238
91251
  encrypt: encrypt$1,
91239
91252
  importKey
91240
91253
  }, Symbol.toStringTag, { value: "Module" }));
91241
- const version$1 = "5.0.0-beta.25";
91254
+ const version$1 = "5.0.0-beta.26";
91242
91255
  const WorldCacheKey = Symbol.for("@workflow/world//cache");
91243
91256
  const WorldCachePromiseKey = Symbol.for("@workflow/world//cachePromise");
91244
91257
  const GetWorldFnKey$1 = Symbol.for("@workflow/world//getWorldFn");
@@ -122224,7 +122237,7 @@ function createLocalWorld(args) {
122224
122237
  const basedir = mergedConfig.dataDir;
122225
122238
  const hooksDir = path$3.join(basedir, "hooks");
122226
122239
  const taggedHookFiles = await listTaggedFiles(hooksDir, tag);
122227
- const { HookSchema: HookSchema2 } = await import("./index-BELZxbAO.js");
122240
+ const { HookSchema: HookSchema2 } = await import("./index-BgRt1-Z6.js");
122228
122241
  await Promise.all(taggedHookFiles.map(async (hookFile) => {
122229
122242
  const hook = await readJSON(path$3.join(hooksDir, hookFile), HookSchema2);
122230
122243
  if (hook == null ? void 0 : hook.token) {
@@ -122259,6 +122272,67 @@ function createLocalWorld(args) {
122259
122272
  }
122260
122273
  };
122261
122274
  }
122275
+ let _dispatcher;
122276
+ let _eventsDispatcher;
122277
+ let _streamDispatcher;
122278
+ const BASE_AGENT_OPTIONS = {
122279
+ connections: 8,
122280
+ keepAliveTimeout: 1e4,
122281
+ // HTTP/1.1 pipelining is disabled (pipelining: 1) because it causes
122282
+ // head-of-line blocking that deadlocks the webhook respondWith mechanism.
122283
+ pipelining: 1
122284
+ };
122285
+ const DEFAULT_AGENT_OPTIONS = {
122286
+ ...BASE_AGENT_OPTIONS,
122287
+ allowH2: false
122288
+ };
122289
+ const EVENTS_AGENT_OPTIONS = {
122290
+ ...BASE_AGENT_OPTIONS,
122291
+ allowH2: true
122292
+ };
122293
+ const RETRY_AGENT_OPTIONS = {
122294
+ // Observe Retry-After header if received
122295
+ retryAfter: true,
122296
+ // Retry 5xx in-process (genuine transient blips recover fast), but NOT 429.
122297
+ // The Vercel firewall issues a challenge as a 429: our server-to-server
122298
+ // client cannot solve a challenge, so in-process retries just re-trigger it
122299
+ // ~5× per request and amplify load against an already-overloaded firewall
122300
+ // during an incident. Letting 429 pass through surfaces it immediately to
122301
+ // makeRequest — which maps it to a ThrottleError carrying the
122302
+ // `x-vercel-mitigated` / `x-vercel-id` headers — and the queue does the
122303
+ // (backed-off) retry instead. This is the long-standing "let 429s pass
122304
+ // through" intent. (undici default is [500, 502, 503, 504, 429].)
122305
+ statusCodes: [500, 502, 503, 504]
122306
+ };
122307
+ const STREAM_RETRY_OPTIONS = {
122308
+ retryAfter: true,
122309
+ methods: ["PUT"],
122310
+ statusCodes: [429]
122311
+ };
122312
+ function getDispatcher(config2) {
122313
+ return (config2 == null ? void 0 : config2.dispatcher) ?? getDefaultDispatcher();
122314
+ }
122315
+ function getEventsDispatcher(config2) {
122316
+ return (config2 == null ? void 0 : config2.dispatcher) ?? getDefaultEventsDispatcher();
122317
+ }
122318
+ function getStreamDispatcher(config2) {
122319
+ return (config2 == null ? void 0 : config2.dispatcher) ?? getDefaultStreamDispatcher();
122320
+ }
122321
+ function makeRetryDispatcher(agentOptions, retryOptions) {
122322
+ return new undiciExports.RetryAgent(new undiciExports.Agent(agentOptions), retryOptions);
122323
+ }
122324
+ function getDefaultDispatcher() {
122325
+ _dispatcher ?? (_dispatcher = makeRetryDispatcher(DEFAULT_AGENT_OPTIONS, RETRY_AGENT_OPTIONS));
122326
+ return _dispatcher;
122327
+ }
122328
+ function getDefaultEventsDispatcher() {
122329
+ _eventsDispatcher ?? (_eventsDispatcher = makeRetryDispatcher(EVENTS_AGENT_OPTIONS, RETRY_AGENT_OPTIONS));
122330
+ return _eventsDispatcher;
122331
+ }
122332
+ function getDefaultStreamDispatcher() {
122333
+ _streamDispatcher ?? (_streamDispatcher = makeRetryDispatcher(EVENTS_AGENT_OPTIONS, STREAM_RETRY_OPTIONS));
122334
+ return _streamDispatcher;
122335
+ }
122262
122336
  var getContext_1;
122263
122337
  var hasRequiredGetContext;
122264
122338
  function requireGetContext() {
@@ -122377,8 +122451,8 @@ function requireGetVercelOidcToken() {
122377
122451
  }
122378
122452
  try {
122379
122453
  const [{ getTokenPayload, isExpired }, { refreshToken }] = await Promise.all([
122380
- await import("./token-util-CCeU4-vR.js").then((n) => n.t),
122381
- await import("./token-guLCf66r.js").then((n) => n.t)
122454
+ await import("./token-util-CaJAmsYa.js").then((n) => n.t),
122455
+ await import("./token-DK_R23fr.js").then((n) => n.t)
122382
122456
  ]);
122383
122457
  if (!token || isExpired(getTokenPayload(token), options == null ? void 0 : options.expirationBufferMs)) {
122384
122458
  await refreshToken(options);
@@ -122941,63 +123015,218 @@ function requireDist() {
122941
123015
  return dist;
122942
123016
  }
122943
123017
  var distExports = requireDist();
122944
- let _dispatcher;
122945
- let _eventsDispatcher;
122946
- let _streamDispatcher;
122947
- const BASE_AGENT_OPTIONS = {
122948
- connections: 8,
122949
- keepAliveTimeout: 1e4,
122950
- // HTTP/1.1 pipelining is disabled (pipelining: 1) because it causes
122951
- // head-of-line blocking that deadlocks the webhook respondWith mechanism.
122952
- pipelining: 1
122953
- };
122954
- const DEFAULT_AGENT_OPTIONS = {
122955
- ...BASE_AGENT_OPTIONS,
122956
- allowH2: false
122957
- };
122958
- const EVENTS_AGENT_OPTIONS = {
122959
- ...BASE_AGENT_OPTIONS,
122960
- allowH2: true
122961
- };
122962
- const RETRY_AGENT_OPTIONS = {
122963
- // Observe Retry-After header if received
122964
- retryAfter: true
122965
- // By default, we observe re-try headers, and also separately
122966
- // re-try on these status codes: 429 / 500 / 502 / 503 / 504.
122967
- // TODO: We might want to let 429s pass through, so that we can do
122968
- // runtime retry-after handling through the queue.
122969
- };
122970
- const STREAM_RETRY_OPTIONS = {
122971
- retryAfter: true,
122972
- methods: ["PUT"],
122973
- statusCodes: [429]
122974
- };
122975
- function getDispatcher(config2) {
122976
- return (config2 == null ? void 0 : config2.dispatcher) ?? getDefaultDispatcher();
123018
+ let otelApiPromise = null;
123019
+ async function getOtelApi() {
123020
+ if (!otelApiPromise) {
123021
+ otelApiPromise = import("./index-Dq5jTBN4.js").catch(() => null);
123022
+ }
123023
+ return otelApiPromise;
122977
123024
  }
122978
- function getEventsDispatcher(config2) {
122979
- return (config2 == null ? void 0 : config2.dispatcher) ?? getDefaultEventsDispatcher();
123025
+ let tracerPromise = null;
123026
+ async function getTracer() {
123027
+ if (!tracerPromise) {
123028
+ tracerPromise = getOtelApi().then((otel) => otel ? otel.trace.getTracer("workflow") : null);
123029
+ }
123030
+ return tracerPromise;
122980
123031
  }
122981
- function getStreamDispatcher(config2) {
122982
- return (config2 == null ? void 0 : config2.dispatcher) ?? getDefaultStreamDispatcher();
123032
+ async function trace(spanName2, ...args) {
123033
+ const [tracer, otel] = await Promise.all([getTracer(), getOtelApi()]);
123034
+ const { fn: fn2, opts } = typeof args[0] === "function" ? { fn: args[0], opts: {} } : { fn: args[1], opts: args[0] };
123035
+ if (!fn2)
123036
+ throw new Error("Function to trace must be provided");
123037
+ if (!tracer || !otel) {
123038
+ return await fn2();
123039
+ }
123040
+ return tracer.startActiveSpan(spanName2, opts, async (span) => {
123041
+ try {
123042
+ const result = await fn2(span);
123043
+ span.setStatus({ code: otel.SpanStatusCode.OK });
123044
+ return result;
123045
+ } catch (e) {
123046
+ span.setStatus({
123047
+ code: otel.SpanStatusCode.ERROR,
123048
+ message: e.message
123049
+ });
123050
+ throw e;
123051
+ } finally {
123052
+ span.end();
123053
+ }
123054
+ });
122983
123055
  }
122984
- function getDefaultDispatcher() {
122985
- if (!_dispatcher) {
122986
- _dispatcher = new undiciExports.RetryAgent(new undiciExports.Agent(DEFAULT_AGENT_OPTIONS), RETRY_AGENT_OPTIONS);
123056
+ async function getSpanKind(field) {
123057
+ const otel = await getOtelApi();
123058
+ if (!otel)
123059
+ return void 0;
123060
+ return otel.SpanKind[field];
123061
+ }
123062
+ async function injectTraceContextIntoHeaders(headers2) {
123063
+ const otel = await getOtelApi();
123064
+ if (!otel)
123065
+ return;
123066
+ const carrier = {};
123067
+ otel.propagation.inject(otel.context.active(), carrier);
123068
+ for (const [key, value] of Object.entries(carrier)) {
123069
+ headers2.set(key, value);
122987
123070
  }
122988
- return _dispatcher;
122989
123071
  }
122990
- function getDefaultEventsDispatcher() {
122991
- if (!_eventsDispatcher) {
122992
- _eventsDispatcher = new undiciExports.RetryAgent(new undiciExports.Agent(EVENTS_AGENT_OPTIONS), RETRY_AGENT_OPTIONS);
123072
+ function SemanticConvention(...names) {
123073
+ return (value) => Object.fromEntries(names.map((name2) => [name2, value]));
123074
+ }
123075
+ const HttpRequestMethod = SemanticConvention("http.request.method");
123076
+ const UrlFull = SemanticConvention("url.full");
123077
+ const ServerAddress = SemanticConvention("server.address");
123078
+ const ServerPort = SemanticConvention("server.port");
123079
+ const HttpResponseStatusCode = SemanticConvention("http.response.status_code");
123080
+ const ErrorType = SemanticConvention("error.type");
123081
+ const WorldParseFormat = SemanticConvention("workflow.world.parse.format");
123082
+ const PeerService = SemanticConvention("peer.service");
123083
+ const RpcSystem = SemanticConvention("rpc.system");
123084
+ const RpcService = SemanticConvention("rpc.service");
123085
+ const RpcMethod = SemanticConvention("rpc.method");
123086
+ const WorkflowRunId = SemanticConvention("workflow.run.id");
123087
+ const StepId = SemanticConvention("step.id");
123088
+ const REQUEST_TIMEOUT_MS = 6e4;
123089
+ const HTTP_DEBUG_ENABLED = typeof process !== "undefined" && typeof process.env.DEBUG === "string" && (process.env.DEBUG.includes("workflow:") || process.env.DEBUG === "*");
123090
+ const DIAGNOSTIC_HEADERS = [
123091
+ "x-vercel-id",
123092
+ "x-vercel-error",
123093
+ "x-vercel-mitigated"
123094
+ ];
123095
+ function getVercelDiagnostics(headers2) {
123096
+ return DIAGNOSTIC_HEADERS.flatMap((header) => {
123097
+ const value = headers2.get(header);
123098
+ return value ? [`${header}=${value}`] : [];
123099
+ });
123100
+ }
123101
+ function formatVercelDiagnostics(headers2) {
123102
+ const diagnostics2 = getVercelDiagnostics(headers2);
123103
+ return diagnostics2.length > 0 ? ` (${diagnostics2.join("; ")})` : "";
123104
+ }
123105
+ function httpLog(method, label, response2, ms2) {
123106
+ if (!HTTP_DEBUG_ENABLED)
123107
+ return;
123108
+ const diagnostics2 = getVercelDiagnostics(response2.headers);
123109
+ const suffix = diagnostics2.length > 0 ? `; ${diagnostics2.join("; ")}` : "";
123110
+ console.debug(`[workflow:world-vercel:http] ${method} ${label} -> ${response2.status} (${ms2}ms${suffix})`);
123111
+ }
123112
+ function logCurlRepro(method, url2, headers2) {
123113
+ if (!process.env.DEBUG)
123114
+ return;
123115
+ const stringifiedHeaders = Array.from(headers2.entries()).filter(([key]) => key.toLowerCase() !== "authorization").map(([key, value]) => `-H "${key}: ${value}"`).join(" ");
123116
+ console.error(`Failed to fetch, reproduce with:
123117
+ curl -X ${method} ${stringifiedHeaders} "${url2}"`);
123118
+ }
123119
+ function parseRetryAfter(value) {
123120
+ if (!value)
123121
+ return void 0;
123122
+ const parsed = parseInt(value, 10);
123123
+ return Number.isNaN(parsed) ? void 0 : parsed;
123124
+ }
123125
+ function errorForResponse(status, message2, opts = {}) {
123126
+ const { retryAfter, code: code2, url: url2, mitigated } = opts;
123127
+ if (status === 409)
123128
+ return new EntityConflictError(message2);
123129
+ if (status === 410)
123130
+ return new RunExpiredError(message2);
123131
+ if (status === 425)
123132
+ return new TooEarlyError(message2, { retryAfter });
123133
+ if (status === 429) {
123134
+ if (isFirewallChallenge429(status, mitigated)) {
123135
+ return new WorkflowWorldError(`${message2} (x-vercel-mitigated=challenge)`, {
123136
+ url: url2,
123137
+ status,
123138
+ code: "TRANSPORT",
123139
+ retryAfter
123140
+ });
123141
+ }
123142
+ return new ThrottleError(message2, { retryAfter });
122993
123143
  }
122994
- return _eventsDispatcher;
123144
+ return new WorkflowWorldError(message2, { url: url2, status, code: code2, retryAfter });
122995
123145
  }
122996
- function getDefaultStreamDispatcher() {
122997
- if (!_streamDispatcher) {
122998
- _streamDispatcher = new undiciExports.RetryAgent(new undiciExports.Agent(EVENTS_AGENT_OPTIONS), STREAM_RETRY_OPTIONS);
123146
+ function isFirewallChallenge429(status, mitigated) {
123147
+ return status === 429 && mitigated === "challenge";
123148
+ }
123149
+ async function resolveVercelApiToken(opts) {
123150
+ return (opts == null ? void 0 : opts.token) ?? process.env.VERCEL_TOKEN ?? await distExports.getVercelOidcToken().catch(() => null);
123151
+ }
123152
+ function parseServer(url2) {
123153
+ try {
123154
+ const parsed = new URL(url2);
123155
+ return {
123156
+ serverAddress: parsed.hostname,
123157
+ serverPort: parsed.port ? parseInt(parsed.port, 10) : parsed.protocol === "https:" ? 443 : 80
123158
+ };
123159
+ } catch {
123160
+ return {};
122999
123161
  }
123000
- return _streamDispatcher;
123162
+ }
123163
+ function httpClientSpanAttributes(args) {
123164
+ const { method, url: url2, peerService } = args;
123165
+ const { serverAddress, serverPort } = parseServer(url2);
123166
+ return {
123167
+ ...HttpRequestMethod(method),
123168
+ ...UrlFull(url2),
123169
+ ...serverAddress ? ServerAddress(serverAddress) : {},
123170
+ ...serverPort ? ServerPort(serverPort) : {},
123171
+ ...PeerService(peerService),
123172
+ ...RpcSystem("http"),
123173
+ ...RpcService(peerService)
123174
+ };
123175
+ }
123176
+ async function instrumentedFetch(opts) {
123177
+ const { method, url: url2, headers: headers2, body: body2, dispatcher: dispatcher2, peerService = "workflow-server", timeoutMs = REQUEST_TIMEOUT_MS, signal: callerSignal, injectTraceContext = true, cacheBust = true, logLabel, buildError } = opts;
123178
+ const label = logLabel ?? url2;
123179
+ return trace(`http ${method}`, { kind: await getSpanKind("CLIENT") }, async (span) => {
123180
+ var _a3, _b2, _c2;
123181
+ span == null ? void 0 : span.setAttributes(httpClientSpanAttributes({ method, url: url2, peerService }));
123182
+ if (injectTraceContext)
123183
+ await injectTraceContextIntoHeaders(headers2);
123184
+ if (cacheBust)
123185
+ headers2.set("X-Request-Time", Date.now().toString());
123186
+ const timeoutSignal = timeoutMs != null ? AbortSignal.timeout(timeoutMs) : void 0;
123187
+ const signal = callerSignal && timeoutSignal ? AbortSignal.any([callerSignal, timeoutSignal]) : callerSignal ?? timeoutSignal;
123188
+ const start2 = Date.now();
123189
+ let response2;
123190
+ try {
123191
+ response2 = await fetch(url2, {
123192
+ method,
123193
+ headers: headers2,
123194
+ body: body2,
123195
+ signal,
123196
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- undici dispatcher type doesn't match @types/node's RequestInit
123197
+ dispatcher: dispatcher2
123198
+ });
123199
+ } catch (error2) {
123200
+ const elapsed = Date.now() - start2;
123201
+ if (error2 instanceof Error && (error2.name === "TimeoutError" || error2.name === "AbortError")) {
123202
+ const timeoutError = new WorkflowWorldError(`${method} ${label} timed out after ${elapsed}ms`, { url: url2, cause: error2 });
123203
+ span == null ? void 0 : span.setAttributes({ ...ErrorType("TIMEOUT") });
123204
+ (_a3 = span == null ? void 0 : span.recordException) == null ? void 0 : _a3.call(span, timeoutError);
123205
+ throw timeoutError;
123206
+ }
123207
+ throw error2;
123208
+ }
123209
+ const ms2 = Date.now() - start2;
123210
+ httpLog(method, label, response2, ms2);
123211
+ span == null ? void 0 : span.setAttributes({ ...HttpResponseStatusCode(response2.status) });
123212
+ if (!response2.ok) {
123213
+ span == null ? void 0 : span.setAttributes({ ...ErrorType(`HTTP ${response2.status}`) });
123214
+ logCurlRepro(method, url2, headers2);
123215
+ if (buildError) {
123216
+ const error3 = await buildError(response2);
123217
+ (_b2 = span == null ? void 0 : span.recordException) == null ? void 0 : _b2.call(span, error3);
123218
+ throw error3;
123219
+ }
123220
+ const text2 = await response2.text().catch(() => "");
123221
+ const error2 = errorForResponse(response2.status, `${method} ${label} -> HTTP ${response2.status}: ${response2.statusText}${text2 ? ` ${text2}` : ""}${formatVercelDiagnostics(response2.headers)}`, {
123222
+ url: url2,
123223
+ retryAfter: parseRetryAfter(response2.headers.get("Retry-After"))
123224
+ });
123225
+ (_c2 = span == null ? void 0 : span.recordException) == null ? void 0 : _c2.call(span, error2);
123226
+ throw error2;
123227
+ }
123228
+ return response2;
123229
+ });
123001
123230
  }
123002
123231
  const KEY_BYTES = 32;
123003
123232
  async function deriveRunKey(deploymentKey, projectId, runId) {
@@ -123023,7 +123252,7 @@ async function deriveRunKey(deploymentKey, projectId, runId) {
123023
123252
  return new Uint8Array(derivedBits);
123024
123253
  }
123025
123254
  async function fetchRunKey(deploymentId, projectId, runId, options) {
123026
- const token = (options == null ? void 0 : options.token) ?? process.env.VERCEL_TOKEN ?? await distExports.getVercelOidcToken().catch(() => null);
123255
+ const token = await resolveVercelApiToken({ token: options == null ? void 0 : options.token });
123027
123256
  if (!token) {
123028
123257
  throw new Error("Cannot fetch run key: no OIDC token or VERCEL_TOKEN available");
123029
123258
  }
@@ -123031,23 +123260,25 @@ async function fetchRunKey(deploymentId, projectId, runId, options) {
123031
123260
  if (options == null ? void 0 : options.teamId) {
123032
123261
  params.set("teamId", options.teamId);
123033
123262
  }
123034
- const response2 = await fetch(`https://api.vercel.com/v1/workflow/run-key/${deploymentId}?${params}`, {
123263
+ const response2 = await instrumentedFetch({
123035
123264
  method: "GET",
123036
- headers: {
123037
- Authorization: `Bearer ${token}`
123038
- },
123039
- // @ts-expect-error -- undici dispatcher is accepted by Node.js fetch but not in @types/node's RequestInit
123040
- dispatcher: getDispatcher({ dispatcher: options == null ? void 0 : options.dispatcher })
123041
- });
123042
- if (!response2.ok) {
123043
- let body2;
123044
- try {
123045
- body2 = await response2.text();
123046
- } catch {
123047
- body2 = "<unable to read response body>";
123265
+ url: `https://api.vercel.com/v1/workflow/run-key/${deploymentId}?${params}`,
123266
+ headers: new Headers({ Authorization: `Bearer ${token}` }),
123267
+ dispatcher: getDispatcher({ dispatcher: options == null ? void 0 : options.dispatcher }),
123268
+ peerService: "vercel-api",
123269
+ // Preserve the prior no-timeout behavior for this Vercel-API call; the
123270
+ // shared RetryAgent still handles transient/5xx retries.
123271
+ timeoutMs: null,
123272
+ buildError: async (res) => {
123273
+ let body2;
123274
+ try {
123275
+ body2 = await res.text();
123276
+ } catch {
123277
+ body2 = "<unable to read response body>";
123278
+ }
123279
+ return new Error(`Failed to fetch run key for ${runId} (deployment ${deploymentId}): HTTP ${res.status} ${res.statusText}${body2 ? ` — ${body2}` : ""}`);
123048
123280
  }
123049
- throw new Error(`Failed to fetch run key for ${runId} (deployment ${deploymentId}): HTTP ${response2.status} ${response2.statusText}${body2 ? ` — ${body2}` : ""}`);
123050
- }
123281
+ });
123051
123282
  const data = await response2.json();
123052
123283
  const result = object$1({ key: string$3().nullable() }).safeParse(data);
123053
123284
  if (!result.success) {
@@ -123092,76 +123323,6 @@ function createGetEncryptionKeyForRun(projectId, teamId, token, dispatcher2) {
123092
123323
  });
123093
123324
  };
123094
123325
  }
123095
- let otelApiPromise = null;
123096
- async function getOtelApi() {
123097
- if (!otelApiPromise) {
123098
- otelApiPromise = import("./index-Dq5jTBN4.js").catch(() => null);
123099
- }
123100
- return otelApiPromise;
123101
- }
123102
- let tracerPromise = null;
123103
- async function getTracer() {
123104
- if (!tracerPromise) {
123105
- tracerPromise = getOtelApi().then((otel) => otel ? otel.trace.getTracer("workflow") : null);
123106
- }
123107
- return tracerPromise;
123108
- }
123109
- async function trace(spanName2, ...args) {
123110
- const [tracer, otel] = await Promise.all([getTracer(), getOtelApi()]);
123111
- const { fn: fn2, opts } = typeof args[0] === "function" ? { fn: args[0], opts: {} } : { fn: args[1], opts: args[0] };
123112
- if (!fn2)
123113
- throw new Error("Function to trace must be provided");
123114
- if (!tracer || !otel) {
123115
- return await fn2();
123116
- }
123117
- return tracer.startActiveSpan(spanName2, opts, async (span) => {
123118
- try {
123119
- const result = await fn2(span);
123120
- span.setStatus({ code: otel.SpanStatusCode.OK });
123121
- return result;
123122
- } catch (e) {
123123
- span.setStatus({
123124
- code: otel.SpanStatusCode.ERROR,
123125
- message: e.message
123126
- });
123127
- throw e;
123128
- } finally {
123129
- span.end();
123130
- }
123131
- });
123132
- }
123133
- async function getSpanKind(field) {
123134
- const otel = await getOtelApi();
123135
- if (!otel)
123136
- return void 0;
123137
- return otel.SpanKind[field];
123138
- }
123139
- async function injectTraceContextIntoHeaders(headers2) {
123140
- const otel = await getOtelApi();
123141
- if (!otel)
123142
- return;
123143
- const carrier = {};
123144
- otel.propagation.inject(otel.context.active(), carrier);
123145
- for (const [key, value] of Object.entries(carrier)) {
123146
- headers2.set(key, value);
123147
- }
123148
- }
123149
- function SemanticConvention(...names) {
123150
- return (value) => Object.fromEntries(names.map((name2) => [name2, value]));
123151
- }
123152
- const HttpRequestMethod = SemanticConvention("http.request.method");
123153
- const UrlFull = SemanticConvention("url.full");
123154
- const ServerAddress = SemanticConvention("server.address");
123155
- const ServerPort = SemanticConvention("server.port");
123156
- const HttpResponseStatusCode = SemanticConvention("http.response.status_code");
123157
- const ErrorType = SemanticConvention("error.type");
123158
- const WorldParseFormat = SemanticConvention("workflow.world.parse.format");
123159
- const PeerService = SemanticConvention("peer.service");
123160
- const RpcSystem = SemanticConvention("rpc.system");
123161
- const RpcService = SemanticConvention("rpc.service");
123162
- const RpcMethod = SemanticConvention("rpc.method");
123163
- const WorkflowRunId = SemanticConvention("workflow.run.id");
123164
- const StepId = SemanticConvention("step.id");
123165
123326
  const WORKFLOW_SERVER_SERVICE = {
123166
123327
  peerService: "workflow-server",
123167
123328
  rpcSystem: "http",
@@ -127758,29 +127919,37 @@ var QueueClient = class {
127758
127919
  setApi(this, new ApiClient({ ...options, region }));
127759
127920
  }
127760
127921
  };
127761
- const version = "5.0.0-beta.21";
127762
- const HTTP_DEBUG_ENABLED = typeof process !== "undefined" && typeof process.env.DEBUG === "string" && (process.env.DEBUG.includes("workflow:") || process.env.DEBUG === "*");
127763
- function httpLog(method, endpoint, response2, ms2) {
127764
- if (HTTP_DEBUG_ENABLED) {
127765
- const responseContext = getResponseDiagnosticHeaders(response2);
127766
- const diagnosticSuffix = responseContext.length > 0 ? `; ${responseContext.join("; ")}` : "";
127767
- console.debug(`[workflow:world-vercel:http] ${method} ${endpoint} -> ${response2.status} (${ms2}ms${diagnosticSuffix})`);
127768
- }
127769
- }
127770
- function getResponseDiagnosticHeaders(response2) {
127771
- return ["x-vercel-id", "x-vercel-error"].flatMap((header) => {
127772
- const value = response2.headers.get(header);
127773
- return value ? [`${header}=${value}`] : [];
127774
- });
127775
- }
127776
- function formatResponseDiagnostics(response2) {
127777
- const headers2 = getResponseDiagnosticHeaders(response2);
127778
- return headers2.length > 0 ? ` (${headers2.join("; ")})` : "";
127779
- }
127780
- const REQUEST_TIMEOUT_MS = 6e4;
127922
+ const version = "5.0.0-beta.22";
127781
127923
  const IDEMPOTENT_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD"]);
127782
127924
  const MAX_BODY_PARSE_RETRIES = 2;
127783
127925
  const BODY_PARSE_RETRY_BASE_MS = 100;
127926
+ const TRANSIENT_TRANSPORT_ERROR_CODES = /* @__PURE__ */ new Set([
127927
+ "UND_ERR_REQ_RETRY",
127928
+ "UND_ERR_SOCKET",
127929
+ "UND_ERR_CONNECT",
127930
+ "UND_ERR_CONNECT_TIMEOUT",
127931
+ "UND_ERR_HEADERS_TIMEOUT",
127932
+ "UND_ERR_BODY_TIMEOUT",
127933
+ "UND_ERR_CLOSED",
127934
+ "ECONNRESET",
127935
+ "ECONNREFUSED",
127936
+ "ENOTFOUND",
127937
+ "EAI_AGAIN",
127938
+ "EPIPE"
127939
+ ]);
127940
+ function getTransientTransportCode(error2) {
127941
+ let current = error2;
127942
+ for (let depth = 0; current != null && depth < 5; depth++) {
127943
+ if (typeof current === "object" && "code" in current) {
127944
+ const code2 = current.code;
127945
+ if (typeof code2 === "string" && TRANSIENT_TRANSPORT_ERROR_CODES.has(code2)) {
127946
+ return code2;
127947
+ }
127948
+ }
127949
+ current = current == null ? void 0 : current.cause;
127950
+ }
127951
+ return void 0;
127952
+ }
127784
127953
  const getWorkflowServerUrlOverride = () => process.env.VERCEL_WORKFLOW_SERVER_URL || "";
127785
127954
  const DEFAULT_RESOLVE_DATA_OPTION = "all";
127786
127955
  function deserializeError(obj) {
@@ -127849,26 +128018,13 @@ async function makeRequest({ endpoint, options = {}, config: config2 = {}, schem
127849
128018
  const method = options.method || "GET";
127850
128019
  const { baseUrl, headers: headers2 } = await getHttpConfig(config2);
127851
128020
  const url2 = `${baseUrl}${endpoint}`;
127852
- let serverAddress;
127853
- let serverPort;
127854
- try {
127855
- const parsedUrl = new URL(url2);
127856
- serverAddress = parsedUrl.hostname;
127857
- serverPort = parsedUrl.port ? parseInt(parsedUrl.port, 10) : parsedUrl.protocol === "https:" ? 443 : 80;
127858
- } catch {
127859
- }
127860
128021
  return trace(`http ${method}`, { kind: await getSpanKind("CLIENT") }, async (span) => {
127861
- var _a3;
127862
- span == null ? void 0 : span.setAttributes({
127863
- ...HttpRequestMethod(method),
127864
- ...UrlFull(url2),
127865
- ...serverAddress && ServerAddress(serverAddress),
127866
- ...serverPort && ServerPort(serverPort),
127867
- // Peer service for Datadog service maps
127868
- ...PeerService("workflow-server"),
127869
- ...RpcSystem("http"),
127870
- ...RpcService("workflow-server")
127871
- });
128022
+ var _a3, _b2, _c2;
128023
+ span == null ? void 0 : span.setAttributes(httpClientSpanAttributes({
128024
+ method,
128025
+ url: url2,
128026
+ peerService: "workflow-server"
128027
+ }));
127872
128028
  headers2.set("Accept", "application/cbor");
127873
128029
  await injectTraceContextIntoHeaders(headers2);
127874
128030
  let body2;
@@ -127898,61 +128054,42 @@ async function makeRequest({ endpoint, options = {}, config: config2 = {}, schem
127898
128054
  } catch (error2) {
127899
128055
  const elapsed = Date.now() - fetchStart;
127900
128056
  if (error2 instanceof Error && (error2.name === "TimeoutError" || error2.name === "AbortError")) {
127901
- const timeoutError = new WorkflowWorldError(`${method} ${endpoint} timed out after ${elapsed}ms`, { url: url2, cause: error2 });
128057
+ const timeoutError = new WorkflowWorldError(`${method} ${endpoint} timed out after ${elapsed}ms`, { url: url2, code: "TIMEOUT", cause: error2 });
127902
128058
  span == null ? void 0 : span.setAttributes({ ...ErrorType("TIMEOUT") });
127903
128059
  (_a3 = span == null ? void 0 : span.recordException) == null ? void 0 : _a3.call(span, timeoutError);
127904
128060
  throw timeoutError;
127905
128061
  }
128062
+ const transportCode = getTransientTransportCode(error2);
128063
+ if (transportCode) {
128064
+ const transportError = new WorkflowWorldError(`${method} ${endpoint} transport failure after ${elapsed}ms (${transportCode})`, { url: url2, code: "TRANSPORT", cause: error2 });
128065
+ span == null ? void 0 : span.setAttributes({ ...ErrorType("TRANSPORT") });
128066
+ (_b2 = span == null ? void 0 : span.recordException) == null ? void 0 : _b2.call(span, transportError);
128067
+ throw transportError;
128068
+ }
127906
128069
  throw error2;
127907
128070
  }
127908
128071
  const fetchMs = Date.now() - fetchStart;
127909
- responseDiagnostics = formatResponseDiagnostics(response2);
128072
+ responseDiagnostics = formatVercelDiagnostics(response2.headers);
127910
128073
  httpLog(method, endpoint, response2, fetchMs);
127911
128074
  span == null ? void 0 : span.setAttributes({
127912
128075
  ...HttpResponseStatusCode(response2.status)
127913
128076
  });
127914
128077
  if (!response2.ok) {
127915
128078
  const errorData = await parseResponseBody(response2).then((r2) => r2.data).catch(() => ({}));
127916
- if (process.env.DEBUG) {
127917
- const stringifiedHeaders = Array.from(headers2.entries()).filter(([key]) => key.toLowerCase() !== "authorization").map(([key, value]) => `-H "${key}: ${value}"`).join(" ");
127918
- console.error(`Failed to fetch, reproduce with:
127919
- curl -X ${request2.method} ${stringifiedHeaders} "${url2}"`);
127920
- }
127921
- let retryAfter;
127922
- const retryAfterHeader = response2.headers.get("Retry-After");
127923
- if (retryAfterHeader) {
127924
- const parsed = parseInt(retryAfterHeader, 10);
127925
- if (!Number.isNaN(parsed)) {
127926
- retryAfter = parsed;
127927
- }
127928
- }
128079
+ logCurlRepro(request2.method, url2, headers2);
128080
+ const retryAfter = parseRetryAfter(response2.headers.get("Retry-After"));
127929
128081
  const defaultMessage = (errorData.message || `${request2.method} ${endpoint} -> HTTP ${response2.status}: ${response2.statusText}`) + responseDiagnostics;
127930
- const throwWithTrace = (error2) => {
127931
- var _a4;
127932
- span == null ? void 0 : span.setAttributes({
127933
- ...ErrorType(errorData.code || `HTTP ${response2.status}`)
127934
- });
127935
- (_a4 = span == null ? void 0 : span.recordException) == null ? void 0 : _a4.call(span, error2);
127936
- throw error2;
127937
- };
127938
- if (response2.status === 409) {
127939
- throwWithTrace(new EntityConflictError(defaultMessage));
127940
- }
127941
- if (response2.status === 410) {
127942
- throwWithTrace(new RunExpiredError(defaultMessage));
127943
- }
127944
- if (response2.status === 425) {
127945
- throwWithTrace(new TooEarlyError(defaultMessage, { retryAfter }));
127946
- }
127947
- if (response2.status === 429) {
127948
- throwWithTrace(new ThrottleError(defaultMessage, { retryAfter }));
127949
- }
127950
- throwWithTrace(new WorkflowWorldError(defaultMessage, {
128082
+ const error2 = errorForResponse(response2.status, defaultMessage, {
127951
128083
  url: url2,
127952
- status: response2.status,
127953
128084
  code: errorData.code,
127954
- retryAfter
127955
- }));
128085
+ retryAfter,
128086
+ mitigated: response2.headers.get("x-vercel-mitigated")
128087
+ });
128088
+ span == null ? void 0 : span.setAttributes({
128089
+ ...ErrorType(errorData.code || `HTTP ${response2.status}`)
128090
+ });
128091
+ (_c2 = span == null ? void 0 : span.recordException) == null ? void 0 : _c2.call(span, error2);
128092
+ throw error2;
127956
128093
  }
127957
128094
  onResponse == null ? void 0 : onResponse(response2);
127958
128095
  try {
@@ -128101,7 +128238,7 @@ const MAX_DELAY_SECONDS = Number(
128101
128238
  // 23 hours - leave 1h buffer before 24h retention limit
128102
128239
  );
128103
128240
  const HANDLER_ERROR_RETRY_AFTER_SECONDS = 1;
128104
- const HANDLER_ERROR_MAX_RETRY_AFTER_SECONDS = 60;
128241
+ const HANDLER_ERROR_MAX_RETRY_AFTER_SECONDS = 900;
128105
128242
  const HANDLER_ERROR_RETRY_JITTER_RATIO = 0.25;
128106
128243
  function getHandlerErrorRetryAfterSeconds(deliveryCount) {
128107
128244
  const backoffSeconds = Math.min(Math.max(HANDLER_ERROR_RETRY_AFTER_SECONDS, 2 ** (deliveryCount - 1)), HANDLER_ERROR_MAX_RETRY_AFTER_SECONDS);
@@ -128235,28 +128372,30 @@ function createResolveLatestDeploymentId(config2) {
128235
128372
  if (!currentDeploymentId) {
128236
128373
  throw new Error("Cannot resolve latest deployment: VERCEL_DEPLOYMENT_ID environment variable is not set");
128237
128374
  }
128238
- const token = (config2 == null ? void 0 : config2.token) ?? process.env.VERCEL_TOKEN ?? await distExports.getVercelOidcToken().catch(() => null);
128375
+ const token = await resolveVercelApiToken(config2);
128239
128376
  if (!token) {
128240
128377
  throw new Error("Cannot resolve latest deployment: no OIDC token or VERCEL_TOKEN available");
128241
128378
  }
128242
128379
  const url2 = `https://api.vercel.com/v1/workflow/resolve-latest-deployment/${encodeURIComponent(currentDeploymentId)}`;
128243
- const response2 = await fetch(url2, {
128380
+ const response2 = await instrumentedFetch({
128244
128381
  method: "GET",
128245
- headers: {
128246
- Authorization: `Bearer ${token}`
128247
- },
128248
- // @ts-expect-error -- undici dispatcher is accepted by Node.js fetch but not in @types/node's RequestInit
128249
- dispatcher: getDispatcher(config2)
128250
- });
128251
- if (!response2.ok) {
128252
- let body2;
128253
- try {
128254
- body2 = await response2.text();
128255
- } catch {
128256
- body2 = "<unable to read response body>";
128382
+ url: url2,
128383
+ headers: new Headers({ Authorization: `Bearer ${token}` }),
128384
+ dispatcher: getDispatcher(config2),
128385
+ peerService: "vercel-api",
128386
+ // Preserve the prior no-timeout behavior for this Vercel-API call; the
128387
+ // shared RetryAgent still handles transient/5xx retries.
128388
+ timeoutMs: null,
128389
+ buildError: async (res) => {
128390
+ let body2;
128391
+ try {
128392
+ body2 = await res.text();
128393
+ } catch {
128394
+ body2 = "<unable to read response body>";
128395
+ }
128396
+ return new Error(`Failed to resolve latest deployment for ${currentDeploymentId}: HTTP ${res.status} ${res.statusText}${body2 ? ` — ${body2}` : ""}`);
128257
128397
  }
128258
- throw new Error(`Failed to resolve latest deployment for ${currentDeploymentId}: HTTP ${response2.status} ${response2.statusText}${body2 ? ` — ${body2}` : ""}`);
128259
- }
128398
+ });
128260
128399
  const data = await response2.json();
128261
128400
  const result = ResolveLatestDeploymentResponseSchema.safeParse(data);
128262
128401
  if (!result.success) {
@@ -128265,6 +128404,181 @@ function createResolveLatestDeploymentId(config2) {
128265
128404
  return result.data.id;
128266
128405
  };
128267
128406
  }
128407
+ const EVENT_RETRY_ELIGIBILITY = {
128408
+ // Creates: conditional create → 409 EntityConflictError if it already exists.
128409
+ run_created: {
128410
+ retryable: true,
128411
+ reason: "conditional create → 409 if exists"
128412
+ },
128413
+ step_created: {
128414
+ retryable: true,
128415
+ reason: "conditional create → 409 if exists"
128416
+ },
128417
+ wait_created: {
128418
+ retryable: true,
128419
+ reason: "conditional create → 409 if exists"
128420
+ },
128421
+ hook_created: {
128422
+ retryable: true,
128423
+ reason: "transactional token uniqueness → 409 if exists"
128424
+ },
128425
+ // Run start: early-returns if already running, writes no duplicate row.
128426
+ run_started: {
128427
+ retryable: true,
128428
+ reason: "early-returns if already running, no duplicate row"
128429
+ },
128430
+ // Terminal transitions: conditional `.where()` excludes terminal states →
128431
+ // 409 before the event row is written.
128432
+ run_completed: {
128433
+ retryable: true,
128434
+ reason: "terminal-state guard → 409, no duplicate row"
128435
+ },
128436
+ run_failed: {
128437
+ retryable: true,
128438
+ reason: "terminal-state guard → 409, no duplicate row"
128439
+ },
128440
+ run_cancelled: {
128441
+ retryable: true,
128442
+ reason: "terminal-state guard → 409, no duplicate row"
128443
+ },
128444
+ step_completed: {
128445
+ retryable: true,
128446
+ reason: "terminal-state guard → 409, no duplicate row"
128447
+ },
128448
+ step_failed: {
128449
+ retryable: true,
128450
+ reason: "terminal-state guard → 409, no duplicate row"
128451
+ },
128452
+ wait_completed: {
128453
+ retryable: true,
128454
+ reason: "waiting-state guard → 409, no duplicate row"
128455
+ },
128456
+ hook_disposed: {
128457
+ retryable: true,
128458
+ reason: "conditional delete (exists) → 409, no duplicate row"
128459
+ },
128460
+ // True idempotency via a correlationId constraint that reuses the eventId.
128461
+ attr_set: {
128462
+ retryable: true,
128463
+ reason: "correlationId constraint reuses eventId (idempotent replay)"
128464
+ },
128465
+ // NOT safe to retry — see the module comment.
128466
+ step_started: {
128467
+ retryable: false,
128468
+ reason: "unconditional attempt increment → a retry double-counts attempts"
128469
+ },
128470
+ step_retrying: {
128471
+ retryable: false,
128472
+ reason: "no duplicate guard → a retry appends a second event row"
128473
+ },
128474
+ hook_received: {
128475
+ retryable: false,
128476
+ reason: "no server guard → a retry duplicates the row / re-delivers payload"
128477
+ },
128478
+ // Server-originated; the SDK never POSTs it.
128479
+ hook_conflict: {
128480
+ retryable: false,
128481
+ reason: "server-originated; never POSTed by the SDK"
128482
+ }
128483
+ };
128484
+ const MAX_EVENT_POST_RETRIES = 2;
128485
+ const EVENT_POST_RETRY_BASE_MS = 100;
128486
+ const EVENT_POST_RETRY_JITTER_MS = 50;
128487
+ const TRANSIENT_CODES = /* @__PURE__ */ new Set([
128488
+ "ECONNRESET",
128489
+ "ECONNREFUSED",
128490
+ "ENOTFOUND",
128491
+ "ENETDOWN",
128492
+ "ENETUNREACH",
128493
+ "EHOSTDOWN",
128494
+ "EHOSTUNREACH",
128495
+ "EPIPE",
128496
+ "ETIMEDOUT",
128497
+ "UND_ERR_SOCKET",
128498
+ "UND_ERR_REQ_RETRY",
128499
+ "UND_ERR_CONNECT_TIMEOUT",
128500
+ "UND_ERR_HEADERS_TIMEOUT",
128501
+ "UND_ERR_BODY_TIMEOUT",
128502
+ // Names (undici/Node surface these on the error or its cause).
128503
+ // `TimeoutError` is our own per-request deadline (`AbortSignal.timeout` in
128504
+ // makeRequest) — a genuinely ambiguous failure worth retrying. We deliberately
128505
+ // do NOT include `AbortError`: that is how an external/caller-supplied
128506
+ // cancellation surfaces (makeRequest composes the caller's signal via
128507
+ // `AbortSignal.any`), and re-issuing a write the caller asked to cancel —
128508
+ // stalling the abort by the full backoff budget — would be wrong.
128509
+ "TimeoutError",
128510
+ "RequestRetryError"
128511
+ ]);
128512
+ function collectErrorMarkers(err, depth = 0) {
128513
+ if (depth > 5 || err === null || typeof err !== "object")
128514
+ return [];
128515
+ const markers2 = [];
128516
+ const e = err;
128517
+ if (typeof e.code === "string")
128518
+ markers2.push(e.code);
128519
+ if (typeof e.name === "string")
128520
+ markers2.push(e.name);
128521
+ if (e.cause)
128522
+ markers2.push(...collectErrorMarkers(e.cause, depth + 1));
128523
+ return markers2;
128524
+ }
128525
+ function isRetryableEventPostError(err) {
128526
+ if (EntityConflictError.is(err) || RunExpiredError.is(err) || TooEarlyError.is(err) || ThrottleError.is(err)) {
128527
+ return false;
128528
+ }
128529
+ if (WorkflowWorldError.is(err)) {
128530
+ if (err.code === "PARSE_ERROR")
128531
+ return true;
128532
+ if (typeof err.status === "number") {
128533
+ return err.status >= 500 && err.status <= 599;
128534
+ }
128535
+ }
128536
+ return collectErrorMarkers(err).some((m2) => TRANSIENT_CODES.has(m2));
128537
+ }
128538
+ const sleep$1 = (ms2) => new Promise((resolve2) => setTimeout(resolve2, ms2));
128539
+ const RETRY_DEBUG_ENABLED = typeof process !== "undefined" && typeof process.env.DEBUG === "string" && (process.env.DEBUG.includes("workflow:") || process.env.DEBUG === "*");
128540
+ function logRetry(message2, fields) {
128541
+ if (!RETRY_DEBUG_ENABLED)
128542
+ return;
128543
+ const suffix = Object.entries(fields).map(([k2, v2]) => `${k2}=${v2}`).join(" ");
128544
+ console.debug(`[workflow:world-vercel:event-retry] ${message2} ${suffix}`);
128545
+ }
128546
+ function errorMarker(err) {
128547
+ if (WorkflowWorldError.is(err)) {
128548
+ return err.code ?? (err.status != null ? `status_${err.status}` : err.name);
128549
+ }
128550
+ return collectErrorMarkers(err)[0] ?? (err instanceof Error ? err.name : "unknown");
128551
+ }
128552
+ async function withEventPostRetry(fn2, eventType) {
128553
+ var _a3;
128554
+ const retryable = ((_a3 = EVENT_RETRY_ELIGIBILITY[eventType]) == null ? void 0 : _a3.retryable) ?? false;
128555
+ for (let attempt = 0; ; attempt++) {
128556
+ try {
128557
+ return await fn2();
128558
+ } catch (err) {
128559
+ const transient = retryable && isRetryableEventPostError(err);
128560
+ if (transient && attempt < MAX_EVENT_POST_RETRIES) {
128561
+ const backoff = EVENT_POST_RETRY_BASE_MS * 2 ** attempt + Math.floor(Math.random() * EVENT_POST_RETRY_JITTER_MS);
128562
+ logRetry("retrying event POST after transient failure", {
128563
+ eventType,
128564
+ attempt: attempt + 1,
128565
+ backoffMs: backoff,
128566
+ error: errorMarker(err)
128567
+ });
128568
+ await sleep$1(backoff);
128569
+ continue;
128570
+ }
128571
+ if (transient) {
128572
+ logRetry("exhausted in-process retries; surfacing for queue redelivery", {
128573
+ eventType,
128574
+ attempts: attempt + 1,
128575
+ error: errorMarker(err)
128576
+ });
128577
+ }
128578
+ throw err;
128579
+ }
128580
+ }
128581
+ }
128268
128582
  const V4_FRAME_CONTENT_TYPE = "application/vnd.workflow.v4-frames";
128269
128583
  function encodeFrame(meta2, body2) {
128270
128584
  const metaBytes = new Uint8Array(encode(meta2));
@@ -128334,15 +128648,16 @@ async function* readerToIterator(reader) {
128334
128648
  yield value;
128335
128649
  }
128336
128650
  }
128337
- async function fetchV4(url2, init2, config2) {
128338
- init2.headers.set("X-Request-Time", Date.now().toString());
128339
- await injectTraceContextIntoHeaders(init2.headers);
128340
- return fetch(url2, {
128651
+ async function fetchV4(url2, init2, config2, opName) {
128652
+ return instrumentedFetch({
128341
128653
  method: init2.method,
128654
+ url: url2,
128342
128655
  headers: init2.headers,
128343
128656
  body: init2.body,
128344
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- undici dispatcher type doesn't match @types/node's RequestInit
128345
- dispatcher: getEventsDispatcher(config2)
128657
+ dispatcher: getEventsDispatcher(config2),
128658
+ timeoutMs: null,
128659
+ logLabel: opName,
128660
+ buildError: async (response2) => errorFromV4Response(response2.status, headersToRecord(response2.headers), await response2.text(), opName, url2)
128346
128661
  });
128347
128662
  }
128348
128663
  function headersToRecord(headers2) {
@@ -128409,7 +128724,7 @@ function buildPostFrameMeta(input) {
128409
128724
  meta2.skipPreload = input.skipPreload;
128410
128725
  return meta2;
128411
128726
  }
128412
- function throwForErrorResponse(statusCode, responseHeaders, errorBody, opName, url2) {
128727
+ function errorFromV4Response(statusCode, responseHeaders, errorBody, opName, url2) {
128413
128728
  let message2 = `v4 ${opName} failed: HTTP ${statusCode}`;
128414
128729
  let code2;
128415
128730
  try {
@@ -128422,26 +128737,12 @@ function throwForErrorResponse(statusCode, responseHeaders, errorBody, opName, u
128422
128737
  if (errorBody)
128423
128738
  message2 += ` ${errorBody}`;
128424
128739
  }
128425
- let retryAfter;
128426
- const retryAfterHeader = readHeader(responseHeaders, "retry-after");
128427
- if (retryAfterHeader) {
128428
- const parsed = parseInt(retryAfterHeader, 10);
128429
- if (!Number.isNaN(parsed))
128430
- retryAfter = parsed;
128431
- }
128432
- if (statusCode === 409)
128433
- throw new EntityConflictError(message2);
128434
- if (statusCode === 410)
128435
- throw new RunExpiredError(message2);
128436
- if (statusCode === 425)
128437
- throw new TooEarlyError(message2, { retryAfter });
128438
- if (statusCode === 429)
128439
- throw new ThrottleError(message2, { retryAfter });
128440
- throw new WorkflowWorldError(message2, {
128441
- status: statusCode,
128740
+ const retryAfter = parseRetryAfter(readHeader(responseHeaders, "retry-after"));
128741
+ return errorForResponse(statusCode, message2, {
128742
+ retryAfter,
128442
128743
  code: code2,
128443
128744
  url: url2,
128444
- retryAfter
128745
+ mitigated: readHeader(responseHeaders, "x-vercel-mitigated")
128445
128746
  });
128446
128747
  }
128447
128748
  async function createWorkflowRunEventV4(input, config2) {
@@ -128450,11 +128751,7 @@ async function createWorkflowRunEventV4(input, config2) {
128450
128751
  headers2.set("Content-Type", "application/octet-stream");
128451
128752
  const frame2 = encodeFrame(buildPostFrameMeta(input), input.payload ?? new Uint8Array(0));
128452
128753
  const url2 = `${baseUrl}/v4/runs/${encodeURIComponent(input.runId)}/events/${encodeURIComponent(input.eventType)}`;
128453
- const response2 = await fetchV4(url2, { method: "POST", headers: headers2, body: frame2 }, config2);
128454
- if (!response2.ok) {
128455
- const errorBody = await response2.text();
128456
- throwForErrorResponse(response2.status, headersToRecord(response2.headers), errorBody, "createEvent", url2);
128457
- }
128754
+ const response2 = await fetchV4(url2, { method: "POST", headers: headers2, body: frame2 }, config2, "createEvent");
128458
128755
  const eventId = response2.headers.get(V4_RESPONSE_HEADERS.eventId);
128459
128756
  const runId = response2.headers.get(V4_RESPONSE_HEADERS.runId);
128460
128757
  const createdAt = response2.headers.get(V4_RESPONSE_HEADERS.createdAt);
@@ -128476,11 +128773,7 @@ function readHeader(responseHeaders, name2) {
128476
128773
  async function getEventV4(runId, eventId, config2) {
128477
128774
  const { baseUrl, headers: headers2 } = await getHttpConfig(config2);
128478
128775
  const url2 = `${baseUrl}/v4/runs/${encodeURIComponent(runId)}/events/${encodeURIComponent(eventId)}`;
128479
- const response2 = await fetchV4(url2, { method: "GET", headers: headers2 }, config2);
128480
- if (!response2.ok) {
128481
- const errorBody = await response2.text();
128482
- throwForErrorResponse(response2.status, headersToRecord(response2.headers), errorBody, "getEvent", url2);
128483
- }
128776
+ const response2 = await fetchV4(url2, { method: "GET", headers: headers2 }, config2, "getEvent");
128484
128777
  const contentType = response2.headers.get("content-type");
128485
128778
  if (!(contentType == null ? void 0 : contentType.startsWith(V4_FRAME_CONTENT_TYPE))) {
128486
128779
  throw new Error(`v4 getEvent: expected ${V4_FRAME_CONTENT_TYPE}, got ${contentType ?? "(none)"}`);
@@ -128492,11 +128785,7 @@ async function getEventV4(runId, eventId, config2) {
128492
128785
  throw new Error(`v4 getEvent: empty frame stream for ${eventId}`);
128493
128786
  }
128494
128787
  async function consumeListFrameStream(url2, headers2, config2, opName) {
128495
- const response2 = await fetchV4(url2, { method: "GET", headers: headers2 }, config2);
128496
- if (!response2.ok) {
128497
- const errorBody = await response2.text();
128498
- throwForErrorResponse(response2.status, headersToRecord(response2.headers), errorBody, opName, url2);
128499
- }
128788
+ const response2 = await fetchV4(url2, { method: "GET", headers: headers2 }, config2, opName);
128500
128789
  const contentType = response2.headers.get("content-type");
128501
128790
  if (!(contentType == null ? void 0 : contentType.startsWith(V4_FRAME_CONTENT_TYPE))) {
128502
128791
  throw new Error(`v4 ${opName}: expected ${V4_FRAME_CONTENT_TYPE}, got ${contentType ?? "(none)"}`);
@@ -128937,7 +129226,7 @@ async function getWorkflowRunEvents(params, config2) {
128937
129226
  }
128938
129227
  async function createWorkflowRunEvent(id2, data, params, config2) {
128939
129228
  try {
128940
- return await createWorkflowRunEventInner(id2, data, params, config2);
129229
+ return await withEventPostRetry(() => createWorkflowRunEventInner(id2, data, params, config2), data.eventType);
128941
129230
  } catch (err) {
128942
129231
  if (hookEventsRequiringExistence.has(data.eventType) && WorkflowWorldError.is(err) && err.status === 404 && data.correlationId) {
128943
129232
  throw new HookNotFoundError(data.correlationId);
@@ -129123,13 +129412,10 @@ function getStreamReadUrl(name2, runId, httpConfig) {
129123
129412
  return new URL(`${httpConfig.baseUrl}/v3/runs/${encodeURIComponent(runId)}/stream/${encodeURIComponent(name2)}`);
129124
129413
  }
129125
129414
  function createStreamRequestError(operation, url2, response2, text2) {
129126
- const context = [`PUT ${url2.origin}${url2.pathname}`];
129127
- for (const header of ["x-vercel-id", "x-vercel-error"]) {
129128
- const value = response2.headers.get(header);
129129
- if (value) {
129130
- context.push(`${header}=${value}`);
129131
- }
129132
- }
129415
+ const context = [
129416
+ `PUT ${url2.origin}${url2.pathname}`,
129417
+ ...getVercelDiagnostics(response2.headers)
129418
+ ];
129133
129419
  return new Error(`Stream ${operation} failed: HTTP ${response2.status} (${context.join("; ")}): ${text2}`);
129134
129420
  }
129135
129421
  function encodeMultiChunks(chunks) {
@@ -129172,17 +129458,17 @@ function createStreamer(config2) {
129172
129458
  const resolvedRunId = await runId;
129173
129459
  const httpConfig = await getHttpConfig(config2);
129174
129460
  const url2 = getStreamUrl(name2, resolvedRunId, httpConfig);
129175
- const response2 = await fetch(url2, {
129461
+ const response2 = await instrumentedFetch({
129176
129462
  method: "PUT",
129463
+ url: url2.toString(),
129177
129464
  body: chunk,
129178
129465
  headers: httpConfig.headers,
129179
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- undici dispatcher type doesn't match @types/node's RequestInit
129180
- dispatcher: getStreamDispatcher(config2)
129466
+ dispatcher: getStreamDispatcher(config2),
129467
+ timeoutMs: null,
129468
+ logLabel: url2.pathname,
129469
+ buildError: async (res) => createStreamRequestError("write", url2, res, await res.text())
129181
129470
  });
129182
- const text2 = await response2.text();
129183
- if (!response2.ok) {
129184
- throw createStreamRequestError("write", url2, response2, text2);
129185
- }
129471
+ await response2.text();
129186
129472
  },
129187
129473
  async writeMulti(runId, name2, chunks) {
129188
129474
  if (chunks.length === 0)
@@ -129194,17 +129480,17 @@ function createStreamer(config2) {
129194
129480
  const batch = chunks.slice(i, i + MAX_CHUNKS_PER_REQUEST);
129195
129481
  const body2 = encodeMultiChunks(batch);
129196
129482
  const url2 = getStreamUrl(name2, resolvedRunId, httpConfig);
129197
- const response2 = await fetch(url2, {
129483
+ const response2 = await instrumentedFetch({
129198
129484
  method: "PUT",
129485
+ url: url2.toString(),
129199
129486
  body: body2,
129200
129487
  headers: httpConfig.headers,
129201
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- undici dispatcher type doesn't match @types/node's RequestInit
129202
- dispatcher: getStreamDispatcher(config2)
129488
+ dispatcher: getStreamDispatcher(config2),
129489
+ timeoutMs: null,
129490
+ logLabel: url2.pathname,
129491
+ buildError: async (res) => createStreamRequestError("write", url2, res, await res.text())
129203
129492
  });
129204
- const text2 = await response2.text();
129205
- if (!response2.ok) {
129206
- throw createStreamRequestError("write", url2, response2, text2);
129207
- }
129493
+ await response2.text();
129208
129494
  }
129209
129495
  },
129210
129496
  async close(runId, name2) {
@@ -129212,16 +129498,16 @@ function createStreamer(config2) {
129212
129498
  const httpConfig = await getHttpConfig(config2);
129213
129499
  httpConfig.headers.set("X-Stream-Done", "true");
129214
129500
  const url2 = getStreamUrl(name2, resolvedRunId, httpConfig);
129215
- const response2 = await fetch(url2, {
129501
+ const response2 = await instrumentedFetch({
129216
129502
  method: "PUT",
129503
+ url: url2.toString(),
129217
129504
  headers: httpConfig.headers,
129218
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- undici dispatcher type doesn't match @types/node's RequestInit
129219
- dispatcher: getStreamDispatcher(config2)
129505
+ dispatcher: getStreamDispatcher(config2),
129506
+ timeoutMs: null,
129507
+ logLabel: url2.pathname,
129508
+ buildError: async (res) => createStreamRequestError("close", url2, res, await res.text())
129220
129509
  });
129221
- const text2 = await response2.text();
129222
- if (!response2.ok) {
129223
- throw createStreamRequestError("close", url2, response2, text2);
129224
- }
129510
+ await response2.text();
129225
129511
  },
129226
129512
  async get(runId, name2, startIndex) {
129227
129513
  const httpConfig = await getHttpConfig(config2);
@@ -129229,12 +129515,15 @@ function createStreamer(config2) {
129229
129515
  if (typeof startIndex === "number") {
129230
129516
  url2.searchParams.set("startIndex", String(startIndex));
129231
129517
  }
129232
- const response2 = await fetch(url2, {
129233
- headers: httpConfig.headers
129518
+ const response2 = await instrumentedFetch({
129519
+ method: "GET",
129520
+ url: url2.toString(),
129521
+ headers: httpConfig.headers,
129522
+ dispatcher: void 0,
129523
+ timeoutMs: null,
129524
+ logLabel: url2.pathname,
129525
+ buildError: (res) => new Error(`Failed to fetch stream: ${res.status}`)
129234
129526
  });
129235
- if (!response2.ok) {
129236
- throw new Error(`Failed to fetch stream: ${response2.status}`);
129237
- }
129238
129527
  if (!response2.body) {
129239
129528
  throw new Error("No response body for stream");
129240
129529
  }
@@ -129267,12 +129556,15 @@ function createStreamer(config2) {
129267
129556
  async list(runId) {
129268
129557
  const httpConfig = await getHttpConfig(config2);
129269
129558
  const url2 = new URL(`${httpConfig.baseUrl}/v2/runs/${encodeURIComponent(runId)}/streams`);
129270
- const response2 = await fetch(url2, {
129271
- headers: httpConfig.headers
129559
+ const response2 = await instrumentedFetch({
129560
+ method: "GET",
129561
+ url: url2.toString(),
129562
+ headers: httpConfig.headers,
129563
+ dispatcher: void 0,
129564
+ timeoutMs: null,
129565
+ logLabel: url2.pathname,
129566
+ buildError: (res) => new Error(`Failed to list streams: ${res.status}`)
129272
129567
  });
129273
- if (!response2.ok) {
129274
- throw new Error(`Failed to list streams: ${response2.status}`);
129275
- }
129276
129568
  return await response2.json();
129277
129569
  }
129278
129570
  }
@@ -132361,7 +132653,7 @@ async function start$1(workflow, argsOrOptions, options) {
132361
132653
  if (runCreatedResult.status === "rejected") {
132362
132654
  const err = runCreatedResult.reason;
132363
132655
  if (EntityConflictError.is(err)) ;
132364
- else if (isRetryableStartError(err)) {
132656
+ else if (isRetryableWorldError(err)) {
132365
132657
  resilientStart = true;
132366
132658
  runtimeLogger.warn("Run creation event failed, but the run was accepted via the queue. The run_created event will be re-tried async by the runtime.", { workflowRunId: runId, error: err.message });
132367
132659
  } else {
@@ -132391,13 +132683,6 @@ async function start$1(workflow, argsOrOptions, options) {
132391
132683
  });
132392
132684
  });
132393
132685
  }
132394
- function isRetryableStartError(err) {
132395
- if (ThrottleError.is(err))
132396
- return true;
132397
- if (WorkflowWorldError.is(err) && err.status && err.status >= 500)
132398
- return true;
132399
- return false;
132400
- }
132401
132686
  const normalizeWorkflowArgs = (args) => {
132402
132687
  return Array.isArray(args) ? args : [args];
132403
132688
  };