callman-core 1.25.1 → 1.26.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.
Files changed (65) hide show
  1. package/dist/host/db/mysqlAdapter.d.ts.map +1 -1
  2. package/dist/host/db/mysqlAdapter.js +39 -9
  3. package/dist/host/db/mysqlAdapter.js.map +1 -1
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +1 -0
  7. package/dist/index.js.map +1 -1
  8. package/dist/request/executeRequest.d.ts +1 -1
  9. package/dist/request/executeRequest.d.ts.map +1 -1
  10. package/dist/request/executeRequest.js +8 -1
  11. package/dist/request/executeRequest.js.map +1 -1
  12. package/dist/scenario-runner/adapters/request-executor.js +12 -3
  13. package/dist/scenario-runner/adapters/request-executor.js.map +1 -1
  14. package/dist/scenario-runner/adapters/script-executor.js +1 -1
  15. package/dist/scenario-runner/adapters/script-executor.js.map +1 -1
  16. package/dist/scenario-runner/adapters/types.d.ts +1 -0
  17. package/dist/scenario-runner/adapters/types.d.ts.map +1 -1
  18. package/dist/scenario-runner/boundSnapshot.d.ts +15 -0
  19. package/dist/scenario-runner/boundSnapshot.d.ts.map +1 -0
  20. package/dist/scenario-runner/boundSnapshot.js +67 -0
  21. package/dist/scenario-runner/boundSnapshot.js.map +1 -0
  22. package/dist/scenario-runner/runScenario.d.ts +1 -1
  23. package/dist/scenario-runner/runScenario.d.ts.map +1 -1
  24. package/dist/scenario-runner/runScenario.js +34 -25
  25. package/dist/scenario-runner/runScenario.js.map +1 -1
  26. package/dist/scenario-runner/runScenarioWithDataset.d.ts.map +1 -1
  27. package/dist/scenario-runner/runScenarioWithDataset.js +21 -6
  28. package/dist/scenario-runner/runScenarioWithDataset.js.map +1 -1
  29. package/dist/scenario-runner/types.d.ts +2 -0
  30. package/dist/scenario-runner/types.d.ts.map +1 -1
  31. package/dist/script/isolated-runner.d.ts +7 -1
  32. package/dist/script/isolated-runner.d.ts.map +1 -1
  33. package/dist/script/isolated-runner.js +11 -5
  34. package/dist/script/isolated-runner.js.map +1 -1
  35. package/dist/script/worker-entry.js +62 -28
  36. package/dist/script/worker-entry.js.map +1 -1
  37. package/dist/script/worker-pool.d.ts +60 -0
  38. package/dist/script/worker-pool.d.ts.map +1 -0
  39. package/dist/script/worker-pool.js +274 -0
  40. package/dist/script/worker-pool.js.map +1 -0
  41. package/dist/types/index.d.ts +1 -0
  42. package/dist/types/index.d.ts.map +1 -1
  43. package/dist-cjs/host/db/mysqlAdapter.js +39 -9
  44. package/dist-cjs/host/db/mysqlAdapter.js.map +1 -1
  45. package/dist-cjs/index.js +4 -1
  46. package/dist-cjs/index.js.map +1 -1
  47. package/dist-cjs/request/executeRequest.js +8 -1
  48. package/dist-cjs/request/executeRequest.js.map +1 -1
  49. package/dist-cjs/scenario-runner/adapters/request-executor.js +12 -3
  50. package/dist-cjs/scenario-runner/adapters/request-executor.js.map +1 -1
  51. package/dist-cjs/scenario-runner/adapters/script-executor.js +1 -1
  52. package/dist-cjs/scenario-runner/adapters/script-executor.js.map +1 -1
  53. package/dist-cjs/scenario-runner/boundSnapshot.js +71 -0
  54. package/dist-cjs/scenario-runner/boundSnapshot.js.map +1 -0
  55. package/dist-cjs/scenario-runner/runScenario.js +34 -25
  56. package/dist-cjs/scenario-runner/runScenario.js.map +1 -1
  57. package/dist-cjs/scenario-runner/runScenarioWithDataset.js +21 -6
  58. package/dist-cjs/scenario-runner/runScenarioWithDataset.js.map +1 -1
  59. package/dist-cjs/script/isolated-runner.js +12 -5
  60. package/dist-cjs/script/isolated-runner.js.map +1 -1
  61. package/dist-cjs/script/worker-entry.js +62 -28
  62. package/dist-cjs/script/worker-entry.js.map +1 -1
  63. package/dist-cjs/script/worker-pool.js +312 -0
  64. package/dist-cjs/script/worker-pool.js.map +1 -0
  65. package/package.json +1 -1
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ // Size-capped deep copy of a runtime value for event context snapshots
3
+ // (`RunScenarioOptions.eventContextMode: "bounded"`).
4
+ //
5
+ // The caps are deliberately LOOSER than the backend report mapper's persist-
6
+ // time truncation (16 KB strings / 50 array items / 50 keys / depth 6), so
7
+ // everything the mapper keeps is still present verbatim after bounding —
8
+ // the persisted report is byte-identical whether bounding ran or not. What
9
+ // changes is what stays in the HEAP while the run is in flight: a bounded
10
+ // snapshot never holds a reference to a multi-megabyte response body.
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.boundSnapshot = exports.DEFAULT_BOUND_SNAPSHOT_LIMITS = void 0;
13
+ exports.DEFAULT_BOUND_SNAPSHOT_LIMITS = {
14
+ maxStringLength: 32 * 1024,
15
+ maxArrayItems: 100,
16
+ maxObjectKeys: 100,
17
+ maxDepth: 8,
18
+ };
19
+ const TRUNCATED = "…[truncated]";
20
+ const boundValueAt = (value, depth, limits) => {
21
+ if (value === null || value === undefined)
22
+ return value;
23
+ switch (typeof value) {
24
+ case "string":
25
+ return value.length > limits.maxStringLength
26
+ ? `${value.slice(0, limits.maxStringLength)}${TRUNCATED}`
27
+ : value;
28
+ case "number":
29
+ case "boolean":
30
+ return value;
31
+ case "bigint":
32
+ return value.toString();
33
+ case "function":
34
+ case "symbol":
35
+ return undefined;
36
+ default:
37
+ break;
38
+ }
39
+ if (value instanceof Date)
40
+ return new Date(value.getTime());
41
+ if (depth >= limits.maxDepth)
42
+ return TRUNCATED;
43
+ if (Array.isArray(value)) {
44
+ const kept = value.slice(0, limits.maxArrayItems).map((item) => boundValueAt(item, depth + 1, limits));
45
+ return kept;
46
+ }
47
+ if (typeof value.toJSON === "function") {
48
+ return boundValueAt(value.toJSON(), depth, limits);
49
+ }
50
+ const out = {};
51
+ let count = 0;
52
+ for (const [key, entry] of Object.entries(value)) {
53
+ if (count >= limits.maxObjectKeys)
54
+ break;
55
+ const bounded = boundValueAt(entry, depth + 1, limits);
56
+ if (bounded !== undefined) {
57
+ out[key] = bounded;
58
+ count += 1;
59
+ }
60
+ }
61
+ return out;
62
+ };
63
+ /**
64
+ * Returns a bounded deep copy of `value`. `undefined` and `null` pass
65
+ * through unchanged; typed callers cast the result back to their shape —
66
+ * bounding never changes the top-level structure, only trims what is nested
67
+ * inside it.
68
+ */
69
+ const boundSnapshot = (value, limits = exports.DEFAULT_BOUND_SNAPSHOT_LIMITS) => (value === null || value === undefined ? value : boundValueAt(value, 0, limits));
70
+ exports.boundSnapshot = boundSnapshot;
71
+ //# sourceMappingURL=boundSnapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boundSnapshot.js","sourceRoot":"","sources":["../../src/scenario-runner/boundSnapshot.ts"],"names":[],"mappings":";AAAA,uEAAuE;AACvE,sDAAsD;AACtD,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,yEAAyE;AACzE,2EAA2E;AAC3E,0EAA0E;AAC1E,sEAAsE;;;AASzD,QAAA,6BAA6B,GAAwB;IAChE,eAAe,EAAE,EAAE,GAAG,IAAI;IAC1B,aAAa,EAAE,GAAG;IAClB,aAAa,EAAE,GAAG;IAClB,QAAQ,EAAE,CAAC;CACZ,CAAC;AAEF,MAAM,SAAS,GAAG,cAAc,CAAC;AAEjC,MAAM,YAAY,GAAG,CAAC,KAAc,EAAE,KAAa,EAAE,MAA2B,EAAW,EAAE;IAC3F,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACxD,QAAQ,OAAO,KAAK,EAAE,CAAC;QACrB,KAAK,QAAQ;YACX,OAAO,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,eAAe;gBAC1C,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,eAAe,CAAC,GAAG,SAAS,EAAE;gBACzD,CAAC,CAAC,KAAK,CAAC;QACZ,KAAK,QAAQ,CAAC;QACd,KAAK,SAAS;YACZ,OAAO,KAAK,CAAC;QACf,KAAK,QAAQ;YACX,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC1B,KAAK,UAAU,CAAC;QAChB,KAAK,QAAQ;YACX,OAAO,SAAS,CAAC;QACnB;YACE,MAAM;IACV,CAAC;IACD,IAAI,KAAK,YAAY,IAAI;QAAE,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5D,IAAI,KAAK,IAAI,MAAM,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAC;IAC/C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QACvG,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,OAAQ,KAA8B,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QACjE,OAAO,YAAY,CAAE,KAAmC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACpF,CAAC;IACD,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,EAAE,CAAC;QAC5E,IAAI,KAAK,IAAI,MAAM,CAAC,aAAa;YAAE,MAAM;QACzC,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;QACvD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,GAAG,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;YACnB,KAAK,IAAI,CAAC,CAAC;QACb,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAEF;;;;;GAKG;AACI,MAAM,aAAa,GAAG,CAC3B,KAAQ,EACR,SAA8B,qCAA6B,EACxD,EAAE,CAAC,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAE,YAAY,CAAC,KAAK,EAAE,CAAC,EAAE,MAAM,CAAO,CAAC,CAAC;AAHnF,QAAA,aAAa,iBAGsE"}
@@ -7,6 +7,7 @@ const assertion_js_1 = require("./assertion.js");
7
7
  const graphTraversal_js_1 = require("./graphTraversal.js");
