@testsmith/api-spector 0.7.7 → 0.7.9

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 (31) hide show
  1. package/bin/cli.js +4 -0
  2. package/out/main/chunks/{broker-client-Df4PpJqB.js → broker-client-CJBfpvbd.js} +4 -1
  3. package/out/main/chunks/{flow-engine-BVzjz4lJ.js → flow-engine-BxwjEy37.js} +66 -1
  4. package/out/main/chunks/{handle-Bz0C56Eq.js → handle-Crv1i9hb.js} +60 -0
  5. package/out/main/chunks/{import-BhGBiW7j.js → import-DTcZMRNu.js} +2 -2
  6. package/out/main/chunks/perf-report-ChaO3K0w.js +124 -0
  7. package/out/main/chunks/perf-run-Co_5unBR.js +578 -0
  8. package/out/main/chunks/{request-collection-KGPuvN7o.js → request-collection-gkOYlWml.js} +68 -11
  9. package/out/main/chunks/{request-exec-B-F0K-pN.js → request-exec-CgyqbNWk.js} +445 -13
  10. package/out/main/chunks/run-concurrent-468tH0AX.js +26 -0
  11. package/out/main/chunks/{soap-handler-DqIPcIQL.js → soap-handler-Brr7BPWO.js} +2 -2
  12. package/out/main/contract.js +6 -3
  13. package/out/main/flow.js +8 -5
  14. package/out/main/index.js +1352 -185
  15. package/out/main/lib.js +6 -3
  16. package/out/main/perf-worker.js +45 -0
  17. package/out/main/perf.js +253 -0
  18. package/out/main/runner.js +181 -7
  19. package/out/main/socketio.js +172 -0
  20. package/out/main/wsdl.js +3 -3
  21. package/out/preload/index.js +127 -2
  22. package/out/renderer/assets/{GraphQLEditor-BXpdmpn6.js → GraphQLEditor-CXvLKrnv.js} +59 -14
  23. package/out/renderer/assets/{SoapEditor-De6WlP6E.js → SoapEditor-7hxhISPZ.js} +3 -3
  24. package/out/renderer/assets/ajv-CJPwFjiP.js +6718 -0
  25. package/out/renderer/assets/{codemirror-F6m3Hm1M.js → codemirror-CdIFBPs2.js} +1214 -1207
  26. package/out/renderer/assets/{index-Gcd_t6pX.js → index-BUFSn_qD.js} +15344 -12285
  27. package/out/renderer/assets/index-DkhdKzQJ.css +627 -0
  28. package/out/renderer/index.html +4 -4
  29. package/package.json +12 -6
  30. package/out/renderer/assets/ajv-2MAg6kGF.js +0 -6153
  31. package/out/renderer/assets/index-CYArpqm5.css +0 -627
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  const undici = require("undici");
25
25
  const promises$1 = require("fs/promises");
26
26
  const nodeTls = require("tls");
27
- const handle = require("./handle-Bz0C56Eq.js");
27
+ const handle = require("./handle-Crv1i9hb.js");
28
28
  const fs = require("node:fs");
29
29
  const os = require("node:os");
30
30
  const path = require("node:path");
@@ -35,6 +35,9 @@ const vm = require("node:vm");
35
35
  const tv4 = require("tv4");
36
36
  const jsonpathPlus = require("jsonpath-plus");
37
37
  const xmldom = require("@xmldom/xmldom");
38
+ const mqtt = require("mqtt");
39
+ const WebSocket = require("ws");
40
+ const socket_ioClient = require("socket.io-client");
38
41
  const http = require("node:http");
39
42
  const Ajv = require("ajv");
40
43
  function _interopNamespaceDefault(e) {
@@ -838,6 +841,10 @@ function buildUrl(baseUrl, params, vars) {
838
841
  templateTokens.add(String(name).trim());
839
842
  return "";
840
843
  });
844
+ baseUrl.replaceAll(/\[([A-Za-z_]\w*)\]/g, (_m, name) => {
845
+ templateTokens.add(String(name));
846
+ return "";
847
+ });
841
848
  const enabled = (params ?? []).filter((p) => p.enabled && p.key);
842
849
  const pathRows = [];
843
850
  const queryRows = [];
@@ -850,7 +857,8 @@ function buildUrl(baseUrl, params, vars) {
850
857
  ...vars,
851
858
  ...Object.fromEntries(pathRows.map((p) => [p.key, interpolate(p.value, vars)]))
852
859
  } : vars;
853
- const url = interpolate(baseUrl, mergedVars);
860
+ let url = interpolate(baseUrl, mergedVars);
861
+ url = url.replaceAll(/\[([A-Za-z_]\w*)\]/g, (m, name) => name in mergedVars ? mergedVars[name] : m);
854
862
  if (!queryRows.length) return url;
