@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.
- package/dist/.well-known/workflow/v1/flow.js +121 -39
- package/dist/.well-known/workflow/v1/flow.js.map +1 -1
- package/dist/.well-known/workflow/v1/manifest.json +28 -28
- package/dist/.well-known/workflow/v1/step.js +127 -41
- package/dist/.well-known/workflow/v1/step.js.map +1 -1
- package/package.json +3 -3
|
@@ -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 *
|
|
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(
|
|
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(
|
|
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}.
|
|
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}.
|
|
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}.
|
|
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
|
|
41390
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
45970
|
-
|
|
45971
|
-
|
|
45972
|
-
|
|
45973
|
-
|
|
45974
|
-
|
|
45975
|
-
|
|
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
|
-
|
|
45978
|
-
controller.enqueue(obj);
|
|
46051
|
+
controller.enqueue(parse3(line, revivers));
|
|
45979
46052
|
}
|
|
45980
46053
|
}
|
|
45981
46054
|
},
|
|
45982
46055
|
flush(controller) {
|
|
45983
|
-
if (buffer
|
|
45984
|
-
|
|
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,
|
|
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,
|
|
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.
|
|
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({
|