@testsmith/api-spector 0.8.3 → 0.8.5

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.
@@ -3,7 +3,7 @@ const promises = require("node:fs/promises");
3
3
  const path = require("node:path");
4
4
  const crypto = require("node:crypto");
5
5
  const undici = require("undici");
6
- const requestExec = require("./request-exec-CEmSNDIG.js");
6
+ const requestExec = require("./request-exec-WMdzNu1m.js");
7
7
  const Ajv = require("ajv");
8
8
  const jsYaml = require("js-yaml");
9
9
  require("node:http");
@@ -82,6 +82,7 @@ const IPC = {
82
82
  http: "import:http",
83
83
  har: "import:har",
84
84
  arazzo: "import:arazzo",
85
+ wsdl: "import:wsdl",
85
86
  spector: "import:spector",
86
87
  openapiSchemas: "import:openapi-schemas",
87
88
  openapiSchemasUrl: "import:openapi-schemas-url"
@@ -282,6 +283,8 @@ const IPC = {
282
283
  },
283
284
  // ─── Cloud (API Spector Cloud integration) ──────────────────────────────────
284
285
  cloud: {
286
+ /** One-click connect: browser consent + PKCE, returns a fresh token. */
287
+ connect: "cloud:connect",
285
288
  /** Verify the endpoint + token (GET /api/me). */
286
289
  test: "cloud:test",
287
290
  /** Push a mock server definition (POST /api/mocks). */
@@ -1,22 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const uuid = require("uuid");
4
- const soapHandler = require("./soap-handler-Brr7BPWO.js");
5
- require("./handle-Crv1i9hb.js");
4
+ const soapHandler = require("./soap-handler-BF5ii0UV.js");
5
+ require("./handle-_4XMUlwm.js");
6
6
  require("node:https");
7
7
  require("node:http");
8
8
  require("@xmldom/xmldom");
9
- const SOAP_11_CONTENT_TYPE = "text/xml; charset=utf-8";
10
- const SOAP_12_CONTENT_TYPE = "application/soap+xml; charset=utf-8";
11
- function contentTypeForSoap(version) {
12
- return version === "1.2" ? SOAP_12_CONTENT_TYPE : SOAP_11_CONTENT_TYPE;
13
- }
14
- function withContentType(headers, value) {
15
- const idx = headers.findIndex((h) => h.key.toLowerCase() === "content-type");
16
- const next = { key: "Content-Type", value, enabled: true };
17
- if (idx === -1) return [...headers, next];
18
- return headers.map((h, i) => i === idx ? { ...h, value, enabled: true } : h);
19
- }
20
9
  function buildRequestsFromWsdl(parsed) {
21
10
  const out = [];
22
11
  const byName = /* @__PURE__ */ new Map();
@@ -25,13 +14,13 @@ function buildRequestsFromWsdl(parsed) {
25
14
  if (!existing || existing.soapVersion === "1.2" && op.soapVersion === "1.1") byName.set(op.name, op);
26
15
  }
27
16
  for (const op of byName.values()) {
28
- const ct = contentTypeForSoap(op.soapVersion);
17
+ const ct = soapHandler.contentTypeForSoap(op.soapVersion);
29
18
  const req = {
30
19
  id: uuid.v4(),
31
20
  name: op.name,
32
21
  method: "POST",
33
22
  url: op.endpoint ?? "",
34
- headers: withContentType([], ct),
23
+ headers: soapHandler.withContentType([], ct),
35
24
  params: [],
36
25
  auth: { type: "none" },
37
26
  protocol: "soap",
@@ -102,7 +91,7 @@ function buildMockFromWsdl(name, parsed, existingPorts = []) {
102
91
  method: "POST",
103
92
  path: routePath,
104
93
  statusCode: 200,
105
- headers: { "Content-Type": contentTypeForSoap(version) },
94
+ headers: { "Content-Type": soapHandler.contentTypeForSoap(version) },
106
95
  body: "",
107
96
  description: `SOAP ${version} - dispatched per operation`,
108
97
  script: soapHandler.buildMockDispatchScript(),
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- const requestExec = require("./request-exec-CEmSNDIG.js");
2
+ const requestExec = require("./request-exec-WMdzNu1m.js");
3
3
  const grpc = require("@grpc/grpc-js");
4
4
  const protoLoader = require("@grpc/proto-loader");
5
5
  const fs = require("node:fs");
@@ -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-Crv1i9hb.js");
27
+ const handle = require("./handle-_4XMUlwm.js");
28
28
  const fs = require("node:fs");
29
29
  const os = require("node:os");
30
30
  const path = require("node:path");
@@ -786,6 +786,8 @@ async function getSecret(ref) {
786
786
  }
787
787
  return process.env[ref] ?? null;
788
788
  }
789
+ const PATH_PARAM_PATTERN = String.raw`\[([A-Za-z_]\w*)\]|(?<!\{)\{([A-Za-z_]\w*)\}(?!\})`;
790
+ const PATH_PARAM_RE = new RegExp(PATH_PARAM_PATTERN, "g");
789
791
  let _fakerCache$1 = null;
790
792
  async function getFaker$1() {
791
793
  _fakerCache$1 ??= await import("@faker-js/faker");
@@ -841,8 +843,8 @@ function buildUrl(baseUrl, params, vars) {
841
843
  templateTokens.add(String(name).trim());
842
844
  return "";
843
845
  });
844
- baseUrl.replaceAll(/\[([A-Za-z_]\w*)\]/g, (_m, name) => {
845
- templateTokens.add(String(name));
846
+ baseUrl.replaceAll(PATH_PARAM_RE, (_m, g1, g2) => {
847
+ templateTokens.add(g1 ?? g2);
846
848
  return "";
847
849
  });
848
850
  const enabled = (params ?? []).filter((p) => p.enabled && p.key);
@@ -858,7 +860,10 @@ function buildUrl(baseUrl, params, vars) {
858
860
  ...Object.fromEntries(pathRows.map((p) => [p.key, interpolate(p.value, vars)]))
859
861
  } : vars;
860
862
  let url = interpolate(baseUrl, mergedVars);
861
- url = url.replaceAll(/\[([A-Za-z_]\w*)\]/g, (m, name) => name in mergedVars ? mergedVars[name] : m);
863
+ url = url.replaceAll(PATH_PARAM_RE, (m, g1, g2) => {
864
+ const name = g1 ?? g2;
865
+ return name in mergedVars ? mergedVars[name] : m;
866
+ });
862
867
  if (!queryRows.length) return url;
863
868
  const sep = url.includes("?") ? "&" : "?";
864
869
  const qs = queryRows.map((p) => `${encodeURIComponent(interpolate(p.key, vars))}=${encodeURIComponent(interpolate(p.value, vars))}`).join("&");
@@ -1559,6 +1564,63 @@ async function readStream(body, kind, startMs, opts = {}) {
1559
1564
  }
1560
1565
  return { events, text, close, firstEventMs: Math.max(firstEventMs, 0) };
1561
1566
  }
1567
+ function jsonCommentRanges(input) {
1568
+ const ranges = [];
1569
+ const n = input.length;
1570
+ let i = 0;
1571
+ let inString = false;
1572
+ while (i < n) {
1573
+ const c = input[i];
1574
+ if (inString) {
1575
+ if (c === "\\") {
1576
+ i += 2;
1577
+ continue;
1578
+ }
1579
+ if (c === '"') inString = false;
1580
+ i++;
1581
+ continue;
1582
+ }
1583
+ if (c === '"') {
1584
+ inString = true;
1585
+ i++;
1586
+ continue;
1587
+ }
1588
+ const next = input[i + 1];
1589
+ if (c === "/" && next === "/") {
1590
+ const from = i;
1591
+ i += 2;
1592
+ while (i < n && input[i] !== "\n") i++;
1593
+ ranges.push({ from, to: i, type: "line" });
1594
+ continue;
1595
+ }
1596
+ if (c === "/" && next === "*") {
1597
+ const from = i;
1598
+ i += 2;
1599
+ while (i < n && !(input[i] === "*" && input[i + 1] === "/")) i++;
1600
+ i = Math.min(i + 2, n);
1601
+ ranges.push({ from, to: i, type: "block" });
1602
+ continue;
1603
+ }
1604
+ i++;
1605
+ }
1606
+ return ranges;
1607
+ }
1608
+ function stripJsonComments(input) {
1609
+ const ranges = jsonCommentRanges(input);
1610
+ if (!ranges.length) return input;
1611
+ let out = "";
1612
+ let pos = 0;
1613
+ for (const r of ranges) {
1614
+ out += input.slice(pos, r.from);
1615
+ if (r.type === "block") {
1616
+ const seg = input.slice(r.from, r.to);
1617
+ for (let k = 0; k < seg.length; k++) if (seg[k] === "\n") out += "\n";
1618
+ }
1619
+ pos = r.to;
1620
+ }
1621
+ out += input.slice(pos);
1622
+ return out;
1623
+ }
1562
1624
  async function runMqttTest(cfg) {
1563
1625
  const messages = [];
1564
1626
  const collectMs = Math.max(0, Math.min(6e4, Math.floor(cfg.collectMs ?? 2e3)));
@@ -2460,7 +2522,7 @@ async function buildDispatcher(proxy, tls) {
2460
2522
  function buildBodyAndApplyHeaders(req, vars, headers) {
2461
2523
  let body;
2462
2524
  if (req.body.mode === "json" && req.body.json) {
2463
- body = interpolate(req.body.json, vars);
2525
+ body = interpolate(stripJsonComments(req.body.json), vars);
2464
2526
  if (!headers.has("content-type")) headers.set("Content-Type", "application/json");
2465
2527
  } else if (req.body.mode === "form" && req.body.form) {
2466
2528
  body = req.body.form.filter((p) => p.enabled && p.key).map((p) => `${encodeURIComponent(interpolate(p.key, vars))}=${encodeURIComponent(interpolate(p.value, vars))}`).join("&");
@@ -2474,7 +2536,7 @@ function buildBodyAndApplyHeaders(req, vars, headers) {
2474
2536
  const rawVars = gql.variables?.trim();
2475
2537
  if (rawVars) {
2476
2538
  try {
2477
- gqlBody.variables = JSON.parse(interpolate(rawVars, vars));
2539
+ gqlBody.variables = JSON.parse(interpolate(stripJsonComments(rawVars), vars));
2478
2540
  } catch {
2479
2541
  }
2480
2542
  }
@@ -2633,6 +2695,9 @@ async function executeRunnerRequest(opts) {
2633
2695
  status: "running"
2634
2696
  };
2635
2697
  const dynamicVars = await buildDynamicVars();
2698
+ if (req.variables && Object.keys(req.variables).length > 0) {
2699
+ localVars = { ...req.variables, ...localVars };
2700
+ }
2636
2701
  if (localVars && Object.keys(localVars).length > 0) {
2637
2702
  localVars = resolveDataRow(localVars, mergeVars(envVars, collectionVars, globals2, {}, dynamicVars, folderVars));
2638
2703
  }
@@ -2949,4 +3014,5 @@ exports.runSocketIoTest = runSocketIoTest;
2949
3014
  exports.runWsTest = runWsTest;
2950
3015
  exports.setGlobals = setGlobals;
2951
3016
  exports.setSecretsConfig = setSecretsConfig;
3017
+ exports.stripJsonComments = stripJsonComments;
2952
3018
  exports.syntheticHttpFailure = syntheticHttpFailure;
@@ -1,8 +1,19 @@
1
1
  "use strict";
2
- const handle = require("./handle-Crv1i9hb.js");
2
+ const handle = require("./handle-_4XMUlwm.js");
3
3
  const https = require("node:https");
4
4
  const http = require("node:http");
5
5
  const xmldom = require("@xmldom/xmldom");
6
+ const SOAP_11_CONTENT_TYPE = "text/xml; charset=utf-8";
7
+ const SOAP_12_CONTENT_TYPE = "application/soap+xml; charset=utf-8";
8
+ function contentTypeForSoap(version) {
9
+ return version === "1.2" ? SOAP_12_CONTENT_TYPE : SOAP_11_CONTENT_TYPE;
10
+ }
11
+ function withContentType(headers, value) {
12
+ const idx = headers.findIndex((h) => h.key.toLowerCase() === "content-type");
13
+ const next = { key: "Content-Type", value, enabled: true };
14
+ if (idx === -1) return [...headers, next];
15
+ return headers.map((h, i) => i === idx ? { ...h, value, enabled: true } : h);
16
+ }
6
17
  function fetchUrl(url, headers = {}) {
7
18
  return new Promise((resolveP, rejectP) => {
8
19
  const lib = url.startsWith("https") ? https : http;
@@ -313,13 +324,25 @@ function registerSoapHandlers(ipc) {
313
324
  handle.handleIpc(ipc, handle.IPC.wsdl.import, async (_event, opts) => {
314
325
  const { validateWsdlImport } = await Promise.resolve().then(() => require("./ipc-validate-sqUFqRmE.js"));
315
326
  validateWsdlImport(opts);
316
- const { importWsdl } = await Promise.resolve().then(() => require("./import-DTcZMRNu.js"));
327
+ const { importWsdl } = await Promise.resolve().then(() => require("./import-ujxXe3Uu.js"));
317
328
  const wsdlText = opts.xml ?? (opts.url ? await fetchUrl(opts.url) : "");
318
329
  if (!wsdlText) throw new Error("wsdl:import requires either `url` or `xml`");
319
330
  return importWsdl(wsdlText, { name: opts.name, existingMockPorts: opts.existingMockPorts });
320
331
  });
321
332
  }
333
+ const soapHandler = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
334
+ __proto__: null,
335
+ buildEnvelopeTemplate,
336
+ buildMockDispatchScript,
337
+ buildResponseEnvelope,
338
+ fetchUrl,
339
+ parseWsdl,
340
+ registerSoapHandlers
341
+ }, Symbol.toStringTag, { value: "Module" }));
322
342
  exports.buildMockDispatchScript = buildMockDispatchScript;
323
343
  exports.buildResponseEnvelope = buildResponseEnvelope;
344
+ exports.contentTypeForSoap = contentTypeForSoap;
324
345
  exports.parseWsdl = parseWsdl;
325
346
  exports.registerSoapHandlers = registerSoapHandlers;
347
+ exports.soapHandler = soapHandler;
348
+ exports.withContentType = withContentType;
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
  const promises = require("node:fs/promises");
4
4
  const path = require("node:path");
5
- const brokerClient = require("./chunks/broker-client-BQBPAPCZ.js");
5
+ const brokerClient = require("./chunks/broker-client-BLNAmcIO.js");
6
6
  const escape = require("./chunks/escape-DDVAlOvZ.js");
7
7
  const crypto = require("node:crypto");
8
8
  const undici = require("undici");
@@ -11,10 +11,10 @@ const cliCommon = require("./chunks/cli-common-GnihVSjU.js");
11
11
  const node_child_process = require("node:child_process");
12
12
  const jsYaml = require("js-yaml");
13
13
  const environments = require("./chunks/environments-iM3SUM-4.js");
14
- require("./chunks/request-exec-CEmSNDIG.js");
14
+ require("./chunks/request-exec-WMdzNu1m.js");
15
15
  require("fs/promises");
16
16
  require("tls");
17
- require("./chunks/handle-Crv1i9hb.js");
17
+ require("./chunks/handle-_4XMUlwm.js");
18
18
  require("node:fs");
19
19
  require("dayjs");
20
20
  require("node:vm");
package/out/main/flow.js CHANGED
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
  const promises = require("node:fs/promises");
4
4
  const path = require("node:path");
5
- const requestExec = require("./chunks/request-exec-CEmSNDIG.js");
5
+ const requestExec = require("./chunks/request-exec-WMdzNu1m.js");
6
6
  const requestCollection = require("./chunks/request-collection-gkOYlWml.js");
7
7
  const environments = require("./chunks/environments-iM3SUM-4.js");
8
8
  const flowEngine = require("./chunks/flow-engine-BxwjEy37.js");
@@ -10,7 +10,7 @@ const cliCommon = require("./chunks/cli-common-GnihVSjU.js");
10
10
  require("undici");
11
11
  require("fs/promises");
12
12
  require("tls");
13
- require("./chunks/handle-Crv1i9hb.js");
13
+ require("./chunks/handle-_4XMUlwm.js");
14
14
  require("node:fs");
15
15
  require("node:os");
16
16
  require("node:crypto");
@@ -268,7 +268,7 @@ async function main() {
268
268
  const envName = args.environment ?? args.env;
269
269
  const env = environments.selectEnvironment(workspace, environments$1, envName);
270
270
  const verbose = Boolean(args.verbose);
271
- const version = `v${"0.8.3"}`;
271
+ const version = `v${"0.8.5"}`;
272
272
  console.log("");
273
273
  console.log(cliCommon.color(" API Flow Runner" + (version ? ` ${version}` : ""), cliCommon.C.bold, cliCommon.C.white));
274
274
  console.log(cliCommon.color(` Flow: ${flow.name}`, cliCommon.C.gray));