@withone/cli 1.47.6 → 1.47.7
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.
|
@@ -1289,7 +1289,7 @@ async function executeSubflowStep(step, context, api, permissions, allowedAction
|
|
|
1289
1289
|
if (flowStack.includes(resolvedKey)) {
|
|
1290
1290
|
throw new Error(`Circular flow detected: ${[...flowStack, resolvedKey].join(" \u2192 ")}`);
|
|
1291
1291
|
}
|
|
1292
|
-
const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-
|
|
1292
|
+
const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-7VRNSKWU.js");
|
|
1293
1293
|
const { flow: subFlow, rootDir: subRootDir } = loadFlowWithMeta2(resolvedKey);
|
|
1294
1294
|
const subContext = await executeFlow(
|
|
1295
1295
|
subFlow,
|
|
@@ -1503,16 +1503,17 @@ async function executeSingleStep(step, context, api, permissions, allowedActionI
|
|
|
1503
1503
|
}
|
|
1504
1504
|
const startTime = Date.now();
|
|
1505
1505
|
let lastError;
|
|
1506
|
-
const
|
|
1506
|
+
const onError = step.onError ?? context._defaultOnError;
|
|
1507
|
+
const maxAttempts = onError?.strategy === "retry" && onError.retries ? onError.retries + 1 : 1;
|
|
1507
1508
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
1508
1509
|
try {
|
|
1509
1510
|
if (attempt > 1) {
|
|
1510
|
-
const delay = computeRetryDelay(
|
|
1511
|
+
const delay = computeRetryDelay(onError, attempt);
|
|
1511
1512
|
options.onEvent?.({
|
|
1512
1513
|
event: "step:retry",
|
|
1513
1514
|
stepId: step.id,
|
|
1514
1515
|
attempt,
|
|
1515
|
-
maxRetries:
|
|
1516
|
+
maxRetries: onError.retries,
|
|
1516
1517
|
delayMs: delay
|
|
1517
1518
|
});
|
|
1518
1519
|
await sleep2(delay);
|
|
@@ -1599,8 +1600,8 @@ async function executeSingleStep(step, context, api, permissions, allowedActionI
|
|
|
1599
1600
|
if (attempt === maxAttempts) {
|
|
1600
1601
|
break;
|
|
1601
1602
|
}
|
|
1602
|
-
if (
|
|
1603
|
-
const decision = shouldRetryError(lastError,
|
|
1603
|
+
if (onError?.strategy === "retry" && (onError.retryOn || onError.failFastOn)) {
|
|
1604
|
+
const decision = shouldRetryError(lastError, onError);
|
|
1604
1605
|
if (!decision.retry) {
|
|
1605
1606
|
options.onEvent?.({
|
|
1606
1607
|
event: "step:retry-skip",
|
|
@@ -1614,7 +1615,7 @@ async function executeSingleStep(step, context, api, permissions, allowedActionI
|
|
|
1614
1615
|
}
|
|
1615
1616
|
}
|
|
1616
1617
|
const errorMessage = lastError?.message || "Unknown error";
|
|
1617
|
-
const strategy =
|
|
1618
|
+
const strategy = onError?.strategy || "fail";
|
|
1618
1619
|
const retriesUsed = Math.max(0, maxAttempts - 1);
|
|
1619
1620
|
const isTimeout = lastError instanceof StepTimeoutError;
|
|
1620
1621
|
const errorCode = lastError?.errorCode;
|
|
@@ -1629,7 +1630,7 @@ async function executeSingleStep(step, context, api, permissions, allowedActionI
|
|
|
1629
1630
|
context.steps[step.id] = result;
|
|
1630
1631
|
return result;
|
|
1631
1632
|
}
|
|
1632
|
-
if (strategy === "fallback" &&
|
|
1633
|
+
if (strategy === "fallback" && onError?.fallbackStepId) {
|
|
1633
1634
|
const result = {
|
|
1634
1635
|
status: isTimeout ? "timeout" : "failed",
|
|
1635
1636
|
error: errorMessage,
|
|
@@ -1750,6 +1751,7 @@ async function executeFlow(flow, inputs, api, permissions, allowedActionIds, opt
|
|
|
1750
1751
|
loop: {}
|
|
1751
1752
|
};
|
|
1752
1753
|
context.input = resolvedInputs;
|
|
1754
|
+
context._defaultOnError = flow.defaultOnError;
|
|
1753
1755
|
const completedStepIds = resumeState ? new Set(resumeState.completedSteps) : void 0;
|
|
1754
1756
|
if (options.dryRun && !options.mock) {
|
|
1755
1757
|
options.onEvent?.({
|
|
@@ -1807,7 +1809,8 @@ var FLOW_SCHEMA = {
|
|
|
1807
1809
|
description: { type: "string", required: false, description: "What this flow does" },
|
|
1808
1810
|
version: { type: "string", required: false, description: "Semver or arbitrary version string" },
|
|
1809
1811
|
inputs: { type: "object", required: true, description: "Input declarations (Record<string, InputDeclaration>)" },
|
|
1810
|
-
steps: { type: "array", required: true, description: "Ordered array of steps", stepsArray: true }
|
|
1812
|
+
steps: { type: "array", required: true, description: "Ordered array of steps", stepsArray: true },
|
|
1813
|
+
defaultOnError: { type: "object", required: false, description: 'Default error strategy inherited by every step without its own `onError` (e.g. { "strategy": "continue" }). A step opts out with its own `onError`.' }
|
|
1811
1814
|
},
|
|
1812
1815
|
inputFields: {
|
|
1813
1816
|
type: { type: "string", required: true, description: "Data type: string, number, boolean, object, array", enum: ["string", "number", "boolean", "object", "array"] },
|
package/dist/index.js
CHANGED
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
searchCachePath,
|
|
31
31
|
validateActionInput,
|
|
32
32
|
writeCache
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-KWGN3RJR.js";
|
|
34
34
|
import {
|
|
35
35
|
memSqlCommand
|
|
36
36
|
} from "./chunk-QV3Y5N5G.js";
|
|
@@ -3101,6 +3101,16 @@ function validateFlowSchema(flow2) {
|
|
|
3101
3101
|
if (f.version !== void 0 && typeof f.version !== "string") {
|
|
3102
3102
|
errors.push({ path: "version", message: '"version" must be a string' });
|
|
3103
3103
|
}
|
|
3104
|
+
if (f.defaultOnError !== void 0) {
|
|
3105
|
+
if (!f.defaultOnError || typeof f.defaultOnError !== "object" || Array.isArray(f.defaultOnError)) {
|
|
3106
|
+
errors.push({ path: "defaultOnError", message: '"defaultOnError" must be an object (e.g. { "strategy": "continue" })' });
|
|
3107
|
+
} else {
|
|
3108
|
+
const oe = f.defaultOnError;
|
|
3109
|
+
if (!FLOW_SCHEMA.errorStrategies.includes(oe.strategy)) {
|
|
3110
|
+
errors.push({ path: "defaultOnError.strategy", message: `Error strategy must be one of: ${FLOW_SCHEMA.errorStrategies.join(", ")}` });
|
|
3111
|
+
}
|
|
3112
|
+
}
|
|
3113
|
+
}
|
|
3104
3114
|
if (!f.inputs || typeof f.inputs !== "object" || Array.isArray(f.inputs)) {
|
|
3105
3115
|
errors.push({ path: "inputs", message: 'Flow must have an "inputs" object' });
|
|
3106
3116
|
} else {
|
package/package.json
CHANGED
|
@@ -566,6 +566,22 @@ the outputSchema declaration.
|
|
|
566
566
|
|
|
567
567
|
Strategies: `fail` (default), `continue`, `retry`, `fallback`.
|
|
568
568
|
|
|
569
|
+
**Flow-level default (cli#93).** Set `defaultOnError` at the top of the flow and every step without its own `onError` inherits it — handy when most steps should `continue` (e.g. rendering/formatting pipelines) and you don't want to repeat it N times. A step opts out by declaring its own `onError`:
|
|
570
|
+
|
|
571
|
+
```json
|
|
572
|
+
{
|
|
573
|
+
"key": "render-report",
|
|
574
|
+
"defaultOnError": { "strategy": "continue" },
|
|
575
|
+
"steps": [
|
|
576
|
+
{ "id": "critical", "onError": { "strategy": "fail" }, ... }, // stays fatal
|
|
577
|
+
{ "id": "chart", ... }, // inherits continue
|
|
578
|
+
{ "id": "thumbnail", ... } // inherits continue
|
|
579
|
+
]
|
|
580
|
+
}
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
Scoped per-flow: a sub-flow uses its own `defaultOnError`, not the parent's.
|
|
584
|
+
|
|
569
585
|
**Retry backoff.** By default each retry waits exactly `retryDelayMs`. For rate-limited APIs add `"backoff": "exponential"` (or `"exponential-jitter"`) and an optional `"maxDelayMs"` cap (defaults to 30000):
|
|
570
586
|
|
|
571
587
|
```json
|