8
8
  const websocket_js_1 = require("./websocket.js");
9
9
  const executionPolicyRunner_js_1 = require("./executionPolicyRunner.js");
10
+ const boundSnapshot_js_1 = require("./boundSnapshot.js");
10
11
  const nodePolicy_js_1 = require("./nodePolicy.js");
11
12
  const templateResolver_js_1 = require("./templateResolver.js");
12
13
  const waitNodeExecutor_js_1 = require("./waitNodeExecutor.js");
@@ -113,19 +114,24 @@ const createInputSnapshot = (context) => ({
113
114
  result: context.redisResult ?? null,
114
115
  },
115
116
  });
116
- const createContextSnapshot = (context) => ({
117
- environment: { ...context.environment },
118
- globals: { ...context.globals },
119
- workflowContext: { ...context.workflowContext },
120
- nodeMetaByLabel: cloneNodeMetaByLabel(context.nodeMetaByLabel),
121
- workflowMeta: cloneWorkflowExecutionMeta(context.workflowMeta),
122
- responseRoot: context.responseRoot ? { ...context.responseRoot } : null,
123
- lastResponse: context.lastResponse,
124
- dbResult: context.dbResult,
125
- kafkaEvent: context.kafkaEvent,
126
- kafkaCapture: context.kafkaCapture,
127
- redisResult: context.redisResult,
128
- });
117
+ const createContextSnapshot = (context, mode = "full") => {
118
+ // "bounded": the payload-bearing slots are size-capped copies instead of
119
+ // references, so the event log never pins a node's full response body.
120
+ const bound = mode === "bounded" ? boundSnapshot_js_1.boundSnapshot : (value) => value;
121
+ return {
122
+ environment: { ...context.environment },
123
+ globals: { ...context.globals },
124
+ workflowContext: bound({ ...context.workflowContext }),
125
+ nodeMetaByLabel: cloneNodeMetaByLabel(context.nodeMetaByLabel),
126
+ workflowMeta: cloneWorkflowExecutionMeta(context.workflowMeta),
127
+ responseRoot: context.responseRoot ? bound({ ...context.responseRoot }) : null,
128
+ lastResponse: bound(context.lastResponse),
129
+ dbResult: bound(context.dbResult),
130
+ kafkaEvent: bound(context.kafkaEvent),
131
+ kafkaCapture: bound(context.kafkaCapture),
132
+ redisResult: bound(context.redisResult),
133
+ };
134
+ };
129
135
  const buildKafkaEventValue = (message) => {
130
136
  const fallbackValue = {
131
137
  value: message.valueJson ?? message.valueText,
@@ -560,7 +566,7 @@ const callHandler = async (handlers, event) => {
560
566
  return;
561
567
  }
562
568
  };
563
- const runScenario = async ({ scenario, environment = {}, globals = {}, runtimeAdapters, eventHandlers, signal, minNodeVisualStateMs = DEFAULT_MIN_NODE_VISUAL_STATE_MS, }) => {
569
+ const runScenario = async ({ scenario, environment = {}, globals = {}, runtimeAdapters, eventHandlers, signal, minNodeVisualStateMs = DEFAULT_MIN_NODE_VISUAL_STATE_MS, eventContextMode = "full", }) => {
564
570
  const runId = createRunId();
565
571
  const startedAtMs = Date.now();
566
572
  const startedAt = new Date(startedAtMs).toISOString();
@@ -571,6 +577,9 @@ const runScenario = async ({ scenario, environment = {}, globals = {}, runtimeAd
571
577
  const localStatuses = new Map(runtimeStepIds.map((stepId) => [stepId, "idle"]));
572
578
  const records = new Map();
573
579
  const events = [];
580
+ // Every emitted event carries a context snapshot; `runtimeContext` is
581
+ // assigned just below and is always initialised before the first emit.
582
+ const snapshotContext = () => createContextSnapshot(runtimeContext, eventContextMode);
574
583
  const initialWorkflowMeta = createInitialWorkflowMeta({
575
584
  startedAt,
576
585
  totalNodes: runtimeStepIds.length,
@@ -980,7 +989,7 @@ const runScenario = async ({ scenario, environment = {}, globals = {}, runtimeAd
980
989
  runId,
981
990
  stepId,
982
991
  node,
983
- context: createContextSnapshot(runtimeContext),
992
+ context: snapshotContext(),
984
993
  kafkaCapturePlans,
985
994
  captureFromTimestampMs: startedAtMs,
986
995
  signal,
@@ -1041,7 +1050,7 @@ const runScenario = async ({ scenario, environment = {}, globals = {}, runtimeAd
1041
1050
  },
1042
1051
  }
1043
1052
  : {}),
1044
- context: createContextSnapshot(runtimeContext),
1053
+ context: snapshotContext(),
1045
1054
  signal,
1046
1055
  });
1047
1056
  runtimeContext.dbResult = dbResult.dbResult;
@@ -1074,7 +1083,7 @@ const runScenario = async ({ scenario, environment = {}, globals = {}, runtimeAd
1074
1083
  runId,
1075
1084
  stepId,
1076
1085
  node,
1077
- context: createContextSnapshot(runtimeContext),
1086
+ context: snapshotContext(),
1078
1087
  signal,
1079
1088
  });
1080
1089
  scriptSource = scriptResult.scriptSource;
@@ -1098,7 +1107,7 @@ const runScenario = async ({ scenario, environment = {}, globals = {}, runtimeAd
1098
1107
  stepId,
1099
1108
  node,
1100
1109
  resolvedCommands,
1101
- context: createContextSnapshot(runtimeContext),
1110
+ context: snapshotContext(),
1102
1111
  signal,
1103
1112
  });
1104
1113
  runtimeContext.redisResult = redisResult.redisResult;
@@ -1150,7 +1159,7 @@ const runScenario = async ({ scenario, environment = {}, globals = {}, runtimeAd
1150
1159
  position: node.position,
1151
1160
  data: { label: node.data.label, config: pollConfig.request },
1152
1161
  },
1153
- context: createContextSnapshot(runtimeContext),
1162
+ context: snapshotContext(),
1154
1163
  kafkaCapturePlans: [],
1155
1164
  captureFromTimestampMs: startedAtMs,
1156
1165
  signal,
@@ -1190,7 +1199,7 @@ const runScenario = async ({ scenario, environment = {}, globals = {}, runtimeAd
1190
1199
  },
1191
1200
  resolvedQuery,
1192
1201
  resolvedParams,
1193
- context: createContextSnapshot(runtimeContext),
1202
+ context: snapshotContext(),
1194
1203
  signal,
1195
1204
  });
1196
1205
  runtimeContext.dbResult = tickResult.dbResult;
@@ -1213,7 +1222,7 @@ const runScenario = async ({ scenario, environment = {}, globals = {}, runtimeAd
1213
1222
  data: { label: node.data.label, config: pollConfig.redis },
1214
1223
  },
1215
1224
  resolvedCommands,
1216
- context: createContextSnapshot(runtimeContext),
1225
+ context: snapshotContext(),
1217
1226
  signal,
1218
1227
  });
1219
1228
  runtimeContext.redisResult = tickResult.redisResult;
@@ -1231,7 +1240,7 @@ const runScenario = async ({ scenario, environment = {}, globals = {}, runtimeAd
1231
1240
  position: node.position,
1232
1241
  data: { label: node.data.label, config: pollConfig.script },
1233
1242
  },
1234
- context: createContextSnapshot(runtimeContext),
1243
+ context: snapshotContext(),
1235
1244
  signal,
1236
1245
  });
1237
1246
  scriptSource = tickResult.scriptSource;
@@ -1354,7 +1363,7 @@ const runScenario = async ({ scenario, environment = {}, globals = {}, runtimeAd
1354
1363
  runId,
1355
1364
  stepId,
1356
1365
  node,
1357
- context: createContextSnapshot(runtimeContext),
1366
+ context: snapshotContext(),
1358
1367
  deliveryRequest,
1359
1368
  signal,
1360
1369
  });
@@ -1650,7 +1659,7 @@ const runScenario = async ({ scenario, environment = {}, globals = {}, runtimeAd
1650
1659
  runId,
1651
1660
  stepId,
1652
1661
  node,
1653
- context: createContextSnapshot(runtimeContext),
1662
+ context: snapshotContext(),
1654
1663
  signal,
1655
1664
  });
1656
1665
  throwIfStopped(signal);
@@ -2642,7 +2651,7 @@ const runScenario = async ({ scenario, environment = {}, globals = {}, runtimeAd
2642
2651
  durationMs: Date.now() - startedAtMs,
2643
2652
  totalSteps: runtimeStepIds.length,
2644
2653
  completedSteps: Array.from(localStatuses.values()).filter(isTerminalStatus).length,
2645
- context: createContextSnapshot(runtimeContext),
2654
+ context: snapshotContext(),
2646
2655
  workflowMeta: cloneWorkflowExecutionMeta(finalWorkflowMeta),
2647
2656
  nodeExecutions: runtimeStepIds.map((stepId) => {
2648
2657
  const descriptor = runtimeStepDescriptors.find((entry) => entry.stepId === stepId);