@testsmith/api-spector 0.8.9 → 0.9.1

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-s7k-oRi2.js");
6
+ const requestExec = require("./request-exec-DroNv29-.js");
7
7
  const Ajv = require("ajv");
8
8
  const jsYaml = require("js-yaml");
9
9
  require("node:http");
@@ -2024,8 +2024,8 @@ h1 { font-size: 20px; margin: 0 0 4px; }
2024
2024
  .card.pend { border-color: #92600a; }
2025
2025
  .method { font: 700 12px ui-monospace,SFMono-Regular,Menlo,monospace; width: 56px; flex-shrink: 0; color: #6aa3c8; }
2026
2026
  .name { flex: 1; color: #e4e3ea; font-weight: 500; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2027
- .url { color: #7a7785; font: 11px ui-monospace,monospace; max-width: 280px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2028
- .dur { color: #7a7785; font-size: 11px; }
2027
+ .url { color: #9d9aa8; font: 11px ui-monospace,monospace; max-width: 280px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2028
+ .dur { color: #9d9aa8; font-size: 11px; }
2029
2029
  .code { font: 700 12px ui-monospace,monospace; }
2030
2030
  .code.s2 { color: #9fc93c; } .code.s3 { color: #fbbf24; } .code.s4, .code.s5 { color: #f87171; }
2031
2031
  .viol { padding: 14px 16px; border-top: 1px solid #3d3b48; display: flex; flex-direction: column; gap: 10px; }
@@ -2034,7 +2034,7 @@ h1 { font-size: 20px; margin: 0 0 4px; }
2034
2034
  .v .path { font: 10px ui-monospace,monospace; color: #9d9aa8; background: #272630; padding: 1px 6px; border-radius: 4px; margin-left: 8px; }
2035
2035
  .v .m { color: #fecaca; font-size: 13px; margin: 4px 0 0; }
2036
2036
  .v .ea { font: 11px ui-monospace,monospace; margin-top: 4px; display: flex; gap: 18px; }
2037
- .v .ea .lab { color: #7a7785; }
2037
+ .v .ea .lab { color: #9d9aa8; }
2038
2038
  .v .ea .exp { color: #9fc93c; } .v .ea .act { color: #f87171; }
2039
2039
  .pass-note { color: #9fc93c; font-size: 13px; padding: 12px 16px; border-top: 1px solid #3d3b48; }
2040
2040
  table { border-collapse: collapse; width: 100%; margin-top: 16px; font-size: 13px; }
@@ -2044,10 +2044,10 @@ td.cell { text-align: center; }
2044
2044
  .b { display: inline-block; min-width: 56px; padding: 2px 8px; border-radius: 5px; font-size: 11px; font-weight: 700; }
2045
2045
  .b.ok { background: #2d3a12; color: #9fc93c; }
2046
2046
  .b.bad { background: rgba(127,29,29,.55); color: #f87171; }
2047
- .b.na { background: #272630; color: #7a7785; }
2047
+ .b.na { background: #272630; color: #9d9aa8; }
2048
2048
  a.b { text-decoration: none; }
2049
2049
  a.b.ok:hover { background: #4a5e1d; } a.b.bad:hover { background: rgba(127,29,29,.8); }
2050
- .foot { color: #7a7785; font-size: 11px; margin-top: 40px; text-align: center; }
2050
+ .foot { color: #9d9aa8; font-size: 11px; margin-top: 40px; text-align: center; }
2051
2051
  summary { cursor: pointer; list-style: none; }
2052
2052
  summary::-webkit-details-marker { display: none; }
2053
2053
  `;
@@ -79,7 +79,7 @@ function perfReportToHtml(result, meta = {}) {
79
79
  .muted { color: #7f93ab; } .small { font-size: 11px; margin-top: 8px; }
80
80
  code { background: #0d1a28; padding: 1px 5px; border-radius: 4px; color: #f9a8a8; font-size: 12px; }
81
81
  .errs { margin: 0; padding-left: 18px; } .errs li { margin: 3px 0; }
82
- footer { margin-top: 40px; color: #55697f; font-size: 11px; }
82
+ footer { margin-top: 40px; color: #7f93ab; font-size: 11px; }
83
83
  .cols { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; }
84
84
  @media (max-width: 720px) { .kpis { grid-template-columns: repeat(2, 1fr); } .cols { grid-template-columns: 1fr; } }
85
85
  </style></head>
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- const requestExec = require("./request-exec-s7k-oRi2.js");
2
+ const requestExec = require("./request-exec-DroNv29-.js");
3
3
  const grpc = require("@grpc/grpc-js");
4
4
  const protoLoader = require("@grpc/proto-loader");
5
5
  const fs = require("node:fs");
@@ -105,20 +105,21 @@ function readFileTrim(path2) {
105
105
  }
106
106
  function resolveConn$4() {
107
107
  const cfg = getSecretsConfig()?.vault ?? {};
108
- const address = env$4("VAULT_ADDR", "API_SPECTOR_VAULT_ADDR") ?? cfg.address;
108
+ const address = env$4("VAULT_ADDR", "BAO_ADDR", "API_SPECTOR_VAULT_ADDR") ?? cfg.address;
109
109
  if (!address) {
110
- throw new Error("Vault is not configured: set VAULT_ADDR (or settings.secrets.vault.address)");
111
- }
112
- const token = env$4("VAULT_TOKEN", "API_SPECTOR_VAULT_TOKEN") ?? readFileTrim(path.join(os.homedir(), ".vault-token"));
113
- const roleId = env$4("VAULT_ROLE_ID", "API_SPECTOR_VAULT_ROLE_ID") ?? cfg.roleId;
114
- const secretId = env$4("VAULT_SECRET_ID", "API_SPECTOR_VAULT_SECRET_ID");
115
- const jwt = env$4("VAULT_JWT", "API_SPECTOR_VAULT_JWT") ?? (env$4("VAULT_JWT_PATH", "API_SPECTOR_VAULT_JWT_PATH") ? readFileTrim(env$4("VAULT_JWT_PATH", "API_SPECTOR_VAULT_JWT_PATH")) : void 0);
116
- const jwtRole = env$4("VAULT_JWT_ROLE", "API_SPECTOR_VAULT_JWT_ROLE") ?? cfg.jwtRole;
117
- const explicit = env$4("VAULT_AUTH_METHOD", "API_SPECTOR_VAULT_AUTH_METHOD") ?? cfg.authMethod;
110
+ throw new Error("Vault/OpenBao is not configured: set VAULT_ADDR or BAO_ADDR (or settings.secrets.vault.address)");
111
+ }
112
+ const token = env$4("VAULT_TOKEN", "BAO_TOKEN", "API_SPECTOR_VAULT_TOKEN") ?? readFileTrim(path.join(os.homedir(), ".vault-token")) ?? readFileTrim(path.join(os.homedir(), ".bao-token"));
113
+ const roleId = env$4("VAULT_ROLE_ID", "BAO_ROLE_ID", "API_SPECTOR_VAULT_ROLE_ID") ?? cfg.roleId;
114
+ const secretId = env$4("VAULT_SECRET_ID", "BAO_SECRET_ID", "API_SPECTOR_VAULT_SECRET_ID");
115
+ const jwtPath = env$4("VAULT_JWT_PATH", "BAO_JWT_PATH", "API_SPECTOR_VAULT_JWT_PATH");
116
+ const jwt = env$4("VAULT_JWT", "BAO_JWT", "API_SPECTOR_VAULT_JWT") ?? (jwtPath ? readFileTrim(jwtPath) : void 0);
117
+ const jwtRole = env$4("VAULT_JWT_ROLE", "BAO_JWT_ROLE", "API_SPECTOR_VAULT_JWT_ROLE") ?? cfg.jwtRole;
118
+ const explicit = env$4("VAULT_AUTH_METHOD", "BAO_AUTH_METHOD", "API_SPECTOR_VAULT_AUTH_METHOD") ?? cfg.authMethod;
118
119
  const authMethod = explicit ?? (token ? "token" : roleId ? "approle" : jwt ? "jwt" : "token");
119
120
  return {
120
121
  address: address.replace(/\/+$/, ""),
121
- namespace: env$4("VAULT_NAMESPACE", "API_SPECTOR_VAULT_NAMESPACE") ?? cfg.namespace,
122
+ namespace: env$4("VAULT_NAMESPACE", "BAO_NAMESPACE", "API_SPECTOR_VAULT_NAMESPACE") ?? cfg.namespace,
122
123
  authMethod,
123
124
  token,
124
125
  roleId,
@@ -126,9 +127,9 @@ function resolveConn$4() {
126
127
  jwt,
127
128
  jwtRole,
128
129
  loginMount: cfg.loginMount,
129
- kvVersion: env$4("VAULT_KV_VERSION", "API_SPECTOR_VAULT_KV_VERSION") ?? cfg.kvVersion ?? "auto",
130
- skipVerify: (env$4("VAULT_SKIP_VERIFY", "API_SPECTOR_VAULT_SKIP_VERIFY") ?? "").toLowerCase() === "true" || cfg.skipVerify === true,
131
- caPath: env$4("VAULT_CACERT", "API_SPECTOR_VAULT_CACERT")
130
+ kvVersion: env$4("VAULT_KV_VERSION", "BAO_KV_VERSION", "API_SPECTOR_VAULT_KV_VERSION") ?? cfg.kvVersion ?? "auto",
131
+ skipVerify: (env$4("VAULT_SKIP_VERIFY", "BAO_SKIP_VERIFY", "API_SPECTOR_VAULT_SKIP_VERIFY") ?? "").toLowerCase() === "true" || cfg.skipVerify === true,
132
+ caPath: env$4("VAULT_CACERT", "BAO_CACERT", "API_SPECTOR_VAULT_CACERT")
132
133
  };
133
134
  }
134
135
  let cachedToken$2 = null;
@@ -202,15 +203,15 @@ async function clientToken(conn) {
202
203
  cachedToken$2 = { value: token, expiresAt: ttl > 0 ? now + ttl * 1e3 : now + 5 * 6e4 };
203
204
  return token;
204
205
  }
205
- async function readSecret(refBody) {
206
+ async function readSecret(refBody, scheme) {
206
207
  const hash = refBody.lastIndexOf("#");
207
208
  if (hash < 0) {
208
- throw new Error(`Vault reference must be 'vault:<path>#<key>' (got 'vault:${refBody}')`);
209
+ throw new Error(`${scheme} reference must be '${scheme}:<path>#<key>' (got '${scheme}:${refBody}')`);
209
210
  }
210
211
  const path2 = refBody.slice(0, hash).replace(/^\/+/, "");
211
212
  const key = refBody.slice(hash + 1);
212
213
  if (!path2 || !key) {
213
- throw new Error(`Vault reference must be 'vault:<path>#<key>' (got 'vault:${refBody}')`);
214
+ throw new Error(`${scheme} reference must be '${scheme}:<path>#<key>' (got '${scheme}:${refBody}')`);
214
215
  }
215
216
  const conn = resolveConn$4();
216
217
  const cacheKey = `${conn.address}|${conn.namespace ?? ""}|${path2}`;
@@ -235,7 +236,11 @@ async function readSecret(refBody) {
235
236
  }
236
237
  const vaultProvider = {
237
238
  scheme: "vault",
238
- resolve: (refBody) => readSecret(refBody)
239
+ resolve: (refBody) => readSecret(refBody, "vault")
240
+ };
241
+ const openBaoProvider = {
242
+ scheme: "bao",
243
+ resolve: (refBody) => readSecret(refBody, "bao")
239
244
  };
240
245
  function hmac(key, data) {
241
246
  return crypto.createHmac("sha256", key).update(data, "utf8").digest();
@@ -658,6 +663,7 @@ const gcpSecretManagerProvider = {
658
663
  resolve: (refBody) => resolve(refBody)
659
664
  };
660
665
  registerSecretProvider(vaultProvider);
666
+ registerSecretProvider(openBaoProvider);
661
667
  registerSecretProvider(awsSecretsProvider);
662
668
  registerSecretProvider(azureKeyVaultProvider);
663
669
  registerSecretProvider(onePasswordProvider);
@@ -791,7 +797,7 @@ async function buildDynamicVars() {
791
797
  };
792
798
  }
793
799
  function interpolate(str, vars) {
794
- return str.replaceAll(/\{\{([^}]+)\}\}/g, (match, key) => {
800
+ return str.replaceAll(/\{\{\s*((?:[^{}]|\{[^{}]*\})+?)\s*\}\}/g, (match, key) => {
795
801
  const trimmed = key.trim();
796
802
  if (trimmed in vars) return vars[trimmed];
797
803
  if (_exprContext && (trimmed.includes(".") || trimmed.includes("("))) {
@@ -811,7 +817,7 @@ function resolveDataRow(row, scope) {
811
817
  }
812
818
  function buildUrl(baseUrl, params, vars) {
813
819
  const templateTokens = /* @__PURE__ */ new Set();
814
- baseUrl.replaceAll(/\{\{([^}]+)\}\}/g, (_m, name) => {
820
+ baseUrl.replaceAll(/\{\{\s*((?:[^{}]|\{[^{}]*\})+?)\s*\}\}/g, (_m, name) => {
815
821
  templateTokens.add(String(name).trim());
816
822
  return "";
817
823
  });
@@ -1130,10 +1136,11 @@ function buildAt(ctx, testResults, consoleOutput) {
1130
1136
  fn();
1131
1137
  testResults.push({ name, passed: true });
1132
1138
  } catch (err) {
1139
+ const line = scriptLineOf(err);
1133
1140
  testResults.push({
1134
1141
  name,
1135
1142
  passed: false,
1136
- error: err instanceof Error ? err.message : String(err)
1143
+ error: (err instanceof Error ? err.message : String(err)) + (line ? ` (line ${line})` : "")
1137
1144
  });
1138
1145
  }
1139
1146
  },
@@ -1254,6 +1261,13 @@ function buildSandbox(scriptCtx, testResults, consoleOutput, faker) {
1254
1261
  setInterval: void 0
1255
1262
  };
1256
1263
  }
1264
+ function scriptLineOf(err) {
1265
+ if (err instanceof Error && err.stack) {
1266
+ const m = err.stack.match(/script\.js:(\d+):\d+/);
1267
+ if (m) return Number(m[1]);
1268
+ }
1269
+ return void 0;
1270
+ }
1257
1271
  async function runScript(code, ctx, timeoutMs = 5e3) {
1258
1272
  const faker = await getFaker();
1259
1273
  const testResults = [];
@@ -1279,6 +1293,7 @@ async function runScript(code, ctx, timeoutMs = 5e3) {
1279
1293
  try {
1280
1294
  vm__namespace.runInNewContext(code, sandbox, { timeout: timeoutMs, filename: "script.js" });
1281
1295
  } catch (err) {
1296
+ const line = scriptLineOf(err);
1282
1297
  const message = err instanceof Error ? err.message : String(err);
1283
1298
  return {
1284
1299
  testResults,
@@ -1288,7 +1303,7 @@ async function runScript(code, ctx, timeoutMs = 5e3) {
1288
1303
  updatedGlobals: globalsCopy,
1289
1304
  updatedLocalVars: localVarsCopy,
1290
1305
  updatedFolderVars: folderCopy,
1291
- error: message
1306
+ error: (line ? `Line ${line}: ` : "") + message
1292
1307
  };
1293
1308
  }
1294
1309
  return {
@@ -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-170x6Jx9.js");
5
+ const brokerClient = require("./chunks/broker-client-JU-AwkVE.js");
6
6
  const escape = require("./chunks/escape-DDVAlOvZ.js");
7
7
  const crypto = require("node:crypto");
8
8
  const undici = require("undici");
@@ -11,7 +11,7 @@ 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-s7k-oRi2.js");
14
+ require("./chunks/request-exec-DroNv29-.js");
15
15
  require("fs/promises");
16
16
  require("tls");
17
17
  require("./chunks/handle-_4XMUlwm.js");
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-s7k-oRi2.js");
5
+ const requestExec = require("./chunks/request-exec-DroNv29-.js");
6
6
  const requestCollection = require("./chunks/request-collection-zRRUfg0X.js");
7
7
  const environments = require("./chunks/environments-iM3SUM-4.js");
8
8
  const flowEngine = require("./chunks/flow-engine-BxwjEy37.js");
@@ -43,6 +43,9 @@ function pretty(v) {
43
43
  return esc(String(v));
44
44
  }
45
45
  }
46
+ function headerLines(h) {
47
+ return Object.entries(h).map(([k, v]) => `${k}: ${v}`).join("\n");
48
+ }
46
49
  const STATUS_CLS = {
47
50
  passed: "badge-pass",
48
51
  failed: "badge-fail",
@@ -60,8 +63,18 @@ function blockDetail(b) {
60
63
  ).join("");
61
64
  parts.push(`<div class="section-label">Tests</div><div class="tests-wrap">${rows}</div>`);
62
65
  }
63
- if (b.type === "request" && b.resolvedUrl) {
64
- parts.push(`<div class="section-label">Request</div><div class="mono url">${esc(b.method ?? "")} ${esc(b.resolvedUrl)}</div>`);
66
+ if (b.type === "request" && (b.resolvedUrl || b.http)) {
67
+ const h = b.http;
68
+ parts.push('<div class="section-label">Request</div>');
69
+ if (b.resolvedUrl) parts.push(`<div class="mono url">${esc(b.method ?? "")} ${esc(b.resolvedUrl)}</div>`);
70
+ if (h?.reqHeaders && Object.keys(h.reqHeaders).length) parts.push(`<pre class="code-block">${esc(headerLines(h.reqHeaders))}</pre>`);
71
+ if (h?.reqBody) parts.push(`<pre class="code-block">${pretty(h.reqBody)}</pre>`);
72
+ parts.push('<div class="section-label">Response</div>');
73
+ const statusLine = b.httpStatus != null ? `${b.httpStatus}${h?.statusText ? " " + h.statusText : ""}${h?.bodySize != null ? ` · ${h.bodySize} bytes` : ""}` : "(no response received)";
74
+ parts.push(`<div class="mono url">${esc(statusLine)}</div>`);
75
+ if (h?.resHeaders && Object.keys(h.resHeaders).length) parts.push(`<pre class="code-block">${esc(headerLines(h.resHeaders))}</pre>`);
76
+ if (h?.resBody) parts.push(`<pre class="code-block">${pretty(h.resBody)}</pre>`);
77
+ if (h?.truncated) parts.push('<div class="muted" style="font-size:11px">Request/response body truncated for the report.</div>');
65
78
  }
66
79
  if (b.type === "log" && b.message) {
67
80
  parts.push(`<div class="section-label">Message</div><pre class="code-block">${esc(b.message)}</pre>`);
@@ -268,7 +281,7 @@ async function main() {
268
281
  const envName = args.environment ?? args.env;
269
282
  const env = environments.selectEnvironment(workspace, environments$1, envName);
270
283
  const verbose = Boolean(args.verbose);
271
- const version = `v${"0.8.9"}`;
284
+ const version = `v${"0.9.1"}`;
272
285
  console.log("");
273
286
  console.log(cliCommon.color(" API Flow Runner" + (version ? ` ${version}` : ""), cliCommon.C.bold, cliCommon.C.white));
274
287
  console.log(cliCommon.color(` Flow: ${flow.name}`, cliCommon.C.gray));
package/out/main/index.js CHANGED
@@ -4,12 +4,13 @@ const handle = require("./chunks/handle-_4XMUlwm.js");
4
4
  const path = require("node:path");
5
5
  const fs = require("node:fs");
6
6
  const registerHandlers = require("./register-handlers.js");
7
- const requestExec = require("./chunks/request-exec-s7k-oRi2.js");
7
+ const requestExec = require("./chunks/request-exec-DroNv29-.js");
8
8
  const electronUpdater = require("electron-updater");
9
9
  const mockServer = require("./chunks/mock-server-C4kTFkod.js");
10
10
  require("node:fs/promises");
11
11
  require("node:crypto");
12
12
  require("jszip");
13
+ require("simple-git");
13
14
  require("./chunks/data-files-BYqhsoPe.js");
14
15
  require("./chunks/request-collection-zRRUfg0X.js");
15
16
  require("uuid");
@@ -26,13 +27,12 @@ require("./chunks/flow-engine-BxwjEy37.js");
26
27
  require("ws");
27
28
  require("socket.io-client");
28
29
  require("mqtt");
29
- require("./chunks/perf-report-ChaO3K0w.js");
30
+ require("./chunks/perf-report-KXGZgCDY.js");
30
31
  require("node:os");
31
32
  require("@grpc/grpc-js");
32
33
  require("@grpc/proto-loader");
33
34
  require("./chunks/escape-DDVAlOvZ.js");
34
- require("./chunks/broker-client-170x6Jx9.js");
35
- require("simple-git");
35
+ require("./chunks/broker-client-JU-AwkVE.js");
36
36
  require("./chunks/recorder-BkO8G_mB.js");
37
37
  require("fs/promises");
38
38
  require("tls");
@@ -50,7 +50,7 @@ function isNewer(a, b) {
50
50
  return a2 > b2;
51
51
  }
52
52
  async function checkForUpdate() {
53
- const current = "0.8.9";
53
+ const current = "0.9.1";
54
54
  try {
55
55
  const res = await fetch(REGISTRY_URL, { signal: AbortSignal.timeout(4e3) });
56
56
  if (!res.ok) return null;
package/out/main/lib.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const mockServer = require("./chunks/mock-server-C4kTFkod.js");
4
- const requestExec = require("./chunks/request-exec-s7k-oRi2.js");
4
+ const requestExec = require("./chunks/request-exec-DroNv29-.js");
5
5
  const flowEngine = require("./chunks/flow-engine-BxwjEy37.js");
6
6
  require("node:http");
7
7
  require("node:crypto");
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
- const perfRun = require("./chunks/perf-run-wfdvpJev.js");
3
- const requestExec = require("./chunks/request-exec-s7k-oRi2.js");
2
+ const perfRun = require("./chunks/perf-run-BEbf2piB.js");
3
+ const requestExec = require("./chunks/request-exec-DroNv29-.js");
4
4
  require("@grpc/grpc-js");
5
5
  require("@grpc/proto-loader");
6
6
  require("node:fs");
package/out/main/perf.js CHANGED
@@ -2,12 +2,12 @@
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-s7k-oRi2.js");
5
+ const requestExec = require("./chunks/request-exec-DroNv29-.js");
6
6
  const requestCollection = require("./chunks/request-collection-zRRUfg0X.js");
7
7
  const environments = require("./chunks/environments-iM3SUM-4.js");
8
8
  const flowEngine = require("./chunks/flow-engine-BxwjEy37.js");
9
- const perfRun = require("./chunks/perf-run-wfdvpJev.js");
10
- const perfReport = require("./chunks/perf-report-ChaO3K0w.js");
9
+ const perfRun = require("./chunks/perf-run-BEbf2piB.js");
10
+ const perfReport = require("./chunks/perf-report-KXGZgCDY.js");
11
11
  const cliCommon = require("./chunks/cli-common-GnihVSjU.js");
12
12
  require("undici");
13
13
  require("fs/promises");
@@ -191,7 +191,7 @@ async function main() {
191
191
  targetLabel = `flow: ${flow.name}`;
192
192
  }
193
193
  const load = perfRun.deriveLoad(plan);
194
- const version = `v${"0.8.9"}`;
194
+ const version = `v${"0.9.1"}`;
195
195
  console.log("");
196
196
  console.log(cliCommon.color(" API Performance" + (version ? ` ${version}` : ""), cliCommon.C.bold, cliCommon.C.white));
197
197
  console.log(cliCommon.color(` Plan: ${plan.name}`, cliCommon.C.gray));
@@ -28,9 +28,10 @@ const promises = require("node:fs/promises");
28
28
  const path = require("node:path");
29
29
  const crypto = require("node:crypto");
30
30
  const JSZip = require("jszip");
31
+ const simpleGit = require("simple-git");
31
32
  const dataFiles = require("./chunks/data-files-BYqhsoPe.js");
32
33
  const requestCollection = require("./chunks/request-collection-zRRUfg0X.js");
33
- const requestExec = require("./chunks/request-exec-s7k-oRi2.js");
34
+ const requestExec = require("./chunks/request-exec-DroNv29-.js");
34
35
  const ipcValidate = require("./chunks/ipc-validate-sqUFqRmE.js");
35
36
  const uuid = require("uuid");
36
37
  const jsYaml = require("js-yaml");
@@ -43,14 +44,13 @@ const http = require("node:http");
43
44
  const WebSocket = require("ws");
44
45
  const socket_ioClient = require("socket.io-client");
45
46
  const mqtt = require("mqtt");
46
- const perfReport = require("./chunks/perf-report-ChaO3K0w.js");
47
+ const perfReport = require("./chunks/perf-report-KXGZgCDY.js");
47
48
  const fs = require("node:fs");
48
49
  const os = require("node:os");
49
50
  const grpc = require("@grpc/grpc-js");
50
51
  const protoLoader = require("@grpc/proto-loader");
51
52
  const escape = require("./chunks/escape-DDVAlOvZ.js");
52
- const brokerClient = require("./chunks/broker-client-170x6Jx9.js");
53
- const simpleGit = require("simple-git");
53
+ const brokerClient = require("./chunks/broker-client-JU-AwkVE.js");
54
54
  const recorder = require("./chunks/recorder-BkO8G_mB.js");
55
55
  require("fs/promises");
56
56
  require("tls");
@@ -481,10 +481,8 @@ Create a workspace in this folder and add "${path.basename(wsPath)}" to it? The
481
481
  return { workspace: parsed, workspacePath: wsPath };
482
482
  });
483
483
  handle.handleIpc(ipc, handle.IPC.file.openFromGit, async (_e, repoUrl) => {
484
- const archiveUrl = await resolveArchiveUrl(repoUrl);
485
- if (!archiveUrl) {
486
- throw new Error("unsupported URL — use a public GitHub repo URL or a direct .zip link");
487
- }
484
+ const url = repoUrl.trim();
485
+ if (!url) throw new Error("Enter a repository URL");
488
486
  const pick = await electron.dialog.showOpenDialog({
489
487
  title: "Choose a folder to clone the repository into",
490
488
  properties: ["openDirectory", "createDirectory"],
@@ -492,7 +490,7 @@ Create a workspace in this folder and add "${path.basename(wsPath)}" to it? The
492
490
  });
493
491
  if (pick.canceled || pick.filePaths.length === 0) return null;
494
492
  const parent = pick.filePaths[0];
495
- const repoName = (/github\.com\/[^/]+\/([^/#?]+)/i.exec(repoUrl)?.[1] ?? "repository").replace(/\.git$/i, "").replaceAll(/[^a-zA-Z0-9._-]+/g, "-") || "repository";
493
+ const repoName = (/[/:]([^/:]+?)(?:\.git)?\/?$/.exec(url)?.[1] ?? "repository").replaceAll(/[^a-zA-Z0-9._-]+/g, "-") || "repository";
496
494
  const destDir = path.join(parent, repoName);
497
495
  try {
498
496
  const existing = await promises.readdir(destDir);
@@ -502,9 +500,20 @@ Create a workspace in this folder and add "${path.basename(wsPath)}" to it? The
502
500
  } catch (err) {
503
501
  if (err instanceof Error && err.message.includes("already exists")) throw err;
504
502
  }
505
- await promises.mkdir(destDir, { recursive: true });
506
- const buf = await downloadArchive(archiveUrl);
507
- await extractZip(buf, destDir);
503
+ try {
504
+ await simpleGit.simpleGit(parent).clone(url, destDir);
505
+ } catch (err) {
506
+ const msg = err instanceof Error ? err.message : String(err);
507
+ const gitMissing = /not found|ENOENT|not recognized|command not found|spawn git/i.test(msg);
508
+ const archiveUrl = gitMissing ? await resolveArchiveUrl(url).catch(() => null) : null;
509
+ if (gitMissing && archiveUrl) {
510
+ await promises.mkdir(destDir, { recursive: true });
511
+ const buf = await downloadArchive(archiveUrl);
512
+ await extractZip(buf, destDir);
513
+ } else {
514
+ throw new Error(`git clone failed: ${msg}`);
515
+ }
516
+ }
508
517
  const wsPath = await findWorkspaceSpector(destDir);
509
518
  const parsed = JSON.parse(await promises.readFile(wsPath, "utf8"));
510
519
  workspaceDir = path.dirname(wsPath);
@@ -5604,7 +5613,10 @@ function registerFlowHandler(ipc) {
5604
5613
  testResults: result.testResults,
5605
5614
  name: result.name,
5606
5615
  method: result.method,
5607
- resolvedUrl: result.resolvedUrl
5616
+ resolvedUrl: result.resolvedUrl,
5617
+ // The request actually sent (resolved headers/body), so the run log
5618
+ // and report can show it — especially on failures.
5619
+ sentRequest: result.sentRequest ? { method: result.method, url: result.resolvedUrl, headers: result.sentRequest.headers, body: result.sentRequest.body } : void 0
5608
5620
  };
5609
5621
  },
5610
5622
  runScript: async (code, input) => {
@@ -7216,11 +7228,11 @@ function generateHtml(payload) {
7216
7228
  .collection { margin-bottom: 3rem; }
7217
7229
  .collection-desc, .folder-desc, .desc { color: #94a3b8; font-size: .9rem; margin: .25rem 0 1rem; }
7218
7230
  .request { background: #1e2433; border: 1px solid #2d3748; border-radius: 8px; padding: 1rem 1.25rem; margin: 1rem 0; }
7219
- .label { font-size: .7rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: #64748b; margin: .75rem 0 .3rem; }
7231
+ .label { font-size: .7rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: #94a3b8; margin: .75rem 0 .3rem; }
7220
7232
  pre { background: #131924; border: 1px solid #2d3748; border-radius: 6px; padding: .75rem 1rem; overflow-x: auto; margin: 0; }
7221
7233
  code { font-family: 'JetBrains Mono', 'Fira Mono', monospace; font-size: .8rem; color: #a5f3fc; }
7222
7234
  table { border-collapse: collapse; width: 100%; font-size: .85rem; margin: .25rem 0; }
7223
- th { background: #131924; color: #64748b; font-weight: 600; text-align: left; padding: .4rem .6rem; border: 1px solid #2d3748; }
7235
+ th { background: #131924; color: #94a3b8; font-weight: 600; text-align: left; padding: .4rem .6rem; border: 1px solid #2d3748; }
7224
7236
  td { padding: .35rem .6rem; border: 1px solid #2d3748; color: #cbd5e1; font-family: monospace; font-size: .8rem; }
7225
7237
  .auth-type { background: #1e2433; border: 1px solid #2d3748; border-radius: 4px; display: inline-block; padding: .2rem .6rem; font-size: .8rem; color: #a5f3fc; margin: 0; }
7226
7238
  .folder-heading { color: #94a3b8; font-size: 1.05rem; }
@@ -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-s7k-oRi2.js");
5
+ const requestExec = require("./chunks/request-exec-DroNv29-.js");
6
6
  const requestCollection = require("./chunks/request-collection-zRRUfg0X.js");
7
7
  const escape = require("./chunks/escape-DDVAlOvZ.js");
8
8
  const runConcurrent = require("./chunks/run-concurrent-468tH0AX.js");
@@ -173,18 +173,18 @@ function buildHtmlReport(results, summary, meta = {}) {
173
173
  :root {
174
174
  --bg: #0f1117; --bg-surface: #161b22; --bg-panel: #0d1117;
175
175
  --border: #21262d; --border-hover:#30363d;
176
- --text: #c9d1d9; --text-bright: #e6edf3; --text-muted: #8b949e; --text-dim: #484f58;
176
+ --text: #c9d1d9; --text-bright: #e6edf3; --text-muted: #8b949e; --text-dim: #818992;
177
177
  --green: #3fb950; --red: #f85149; --amber: #d29922; --blue: #79c0ff;
178
178
  --badge-pass-bg: #0d3a1e; --badge-fail-bg: #3d1014; --badge-err-bg: #3d2a00; --badge-skip-bg: #21262d;
179
179
  --hook-before-border: #7c3aed; --hook-after-border: #0e7490;
180
180
  --hook-before-bg: #4c1d95; --hook-before-fg: #c4b5fd;
181
181
  --hook-after-bg: #164e63; --hook-after-fg: #67e8f9;
182
- --link: #3d7fb2;
182
+ --link: #58a6ff;
183
183
  }
184
184
  html.light {
185
185
  --bg: #ffffff; --bg-surface: #f6f8fa; --bg-panel: #ffffff;
186
186
  --border: #d0d7de; --border-hover:#c4c9cf;
187
- --text: #1f2328; --text-bright: #1f2328; --text-muted: #656d76; --text-dim: #8b949e;
187
+ --text: #1f2328; --text-bright: #1f2328; --text-muted: #656d76; --text-dim: #6b7280;
188
188
  --green: #1a7f37; --red: #cf222e; --amber: #9a6700; --blue: #0969da;
189
189
  --badge-pass-bg: #dafbe1; --badge-fail-bg: #ffebe9; --badge-err-bg: #fff8c5; --badge-skip-bg: #f6f8fa;
190
190
  --hook-before-border: #8b5cf6; --hook-after-border: #06b6d4;
@@ -551,7 +551,7 @@ async function main() {
551
551
  } else if (!envName && workspace.settings?.defaultEnvironment && !env) {
552
552
  console.warn(cliCommon.color(`Warning: default environment "${workspace.settings.defaultEnvironment}" not found. Running without environment.`, cliCommon.C.yellow));
553
553
  }
554
- const version = `v${"0.8.9"}`;
554
+ const version = `v${"0.9.1"}`;
555
555
  console.log("");
556
556
  console.log(cliCommon.color(" API Test Runner" + (version ? ` ${version}` : ""), cliCommon.C.bold, cliCommon.C.white));
557
557
  console.log(cliCommon.color(` Workspace: ${wsPath}`, cliCommon.C.gray));
@@ -1,5 +1,5 @@
1
1
  import { l as linter, E as EditorView, L as LanguageSupport, i as LRLanguage, s as styleTags, m as indentNodeProp, n as delimitedIndent, p as foldNodeProp, q as foldInside, S as StateField, u as LRParser, v as StateEffect, w as tags, a as reactExports, j as jsxRuntimeExports, e as ReactCodeMirror, o as oneDark, d as json } from "./codemirror-BKmwMUlV.js";
2
- import { u as useT, a as useStore, b as useActiveEnvironment, i as isSubscriptionQuery } from "./index-D_-cF6J0.js";
2
+ import { u as useT, a as useStore, b as useActiveEnvironment, i as isSubscriptionQuery } from "./index-Bf9-CiTh.js";
3
3
  import "./ajv-CJPwFjiP.js";
4
4
  function devAssert(condition, message) {
5
5
  const booleanCondition = Boolean(condition);
@@ -1,5 +1,5 @@
1
1
  import { a as reactExports, j as jsxRuntimeExports, e as ReactCodeMirror, o as oneDark, x as xml } from "./codemirror-BKmwMUlV.js";
2
- import { u as useT, c as btnPrimaryCls, d as commentKeymap } from "./index-D_-cF6J0.js";
2
+ import { u as useT, c as btnPrimaryCls, d as commentKeymap } from "./index-Bf9-CiTh.js";
3
3
  import "./ajv-CJPwFjiP.js";
4
4
  const SOAP_11_CONTENT_TYPE = "text/xml; charset=utf-8";
5
5
  const SOAP_12_CONTENT_TYPE = "application/soap+xml; charset=utf-8";