@workflow/world-testing 4.1.0-beta.56 → 4.1.0-beta.57

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.
@@ -40268,7 +40268,7 @@ async function withWindowsRetry(fn, maxRetries = 5) {
40268
40268
  const isRetryable = attempt < maxRetries && retryableErrors.includes(error45.code);
40269
40269
  if (!isRetryable)
40270
40270
  throw error45;
40271
- const delay = baseDelayMs * Math.pow(2, attempt) + Math.random() * baseDelayMs;
40271
+ const delay = baseDelayMs * 2 ** attempt + Math.random() * baseDelayMs;
40272
40272
  await new Promise((resolve2) => setTimeout(resolve2, delay));
40273
40273
  }
40274
40274
  }
@@ -40375,9 +40375,13 @@ async function deleteJSON(filePath) {
40375
40375
  }
40376
40376
  __name(deleteJSON, "deleteJSON");
40377
40377
  async function listJSONFiles(dirPath) {
40378
+ return listFilesByExtension(dirPath, ".json");
40379
+ }
40380
+ __name(listJSONFiles, "listJSONFiles");
40381
+ async function listFilesByExtension(dirPath, extension) {
40378
40382
  try {
40379
40383
  const files = await import_node_fs.promises.readdir(dirPath);
40380
- return files.filter((f) => f.endsWith(".json")).map((f) => f.replace(".json", ""));
40384
+ return files.filter((f) => f.endsWith(extension)).map((f) => f.slice(0, -extension.length));
40381
40385
  }
40382
40386
  catch (error45) {
40383
40387
  if (error45.code === "ENOENT")
@@ -40385,7 +40389,7 @@ async function listJSONFiles(dirPath) {
40385
40389
  throw error45;
40386
40390
  }
40387
40391
  }
40388
- __name(listJSONFiles, "listJSONFiles");
40392
+ __name(listFilesByExtension, "listFilesByExtension");
40389
40393
  function parseCursor(cursor) {
40390
40394
  if (!cursor)
40391
40395
  return null;
@@ -41294,7 +41298,7 @@ function createStreamer(basedir) {
41294
41298
  chunk: chunkBuffer,
41295
41299
  eof: false
41296
41300
  });
41297
- const chunkPath = import_node_path8.default.join(basedir, "streams", "chunks", `${name}-${chunkId}.json`);
41301
+ const chunkPath = import_node_path8.default.join(basedir, "streams", "chunks", `${name}-${chunkId}.bin`);
41298
41302
  await write(chunkPath, serialized);
41299
41303
  const chunkData = Uint8Array.from(chunkBuffer);
41300
41304
  streamEmitter.emit(`chunk:${name}`, {
@@ -41316,7 +41320,7 @@ function createStreamer(basedir) {
41316
41320
  chunk: chunkBuffer,
41317
41321
  eof: false
41318
41322
  });
41319
- const chunkPath = import_node_path8.default.join(basedir, "streams", "chunks", `${name}-${chunkId}.json`);
41323
+ const chunkPath = import_node_path8.default.join(basedir, "streams", "chunks", `${name}-${chunkId}.bin`);
41320
41324
  await write(chunkPath, serialized);
41321
41325
  return {
41322
41326
  chunkId,
@@ -41336,7 +41340,7 @@ function createStreamer(basedir) {
41336
41340
  const chunkId = `chnk_${monotonicUlid2()}`;
41337
41341
  const runId = await _runId;
41338
41342
  await registerStreamForRun(runId, name);
41339
- const chunkPath = import_node_path8.default.join(basedir, "streams", "chunks", `${name}-${chunkId}.json`);
41343
+ const chunkPath = import_node_path8.default.join(basedir, "streams", "chunks", `${name}-${chunkId}.bin`);
41340
41344
  await write(chunkPath, serializeChunk({ chunk: Buffer.from([]), eof: true }));
41341
41345
  streamEmitter.emit(`close:${name}`, { streamName: name });
41342
41346
  },
@@ -41386,8 +41390,16 @@ function createStreamer(basedir) {
41386
41390
  removeListeners = closeListener;
41387
41391
  streamEmitter.on(`chunk:${name}`, chunkListener);
41388
41392
  streamEmitter.on(`close:${name}`, closeListener);
41389
- const files = await listJSONFiles(chunksDir);
41390
- const chunkFiles = files.filter((file2) => file2.startsWith(`${name}-`)).sort();
41393
+ const [binFiles, jsonFiles] = await Promise.all([
41394
+ listFilesByExtension(chunksDir, ".bin"),
41395
+ listFilesByExtension(chunksDir, ".json")
41396
+ ]);
41397
+ const fileExtMap = /* @__PURE__ */ new Map();
41398
+ for (const f of jsonFiles)
41399
+ fileExtMap.set(f, ".json");
41400
+ for (const f of binFiles)
41401
+ fileExtMap.set(f, ".bin");
41402
+ const chunkFiles = [...fileExtMap.keys()].filter((file2) => file2.startsWith(`${name}-`)).sort();
41391
41403
  let isComplete = false;
41392
41404
  for (let i = startIndex; i < chunkFiles.length; i++) {
41393
41405
  const file2 = chunkFiles[i];
@@ -41395,7 +41407,8 @@ function createStreamer(basedir) {
41395
41407
  if (deliveredChunkIds.has(chunkId)) {
41396
41408
  continue;
41397
41409
  }
41398
- const chunk = deserializeChunk(await readBuffer(import_node_path8.default.join(chunksDir, `${file2}.json`)));
41410
+ const ext = fileExtMap.get(file2) ?? ".bin";
41411
+ const chunk = deserializeChunk(await readBuffer(import_node_path8.default.join(chunksDir, `${file2}${ext}`)));
41399
41412
  if (chunk?.eof === true) {
41400
41413
  isComplete = true;
41401
41414
  break;
@@ -44973,10 +44986,10 @@ var getWorld = /* @__PURE__ */ __name(() => {
44973
44986
  return globalSymbols[WorldCache];
44974
44987
  }, "getWorld");
44975
44988
  // ../core/dist/runtime/helpers.js
44976
- var SAFE_WORKFLOW_NAME_PATTERN = /^[a-zA-Z0-9_\-./]+$/;
44989
+ var SAFE_WORKFLOW_NAME_PATTERN = /^[a-zA-Z0-9_\-./@]+$/;
44977
44990
  function getWorkflowQueueName(workflowName) {
44978
44991
  if (!SAFE_WORKFLOW_NAME_PATTERN.test(workflowName)) {
44979
- throw new Error(`Invalid workflow name "${workflowName}": must only contain alphanumeric characters, underscores, hyphens, dots, or forward slashes`);
44992
+ throw new Error(`Invalid workflow name "${workflowName}": must only contain alphanumeric characters, underscores, hyphens, dots, forward slashes, or at signs`);
44980
44993
  }
44981
44994
  return `__wkf_workflow_${workflowName}`;
44982
44995
  }
@@ -45144,6 +45157,30 @@ async function withThrottleRetry(fn) {
45144
45157
  }
45145
45158
  }
45146
45159
  __name(withThrottleRetry, "withThrottleRetry");
45160
+ async function withServerErrorRetry(fn) {
45161
+ const delays = [500, 1e3, 2e3];
45162
+ for (let attempt = 0; attempt <= delays.length; attempt++) {
45163
+ try {
45164
+ return await fn();
45165
+ }
45166
+ catch (err) {
45167
+ if (WorkflowAPIError.is(err) && err.status !== void 0 && err.status >= 500 && attempt < delays.length) {
45168
+ runtimeLogger.warn("Server error (5xx) from workflow-server, retrying in-process", {
45169
+ status: err.status,
45170
+ attempt: attempt + 1,
45171
+ maxRetries: delays.length,
45172
+ nextDelayMs: delays[attempt],
45173
+ url: err.url
45174
+ });
45175
+ await new Promise((resolve2) => setTimeout(resolve2, delays[attempt]));
45176
+ continue;
45177
+ }
45178
+ throw err;
45179
+ }
45180
+ }
45181
+ throw new Error("withServerErrorRetry: unreachable");
45182
+ }
45183
+ __name(withServerErrorRetry, "withServerErrorRetry");
45147
45184
  // ../core/dist/runtime/suspension-handler.js
45148
45185
  var import_functions = __toESM(require_functions(), 1);
45149
45186
  // ../serde/dist/index.js
@@ -45944,14 +45981,19 @@ function getStreamType(stream) {
45944
45981
  }
45945
45982
  }
45946
45983
  __name(getStreamType, "getStreamType");
45984
+ var FRAME_HEADER_SIZE = 4;
45947
45985
  function getSerializeStream(reducers) {
45948
45986
  const encoder = new TextEncoder();
45949
45987
  const stream = new TransformStream({
45950
45988
  transform(chunk, controller) {
45951
45989
  try {
45952
45990
  const serialized = stringify(chunk, reducers);
45953
- controller.enqueue(encoder.encode(`${serialized}
45954
- `));
45991
+ const payload = encoder.encode(serialized);
45992
+ const prefixed = encodeWithFormatPrefix(SerializationFormat.DEVALUE_V1, payload);
45993
+ const frame = new Uint8Array(FRAME_HEADER_SIZE + prefixed.length);
45994
+ new DataView(frame.buffer).setUint32(0, prefixed.length, false);
45995
+ frame.set(prefixed, FRAME_HEADER_SIZE);
45996
+ controller.enqueue(frame);
45955
45997
  }
45956
45998
  catch (error45) {
45957
45999
  controller.error(new WorkflowRuntimeError(formatSerializationError("stream chunk", error45), { slug: "serialization-failed", cause: error45 }));
@@ -45963,26 +46005,56 @@ function getSerializeStream(reducers) {
45963
46005
  __name(getSerializeStream, "getSerializeStream");
45964
46006
  function getDeserializeStream(revivers) {
45965
46007
  const decoder2 = new TextDecoder();
45966
- let buffer = "";
46008
+ let buffer = new Uint8Array(0);
46009
+ function appendToBuffer(data) {
46010
+ const newBuffer = new Uint8Array(buffer.length + data.length);
46011
+ newBuffer.set(buffer, 0);
46012
+ newBuffer.set(data, buffer.length);
46013
+ buffer = newBuffer;
46014
+ }
46015
+ __name(appendToBuffer, "appendToBuffer");
46016
+ function processFrames(controller) {
46017
+ while (buffer.length >= FRAME_HEADER_SIZE) {
46018
+ const frameLength = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength).getUint32(0, false);
46019
+ if (buffer.length < FRAME_HEADER_SIZE + frameLength) {
46020
+ break;
46021
+ }
46022
+ const frameData = buffer.slice(FRAME_HEADER_SIZE, FRAME_HEADER_SIZE + frameLength);
46023
+ buffer = buffer.slice(FRAME_HEADER_SIZE + frameLength);
46024
+ const { format, payload } = decodeFormatPrefix(frameData);
46025
+ if (format === SerializationFormat.DEVALUE_V1) {
46026
+ const text = decoder2.decode(payload);
46027
+ controller.enqueue(parse3(text, revivers));
46028
+ }
46029
+ }
46030
+ }
46031
+ __name(processFrames, "processFrames");
45967
46032
  const stream = new TransformStream({
45968
46033
  transform(chunk, controller) {
45969
- buffer += decoder2.decode(chunk, { stream: true });
45970
- while (true) {
45971
- const newlineIndex = buffer.indexOf("\n");
45972
- if (newlineIndex === -1)
45973
- break;
45974
- const line = buffer.slice(0, newlineIndex);
45975
- buffer = buffer.slice(newlineIndex + 1);
46034
+ if (buffer.length === 0 && chunk.length >= FRAME_HEADER_SIZE) {
46035
+ const possibleLength = new DataView(chunk.buffer, chunk.byteOffset, chunk.byteLength).getUint32(0, false);
46036
+ if (possibleLength > 0 && possibleLength < 1e8) {
46037
+ appendToBuffer(chunk);
46038
+ processFrames(controller);
46039
+ return;
46040
+ }
46041
+ }
46042
+ else if (buffer.length > 0) {
46043
+ appendToBuffer(chunk);
46044
+ processFrames(controller);
46045
+ return;
46046
+ }
46047
+ const text = decoder2.decode(chunk);
46048
+ const lines = text.split("\n");
46049
+ for (const line of lines) {
45976
46050
  if (line.length > 0) {
45977
- const obj = parse3(line, revivers);
45978
- controller.enqueue(obj);
46051
+ controller.enqueue(parse3(line, revivers));
45979
46052
  }
45980
46053
  }
45981
46054
  },
45982
46055
  flush(controller) {
45983
- if (buffer && buffer.length > 0) {
45984
- const obj = parse3(buffer, revivers);
45985
- controller.enqueue(obj);
46056
+ if (buffer.length > 0) {
46057
+ processFrames(controller);
45986
46058
  }
45987
46059
  }
45988
46060
  });
@@ -48447,11 +48519,11 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
48447
48519
  });
48448
48520
  let step;
48449
48521
  try {
48450
- const startResult = await world.events.create(workflowRunId, {
48522
+ const startResult = await withServerErrorRetry(() => world.events.create(workflowRunId, {
48451
48523
  eventType: "step_started",
48452
48524
  specVersion: SPEC_VERSION_CURRENT,
48453
48525
  correlationId: stepId
48454
- });
48526
+ }));
48455
48527
  if (!startResult.step) {
48456
48528
  throw new WorkflowRuntimeError(`step_started event for "${stepId}" did not return step entity`);
48457
48529
  }
@@ -48487,7 +48559,7 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
48487
48559
  "step.name": stepName,
48488
48560
  "step.id": stepId
48489
48561
  });
48490
- await queueMessage(world, `__wkf_workflow_${workflowName}`, {
48562
+ await queueMessage(world, getWorkflowQueueName(workflowName), {
48491
48563
  runId: workflowRunId,
48492
48564
  traceCarrier: await serializeTraceCarrier(),
48493
48565
  requestedAt: /* @__PURE__ */ new Date()
@@ -48615,21 +48687,21 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
48615
48687
  throw err;
48616
48688
  }));
48617
48689
  const [, traceCarrier] = await Promise.all([
48618
- world.events.create(workflowRunId, {
48690
+ withServerErrorRetry(() => world.events.create(workflowRunId, {
48619
48691
  eventType: "step_completed",
48620
48692
  specVersion: SPEC_VERSION_CURRENT,
48621
48693
  correlationId: stepId,
48622
48694
  eventData: {
48623
48695
  result
48624
48696
  }
48625
- }),
48697
+ })),
48626
48698
  serializeTraceCarrier()
48627
48699
  ]);
48628
48700
  span?.setAttributes({
48629
48701
  ...StepStatus("completed"),
48630
48702
  ...StepResultType(typeof result)
48631
48703
  });
48632
- await queueMessage(world, `__wkf_workflow_${workflowName}`, {
48704
+ await queueMessage(world, getWorkflowQueueName(workflowName), {
48633
48705
  runId: workflowRunId,
48634
48706
  traceCarrier,
48635
48707
  requestedAt: /* @__PURE__ */ new Date()
@@ -48661,6 +48733,16 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
48661
48733
  });
48662
48734
  return;
48663
48735
  }
48736
+ if (err.status !== void 0 && err.status >= 500) {
48737
+ runtimeLogger.warn("Persistent server error (5xx) during step, deferring to queue retry", {
48738
+ status: err.status,
48739
+ workflowRunId,
48740
+ stepId,
48741
+ error: err.message,
48742
+ url: err.url
48743
+ });
48744
+ throw err;
48745
+ }
48664
48746
  }
48665
48747
  if (isFatal) {
48666
48748
  stepLogger.error("Encountered FatalError while executing step, bubbling up to parent workflow", {
@@ -48668,7 +48750,7 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
48668
48750
  stepName,
48669
48751
  errorStack: normalizedStack
48670
48752
  });
48671
- await world.events.create(workflowRunId, {
48753
+ await withServerErrorRetry(() => world.events.create(workflowRunId, {
48672
48754
  eventType: "step_failed",
48673
48755
  specVersion: SPEC_VERSION_CURRENT,
48674
48756
  correlationId: stepId,
@@ -48676,7 +48758,7 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
48676
48758
  error: normalizedError.message,
48677
48759
  stack: normalizedStack
48678
48760
  }
48679
- });
48761
+ }));
48680
48762
  span?.setAttributes({
48681
48763
  ...StepStatus("failed"),
48682
48764
  ...StepFatalError(true)
@@ -48699,7 +48781,7 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
48699
48781
  errorStack: normalizedStack
48700
48782
  });
48701
48783
  const errorMessage = `Step "${stepName}" failed after ${maxRetries2} ${pluralize("retry", "retries", maxRetries2)}: ${normalizedError.message}`;
48702
- await world.events.create(workflowRunId, {
48784
+ await withServerErrorRetry(() => world.events.create(workflowRunId, {
48703
48785
  eventType: "step_failed",
48704
48786
  specVersion: SPEC_VERSION_CURRENT,
48705
48787
  correlationId: stepId,
@@ -48707,7 +48789,7 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
48707
48789
  error: errorMessage,
48708
48790
  stack: normalizedStack
48709
48791
  }
48710
- });
48792
+ }));
48711
48793
  span?.setAttributes({
48712
48794
  ...StepStatus("failed"),
48713
48795
  ...StepRetryExhausted(true)
@@ -48730,7 +48812,7 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
48730
48812
  errorStack: normalizedStack
48731
48813
  });
48732
48814
  }
48733
- await world.events.create(workflowRunId, {
48815
+ await withServerErrorRetry(() => world.events.create(workflowRunId, {
48734
48816
  eventType: "step_retrying",
48735
48817
  specVersion: SPEC_VERSION_CURRENT,
48736
48818
  correlationId: stepId,
@@ -48741,7 +48823,7 @@ var stepHandler = getWorldHandlers().createQueueHandler("__wkf_step_", async (me
48741
48823
  retryAfter: err.retryAfter
48742
48824
  }
48743
48825
  }
48744
- });
48826
+ }));
48745
48827
  const timeoutSeconds = Math.max(1, RetryableError.is(err) ? Math.ceil((+err.retryAfter.getTime() - Date.now()) / 1e3) : 1);
48746
48828
  span?.setAttributes({
48747
48829
  ...StepRetryTimeoutSeconds(timeoutSeconds),
@@ -49172,7 +49254,7 @@ function getWritable(options = {}) {
49172
49254
  __name(getWritable, "getWritable");
49173
49255
 
49174
49256
  // ../workflow/dist/stdlib.js
49175
- var fetch = globalThis[Symbol.for("WORKFLOW_USE_STEP")]("step//workflow@4.1.0-beta.55//fetch");
49257
+ var fetch = globalThis[Symbol.for("WORKFLOW_USE_STEP")]("step//workflow@4.1.0-beta.56//fetch");
49176
49258
 
49177
49259
  // ../../node_modules/.pnpm/zod@4.1.11/node_modules/zod/v4/core/core.js
49178
49260
  var NEVER = Object.freeze({