callman-core 1.15.0 → 1.17.0
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/contract/contractValidator.d.ts.map +1 -1
- package/dist/contract/contractValidator.js +19 -2
- package/dist/contract/contractValidator.js.map +1 -1
- package/dist/contract/xpathResolver.d.ts +7 -0
- package/dist/contract/xpathResolver.d.ts.map +1 -0
- package/dist/contract/xpathResolver.js +69 -0
- package/dist/contract/xpathResolver.js.map +1 -0
- package/dist/host/connections.d.ts +3 -0
- package/dist/host/connections.d.ts.map +1 -1
- package/dist/host/connections.js +3 -0
- package/dist/host/connections.js.map +1 -1
- package/dist/host/db/connectionMapping.d.ts +3 -1
- package/dist/host/db/connectionMapping.d.ts.map +1 -1
- package/dist/host/db/connectionMapping.js +3 -0
- package/dist/host/db/connectionMapping.js.map +1 -1
- package/dist/host/db/db-query-reference.d.ts.map +1 -1
- package/dist/host/db/db-query-reference.js +12 -1
- package/dist/host/db/db-query-reference.js.map +1 -1
- package/dist/host/db/mssqlAdapter.d.ts +8 -0
- package/dist/host/db/mssqlAdapter.d.ts.map +1 -0
- package/dist/host/db/mssqlAdapter.js +118 -0
- package/dist/host/db/mssqlAdapter.js.map +1 -0
- package/dist/host/db/queryExecutor.d.ts.map +1 -1
- package/dist/host/db/queryExecutor.js +8 -0
- package/dist/host/db/queryExecutor.js.map +1 -1
- package/dist/host/db/sqlNormalize.d.ts +1 -1
- package/dist/host/db/sqlNormalize.d.ts.map +1 -1
- package/dist/host/db/types.d.ts +5 -1
- package/dist/host/db/types.d.ts.map +1 -1
- package/dist/host/index.d.ts +2 -1
- package/dist/host/index.d.ts.map +1 -1
- package/dist/host/index.js +2 -1
- package/dist/host/index.js.map +1 -1
- package/dist/host/redis/redisService.d.ts +17 -0
- package/dist/host/redis/redisService.d.ts.map +1 -1
- package/dist/host/redis/redisService.js +233 -40
- package/dist/host/redis/redisService.js.map +1 -1
- package/dist/host/redis/types.d.ts +4 -0
- package/dist/host/redis/types.d.ts.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/scenario-runner/adapters/helpers/request-helpers.d.ts.map +1 -1
- package/dist/scenario-runner/adapters/helpers/request-helpers.js +36 -2
- package/dist/scenario-runner/adapters/helpers/request-helpers.js.map +1 -1
- package/dist/scenario-runner/adapters/request-executor.d.ts.map +1 -1
- package/dist/scenario-runner/adapters/request-executor.js +35 -0
- package/dist/scenario-runner/adapters/request-executor.js.map +1 -1
- package/dist/scenario-runner/adapters/types.d.ts +5 -0
- package/dist/scenario-runner/adapters/types.d.ts.map +1 -1
- package/dist/scenario-runner/condition.d.ts +4 -0
- package/dist/scenario-runner/condition.d.ts.map +1 -1
- package/dist/scenario-runner/condition.js +91 -9
- package/dist/scenario-runner/condition.js.map +1 -1
- package/dist/scenario-runner/conditionTypes.d.ts +14 -0
- package/dist/scenario-runner/conditionTypes.d.ts.map +1 -1
- package/dist/scenario-runner/extraction.d.ts +10 -0
- package/dist/scenario-runner/extraction.d.ts.map +1 -0
- package/dist/scenario-runner/extraction.js +147 -0
- package/dist/scenario-runner/extraction.js.map +1 -0
- package/dist/scenario-runner/graphTraversal.d.ts +3 -0
- package/dist/scenario-runner/graphTraversal.d.ts.map +1 -1
- package/dist/scenario-runner/graphTraversal.js +4 -0
- package/dist/scenario-runner/graphTraversal.js.map +1 -1
- package/dist/scenario-runner/index.d.ts +1 -0
- package/dist/scenario-runner/index.d.ts.map +1 -1
- package/dist/scenario-runner/index.js +2 -0
- package/dist/scenario-runner/index.js.map +1 -1
- package/dist/scenario-runner/nodePolicy.d.ts.map +1 -1
- package/dist/scenario-runner/nodePolicy.js +3 -0
- package/dist/scenario-runner/nodePolicy.js.map +1 -1
- package/dist/scenario-runner/runScenario.d.ts.map +1 -1
- package/dist/scenario-runner/runScenario.js +357 -8
- package/dist/scenario-runner/runScenario.js.map +1 -1
- package/dist/scenario-runner/types.d.ts +90 -5
- package/dist/scenario-runner/types.d.ts.map +1 -1
- package/dist/script/types.d.ts +4 -0
- package/dist/script/types.d.ts.map +1 -1
- package/dist/soap/envelope.d.ts +4 -0
- package/dist/soap/envelope.d.ts.map +1 -0
- package/dist/soap/envelope.js +25 -0
- package/dist/soap/envelope.js.map +1 -0
- package/dist/soap/transport.d.ts +22 -0
- package/dist/soap/transport.d.ts.map +1 -0
- package/dist/soap/transport.js +58 -0
- package/dist/soap/transport.js.map +1 -0
- package/dist/soap/wsSecurity.d.ts +19 -0
- package/dist/soap/wsSecurity.d.ts.map +1 -0
- package/dist/soap/wsSecurity.js +66 -0
- package/dist/soap/wsSecurity.js.map +1 -0
- package/dist-cjs/contract/contractValidator.js +19 -2
- package/dist-cjs/contract/contractValidator.js.map +1 -1
- package/dist-cjs/contract/xpathResolver.js +76 -0
- package/dist-cjs/contract/xpathResolver.js.map +1 -0
- package/dist-cjs/host/connections.js +3 -0
- package/dist-cjs/host/connections.js.map +1 -1
- package/dist-cjs/host/db/connectionMapping.js +3 -0
- package/dist-cjs/host/db/connectionMapping.js.map +1 -1
- package/dist-cjs/host/db/db-query-reference.js +12 -1
- package/dist-cjs/host/db/db-query-reference.js.map +1 -1
- package/dist-cjs/host/db/mssqlAdapter.js +124 -0
- package/dist-cjs/host/db/mssqlAdapter.js.map +1 -0
- package/dist-cjs/host/db/queryExecutor.js +8 -0
- package/dist-cjs/host/db/queryExecutor.js.map +1 -1
- package/dist-cjs/host/index.js +8 -1
- package/dist-cjs/host/index.js.map +1 -1
- package/dist-cjs/host/redis/redisService.js +237 -42
- package/dist-cjs/host/redis/redisService.js.map +1 -1
- package/dist-cjs/index.js +13 -1
- package/dist-cjs/index.js.map +1 -1
- package/dist-cjs/scenario-runner/adapters/helpers/request-helpers.js +36 -2
- package/dist-cjs/scenario-runner/adapters/helpers/request-helpers.js.map +1 -1
- package/dist-cjs/scenario-runner/adapters/request-executor.js +35 -0
- package/dist-cjs/scenario-runner/adapters/request-executor.js.map +1 -1
- package/dist-cjs/scenario-runner/condition.js +93 -10
- package/dist-cjs/scenario-runner/condition.js.map +1 -1
- package/dist-cjs/scenario-runner/extraction.js +151 -0
- package/dist-cjs/scenario-runner/extraction.js.map +1 -0
- package/dist-cjs/scenario-runner/graphTraversal.js +5 -1
- package/dist-cjs/scenario-runner/graphTraversal.js.map +1 -1
- package/dist-cjs/scenario-runner/index.js +2 -0
- package/dist-cjs/scenario-runner/index.js.map +1 -1
- package/dist-cjs/scenario-runner/nodePolicy.js +3 -0
- package/dist-cjs/scenario-runner/nodePolicy.js.map +1 -1
- package/dist-cjs/scenario-runner/runScenario.js +355 -6
- package/dist-cjs/scenario-runner/runScenario.js.map +1 -1
- package/dist-cjs/soap/envelope.js +29 -0
- package/dist-cjs/soap/envelope.js.map +1 -0
- package/dist-cjs/soap/transport.js +62 -0
- package/dist-cjs/soap/transport.js.map +1 -0
- package/dist-cjs/soap/wsSecurity.js +74 -0
- package/dist-cjs/soap/wsSecurity.js.map +1 -0
- package/package.json +6 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nodePolicy.d.ts","sourceRoot":"","sources":["../../src/scenario-runner/nodePolicy.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,wBAAwB,EACxB,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,EACZ,2BAA2B,EAC3B,yBAAyB,EACzB,6BAA6B,EAC7B,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,qCAAqC,EAAE,2BAOnD,CAAC;
|
|
1
|
+
{"version":3,"file":"nodePolicy.d.ts","sourceRoot":"","sources":["../../src/scenario-runner/nodePolicy.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,wBAAwB,EACxB,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,EACZ,2BAA2B,EAC3B,yBAAyB,EACzB,6BAA6B,EAC7B,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,qCAAqC,EAAE,2BAOnD,CAAC;AAyDF,eAAO,MAAM,mCAAmC,GAC9C,YAAY,YAAY,GAAG,6BAA6B,KACvD,UAAU,IAAI,yBAAyB,GAAG,6BAI5C,CAAC;AAEF,eAAO,MAAM,oCAAoC,GAC/C,OAAO,OAAO,EACd,WAAU,2BAAmE,KAC5E,2BA+DF,CAAC;AAEF,eAAO,MAAM,oCAAoC,QAAO,2BACJ,CAAC;AAErD,eAAO,MAAM,uCAAuC,GAClD,MAAM,6BAA6B,KAClC,2BAAqF,CAAC;AAEzF,eAAO,MAAM,8BAA8B,GACzC,MAAM,yBAAyB,KAC9B,2BAIA,CAAC;AAEJ,eAAO,MAAM,0BAA0B,GACrC,QAAQ,2BAA2B,KAClC,MAA4E,CAAC;AAEhF,eAAO,MAAM,2BAA2B,GACtC,MAAM,yBAAyB,KAC9B,MAAM,EAeR,CAAC;AAEF,eAAO,MAAM,gCAAgC,GAC3C,KAAK,SACD,mBAAmB,GACnB,cAAc,GACd,gBAAgB,GAChB,kBAAkB,GAClB,iBAAiB,GACjB,iBAAiB,GACjB,wBAAwB,GACxB,eAAe,GACf,sBAAsB,GACtB,eAAe,EAEnB,MAAM,KAAK,EACX,iBAAiB,2BAA2B,KAC3C,KASD,CAAC"}
|
|
@@ -38,6 +38,9 @@ const RECOMMENDED_NEW_NODE_POLICY_PRESETS = {
|
|
|
38
38
|
},
|
|
39
39
|
},
|
|
40
40
|
"set-vars": STRICT_SCENARIO_NODE_EXECUTION_POLICY,
|
|
41
|
+
// The poll loop IS the retry mechanism for this node type — retry stays
|
|
42
|
+
// off (and is force-disabled at execution time in runScenario).
|
|
43
|
+
poll: STRICT_SCENARIO_NODE_EXECUTION_POLICY,
|
|
41
44
|
end: STRICT_SCENARIO_NODE_EXECUTION_POLICY,
|
|
42
45
|
aggregator: STRICT_SCENARIO_NODE_EXECUTION_POLICY,
|
|
43
46
|
subscenario: STRICT_SCENARIO_NODE_EXECUTION_POLICY,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nodePolicy.js","sourceRoot":"","sources":["../../src/scenario-runner/nodePolicy.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"nodePolicy.js","sourceRoot":"","sources":["../../src/scenario-runner/nodePolicy.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runScenario.d.ts","sourceRoot":"","sources":["../../src/scenario-runner/runScenario.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runScenario.d.ts","sourceRoot":"","sources":["../../src/scenario-runner/runScenario.ts"],"names":[],"mappings":"AA+CA,OAAO,KAAK,EAKV,kBAAkB,EAUlB,iBAAiB,EAKlB,MAAM,YAAY,CAAC;AA+sBpB,eAAO,MAAM,WAAW,GAAU,mGAQ/B,kBAAkB,KAAG,OAAO,CAAC,iBAAiB,CAw+DhD,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { buildConditionOutputPayload, evaluateConditionConfig, evaluateConditionRule, validateConditionConfig, } from "./condition.js";
|
|
1
|
+
import { buildConditionOutputPayload, evaluateConditionConfig, evaluateConditionRule, resolveConditionRuntimeValue, validateConditionConfig, } from "./condition.js";
|
|
2
|
+
import { applyExtract } from "./extraction.js";
|
|
2
3
|
import { evaluateAssertionConfig, validateAssertionConfig, } from "./assertion.js";
|
|
3
|
-
import { createSubScenarioStepId, buildRuntimeStepDescriptors, DEFAULT_END_LOOP_DELAY_MS, DEFAULT_END_LOOP_ITERATIONS, flattenScenarioNodesForContext, MAX_END_LOOP_ITERATIONS, } from "./graphTraversal.js";
|
|
4
|
+
import { createSubScenarioStepId, buildRuntimeStepDescriptors, DEFAULT_END_LOOP_DELAY_MS, DEFAULT_END_LOOP_ITERATIONS, flattenScenarioNodesForContext, MAX_END_LOOP_ITERATIONS, DEFAULT_POLL_INTERVAL_MS, DEFAULT_POLL_MAX_ATTEMPTS, MAX_POLL_ATTEMPTS, } from "./graphTraversal.js";
|
|
4
5
|
import { executeWithScenarioNodePolicy } from "./executionPolicyRunner.js";
|
|
5
6
|
import { getLegacyScenarioNodeExecutionPolicy, getScenarioNodeExecutionPolicy, supportsScenarioNodeExecutionPolicy, } from "./nodePolicy.js";
|
|
6
7
|
import { buildScenarioExecutionGraph, buildScenarioTemplateValues, collectExclusiveBranchNodeIds, evaluateScenarioExpression, resolveScenarioJsonTemplateString, resolveScenarioTemplateString, } from "./templateResolver.js";
|
|
@@ -399,6 +400,19 @@ const updateRecordFromEvent = (records, event) => {
|
|
|
399
400
|
});
|
|
400
401
|
return;
|
|
401
402
|
}
|
|
403
|
+
if (event.type === "step:poll") {
|
|
404
|
+
// Tick progress only — the terminal success/fail event owns the rest.
|
|
405
|
+
records.set(event.stepId, {
|
|
406
|
+
...current,
|
|
407
|
+
stepType: event.stepType,
|
|
408
|
+
title: event.title,
|
|
409
|
+
attempts: event.attempt,
|
|
410
|
+
currentAttempt: event.attempt,
|
|
411
|
+
maxAttempts: event.maxAttempts,
|
|
412
|
+
startedAt: current.startedAt ?? event.at,
|
|
413
|
+
});
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
402
416
|
if (event.type === "step:condition") {
|
|
403
417
|
records.set(event.stepId, {
|
|
404
418
|
...current,
|
|
@@ -443,6 +457,9 @@ const updateRecordFromEvent = (records, event) => {
|
|
|
443
457
|
retryDelayMs: event.retryDelayMs ?? current.retryDelayMs,
|
|
444
458
|
failurePolicy: event.failurePolicy ?? current.failurePolicy,
|
|
445
459
|
continuedAfterFailure: event.continuedAfterFailure ?? current.continuedAfterFailure,
|
|
460
|
+
errorHandled: event.type === "step:fail"
|
|
461
|
+
? (event.errorHandled ?? current.errorHandled)
|
|
462
|
+
: current.errorHandled,
|
|
446
463
|
errors: event.errors ?? current.errors,
|
|
447
464
|
durationMs: event.durationMs ?? current.durationMs,
|
|
448
465
|
statusCode: event.statusCode ?? current.statusCode,
|
|
@@ -488,6 +505,9 @@ const callHandler = async (handlers, event) => {
|
|
|
488
505
|
case "step:retry":
|
|
489
506
|
await handlers?.onNodeRetry?.(event);
|
|
490
507
|
return;
|
|
508
|
+
case "step:poll":
|
|
509
|
+
await handlers?.onPollTick?.(event);
|
|
510
|
+
return;
|
|
491
511
|
case "step:success":
|
|
492
512
|
await handlers?.onNodeSuccess?.(event);
|
|
493
513
|
return;
|
|
@@ -712,6 +732,38 @@ export const runScenario = async ({ scenario, environment = {}, globals = {}, ru
|
|
|
712
732
|
const markRemainingNodesSkipped = async (reason) => {
|
|
713
733
|
await markNodeIdsSkipped(rootScope, rootScope.graph.nodeMap.keys(), reason);
|
|
714
734
|
};
|
|
735
|
+
// After a failure is routed into error edges, the node's NORMAL outgoing
|
|
736
|
+
// subtree must not linger idle (an idle source blocks downstream joins in
|
|
737
|
+
// isNodeReady). Skip everything reachable from the normal edges that is
|
|
738
|
+
// NOT also reachable from the taken error edges — shared downstream joins
|
|
739
|
+
// stay runnable.
|
|
740
|
+
const skipUntakenNormalBranches = async (scope, nodeId, errorEdges) => {
|
|
741
|
+
const outgoing = scope.graph.outgoingMap.get(nodeId) ?? [];
|
|
742
|
+
const normalTargets = outgoing
|
|
743
|
+
.filter((edge) => (edge.type ?? "default") !== "error")
|
|
744
|
+
.map((edge) => edge.target);
|
|
745
|
+
if (normalTargets.length === 0) {
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
const collectReachable = (startIds) => {
|
|
749
|
+
const stack = [...startIds];
|
|
750
|
+
const seen = new Set();
|
|
751
|
+
while (stack.length > 0) {
|
|
752
|
+
const current = stack.pop();
|
|
753
|
+
if (!current || seen.has(current)) {
|
|
754
|
+
continue;
|
|
755
|
+
}
|
|
756
|
+
seen.add(current);
|
|
757
|
+
for (const edge of scope.graph.outgoingMap.get(current) ?? []) {
|
|
758
|
+
stack.push(edge.target);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
return seen;
|
|
762
|
+
};
|
|
763
|
+
const reachableFromError = collectReachable(errorEdges.map((edge) => edge.target));
|
|
764
|
+
const untaken = Array.from(collectReachable(normalTargets)).filter((candidate) => !reachableFromError.has(candidate));
|
|
765
|
+
await markNodeIdsSkipped(scope, untaken, "Error branch taken");
|
|
766
|
+
};
|
|
715
767
|
const markScopeRemainingNodesSkipped = async (scope, reason) => {
|
|
716
768
|
await markNodeIdsSkipped(scope, scope.graph.nodeMap.keys(), reason);
|
|
717
769
|
};
|
|
@@ -760,11 +812,24 @@ export const runScenario = async ({ scenario, environment = {}, globals = {}, ru
|
|
|
760
812
|
if (!node) {
|
|
761
813
|
return;
|
|
762
814
|
}
|
|
815
|
+
// Synchronous claim: nothing may await between the idle/ready checks
|
|
816
|
+
// above and this line, or two branches converging on a join could both
|
|
817
|
+
// execute it (each inbound edge calls executeNode once).
|
|
818
|
+
localStatuses.set(stepId, "running");
|
|
763
819
|
const title = buildTitle(node);
|
|
764
820
|
const nodeLabel = node.data.label.trim();
|
|
765
|
-
|
|
821
|
+
let executionPolicy = supportsScenarioNodeExecutionPolicy(node)
|
|
766
822
|
? withNotificationFailurePolicyOverride(node, getScenarioNodeExecutionPolicy(node))
|
|
767
823
|
: getLegacyScenarioNodeExecutionPolicy();
|
|
824
|
+
if (node.type === "poll") {
|
|
825
|
+
// The poll loop REPLACES per-node retry (nested retry loops would be
|
|
826
|
+
// unexplainable). onFailure — incl. error edges — still governs the
|
|
827
|
+
// timeout outcome.
|
|
828
|
+
executionPolicy = {
|
|
829
|
+
...executionPolicy,
|
|
830
|
+
retry: { enabled: false, maxAttempts: 0, delayMs: 0 },
|
|
831
|
+
};
|
|
832
|
+
}
|
|
768
833
|
const executionStartedAtMs = Date.now();
|
|
769
834
|
let inputData = createInputSnapshot(runtimeContext);
|
|
770
835
|
let statusCode = null;
|
|
@@ -982,6 +1047,223 @@ export const runScenario = async ({ scenario, environment = {}, globals = {}, ru
|
|
|
982
1047
|
throw new ScenarioNodeFailureError(redisResult.failureMessage);
|
|
983
1048
|
}
|
|
984
1049
|
}
|
|
1050
|
+
if (node.type === "poll") {
|
|
1051
|
+
const pollConfig = node.data.config;
|
|
1052
|
+
const blockingPollIssue = validateConditionConfig(pollConfig.successCondition).find((issue) => issue.severity === "error");
|
|
1053
|
+
if (blockingPollIssue) {
|
|
1054
|
+
throw new ScenarioNodeFailureError(`Poll success condition is invalid: ${blockingPollIssue.message}`);
|
|
1055
|
+
}
|
|
1056
|
+
const pollStartedAtMs = Date.now();
|
|
1057
|
+
const pollMaxAttempts = Math.min(MAX_POLL_ATTEMPTS, Math.max(1, Math.round(pollConfig.maxAttempts ?? DEFAULT_POLL_MAX_ATTEMPTS)));
|
|
1058
|
+
const pollBaseIntervalMs = Math.max(0, Math.round(pollConfig.intervalMs ?? DEFAULT_POLL_INTERVAL_MS));
|
|
1059
|
+
const pollTimeoutMs = typeof pollConfig.timeoutMs === "number" && pollConfig.timeoutMs > 0
|
|
1060
|
+
? Math.round(pollConfig.timeoutMs)
|
|
1061
|
+
: null;
|
|
1062
|
+
// Thinned emission keeps stored events bounded (~100 tick events).
|
|
1063
|
+
const pollEmitStride = Math.max(1, Math.ceil(pollMaxAttempts / 100));
|
|
1064
|
+
// One tick = the embedded action through the SAME host adapters real
|
|
1065
|
+
// nodes use (desktop IPC / backend drivers both covered), publishing
|
|
1066
|
+
// results into the runtime context exactly like the real node would,
|
|
1067
|
+
// so the success condition AND downstream nodes read the last
|
|
1068
|
+
// attempt's data. Returns the action's error message, or null.
|
|
1069
|
+
const runPollTick = async () => {
|
|
1070
|
+
const tickValues = buildScenarioTemplateValues({
|
|
1071
|
+
environment: runtimeContext.environment,
|
|
1072
|
+
globals: runtimeContext.globals,
|
|
1073
|
+
workflowContext: runtimeContext.workflowContext,
|
|
1074
|
+
nodeMetaByLabel: runtimeContext.nodeMetaByLabel,
|
|
1075
|
+
responseRoot: runtimeContext.responseRoot,
|
|
1076
|
+
dbResult: runtimeContext.dbResult,
|
|
1077
|
+
kafkaEvent: runtimeContext.kafkaEvent,
|
|
1078
|
+
redisResult: runtimeContext.redisResult,
|
|
1079
|
+
});
|
|
1080
|
+
if (pollConfig.actionType === "request") {
|
|
1081
|
+
if (!pollConfig.request) {
|
|
1082
|
+
throw new ScenarioNodeFailureError("Poll node has no request configuration.");
|
|
1083
|
+
}
|
|
1084
|
+
const tickResult = await runtimeAdapters.requestExecutor({
|
|
1085
|
+
runId,
|
|
1086
|
+
stepId,
|
|
1087
|
+
node: {
|
|
1088
|
+
id: node.id,
|
|
1089
|
+
type: "request",
|
|
1090
|
+
position: node.position,
|
|
1091
|
+
data: { label: node.data.label, config: pollConfig.request },
|
|
1092
|
+
},
|
|
1093
|
+
context: createContextSnapshot(runtimeContext),
|
|
1094
|
+
kafkaCapturePlans: [],
|
|
1095
|
+
captureFromTimestampMs: startedAtMs,
|
|
1096
|
+
signal,
|
|
1097
|
+
});
|
|
1098
|
+
if (tickResult.cancelled) {
|
|
1099
|
+
throw new ScenarioStopError();
|
|
1100
|
+
}
|
|
1101
|
+
runtimeContext.environment = { ...tickResult.environment };
|
|
1102
|
+
runtimeContext.globals = { ...tickResult.globals };
|
|
1103
|
+
runtimeContext.lastResponse = tickResult.response;
|
|
1104
|
+
runtimeContext.responseRoot = tickResult.responseRoot;
|
|
1105
|
+
response = tickResult.response;
|
|
1106
|
+
statusCode = tickResult.response.status;
|
|
1107
|
+
testResults = tickResult.testResults;
|
|
1108
|
+
contractResults = tickResult.contractResults;
|
|
1109
|
+
contractSummary = tickResult.contractSummary;
|
|
1110
|
+
contractValidationError = tickResult.contractValidationError;
|
|
1111
|
+
dbAssertionResults = tickResult.dbAssertionResults;
|
|
1112
|
+
redisAssertionResults = tickResult.redisAssertionResults;
|
|
1113
|
+
return tickResult.failureMessage ?? null;
|
|
1114
|
+
}
|
|
1115
|
+
if (pollConfig.actionType === "db") {
|
|
1116
|
+
if (!pollConfig.db) {
|
|
1117
|
+
throw new ScenarioNodeFailureError("Poll node has no database configuration.");
|
|
1118
|
+
}
|
|
1119
|
+
const resolvedQuery = resolveScenarioTemplateString(pollConfig.db.query, tickValues);
|
|
1120
|
+
const resolvedParams = (pollConfig.db.params ?? []).map((param) => resolveScenarioTemplateString(param, tickValues));
|
|
1121
|
+
const tickResult = await runtimeAdapters.dbExecutor({
|
|
1122
|
+
runId,
|
|
1123
|
+
stepId,
|
|
1124
|
+
node: {
|
|
1125
|
+
id: node.id,
|
|
1126
|
+
type: "db",
|
|
1127
|
+
position: node.position,
|
|
1128
|
+
data: { label: node.data.label, config: pollConfig.db },
|
|
1129
|
+
},
|
|
1130
|
+
resolvedQuery,
|
|
1131
|
+
resolvedParams,
|
|
1132
|
+
context: createContextSnapshot(runtimeContext),
|
|
1133
|
+
signal,
|
|
1134
|
+
});
|
|
1135
|
+
runtimeContext.dbResult = tickResult.dbResult;
|
|
1136
|
+
return tickResult.failureMessage ?? null;
|
|
1137
|
+
}
|
|
1138
|
+
if (pollConfig.actionType === "redis") {
|
|
1139
|
+
if (!pollConfig.redis) {
|
|
1140
|
+
throw new ScenarioNodeFailureError("Poll node has no Redis configuration.");
|
|
1141
|
+
}
|
|
1142
|
+
const resolvedCommands = pollConfig.redis.commands
|
|
1143
|
+
.map((command) => resolveScenarioTemplateString(command, tickValues))
|
|
1144
|
+
.filter((command) => command.trim().length > 0);
|
|
1145
|
+
const tickResult = await runtimeAdapters.redisExecutor({
|
|
1146
|
+
runId,
|
|
1147
|
+
stepId,
|
|
1148
|
+
node: {
|
|
1149
|
+
id: node.id,
|
|
1150
|
+
type: "redis",
|
|
1151
|
+
position: node.position,
|
|
1152
|
+
data: { label: node.data.label, config: pollConfig.redis },
|
|
1153
|
+
},
|
|
1154
|
+
resolvedCommands,
|
|
1155
|
+
context: createContextSnapshot(runtimeContext),
|
|
1156
|
+
signal,
|
|
1157
|
+
});
|
|
1158
|
+
runtimeContext.redisResult = tickResult.redisResult;
|
|
1159
|
+
return tickResult.failureMessage ?? null;
|
|
1160
|
+
}
|
|
1161
|
+
if (!pollConfig.script) {
|
|
1162
|
+
throw new ScenarioNodeFailureError("Poll node has no script configuration.");
|
|
1163
|
+
}
|
|
1164
|
+
const tickResult = await runtimeAdapters.scriptExecutor({
|
|
1165
|
+
runId,
|
|
1166
|
+
stepId,
|
|
1167
|
+
node: {
|
|
1168
|
+
id: node.id,
|
|
1169
|
+
type: "script",
|
|
1170
|
+
position: node.position,
|
|
1171
|
+
data: { label: node.data.label, config: pollConfig.script },
|
|
1172
|
+
},
|
|
1173
|
+
context: createContextSnapshot(runtimeContext),
|
|
1174
|
+
signal,
|
|
1175
|
+
});
|
|
1176
|
+
scriptSource = tickResult.scriptSource;
|
|
1177
|
+
scriptTimeoutMs = tickResult.timeoutMs;
|
|
1178
|
+
scriptLogs = tickResult.logs;
|
|
1179
|
+
testResults = tickResult.testResults;
|
|
1180
|
+
applyVariableMutationsToContext(runtimeContext, tickResult.variableMutations);
|
|
1181
|
+
return tickResult.failureMessage ?? null;
|
|
1182
|
+
};
|
|
1183
|
+
let pollAttempt = 0;
|
|
1184
|
+
let pollPassed = false;
|
|
1185
|
+
let lastTickError = null;
|
|
1186
|
+
for (;;) {
|
|
1187
|
+
throwIfStopped(signal);
|
|
1188
|
+
pollAttempt += 1;
|
|
1189
|
+
lastTickError = await runPollTick();
|
|
1190
|
+
if (lastTickError === null) {
|
|
1191
|
+
const evaluation = evaluateConditionConfig(pollConfig.successCondition, {
|
|
1192
|
+
environment: runtimeContext.environment,
|
|
1193
|
+
globals: runtimeContext.globals,
|
|
1194
|
+
workflowContext: runtimeContext.workflowContext,
|
|
1195
|
+
nodeMetaByLabel: runtimeContext.nodeMetaByLabel,
|
|
1196
|
+
responseRoot: runtimeContext.responseRoot,
|
|
1197
|
+
dbResult: runtimeContext.dbResult,
|
|
1198
|
+
kafkaEvent: runtimeContext.kafkaEvent,
|
|
1199
|
+
redisResult: runtimeContext.redisResult,
|
|
1200
|
+
});
|
|
1201
|
+
const conditionPayload = buildConditionOutputPayload(pollConfig.successCondition, evaluation);
|
|
1202
|
+
conditionResult = evaluation.result;
|
|
1203
|
+
conditionExpression = conditionPayload.expression;
|
|
1204
|
+
conditionPreview = conditionPayload.preview;
|
|
1205
|
+
conditionMode = conditionPayload.mode;
|
|
1206
|
+
conditionDebug = conditionPayload.debug;
|
|
1207
|
+
pollPassed = evaluation.result;
|
|
1208
|
+
}
|
|
1209
|
+
else {
|
|
1210
|
+
conditionResult = false;
|
|
1211
|
+
}
|
|
1212
|
+
const pollElapsedNow = Date.now() - pollStartedAtMs;
|
|
1213
|
+
const budgetExhausted = pollAttempt >= pollMaxAttempts ||
|
|
1214
|
+
(pollTimeoutMs !== null && pollElapsedNow >= pollTimeoutMs);
|
|
1215
|
+
const pollBackoff = pollConfig.backoffMultiplier && pollConfig.backoffMultiplier > 1
|
|
1216
|
+
? Math.min(10, pollConfig.backoffMultiplier)
|
|
1217
|
+
: 1;
|
|
1218
|
+
const nextDelayMs = pollPassed || budgetExhausted
|
|
1219
|
+
? null
|
|
1220
|
+
: Math.min(pollConfig.maxDelayMs && pollConfig.maxDelayMs > 0
|
|
1221
|
+
? Math.round(pollConfig.maxDelayMs)
|
|
1222
|
+
: Number.MAX_SAFE_INTEGER, Math.round(pollBaseIntervalMs * Math.pow(pollBackoff, pollAttempt - 1)));
|
|
1223
|
+
if (pollPassed ||
|
|
1224
|
+
budgetExhausted ||
|
|
1225
|
+
pollAttempt === 1 ||
|
|
1226
|
+
pollAttempt % pollEmitStride === 0) {
|
|
1227
|
+
await emit({
|
|
1228
|
+
type: "step:poll",
|
|
1229
|
+
runId,
|
|
1230
|
+
scenarioId: scenario.id,
|
|
1231
|
+
stepId,
|
|
1232
|
+
stepType: node.type,
|
|
1233
|
+
title,
|
|
1234
|
+
at: new Date().toISOString(),
|
|
1235
|
+
attempt: pollAttempt,
|
|
1236
|
+
maxAttempts: pollMaxAttempts,
|
|
1237
|
+
elapsedMs: pollElapsedNow,
|
|
1238
|
+
timeoutMs: pollTimeoutMs,
|
|
1239
|
+
conditionResult: pollPassed,
|
|
1240
|
+
tickError: lastTickError,
|
|
1241
|
+
nextPollDelayMs: nextDelayMs,
|
|
1242
|
+
});
|
|
1243
|
+
}
|
|
1244
|
+
if (pollPassed || budgetExhausted) {
|
|
1245
|
+
break;
|
|
1246
|
+
}
|
|
1247
|
+
await waitForDuration(nextDelayMs ?? pollBaseIntervalMs);
|
|
1248
|
+
}
|
|
1249
|
+
const pollElapsedMs = Date.now() - pollStartedAtMs;
|
|
1250
|
+
outputData = {
|
|
1251
|
+
attempts: pollAttempt,
|
|
1252
|
+
maxAttempts: pollMaxAttempts,
|
|
1253
|
+
elapsedMs: pollElapsedMs,
|
|
1254
|
+
timedOut: !pollPassed,
|
|
1255
|
+
conditionResult: pollPassed,
|
|
1256
|
+
...(lastTickError ? { lastTickError } : {}),
|
|
1257
|
+
};
|
|
1258
|
+
if (!pollPassed) {
|
|
1259
|
+
if ((pollConfig.onTimeout ?? "fail") === "continue") {
|
|
1260
|
+
shouldMarkPartialSuccess = true;
|
|
1261
|
+
}
|
|
1262
|
+
else {
|
|
1263
|
+
throw new ScenarioNodeFailureError(`Poll did not succeed within ${pollAttempt} attempt(s) (${pollElapsedMs}ms).${lastTickError ? ` Last error: ${lastTickError}` : ""}`);
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
985
1267
|
if (node.type === "notification") {
|
|
986
1268
|
const resolvedMessage = renderNotificationTemplate(node.data.config.messageTemplate, templateValues).trim();
|
|
987
1269
|
const resolvedChannelOverride = node.data.config.channelOverride?.trim()
|
|
@@ -1267,6 +1549,7 @@ export const runScenario = async ({ scenario, environment = {}, globals = {}, ru
|
|
|
1267
1549
|
// may reference a variable set by an earlier one.
|
|
1268
1550
|
const writtenEnvironment = {};
|
|
1269
1551
|
const writtenGlobals = {};
|
|
1552
|
+
const extractionOutcomes = [];
|
|
1270
1553
|
for (const assignment of node.data.config.assignments ?? []) {
|
|
1271
1554
|
if (!assignment || assignment.enabled === false) {
|
|
1272
1555
|
continue;
|
|
@@ -1285,7 +1568,49 @@ export const runScenario = async ({ scenario, environment = {}, globals = {}, ru
|
|
|
1285
1568
|
if (!resolvedKey) {
|
|
1286
1569
|
continue;
|
|
1287
1570
|
}
|
|
1288
|
-
|
|
1571
|
+
let resolvedValue;
|
|
1572
|
+
const extractorType = assignment.extractorType ?? "template";
|
|
1573
|
+
if (extractorType === "jsonpath" || extractorType === "regex") {
|
|
1574
|
+
// Extractor rows resolve `source` with condition-operand path
|
|
1575
|
+
// semantics, then apply the expression. A failed extraction
|
|
1576
|
+
// SKIPS the write (never persists a wrong/empty value
|
|
1577
|
+
// silently) and surfaces the error in outputData.
|
|
1578
|
+
const sourcePath = (assignment.source ?? "").trim();
|
|
1579
|
+
const resolvedSource = resolveConditionRuntimeValue({
|
|
1580
|
+
environment: runtimeContext.environment,
|
|
1581
|
+
globals: runtimeContext.globals,
|
|
1582
|
+
workflowContext: runtimeContext.workflowContext,
|
|
1583
|
+
nodeMetaByLabel: runtimeContext.nodeMetaByLabel,
|
|
1584
|
+
responseRoot: runtimeContext.responseRoot,
|
|
1585
|
+
dbResult: runtimeContext.dbResult,
|
|
1586
|
+
kafkaEvent: runtimeContext.kafkaEvent,
|
|
1587
|
+
redisResult: runtimeContext.redisResult,
|
|
1588
|
+
}, sourcePath);
|
|
1589
|
+
const outcome = applyExtract(resolvedSource.value, {
|
|
1590
|
+
type: extractorType,
|
|
1591
|
+
expression: assignment.expression ?? "",
|
|
1592
|
+
flags: assignment.flags,
|
|
1593
|
+
group: assignment.group,
|
|
1594
|
+
select: assignment.select,
|
|
1595
|
+
});
|
|
1596
|
+
if (outcome.error || typeof outcome.value === "undefined") {
|
|
1597
|
+
extractionOutcomes.push({
|
|
1598
|
+
key: resolvedKey,
|
|
1599
|
+
extractorType,
|
|
1600
|
+
source: sourcePath,
|
|
1601
|
+
error: outcome.error ?? "Extraction produced no value",
|
|
1602
|
+
});
|
|
1603
|
+
continue;
|
|
1604
|
+
}
|
|
1605
|
+
extractionOutcomes.push({ key: resolvedKey, extractorType, source: sourcePath });
|
|
1606
|
+
resolvedValue =
|
|
1607
|
+
typeof outcome.value === "string"
|
|
1608
|
+
? outcome.value
|
|
1609
|
+
: JSON.stringify(outcome.value);
|
|
1610
|
+
}
|
|
1611
|
+
else {
|
|
1612
|
+
resolvedValue = resolveScenarioTemplateString(assignment.value ?? "", rowTemplateValues);
|
|
1613
|
+
}
|
|
1289
1614
|
applyVariableMutationsToContext(runtimeContext, [
|
|
1290
1615
|
{
|
|
1291
1616
|
scope: assignment.scope === "global" ? "global" : "environment",
|
|
@@ -1304,6 +1629,8 @@ export const runScenario = async ({ scenario, environment = {}, globals = {}, ru
|
|
|
1304
1629
|
outputData = {
|
|
1305
1630
|
environment: writtenEnvironment,
|
|
1306
1631
|
globals: writtenGlobals,
|
|
1632
|
+
// Additive: present only when extractor rows ran.
|
|
1633
|
+
...(extractionOutcomes.length > 0 ? { extraction: extractionOutcomes } : {}),
|
|
1307
1634
|
};
|
|
1308
1635
|
}
|
|
1309
1636
|
if (node.type === "aggregator") {
|
|
@@ -1376,7 +1703,14 @@ export const runScenario = async ({ scenario, environment = {}, globals = {}, ru
|
|
|
1376
1703
|
},
|
|
1377
1704
|
});
|
|
1378
1705
|
const durationMs = Math.round(Date.now() - executionStartedAtMs);
|
|
1379
|
-
|
|
1706
|
+
// "error" edges (no-code try/catch): a failure with a drawn handler is
|
|
1707
|
+
// routed into the error branch instead of stopping or continuing on
|
|
1708
|
+
// the normal path — the user's explicit handler overrides onFailure.
|
|
1709
|
+
const errorEdges = policyResult.outcome === "failed" || policyResult.outcome === "continued"
|
|
1710
|
+
? (scope.graph.outgoingMap.get(nodeId) ?? []).filter((edge) => (edge.type ?? "default") === "error")
|
|
1711
|
+
: [];
|
|
1712
|
+
const failureRouted = errorEdges.length > 0;
|
|
1713
|
+
if (policyResult.outcome === "failed" && !failureRouted) {
|
|
1380
1714
|
localStatuses.set(stepId, "failed");
|
|
1381
1715
|
const failedAt = new Date().toISOString();
|
|
1382
1716
|
const nodeMeta = buildNodeExecutionMeta({
|
|
@@ -1449,7 +1783,9 @@ export const runScenario = async ({ scenario, environment = {}, globals = {}, ru
|
|
|
1449
1783
|
});
|
|
1450
1784
|
throw new ScenarioNodeFailureError(policyResult.finalErrorMessage ?? "Scenario node failed");
|
|
1451
1785
|
}
|
|
1452
|
-
if (policyResult.outcome === "continued") {
|
|
1786
|
+
if (policyResult.outcome === "continued" || policyResult.outcome === "failed") {
|
|
1787
|
+
// Either policy-continue, or a failure routed into error edges —
|
|
1788
|
+
// both leave the node terminal as failed_continued so joins unblock.
|
|
1453
1789
|
degradedStepIds.add(stepId);
|
|
1454
1790
|
localStatuses.set(stepId, "failed_continued");
|
|
1455
1791
|
const continuedAt = new Date().toISOString();
|
|
@@ -1495,7 +1831,9 @@ export const runScenario = async ({ scenario, environment = {}, globals = {}, ru
|
|
|
1495
1831
|
retryEnabled: executionPolicy.retry.enabled,
|
|
1496
1832
|
retryDelayMs: executionPolicy.retry.delayMs,
|
|
1497
1833
|
failurePolicy: executionPolicy.onFailure,
|
|
1498
|
-
continuedAfterFailure:
|
|
1834
|
+
continuedAfterFailure: policyResult.outcome === "continued",
|
|
1835
|
+
errorHandled: failureRouted ? true : undefined,
|
|
1836
|
+
errorEdgeIds: failureRouted ? errorEdges.map((edge) => edge.id) : undefined,
|
|
1499
1837
|
errors: policyResult.errors,
|
|
1500
1838
|
nodeMeta,
|
|
1501
1839
|
errorMessage: policyResult.finalErrorMessage ??
|
|
@@ -1667,10 +2005,21 @@ export const runScenario = async ({ scenario, environment = {}, globals = {}, ru
|
|
|
1667
2005
|
syncLoopRoots();
|
|
1668
2006
|
}
|
|
1669
2007
|
}
|
|
2008
|
+
if (failureRouted) {
|
|
2009
|
+
await skipUntakenNormalBranches(scope, nodeId, errorEdges);
|
|
2010
|
+
for (const edge of errorEdges) {
|
|
2011
|
+
throwIfStopped(signal);
|
|
2012
|
+
await executeNode(edge.target, scope.stepIdForEdge(edge.id), {}, scope);
|
|
2013
|
+
}
|
|
2014
|
+
return;
|
|
2015
|
+
}
|
|
1670
2016
|
const outgoingEdges = scope.graph.outgoingMap.get(nodeId) ?? [];
|
|
1671
2017
|
const nextEdges = node.type === "condition"
|
|
1672
2018
|
? outgoingEdges.filter((edge) => (conditionResult ? "yes" : "no") === (edge.type ?? "default"))
|
|
1673
|
-
:
|
|
2019
|
+
: // Error edges are handler paths — never taken on success (or on a
|
|
2020
|
+
// policy-continue without routing). No-op for scenarios that have
|
|
2021
|
+
// no error edges.
|
|
2022
|
+
outgoingEdges.filter((edge) => (edge.type ?? "default") !== "error");
|
|
1674
2023
|
for (const edge of nextEdges) {
|
|
1675
2024
|
throwIfStopped(signal);
|
|
1676
2025
|
await executeNode(edge.target, scope.stepIdForEdge(edge.id), {}, scope);
|