callman-core 1.18.0 → 1.20.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/host/db/connectionMapping.d.ts +4 -0
- package/dist/host/db/connectionMapping.d.ts.map +1 -1
- package/dist/host/db/connectionMapping.js +4 -0
- package/dist/host/db/connectionMapping.js.map +1 -1
- package/dist/host/db/pgClientConfig.d.ts +11 -0
- package/dist/host/db/pgClientConfig.d.ts.map +1 -0
- package/dist/host/db/pgClientConfig.js +83 -0
- package/dist/host/db/pgClientConfig.js.map +1 -0
- package/dist/host/db/pgSessionManager.d.ts +18 -0
- package/dist/host/db/pgSessionManager.d.ts.map +1 -0
- package/dist/host/db/pgSessionManager.js +162 -0
- package/dist/host/db/pgSessionManager.js.map +1 -0
- package/dist/host/db/postgresAdapter.d.ts.map +1 -1
- package/dist/host/db/postgresAdapter.js +7 -36
- package/dist/host/db/postgresAdapter.js.map +1 -1
- package/dist/host/db/queryExecutor.d.ts +4 -0
- package/dist/host/db/queryExecutor.d.ts.map +1 -1
- package/dist/host/db/queryExecutor.js +40 -2
- package/dist/host/db/queryExecutor.js.map +1 -1
- package/dist/host/db/sqlState.d.ts +2 -0
- package/dist/host/db/sqlState.d.ts.map +1 -0
- package/dist/host/db/sqlState.js +14 -0
- package/dist/host/db/sqlState.js.map +1 -0
- package/dist/host/db/types.d.ts +13 -0
- package/dist/host/db/types.d.ts.map +1 -1
- package/dist/host/index.d.ts +3 -0
- package/dist/host/index.d.ts.map +1 -1
- package/dist/host/index.js +7 -0
- package/dist/host/index.js.map +1 -1
- package/dist/scenario-runner/adapters/connection-config.d.ts +4 -0
- package/dist/scenario-runner/adapters/connection-config.d.ts.map +1 -1
- package/dist/scenario-runner/adapters/db-executor.d.ts +7 -1
- package/dist/scenario-runner/adapters/db-executor.d.ts.map +1 -1
- package/dist/scenario-runner/adapters/db-executor.js +106 -1
- package/dist/scenario-runner/adapters/db-executor.js.map +1 -1
- package/dist/scenario-runner/adapters/index.d.ts +2 -1
- package/dist/scenario-runner/adapters/index.d.ts.map +1 -1
- package/dist/scenario-runner/adapters/index.js +11 -1
- package/dist/scenario-runner/adapters/index.js.map +1 -1
- package/dist/scenario-runner/adapters/types.d.ts +9 -0
- package/dist/scenario-runner/adapters/types.d.ts.map +1 -1
- package/dist/scenario-runner/adapters/websocket-executor.d.ts +4 -0
- package/dist/scenario-runner/adapters/websocket-executor.d.ts.map +1 -0
- package/dist/scenario-runner/adapters/websocket-executor.js +20 -0
- package/dist/scenario-runner/adapters/websocket-executor.js.map +1 -0
- package/dist/scenario-runner/condition.d.ts +1 -0
- package/dist/scenario-runner/condition.d.ts.map +1 -1
- package/dist/scenario-runner/condition.js +138 -2
- package/dist/scenario-runner/condition.js.map +1 -1
- package/dist/scenario-runner/conditionTypes.d.ts +1 -1
- package/dist/scenario-runner/conditionTypes.d.ts.map +1 -1
- package/dist/scenario-runner/graphTraversal.d.ts +8 -0
- package/dist/scenario-runner/graphTraversal.d.ts.map +1 -1
- package/dist/scenario-runner/graphTraversal.js +9 -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 +1 -0
- package/dist/scenario-runner/index.js.map +1 -1
- package/dist/scenario-runner/nodePolicy.d.ts +2 -2
- package/dist/scenario-runner/nodePolicy.d.ts.map +1 -1
- package/dist/scenario-runner/nodePolicy.js +2 -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 +202 -2
- package/dist/scenario-runner/runScenario.js.map +1 -1
- package/dist/scenario-runner/types.d.ts +142 -3
- package/dist/scenario-runner/types.d.ts.map +1 -1
- package/dist/scenario-runner/websocket.d.ts +17 -0
- package/dist/scenario-runner/websocket.d.ts.map +1 -0
- package/dist/scenario-runner/websocket.js +74 -0
- package/dist/scenario-runner/websocket.js.map +1 -0
- package/dist-cjs/host/db/connectionMapping.js +4 -0
- package/dist-cjs/host/db/connectionMapping.js.map +1 -1
- package/dist-cjs/host/db/pgClientConfig.js +90 -0
- package/dist-cjs/host/db/pgClientConfig.js.map +1 -0
- package/dist-cjs/host/db/pgSessionManager.js +170 -0
- package/dist-cjs/host/db/pgSessionManager.js.map +1 -0
- package/dist-cjs/host/db/postgresAdapter.js +7 -36
- package/dist-cjs/host/db/postgresAdapter.js.map +1 -1
- package/dist-cjs/host/db/queryExecutor.js +40 -2
- package/dist-cjs/host/db/queryExecutor.js.map +1 -1
- package/dist-cjs/host/db/sqlState.js +18 -0
- package/dist-cjs/host/db/sqlState.js.map +1 -0
- package/dist-cjs/host/index.js +16 -1
- package/dist-cjs/host/index.js.map +1 -1
- package/dist-cjs/scenario-runner/adapters/db-executor.js +108 -2
- package/dist-cjs/scenario-runner/adapters/db-executor.js.map +1 -1
- package/dist-cjs/scenario-runner/adapters/index.js +14 -1
- package/dist-cjs/scenario-runner/adapters/index.js.map +1 -1
- package/dist-cjs/scenario-runner/adapters/websocket-executor.js +24 -0
- package/dist-cjs/scenario-runner/adapters/websocket-executor.js.map +1 -0
- package/dist-cjs/scenario-runner/condition.js +140 -3
- package/dist-cjs/scenario-runner/condition.js.map +1 -1
- package/dist-cjs/scenario-runner/graphTraversal.js +10 -1
- package/dist-cjs/scenario-runner/graphTraversal.js.map +1 -1
- package/dist-cjs/scenario-runner/index.js +1 -0
- package/dist-cjs/scenario-runner/index.js.map +1 -1
- package/dist-cjs/scenario-runner/nodePolicy.js +2 -0
- package/dist-cjs/scenario-runner/nodePolicy.js.map +1 -1
- package/dist-cjs/scenario-runner/runScenario.js +201 -1
- package/dist-cjs/scenario-runner/runScenario.js.map +1 -1
- package/dist-cjs/scenario-runner/websocket.js +79 -0
- package/dist-cjs/scenario-runner/websocket.js.map +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nodePolicy.js","sourceRoot":"","sources":["../../src/scenario-runner/nodePolicy.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"nodePolicy.js","sourceRoot":"","sources":["../../src/scenario-runner/nodePolicy.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,7 @@ const condition_js_1 = require("./condition.js");
|
|
|
5
5
|
const extraction_js_1 = require("./extraction.js");
|
|
6
6
|
const assertion_js_1 = require("./assertion.js");
|
|
7
7
|
const graphTraversal_js_1 = require("./graphTraversal.js");
|
|
8
|
+
const websocket_js_1 = require("./websocket.js");
|
|
8
9
|
const executionPolicyRunner_js_1 = require("./executionPolicyRunner.js");
|
|
9
10
|
const nodePolicy_js_1 = require("./nodePolicy.js");
|
|
10
11
|
const templateResolver_js_1 = require("./templateResolver.js");
|
|
@@ -47,6 +48,7 @@ const RESERVED_WORKFLOW_ROOT_LABELS = new Set([
|
|
|
47
48
|
"item",
|
|
48
49
|
"each",
|
|
49
50
|
"eaches",
|
|
51
|
+
"ws",
|
|
50
52
|
]);
|
|
51
53
|
const cloneNodeExecutionMeta = (meta) => ({
|
|
52
54
|
...meta,
|
|
@@ -1001,13 +1003,36 @@ const runScenario = async ({ scenario, environment = {}, globals = {}, runtimeAd
|
|
|
1001
1003
|
}
|
|
1002
1004
|
if (node.type === "db") {
|
|
1003
1005
|
const resolvedQuery = (0, templateResolver_js_1.resolveScenarioTemplateString)(node.data.config.query, templateValues);
|
|
1004
|
-
|
|
1006
|
+
// Typed params win over legacy `params`. Types encode into the
|
|
1007
|
+
// wire value here so drivers stay oblivious: `null` → SQL NULL,
|
|
1008
|
+
// `boolean` → real boolean; everything else stays a string and
|
|
1009
|
+
// relies on server-side casts (see DbScenarioParamType docs).
|
|
1010
|
+
const typedParams = node.data.config.typedParams;
|
|
1011
|
+
const resolvedParams = typedParams
|
|
1012
|
+
? typedParams.map((param) => {
|
|
1013
|
+
if (param.type === "null")
|
|
1014
|
+
return null;
|
|
1015
|
+
const resolved = (0, templateResolver_js_1.resolveScenarioTemplateString)(param.value ?? "", templateValues);
|
|
1016
|
+
if (param.type === "boolean") {
|
|
1017
|
+
return ["true", "1", "t", "yes"].includes(resolved.trim().toLowerCase());
|
|
1018
|
+
}
|
|
1019
|
+
return resolved;
|
|
1020
|
+
})
|
|
1021
|
+
: (node.data.config.params ?? []).map((param) => (0, templateResolver_js_1.resolveScenarioTemplateString)(param, templateValues));
|
|
1005
1022
|
const dbResult = await runtimeAdapters.dbExecutor({
|
|
1006
1023
|
runId,
|
|
1007
1024
|
stepId,
|
|
1008
1025
|
node,
|
|
1009
1026
|
resolvedQuery,
|
|
1010
1027
|
resolvedParams,
|
|
1028
|
+
...(node.data.config.useSession
|
|
1029
|
+
? {
|
|
1030
|
+
session: {
|
|
1031
|
+
runId,
|
|
1032
|
+
transactionMode: scenario.dbSettings?.transactionMode ?? "none",
|
|
1033
|
+
},
|
|
1034
|
+
}
|
|
1035
|
+
: {}),
|
|
1011
1036
|
context: createContextSnapshot(runtimeContext),
|
|
1012
1037
|
signal,
|
|
1013
1038
|
});
|
|
@@ -1448,6 +1473,163 @@ const runScenario = async ({ scenario, environment = {}, globals = {}, runtimeAd
|
|
|
1448
1473
|
outputData = runtimeContext.kafkaEvent;
|
|
1449
1474
|
}
|
|
1450
1475
|
}
|
|
1476
|
+
if (node.type === "websocket") {
|
|
1477
|
+
const wsConfig = node.data.config;
|
|
1478
|
+
const resolvedUrl = (0, templateResolver_js_1.resolveScenarioTemplateString)(wsConfig.url ?? "", templateValues).trim();
|
|
1479
|
+
if (!resolvedUrl) {
|
|
1480
|
+
throw new ScenarioNodeFailureError("WebSocket URL is required.");
|
|
1481
|
+
}
|
|
1482
|
+
const configuredSteps = wsConfig.steps ?? [];
|
|
1483
|
+
if (configuredSteps.length > graphTraversal_js_1.MAX_WS_STEPS) {
|
|
1484
|
+
throw new ScenarioNodeFailureError(`WebSocket conversations are capped at ${graphTraversal_js_1.MAX_WS_STEPS} steps.`);
|
|
1485
|
+
}
|
|
1486
|
+
for (const [stepIndex, step] of configuredSteps.entries()) {
|
|
1487
|
+
if (step.kind === "expect" && (!step.rules || step.rules.length === 0)) {
|
|
1488
|
+
throw new ScenarioNodeFailureError(`WebSocket expect step ${stepIndex + 1} has no rules.`);
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
const resolvedHeaders = (wsConfig.headers ?? [])
|
|
1492
|
+
.filter((header) => header.enabled !== false && header.key.trim())
|
|
1493
|
+
.map((header) => ({
|
|
1494
|
+
key: (0, templateResolver_js_1.resolveScenarioTemplateString)(header.key, templateValues).trim(),
|
|
1495
|
+
value: (0, templateResolver_js_1.resolveScenarioTemplateString)(header.value ?? "", templateValues),
|
|
1496
|
+
}));
|
|
1497
|
+
const resolvedSubprotocols = (wsConfig.subprotocols ?? [])
|
|
1498
|
+
.map((protocol) => (0, templateResolver_js_1.resolveScenarioTemplateString)(protocol, templateValues).trim())
|
|
1499
|
+
.filter((protocol) => protocol.length > 0);
|
|
1500
|
+
const connectTimeoutMs = Math.min(graphTraversal_js_1.MAX_WS_CONNECT_TIMEOUT_MS, Math.max(100, Math.round(wsConfig.connectTimeoutMs ?? graphTraversal_js_1.DEFAULT_WS_CONNECT_TIMEOUT_MS)));
|
|
1501
|
+
const resolvedSteps = configuredSteps.map((step) => {
|
|
1502
|
+
if (step.kind === "send") {
|
|
1503
|
+
return {
|
|
1504
|
+
id: step.id,
|
|
1505
|
+
kind: "send",
|
|
1506
|
+
payload: (0, templateResolver_js_1.resolveScenarioJsonTemplateString)(step.payload ?? "", templateValues),
|
|
1507
|
+
};
|
|
1508
|
+
}
|
|
1509
|
+
if (step.kind === "wait") {
|
|
1510
|
+
return {
|
|
1511
|
+
id: step.id,
|
|
1512
|
+
kind: "wait",
|
|
1513
|
+
durationMs: Math.min(graphTraversal_js_1.MAX_WS_WAIT_DURATION_MS, Math.max(0, Math.round(step.durationMs ?? 0))),
|
|
1514
|
+
};
|
|
1515
|
+
}
|
|
1516
|
+
return {
|
|
1517
|
+
id: step.id,
|
|
1518
|
+
kind: "expect",
|
|
1519
|
+
timeoutMs: Math.min(graphTraversal_js_1.MAX_WS_EXPECT_TIMEOUT_MS, Math.max(100, Math.round(step.timeoutMs ?? graphTraversal_js_1.DEFAULT_WS_EXPECT_TIMEOUT_MS))),
|
|
1520
|
+
matchMode: step.matchMode === "any" ? "any" : "all",
|
|
1521
|
+
rules: step.rules,
|
|
1522
|
+
};
|
|
1523
|
+
});
|
|
1524
|
+
const wsExecution = await runtimeAdapters.websocketExecutor({
|
|
1525
|
+
runId,
|
|
1526
|
+
stepId,
|
|
1527
|
+
node,
|
|
1528
|
+
resolvedUrl,
|
|
1529
|
+
resolvedHeaders,
|
|
1530
|
+
subprotocols: resolvedSubprotocols,
|
|
1531
|
+
connectTimeoutMs,
|
|
1532
|
+
steps: resolvedSteps,
|
|
1533
|
+
closeCode: wsConfig.closeCode ?? graphTraversal_js_1.DEFAULT_WS_CLOSE_CODE,
|
|
1534
|
+
rejectUnauthorized: wsConfig.rejectUnauthorized !== false,
|
|
1535
|
+
environment: { ...runtimeContext.environment },
|
|
1536
|
+
globals: { ...runtimeContext.globals },
|
|
1537
|
+
signal,
|
|
1538
|
+
});
|
|
1539
|
+
throwIfStopped(signal);
|
|
1540
|
+
// Authoritative expect evaluation over the recorded frames — the
|
|
1541
|
+
// host's early-stop is advisory only (kafka consume precedent).
|
|
1542
|
+
const evaluationScope = {
|
|
1543
|
+
environment: runtimeContext.environment,
|
|
1544
|
+
globals: runtimeContext.globals,
|
|
1545
|
+
workflowContext: runtimeContext.workflowContext,
|
|
1546
|
+
nodeMetaByLabel: runtimeContext.nodeMetaByLabel,
|
|
1547
|
+
responseRoot: runtimeContext.responseRoot,
|
|
1548
|
+
dbResult: runtimeContext.dbResult,
|
|
1549
|
+
kafkaEvent: runtimeContext.kafkaEvent,
|
|
1550
|
+
redisResult: runtimeContext.redisResult,
|
|
1551
|
+
};
|
|
1552
|
+
const outcomesByIndex = new Map(wsExecution.stepOutcomes.map((outcome) => [outcome.index, outcome]));
|
|
1553
|
+
let conversationBroken = !wsExecution.connected;
|
|
1554
|
+
const stepResults = resolvedSteps.map((step, index) => {
|
|
1555
|
+
const outcome = outcomesByIndex.get(index);
|
|
1556
|
+
const durationMs = outcome && outcome.startedAt && outcome.endedAt
|
|
1557
|
+
? Math.max(0, new Date(outcome.endedAt).getTime() - new Date(outcome.startedAt).getTime())
|
|
1558
|
+
: 0;
|
|
1559
|
+
if (!outcome) {
|
|
1560
|
+
return {
|
|
1561
|
+
index,
|
|
1562
|
+
kind: step.kind,
|
|
1563
|
+
status: "failed",
|
|
1564
|
+
durationMs: 0,
|
|
1565
|
+
error: conversationBroken
|
|
1566
|
+
? "Step not reached — the conversation ended early."
|
|
1567
|
+
: "Step was not executed by the host.",
|
|
1568
|
+
matchedMessageIndex: null,
|
|
1569
|
+
};
|
|
1570
|
+
}
|
|
1571
|
+
if (step.kind !== "expect") {
|
|
1572
|
+
const failed = Boolean(outcome.error);
|
|
1573
|
+
if (failed)
|
|
1574
|
+
conversationBroken = true;
|
|
1575
|
+
return {
|
|
1576
|
+
index,
|
|
1577
|
+
kind: step.kind,
|
|
1578
|
+
status: failed ? "failed" : "passed",
|
|
1579
|
+
durationMs,
|
|
1580
|
+
error: outcome.error ?? null,
|
|
1581
|
+
matchedMessageIndex: null,
|
|
1582
|
+
};
|
|
1583
|
+
}
|
|
1584
|
+
const candidates = wsExecution.messages.filter((message) => message.direction === "received" && message.stepIndex === index);
|
|
1585
|
+
let matchedMessageIndex = null;
|
|
1586
|
+
for (const candidate of candidates) {
|
|
1587
|
+
const evaluation = (0, websocket_js_1.evaluateWebsocketExpect)(step.rules ?? [], step.matchMode ?? "all", evaluationScope, candidate);
|
|
1588
|
+
if (evaluation.passed) {
|
|
1589
|
+
matchedMessageIndex = candidate.index;
|
|
1590
|
+
break;
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
const failed = matchedMessageIndex === null;
|
|
1594
|
+
if (failed)
|
|
1595
|
+
conversationBroken = true;
|
|
1596
|
+
return {
|
|
1597
|
+
index,
|
|
1598
|
+
kind: step.kind,
|
|
1599
|
+
status: failed ? "failed" : "passed",
|
|
1600
|
+
durationMs,
|
|
1601
|
+
error: failed
|
|
1602
|
+
? (outcome.error ??
|
|
1603
|
+
`No message matched within ${step.timeoutMs}ms (${candidates.length} received).`)
|
|
1604
|
+
: null,
|
|
1605
|
+
matchedMessageIndex,
|
|
1606
|
+
};
|
|
1607
|
+
});
|
|
1608
|
+
const failedSteps = stepResults.filter((entry) => entry.status === "failed").length;
|
|
1609
|
+
const wsErrorMessage = !wsExecution.connected
|
|
1610
|
+
? (wsExecution.connectError ?? "WebSocket connection failed.")
|
|
1611
|
+
: failedSteps > 0
|
|
1612
|
+
? (() => {
|
|
1613
|
+
const firstFailed = stepResults.find((entry) => entry.status === "failed");
|
|
1614
|
+
return `WebSocket step ${(firstFailed?.index ?? 0) + 1} (${firstFailed?.kind}) failed: ${firstFailed?.error}`;
|
|
1615
|
+
})()
|
|
1616
|
+
: null;
|
|
1617
|
+
outputData = {
|
|
1618
|
+
url: resolvedUrl,
|
|
1619
|
+
connected: wsExecution.connected,
|
|
1620
|
+
closeCode: wsExecution.closeCode,
|
|
1621
|
+
closeReason: wsExecution.closeReason ?? null,
|
|
1622
|
+
durationMs: wsExecution.durationMs,
|
|
1623
|
+
messageCount: wsExecution.messages.length,
|
|
1624
|
+
messages: wsExecution.messages,
|
|
1625
|
+
steps: stepResults,
|
|
1626
|
+
failedSteps,
|
|
1627
|
+
errorMessage: wsErrorMessage,
|
|
1628
|
+
};
|
|
1629
|
+
if (wsErrorMessage) {
|
|
1630
|
+
throw new ScenarioNodeFailureError(wsErrorMessage);
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1451
1633
|
if (node.type === "condition") {
|
|
1452
1634
|
const conditionIssues = (0, condition_js_1.validateConditionConfig)(node.data.config);
|
|
1453
1635
|
const blockingConditionIssue = conditionIssues.find((issue) => issue.severity === "error");
|
|
@@ -2387,6 +2569,24 @@ const runScenario = async ({ scenario, environment = {}, globals = {}, runtimeAd
|
|
|
2387
2569
|
workflowMeta,
|
|
2388
2570
|
});
|
|
2389
2571
|
}
|
|
2572
|
+
// Release the run's DB sessions (COMMIT/ROLLBACK + connection teardown).
|
|
2573
|
+
// Runs after BOTH outcome paths so `rollback` mode is honored even when
|
|
2574
|
+
// the scenario failed or was stopped mid-transaction. Cleanup must never
|
|
2575
|
+
// mask the run result, hence the swallow-with-log catch.
|
|
2576
|
+
if (runtimeAdapters.dbSessionRelease) {
|
|
2577
|
+
const commitAllowed = scenario.dbSettings?.transactionMode === "commit" &&
|
|
2578
|
+
finalStatus !== "failed" &&
|
|
2579
|
+
finalStatus !== "stopped";
|
|
2580
|
+
try {
|
|
2581
|
+
await runtimeAdapters.dbSessionRelease({
|
|
2582
|
+
runId,
|
|
2583
|
+
outcome: commitAllowed ? "commit" : "rollback",
|
|
2584
|
+
});
|
|
2585
|
+
}
|
|
2586
|
+
catch {
|
|
2587
|
+
// Session teardown failure is not allowed to change the run outcome.
|
|
2588
|
+
}
|
|
2589
|
+
}
|
|
2390
2590
|
const endedAt = new Date().toISOString();
|
|
2391
2591
|
const finalWorkflowMeta = updateWorkflowMetaState({
|
|
2392
2592
|
context: runtimeContext,
|