855
863
  const sep = url.includes("?") ? "&" : "?";
856
864
  const qs = queryRows.map((p) => `${encodeURIComponent(interpolate(p.key, vars))}=${encodeURIComponent(interpolate(p.value, vars))}`).join("&");
@@ -905,9 +913,9 @@ async function buildEnvVars(environment) {
905
913
  }
906
914
  return vars;
907
915
  }
908
- function mergeVars(envVars, collectionVars, globals2, localVars = {}, dynamicVars = {}) {
916
+ function mergeVars(envVars, collectionVars, globals2, localVars = {}, dynamicVars = {}, folderVars = {}) {
909
917
  const out = {};
910
- for (const src of [dynamicVars, globals2, collectionVars, envVars, localVars]) {
918
+ for (const src of [dynamicVars, globals2, collectionVars, folderVars, envVars, localVars]) {
911
919
  for (const [k, v] of Object.entries(src ?? {})) {
912
920
  if (v == null) continue;
913
921
  out[k] = v;
@@ -1091,6 +1099,7 @@ class AssertionError extends Error {
1091
1099
  }
1092
1100
  function buildAt(ctx, testResults, consoleOutput) {
1093
1101
  const { envVars, collectionVars, globals: globals2, localVars, piiMaskPatterns = [] } = ctx;
1102
+ const folderVars = ctx.folderVars ?? {};
1094
1103
  const isSensitiveKey = (key) => piiMaskPatterns.some((p) => key.toLowerCase().includes(p.toLowerCase()));
1095
1104
  function makeVarScope(store, scopeName) {
1096
1105
  return {
@@ -1113,9 +1122,10 @@ function buildAt(ctx, testResults, consoleOutput) {
1113
1122
  variables: makeVarScope(localVars, "variables"),
1114
1123
  environment: makeVarScope(envVars, "environment"),
1115
1124
  collectionVariables: makeVarScope(collectionVars, "collectionVariables"),
1125
+ folder: makeVarScope(folderVars, "folder"),
1116
1126
  globals: makeVarScope(globals2, "globals"),
1117
1127
  // Convenience: get/set across all scopes (local wins)
1118
- variables_get: (key) => localVars[key] ?? envVars[key] ?? collectionVars[key] ?? globals2[key] ?? null,
1128
+ variables_get: (key) => localVars[key] ?? envVars[key] ?? folderVars[key] ?? collectionVars[key] ?? globals2[key] ?? null,
1119
1129
  variables_set: (key, value) => {
1120
1130
  localVars[key] = String(value);
1121
1131
  },
@@ -1174,6 +1184,14 @@ function buildAt(ctx, testResults, consoleOutput) {
1174
1184
  return String(binCode % 10 ** digits).padStart(digits, "0");
1175
1185
  }
1176
1186
  };
1187
+ const collected = ctx.messages ?? ctx.mqttMessages;
1188
+ if (collected) {
1189
+ sp.messages = collected.map((m) => ({
1190
+ ...m,
1191
+ json: () => JSON.parse(m.payload),
1192
+ text: () => m.payload
1193
+ }));
1194
+ }
1177
1195
  if (ctx.response) {
1178
1196
  const resp = ctx.response;
1179
1197
  let parsedJson = void 0;
@@ -1249,12 +1267,17 @@ async function runScript(code, ctx, timeoutMs = 5e3) {
1249
1267
  const collectionCopy = { ...ctx.collectionVars };
1250
1268
  const globalsCopy = { ...ctx.globals };
1251
1269
  const localVarsCopy = { ...ctx.localVars };
1270
+ const folderCopy = { ...ctx.folderVars ?? {} };
1252
1271
  const scriptCtx = {
1253
1272
  envVars: envVarsCopy,
1254
1273
  collectionVars: collectionCopy,
1255
1274
  globals: globalsCopy,
1256
1275
  localVars: localVarsCopy,
1276
+ folderVars: folderCopy,
1257
1277
  response: ctx.response,
1278
+ data: ctx.data,
1279
+ mqttMessages: ctx.mqttMessages,
1280
+ messages: ctx.messages,
1258
1281
  piiMaskPatterns: ctx.piiMaskPatterns
1259
1282
  };
1260
1283
  const sandbox = buildSandbox(scriptCtx, testResults, consoleOutput, faker);
@@ -1269,6 +1292,7 @@ async function runScript(code, ctx, timeoutMs = 5e3) {
1269
1292
  updatedCollectionVars: collectionCopy,
1270
1293
  updatedGlobals: globalsCopy,
1271
1294
  updatedLocalVars: localVarsCopy,
1295
+ updatedFolderVars: folderCopy,
1272
1296
  error: message
1273
1297
  };
1274
1298
  }
@@ -1278,7 +1302,8 @@ async function runScript(code, ctx, timeoutMs = 5e3) {
1278
1302
  updatedEnvVars: envVarsCopy,
1279
1303
  updatedCollectionVars: collectionCopy,
1280
1304
  updatedGlobals: globalsCopy,
1281
- updatedLocalVars: localVarsCopy
1305
+ updatedLocalVars: localVarsCopy,
1306
+ updatedFolderVars: folderCopy
1282
1307
  };
1283
1308
  }
1284
1309
  async function evaluateExpression(code, ctx, timeoutMs = 5e3) {
@@ -1357,6 +1382,7 @@ class StreamFramer {
1357
1382
  constructor(mode) {
1358
1383
  this.mode = mode;
1359
1384
  }
1385
+ mode;
1360
1386
  carry = "";
1361
1387
  /** Feed a decoded text chunk; returns the frames that completed. */
1362
1388
  push(text) {
@@ -1519,6 +1545,314 @@ async function readStream(body, kind, startMs, opts = {}) {
1519
1545
  }
1520
1546
  return { events, text, close, firstEventMs: Math.max(firstEventMs, 0) };
1521
1547
  }
1548
+ async function runMqttTest(cfg) {
1549
+ const messages = [];
1550
+ const collectMs = Math.max(0, Math.min(6e4, Math.floor(cfg.collectMs ?? 2e3)));
1551
+ const clientId = cfg.clientId?.trim() || `api-spector-test-${Date.now().toString(36)}-${Math.random().toString(16).slice(2, 10)}`;
1552
+ return new Promise((resolve2) => {
1553
+ let settled = false;
1554
+ let connected = false;
1555
+ let lastError = "";
1556
+ let client;
1557
+ let timer;
1558
+ const runAssertions = async (connectError) => {
1559
+ if (settled) return;
1560
+ settled = true;
1561
+ if (timer) clearTimeout(timer);
1562
+ try {
1563
+ client?.end(true);
1564
+ } catch {
1565
+ }
1566
+ if (connectError && messages.length === 0) {
1567
+ resolve2({ testResults: [], consoleOutput: [], error: connectError, messages, clientId });
1568
+ return;
1569
+ }
1570
+ const out = await runScript(cfg.script ?? "", {
1571
+ envVars: cfg.envVars ?? {},
1572
+ collectionVars: cfg.collectionVars ?? {},
1573
+ globals: cfg.globals ?? {},
1574
+ localVars: cfg.localVars ?? {},
1575
+ mqttMessages: messages
1576
+ });
1577
+ resolve2({ testResults: out.testResults, consoleOutput: out.consoleOutput, error: out.error, messages, clientId });
1578
+ };
1579
+ try {
1580
+ client = mqtt.connect(cfg.url, {
1581
+ clientId,
1582
+ username: cfg.username?.trim() || void 0,
1583
+ password: cfg.password ? cfg.password : void 0,
1584
+ clean: cfg.cleanSession !== false,
1585
+ reconnectPeriod: 0,
1586
+ connectTimeout: 15e3
1587
+ });
1588
+ } catch (err) {
1589
+ resolve2({ testResults: [], consoleOutput: [], error: err instanceof Error ? err.message : String(err), messages, clientId });
1590
+ return;
1591
+ }
1592
+ client.on("connect", () => {
1593
+ connected = true;
1594
+ const publish = () => {
1595
+ const topic = cfg.publishTopic?.trim();
1596
+ if (!topic) return;
1597
+ if (/[+#]/.test(topic)) return;
1598
+ client.publish(topic, cfg.publishPayload ?? "", { qos: cfg.qos ?? 0, retain: Boolean(cfg.retain) });
1599
+ };
1600
+ const sub = cfg.subscribeTopic?.trim();
1601
+ if (sub) {
1602
+ client.subscribe(sub, { qos: cfg.qos ?? 0 }, () => setTimeout(publish, 100));
1603
+ } else {
1604
+ publish();
1605
+ }
1606
+ timer = setTimeout(() => void runAssertions(), collectMs);
1607
+ });
1608
+ client.on("message", (topic, payload, packet) => {
1609
+ messages.push({ topic, payload: payload.toString("utf8"), qos: packet?.qos, retain: Boolean(packet?.retain), timestamp: Date.now() });
1610
+ });
1611
+ client.on("error", (err) => {
1612
+ const code = err?.code;
1613
+ lastError = [err?.message, code].filter(Boolean).join(" ");
1614
+ void runAssertions(err?.message || "Could not connect to the broker");
1615
+ });
1616
+ client.on("close", () => {
1617
+ if (settled) return;
1618
+ void runAssertions(connected ? `The test connection was dropped by the broker before the window finished${lastError ? ` [${lastError}]` : ""}. Common causes: publishing to a topic that contains a wildcard (+ or #), or another connection using the same client id. Check the broker's log.` : `Could not connect to the broker${lastError ? ` [${lastError}]` : ""}`);
1619
+ });
1620
+ });
1621
+ }
1622
+ function clampWindow(ms) {
1623
+ return Math.max(0, Math.min(6e4, Math.floor(ms ?? 3e3)));
1624
+ }
1625
+ async function assertOver(cfg, messages) {
1626
+ const out = await runScript(cfg.script ?? "", {
1627
+ envVars: cfg.envVars ?? {},
1628
+ collectionVars: cfg.collectionVars ?? {},
1629
+ globals: cfg.globals ?? {},
1630
+ localVars: cfg.localVars ?? {},
1631
+ messages
1632
+ });
1633
+ return { testResults: out.testResults, consoleOutput: out.consoleOutput, error: out.error, messages };
1634
+ }
1635
+ function errorResult(error, messages) {
1636
+ return { testResults: [], consoleOutput: [], error, messages };
1637
+ }
1638
+ function parseJsonObject(text, label) {
1639
+ if (!text || !text.trim()) return void 0;
1640
+ let parsed;
1641
+ try {
1642
+ parsed = JSON.parse(text);
1643
+ } catch {
1644
+ throw new Error(`${label} is not valid JSON`);
1645
+ }
1646
+ return parsed && typeof parsed === "object" ? parsed : void 0;
1647
+ }
1648
+ async function runWsTest(cfg) {
1649
+ const messages = [];
1650
+ const collectMs = clampWindow(cfg.collectMs);
1651
+ return new Promise((resolve2) => {
1652
+ let settled = false;
1653
+ let connected = false;
1654
+ let lastError = "";
1655
+ let ws;
1656
+ let timer;
1657
+ const finish = async (connectError) => {
1658
+ if (settled) return;
1659
+ settled = true;
1660
+ if (timer) clearTimeout(timer);
1661
+ try {
1662
+ ws?.close();
1663
+ } catch {
1664
+ }
1665
+ if (connectError && messages.length === 0) {
1666
+ resolve2(errorResult(connectError, messages));
1667
+ return;
1668
+ }
1669
+ resolve2(await assertOver(cfg, messages));
1670
+ };
1671
+ try {
1672
+ ws = new WebSocket(cfg.url, { headers: cfg.headers });
1673
+ } catch (err) {
1674
+ resolve2(errorResult(err instanceof Error ? err.message : String(err), messages));
1675
+ return;
1676
+ }
1677
+ ws.on("open", () => {
1678
+ connected = true;
1679
+ if (cfg.sendMessage) {
1680
+ try {
1681
+ ws.send(cfg.sendMessage);
1682
+ } catch {
1683
+ }
1684
+ }
1685
+ timer = setTimeout(() => void finish(), collectMs);
1686
+ });
1687
+ ws.on("message", (data) => {
1688
+ const text = data.toString();
1689
+ messages.push({ payload: text, data: text, timestamp: Date.now() });
1690
+ });
1691
+ ws.on("error", (err) => {
1692
+ lastError = err.message;
1693
+ void finish(err.message || "Could not connect to the server");
1694
+ });
1695
+ ws.on("close", () => {
1696
+ if (settled) return;
1697
+ void finish(connected ? `The WebSocket was closed before the window finished${lastError ? ` [${lastError}]` : ""}.` : `Could not connect to the server${lastError ? ` [${lastError}]` : ""}`);
1698
+ });
1699
+ });
1700
+ }
1701
+ function targetUrl(url, namespace) {
1702
+ const ns = (namespace ?? "").trim();
1703
+ if (!ns || ns === "/") return url;
1704
+ return url.replace(/\/+$/, "") + (ns.startsWith("/") ? ns : `/${ns}`);
1705
+ }
1706
+ async function runSocketIoTest(cfg) {
1707
+ const messages = [];
1708
+ const collectMs = clampWindow(cfg.collectMs);
1709
+ let auth;
1710
+ try {
1711
+ auth = parseJsonObject(cfg.auth, "Auth");
1712
+ } catch (e) {
1713
+ return errorResult(e instanceof Error ? e.message : String(e), messages);
1714
+ }
1715
+ let emitArgs = [];
1716
+ if (cfg.emitArgs && cfg.emitArgs.trim()) {
1717
+ try {
1718
+ const parsed = JSON.parse(cfg.emitArgs);
1719
+ emitArgs = Array.isArray(parsed) ? parsed : [parsed];
1720
+ } catch {
1721
+ return errorResult("Emit arguments are not valid JSON", messages);
1722
+ }
1723
+ }
1724
+ return new Promise((resolve2) => {
1725
+ let settled = false;
1726
+ let socket;
1727
+ let timer;
1728
+ const finish = async (connectError) => {
1729
+ if (settled) return;
1730
+ settled = true;
1731
+ if (timer) clearTimeout(timer);
1732
+ try {
1733
+ socket?.disconnect();
1734
+ } catch {
1735
+ }
1736
+ if (connectError && messages.length === 0) {
1737
+ resolve2(errorResult(connectError, messages));
1738
+ return;
1739
+ }
1740
+ resolve2(await assertOver(cfg, messages));
1741
+ };
1742
+ try {
1743
+ socket = socket_ioClient.io(targetUrl(cfg.url, cfg.namespace), {
1744
+ path: cfg.path?.trim() || "/socket.io",
1745
+ transports: ["websocket", "polling"],
1746
+ extraHeaders: cfg.headers,
1747
+ auth,
1748
+ forceNew: true,
1749
+ reconnection: false
1750
+ });
1751
+ } catch (err) {
1752
+ resolve2(errorResult(err instanceof Error ? err.message : String(err), messages));
1753
+ return;
1754
+ }
1755
+ socket.on("connect", () => {
1756
+ const ev = cfg.emitEvent?.trim();
1757
+ if (ev) setTimeout(() => {
1758
+ try {
1759
+ socket.emit(ev, ...emitArgs);
1760
+ } catch {
1761
+ }
1762
+ }, 100);
1763
+ timer = setTimeout(() => void finish(), collectMs);
1764
+ });
1765
+ socket.on("connect_error", (err) => {
1766
+ void finish(`Could not connect to the server${err.message ? ` [${err.message}]` : ""}`);
1767
+ });
1768
+ socket.onAny((event, ...args) => {
1769
+ const payload = JSON.stringify(args.length <= 1 ? args[0] ?? null : args);
1770
+ messages.push({ payload, event, args, timestamp: Date.now() });
1771
+ });
1772
+ });
1773
+ }
1774
+ const GQL_SUB_ID = "1";
1775
+ async function runGraphqlWsTest(cfg) {
1776
+ const messages = [];
1777
+ const collectMs = clampWindow(cfg.collectMs);
1778
+ let variables;
1779
+ let connectionParams;
1780
+ try {
1781
+ variables = parseJsonObject(cfg.variables, "Variables");
1782
+ connectionParams = parseJsonObject(cfg.connectionParams, "Connection params");
1783
+ } catch (e) {
1784
+ return errorResult(e instanceof Error ? e.message : String(e), messages);
1785
+ }
1786
+ return new Promise((resolve2) => {
1787
+ let settled = false;
1788
+ let connected = false;
1789
+ let lastError = "";
1790
+ let ws;
1791
+ let timer;
1792
+ const finish = async (connectError) => {
1793
+ if (settled) return;
1794
+ settled = true;
1795
+ if (timer) clearTimeout(timer);
1796
+ try {
1797
+ ws?.close();
1798
+ } catch {
1799
+ }
1800
+ if (connectError && messages.length === 0) {
1801
+ resolve2(errorResult(connectError, messages));
1802
+ return;
1803
+ }
1804
+ resolve2(await assertOver(cfg, messages));
1805
+ };
1806
+ try {
1807
+ ws = new WebSocket(cfg.url, "graphql-transport-ws", { headers: cfg.headers });
1808
+ } catch (err) {
1809
+ resolve2(errorResult(err instanceof Error ? err.message : String(err), messages));
1810
+ return;
1811
+ }
1812
+ ws.on("open", () => {
1813
+ connected = true;
1814
+ ws.send(JSON.stringify({ type: "connection_init", payload: connectionParams }));
1815
+ timer = setTimeout(() => void finish(), collectMs);
1816
+ });
1817
+ ws.on("message", (raw) => {
1818
+ let msg;
1819
+ try {
1820
+ msg = JSON.parse(raw.toString());
1821
+ } catch {
1822
+ return;
1823
+ }
1824
+ switch (msg.type) {
1825
+ case "connection_ack":
1826
+ ws.send(JSON.stringify({ id: GQL_SUB_ID, type: "subscribe", payload: { query: cfg.query, variables, operationName: cfg.operationName } }));
1827
+ break;
1828
+ case "next": {
1829
+ const payload = msg.payload;
1830
+ const data = payload?.data;
1831
+ messages.push({ payload: JSON.stringify(data ?? payload ?? null), data, errors: payload?.errors, timestamp: Date.now() });
1832
+ break;
1833
+ }
1834
+ case "error":
1835
+ lastError = JSON.stringify(msg.payload);
1836
+ void finish(`The subscription returned an error${lastError ? ` [${lastError}]` : ""}`);
1837
+ break;
1838
+ case "complete":
1839
+ void finish();
1840
+ break;
1841
+ case "ping":
1842
+ ws.send(JSON.stringify({ type: "pong" }));
1843
+ break;
1844
+ }
1845
+ });
1846
+ ws.on("error", (err) => {
1847
+ lastError = err.message;
1848
+ void finish(err.message || "Could not connect to the server");
1849
+ });
1850
+ ws.on("close", () => {
1851
+ if (settled) return;
1852
+ void finish(connected ? `The subscription connection was closed before the window finished${lastError ? ` [${lastError}]` : ""}.` : `Could not connect to the server${lastError ? ` [${lastError}]` : ""}`);
1853
+ });
1854
+ });
1855
+ }
1522
1856
  const SIGNATURE = Buffer.from("NTLMSSP\0", "latin1");
1523
1857
  const F_UNICODE = 1;
1524
1858
  const F_OEM = 2;
@@ -1695,7 +2029,7 @@ async function buildAuthHeaders(auth, vars) {
1695
2029
  const username = interpolate(auth.username ?? "", vars);
1696
2030
  headers["Authorization"] = `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
1697
2031
  }
1698
- if (auth.type === "apikey" && auth.apiKeyIn === "header") {
2032
+ if (auth.type === "apikey" && (auth.apiKeyIn ?? "header") === "header") {
1699
2033
  let value = auth.apiKeyValue ?? "";
1700
2034
  if (!value && auth.apiKeySecretRef) value = await getSecret(auth.apiKeySecretRef) ?? "";
1701
2035
  value = interpolate(value, vars);
@@ -2286,6 +2620,7 @@ async function resolveInlineSecrets(req) {
2286
2620
  async function executeRunnerRequest(opts) {
2287
2621
  const { req, collectionVars, envVars, globals: globals2, dispatcher, piiMaskPatterns, proxy, tls, onScriptOutput } = opts;
2288
2622
  let { localVars } = opts;
2623
+ const folderVars = opts.folderVars ?? {};
2289
2624
  applyRequestDefaults(req);
2290
2625
  const base = {
2291
2626
  requestId: req.id,
@@ -2296,13 +2631,99 @@ async function executeRunnerRequest(opts) {
2296
2631
  };
2297
2632
  const dynamicVars = await buildDynamicVars();
2298
2633
  if (localVars && Object.keys(localVars).length > 0) {
2299
- localVars = resolveDataRow(localVars, mergeVars(envVars, collectionVars, globals2, {}, dynamicVars));
2634
+ localVars = resolveDataRow(localVars, mergeVars(envVars, collectionVars, globals2, {}, dynamicVars, folderVars));
2300
2635
  }
2301
- let vars = mergeVars(envVars, collectionVars, globals2, localVars, dynamicVars);
2636
+ let vars = mergeVars(envVars, collectionVars, globals2, localVars, dynamicVars, folderVars);
2302
2637
  let updatedEnvVars = { ...envVars };
2303
2638
  let updatedCollectionVars = { ...collectionVars };
2304
2639
  let updatedGlobals = { ...globals2 };
2640
+ let updatedFolderVars = { ...folderVars };
2305
2641
  let preScriptError;
2642
+ if (req.protocol === "mqtt") {
2643
+ const m = req.mqtt ?? {};
2644
+ const istr = (s) => s ? interpolate(s, vars) : void 0;
2645
+ const mqttStart = Date.now();
2646
+ const testRes = await runMqttTest({
2647
+ url: interpolate(req.url, vars),
2648
+ clientId: istr(m.clientId),
2649
+ username: istr(m.username),
2650
+ password: m.password ? interpolate(m.password, vars) : void 0,
2651
+ cleanSession: m.cleanSession !== false,
2652
+ subscribeTopic: istr(m.subscribeTopic),
2653
+ qos: m.qos,
2654
+ publishTopic: istr(m.publishTopic),
2655
+ publishPayload: istr(m.publishPayload),
2656
+ retain: m.retain,
2657
+ collectMs: m.collectMs ?? 2e3,
2658
+ script: m.testScript ?? "",
2659
+ envVars,
2660
+ collectionVars,
2661
+ globals: globals2,
2662
+ localVars
2663
+ });
2664
+ const status = testRes.error ? "error" : testRes.testResults.length === 0 ? "skipped" : testRes.testResults.every((t) => t.passed) ? "passed" : "failed";
2665
+ return {
2666
+ result: {
2667
+ ...base,
2668
+ status,
2669
+ durationMs: Date.now() - mqttStart,
2670
+ testResults: testRes.testResults,
2671
+ consoleOutput: testRes.consoleOutput,
2672
+ error: testRes.error
2673
+ },
2674
+ updatedEnvVars,
2675
+ updatedCollectionVars,
2676
+ updatedGlobals,
2677
+ updatedLocalVars: localVars,
2678
+ updatedFolderVars
2679
+ };
2680
+ }
2681
+ if (req.protocol === "websocket" || req.protocol === "socketio") {
2682
+ const rtHeaders = {};
2683
+ for (const h of req.headers ?? []) if (h.enabled && h.key) rtHeaders[interpolate(h.key, vars)] = interpolate(h.value, vars);
2684
+ const istr = (s) => s ? interpolate(s, vars) : void 0;
2685
+ const rtStart = Date.now();
2686
+ const testRes = req.protocol === "websocket" ? await runWsTest({
2687
+ url: interpolate(req.url, vars),
2688
+ headers: rtHeaders,
2689
+ sendMessage: istr(req.websocket?.sendMessage),
2690
+ collectMs: req.websocket?.collectMs ?? 3e3,
2691
+ script: req.websocket?.testScript ?? "",
2692
+ envVars,
2693
+ collectionVars,
2694
+ globals: globals2,
2695
+ localVars
2696
+ }) : await runSocketIoTest({
2697
+ url: interpolate(req.url, vars),
2698
+ namespace: req.socketio?.namespace,
2699
+ auth: istr(req.socketio?.auth),
2700
+ headers: rtHeaders,
2701
+ emitEvent: istr(req.socketio?.emitEvent),
2702
+ emitArgs: istr(req.socketio?.emitArgs),
2703
+ collectMs: req.socketio?.collectMs ?? 3e3,
2704
+ script: req.socketio?.testScript ?? "",
2705
+ envVars,
2706
+ collectionVars,
2707
+ globals: globals2,
2708
+ localVars
2709
+ });
2710
+ const status = testRes.error ? "error" : testRes.testResults.length === 0 ? "skipped" : testRes.testResults.every((t) => t.passed) ? "passed" : "failed";
2711
+ return {
2712
+ result: {
2713
+ ...base,
2714
+ status,
2715
+ durationMs: Date.now() - rtStart,
2716
+ testResults: testRes.testResults,
2717
+ consoleOutput: testRes.consoleOutput,
2718
+ error: testRes.error
2719
+ },
2720
+ updatedEnvVars,
2721
+ updatedCollectionVars,
2722
+ updatedGlobals,
2723
+ updatedLocalVars: localVars,
2724
+ updatedFolderVars
2725
+ };
2726
+ }
2306
2727
  let inlineSecrets = {};
2307
2728
  try {
2308
2729
  inlineSecrets = await resolveInlineSecrets(req);
@@ -2317,7 +2738,8 @@ async function executeRunnerRequest(opts) {
2317
2738
  updatedEnvVars,
2318
2739
  updatedCollectionVars,
2319
2740
  updatedGlobals,
2320
- updatedLocalVars: localVars
2741
+ updatedLocalVars: localVars,
2742
+ updatedFolderVars
2321
2743
  };
2322
2744
  }
2323
2745
  if (Object.keys(inlineSecrets).length) vars = { ...vars, ...inlineSecrets };
@@ -2327,6 +2749,7 @@ async function executeRunnerRequest(opts) {
2327
2749
  collectionVars: { ...collectionVars },
2328
2750
  globals: { ...globals2 },
2329
2751
  localVars: { ...localVars },
2752
+ folderVars: { ...updatedFolderVars },
2330
2753
  piiMaskPatterns
2331
2754
  });
2332
2755
  preScriptError = r.error;
@@ -2334,10 +2757,11 @@ async function executeRunnerRequest(opts) {
2334
2757
  updatedEnvVars = r.updatedEnvVars;
2335
2758
  updatedCollectionVars = r.updatedCollectionVars;
2336
2759
  updatedGlobals = r.updatedGlobals;
2760
+ updatedFolderVars = r.updatedFolderVars;
2337
2761
  patchGlobals(r.updatedGlobals);
2338
2762
  await persistGlobals();
2339
2763
  onScriptOutput?.("pre", r.consoleOutput, r.error);
2340
- vars = mergeVars(updatedEnvVars, updatedCollectionVars, updatedGlobals, localVars, dynamicVars);
2764
+ vars = mergeVars(updatedEnvVars, updatedCollectionVars, updatedGlobals, localVars, dynamicVars, updatedFolderVars);
2341
2765
  if (Object.keys(inlineSecrets).length) vars = { ...vars, ...inlineSecrets };
2342
2766
  }
2343
2767
  const resolvedUrl = buildUrl(req.url, req.params, vars);
@@ -2366,6 +2790,7 @@ async function executeRunnerRequest(opts) {
2366
2790
  collectionVars: updatedCollectionVars,
2367
2791
  globals: updatedGlobals,
2368
2792
  localVars,
2793
+ folderVars: updatedFolderVars,
2369
2794
  response: scriptResponse,
2370
2795
  piiMaskPatterns
2371
2796
  });
@@ -2375,6 +2800,7 @@ async function executeRunnerRequest(opts) {
2375
2800
  updatedEnvVars = r.updatedEnvVars;
2376
2801
  updatedCollectionVars = r.updatedCollectionVars;
2377
2802
  updatedGlobals = r.updatedGlobals;
2803
+ updatedFolderVars = r.updatedFolderVars;
2378
2804
  localVars = r.updatedLocalVars;
2379
2805
  patchGlobals(r.updatedGlobals);
2380
2806
  await persistGlobals();
@@ -2414,7 +2840,8 @@ async function executeRunnerRequest(opts) {
2414
2840
  updatedEnvVars,
2415
2841
  updatedCollectionVars,
2416
2842
  updatedGlobals,
2417
- updatedLocalVars: localVars
2843
+ updatedLocalVars: localVars,
2844
+ updatedFolderVars
2418
2845
  };
2419
2846
  } catch (err) {
2420
2847
  return {
@@ -2428,7 +2855,8 @@ async function executeRunnerRequest(opts) {
2428
2855
  updatedEnvVars,
2429
2856
  updatedCollectionVars,
2430
2857
  updatedGlobals,
2431
- updatedLocalVars: localVars
2858
+ updatedLocalVars: localVars,
2859
+ updatedFolderVars
2432
2860
  };
2433
2861
  }
2434
2862
  }
@@ -2510,7 +2938,11 @@ exports.registerSecretProvider = registerSecretProvider;
2510
2938
  exports.registeredSchemes = registeredSchemes;
2511
2939
  exports.resolveDataRow = resolveDataRow;
2512
2940
  exports.resolveExternalSecret = resolveExternalSecret;
2941
+ exports.runGraphqlWsTest = runGraphqlWsTest;
2942
+ exports.runMqttTest = runMqttTest;
2513
2943
  exports.runScript = runScript;
2944
+ exports.runSocketIoTest = runSocketIoTest;
2945
+ exports.runWsTest = runWsTest;
2514
2946
  exports.setGlobals = setGlobals;
2515
2947
  exports.setSecretsConfig = setSecretsConfig;
2516
2948
  exports.syntheticHttpFailure = syntheticHttpFailure;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ async function runPlanConcurrent(concurrency, items, isBarrier, run) {
3
+ const n = Math.max(1, Math.floor(concurrency));
4
+ const pool = [];
5
+ const settleOne = async () => {
6
+ const done = await Promise.race(pool.map((x) => x.p));
7
+ const pi = pool.findIndex((x) => x.i === done);
8
+ if (pi >= 0) pool.splice(pi, 1);
9
+ };
10
+ const drain = async () => {
11
+ while (pool.length) await settleOne();
12
+ };
13
+ for (let i = 0; i < items.length; i++) {
14
+ const item = items[i];
15
+ if (isBarrier(item)) {
16
+ await drain();
17
+ await run(item, i);
18
+ } else {
19
+ const idx = i;
20
+ pool.push({ p: run(item, idx).then(() => idx), i: idx });
21
+ if (pool.length >= n) await settleOne();
22
+ }
23
+ }
24
+ await drain();
25
+ }
26
+ exports.runPlanConcurrent = runPlanConcurrent;
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- const handle = require("./handle-Bz0C56Eq.js");
2
+ const handle = require("./handle-Crv1i9hb.js");
3
3
  const https = require("node:https");
4
4
  const http = require("node:http");
5
5
  const xmldom = require("@xmldom/xmldom");
@@ -313,7 +313,7 @@ function registerSoapHandlers(ipc) {
313
313
  handle.handleIpc(ipc, handle.IPC.wsdl.import, async (_event, opts) => {
314
314
  const { validateWsdlImport } = await Promise.resolve().then(() => require("./ipc-validate-sqUFqRmE.js"));
315
315
  validateWsdlImport(opts);
316
- const { importWsdl } = await Promise.resolve().then(() => require("./import-BhGBiW7j.js"));
316
+ const { importWsdl } = await Promise.resolve().then(() => require("./import-DTcZMRNu.js"));
317
317
  const wsdlText = opts.xml ?? (opts.url ? await fetchUrl(opts.url) : "");
318
318
  if (!wsdlText) throw new Error("wsdl:import requires either `url` or `xml`");
319
319
  return importWsdl(wsdlText, { name: opts.name, existingMockPorts: opts.existingMockPorts });