@testsmith/api-spector 0.3.9 → 0.4.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.
- package/out/main/chunks/{handle-Coax8Nz1.js → handle-BGYDylL2.js} +6 -0
- package/out/main/chunks/{import-Bilo697Z.js → import-CUcjlmSK.js} +2 -2
- package/out/main/chunks/{request-exec-C0DnGKdd.js → request-exec-DlvyG4rn.js} +1 -1
- package/out/main/chunks/{snapshots-CatB4zLh.js → snapshots-B7rDeWNy.js} +1 -1
- package/out/main/chunks/{soap-handler-B1Huudj7.js → soap-handler-CAyUjzxB.js} +2 -2
- package/out/main/contract.js +3 -3
- package/out/main/index.js +217 -18
- package/out/main/runner.js +3 -3
- package/out/main/wsdl.js +3 -3
- package/out/preload/index.js +9 -0
- package/out/renderer/assets/{index-BdUvP_cg.js → index-DGOQFW5S.js} +577 -82
- package/out/renderer/assets/index-DkZ0bxof.css +2 -0
- package/out/renderer/index.html +2 -2
- package/package.json +1 -1
- package/out/renderer/assets/index-B6kFQEbI.css +0 -2
|
@@ -3,7 +3,9 @@ const IPC = {
|
|
|
3
3
|
// ─── Workspace / File ──────────────────────────────────────────────────────
|
|
4
4
|
file: {
|
|
5
5
|
openWorkspace: "file:openWorkspace",
|
|
6
|
+
openWorkspacePath: "file:openWorkspacePath",
|
|
6
7
|
getLastWorkspace: "file:getLastWorkspace",
|
|
8
|
+
getRecentWorkspaces: "file:getRecentWorkspaces",
|
|
7
9
|
saveWorkspace: "file:saveWorkspace",
|
|
8
10
|
newWorkspace: "file:newWorkspace",
|
|
9
11
|
closeWorkspace: "file:closeWorkspace",
|
|
@@ -153,6 +155,10 @@ const IPC = {
|
|
|
153
155
|
// ─── Shell ─────────────────────────────────────────────────────────────────
|
|
154
156
|
shell: {
|
|
155
157
|
openExternal: "shell:openExternal"
|
|
158
|
+
},
|
|
159
|
+
// ─── App ───────────────────────────────────────────────────────────────────
|
|
160
|
+
app: {
|
|
161
|
+
checkUpdate: "app:checkUpdate"
|
|
156
162
|
}
|
|
157
163
|
};
|
|
158
164
|
function handleIpc(ipc, channel, fn) {
|
|
@@ -1,8 +1,8 @@
|
|
|
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-
|
|
5
|
-
require("./handle-
|
|
4
|
+
const soapHandler = require("./soap-handler-CAyUjzxB.js");
|
|
5
|
+
require("./handle-BGYDylL2.js");
|
|
6
6
|
require("https");
|
|
7
7
|
require("http");
|
|
8
8
|
require("@xmldom/xmldom");
|
|
@@ -23,7 +23,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
));
|
|
24
24
|
const undici = require("undici");
|
|
25
25
|
const promises = require("fs/promises");
|
|
26
|
-
const handle = require("./handle-
|
|
26
|
+
const handle = require("./handle-BGYDylL2.js");
|
|
27
27
|
const crypto = require("crypto");
|
|
28
28
|
const path = require("path");
|
|
29
29
|
const dayjs = require("dayjs");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const undici = require("undici");
|
|
3
|
-
const requestExec = require("./request-exec-
|
|
3
|
+
const requestExec = require("./request-exec-DlvyG4rn.js");
|
|
4
4
|
const promises = require("fs/promises");
|
|
5
5
|
const path = require("path");
|
|
6
6
|
const Ajv = require("ajv");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
const handle = require("./handle-
|
|
2
|
+
const handle = require("./handle-BGYDylL2.js");
|
|
3
3
|
const https = require("https");
|
|
4
4
|
const http = require("http");
|
|
5
5
|
const xmldom = require("@xmldom/xmldom");
|
|
@@ -315,7 +315,7 @@ function registerSoapHandlers(ipc) {
|
|
|
315
315
|
handle.handleIpc(ipc, handle.IPC.wsdl.import, async (_event, opts) => {
|
|
316
316
|
const { validateWsdlImport } = await Promise.resolve().then(() => require("./ipc-validate-k6KI8adf.js"));
|
|
317
317
|
validateWsdlImport(opts);
|
|
318
|
-
const { importWsdl } = await Promise.resolve().then(() => require("./import-
|
|
318
|
+
const { importWsdl } = await Promise.resolve().then(() => require("./import-CUcjlmSK.js"));
|
|
319
319
|
const wsdlText = opts.xml ?? (opts.url ? await fetchUrl(opts.url) : "");
|
|
320
320
|
if (!wsdlText) throw new Error("wsdl:import requires either `url` or `xml`");
|
|
321
321
|
return importWsdl(wsdlText, { name: opts.name, existingMockPorts: opts.existingMockPorts });
|
package/out/main/contract.js
CHANGED
|
@@ -24,14 +24,14 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
const promises = require("fs/promises");
|
|
26
26
|
const path = require("path");
|
|
27
|
-
const snapshots = require("./chunks/snapshots-
|
|
27
|
+
const snapshots = require("./chunks/snapshots-B7rDeWNy.js");
|
|
28
28
|
const crypto = require("crypto");
|
|
29
29
|
const undici = require("undici");
|
|
30
30
|
const os = require("os");
|
|
31
31
|
const cliCommon = require("./chunks/cli-common-CDQY1erJ.js");
|
|
32
32
|
const environments = require("./chunks/environments-iM3SUM-4.js");
|
|
33
|
-
require("./chunks/request-exec-
|
|
34
|
-
require("./chunks/handle-
|
|
33
|
+
require("./chunks/request-exec-DlvyG4rn.js");
|
|
34
|
+
require("./chunks/handle-BGYDylL2.js");
|
|
35
35
|
require("dayjs");
|
|
36
36
|
require("vm");
|
|
37
37
|
require("tv4");
|
package/out/main/index.js
CHANGED
|
@@ -22,12 +22,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
22
22
|
mod
|
|
23
23
|
));
|
|
24
24
|
const electron = require("electron");
|
|
25
|
-
const handle = require("./chunks/handle-
|
|
25
|
+
const handle = require("./chunks/handle-BGYDylL2.js");
|
|
26
26
|
const path = require("path");
|
|
27
27
|
const fs = require("fs");
|
|
28
28
|
const promises = require("fs/promises");
|
|
29
29
|
const crypto = require("crypto");
|
|
30
|
-
const requestExec = require("./chunks/request-exec-
|
|
30
|
+
const requestExec = require("./chunks/request-exec-DlvyG4rn.js");
|
|
31
31
|
const ipcValidate = require("./chunks/ipc-validate-k6KI8adf.js");
|
|
32
32
|
const uuid = require("uuid");
|
|
33
33
|
const jsYaml = require("js-yaml");
|
|
@@ -37,9 +37,9 @@ const requestCollection = require("./chunks/request-collection-CJoXpvOw.js");
|
|
|
37
37
|
const mockServer = require("./chunks/mock-server-DSLR2ulH.js");
|
|
38
38
|
const http = require("http");
|
|
39
39
|
const WebSocket = require("ws");
|
|
40
|
-
const soapHandler = require("./chunks/soap-handler-
|
|
40
|
+
const soapHandler = require("./chunks/soap-handler-CAyUjzxB.js");
|
|
41
41
|
const os = require("os");
|
|
42
|
-
const snapshots = require("./chunks/snapshots-
|
|
42
|
+
const snapshots = require("./chunks/snapshots-B7rDeWNy.js");
|
|
43
43
|
const simpleGit = require("simple-git");
|
|
44
44
|
const recorder = require("./chunks/recorder-0Ij921El.js");
|
|
45
45
|
require("dayjs");
|
|
@@ -50,8 +50,29 @@ require("@xmldom/xmldom");
|
|
|
50
50
|
require("ajv");
|
|
51
51
|
require("https");
|
|
52
52
|
const LAST_WS_FILE = path.join(electron.app.getPath("userData"), "last-workspace.json");
|
|
53
|
+
const RECENTS_FILE = path.join(electron.app.getPath("userData"), "recent-workspaces.json");
|
|
54
|
+
const MAX_RECENTS = 10;
|
|
55
|
+
async function readRecentWorkspaces() {
|
|
56
|
+
try {
|
|
57
|
+
const list = JSON.parse(await promises.readFile(RECENTS_FILE, "utf8"));
|
|
58
|
+
return Array.isArray(list) ? list : [];
|
|
59
|
+
} catch {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function pushRecentWorkspace(wsPath) {
|
|
64
|
+
const name = path.basename(wsPath).replace(/\.(spector|json)$/i, "");
|
|
65
|
+
const list = (await readRecentWorkspaces()).filter((r) => r.path !== wsPath);
|
|
66
|
+
list.unshift({ path: wsPath, name, lastOpened: Date.now() });
|
|
67
|
+
try {
|
|
68
|
+
await promises.writeFile(RECENTS_FILE, JSON.stringify(list.slice(0, MAX_RECENTS), null, 2), "utf8");
|
|
69
|
+
} catch (err) {
|
|
70
|
+
console.warn("file-handler: could not update recent-workspaces", err);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
53
73
|
async function saveLastWorkspacePath(wsPath) {
|
|
54
74
|
await promises.writeFile(LAST_WS_FILE, JSON.stringify({ path: wsPath }), "utf8");
|
|
75
|
+
await pushRecentWorkspace(wsPath);
|
|
55
76
|
}
|
|
56
77
|
async function readLastWorkspacePath() {
|
|
57
78
|
try {
|
|
@@ -380,6 +401,33 @@ Create a workspace in this folder and add "${path.basename(wsPath)}" to it? The
|
|
|
380
401
|
return null;
|
|
381
402
|
}
|
|
382
403
|
});
|
|
404
|
+
handle.handleIpc(ipc, handle.IPC.file.getRecentWorkspaces, async () => {
|
|
405
|
+
const list = await readRecentWorkspaces();
|
|
406
|
+
const alive = await Promise.all(list.map(async (r) => {
|
|
407
|
+
try {
|
|
408
|
+
await promises.readFile(r.path, "utf8");
|
|
409
|
+
return r;
|
|
410
|
+
} catch {
|
|
411
|
+
return null;
|
|
412
|
+
}
|
|
413
|
+
}));
|
|
414
|
+
return alive.filter((r) => r !== null);
|
|
415
|
+
});
|
|
416
|
+
handle.handleIpc(ipc, handle.IPC.file.openWorkspacePath, async (_e, wsPath) => {
|
|
417
|
+
let raw;
|
|
418
|
+
try {
|
|
419
|
+
raw = await promises.readFile(wsPath, "utf8");
|
|
420
|
+
} catch {
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
const parsed = JSON.parse(raw);
|
|
424
|
+
if (looksLikeCollection(parsed)) return null;
|
|
425
|
+
workspaceDir = path.dirname(wsPath);
|
|
426
|
+
workspaceFile = wsPath;
|
|
427
|
+
await requestExec.loadGlobals(workspaceDir);
|
|
428
|
+
await saveLastWorkspacePath(wsPath);
|
|
429
|
+
return { workspace: parsed, workspacePath: wsPath };
|
|
430
|
+
});
|
|
383
431
|
}
|
|
384
432
|
async function tryOpenWorkspaceInDir(dir) {
|
|
385
433
|
let entries;
|
|
@@ -475,6 +523,19 @@ function formatRequestError(err, context) {
|
|
|
475
523
|
if (causeMessage) {
|
|
476
524
|
lines.push(`[request:send] cause=${causeMessage}${causeCode ? ` (code=${causeCode})` : ""}`);
|
|
477
525
|
}
|
|
526
|
+
const certCodes = /* @__PURE__ */ new Set([
|
|
527
|
+
"SELF_SIGNED_CERT_IN_CHAIN",
|
|
528
|
+
"DEPTH_ZERO_SELF_SIGNED_CERT",
|
|
529
|
+
"UNABLE_TO_VERIFY_LEAF_SIGNATURE",
|
|
530
|
+
"UNABLE_TO_GET_ISSUER_CERT_LOCALLY",
|
|
531
|
+
"CERT_HAS_EXPIRED",
|
|
532
|
+
"ERR_TLS_CERT_ALTNAME_INVALID"
|
|
533
|
+
]);
|
|
534
|
+
if (certCodes.has(code ?? "") || certCodes.has(causeCode ?? "")) {
|
|
535
|
+
lines.push(
|
|
536
|
+
'[request:send] hint=A self-signed or untrusted TLS certificate was rejected. Uncheck "Reject unauthorized / self-signed certificates" in Collection or Workspace settings, which also relaxes verification for the proxy connection, or add the CA certificate under TLS settings.'
|
|
537
|
+
);
|
|
538
|
+
}
|
|
478
539
|
if (stack) {
|
|
479
540
|
const preview = stack.split("\n").slice(0, 6).join("\n");
|
|
480
541
|
lines.push("[request:send] stack:");
|
|
@@ -1470,12 +1531,12 @@ function toRequestBody(bodyText, headers) {
|
|
|
1470
1531
|
return { mode: "raw", raw: bodyText, rawContentType: ct || "text/plain" };
|
|
1471
1532
|
}
|
|
1472
1533
|
function extractAuth(headers) {
|
|
1473
|
-
const
|
|
1474
|
-
if (
|
|
1475
|
-
const bearer = /^Bearer\s+(.+)$/i.exec(
|
|
1534
|
+
const authHeader2 = headers.find((h) => h.key.toLowerCase() === "authorization");
|
|
1535
|
+
if (authHeader2) {
|
|
1536
|
+
const bearer = /^Bearer\s+(.+)$/i.exec(authHeader2.value.trim());
|
|
1476
1537
|
if (bearer) {
|
|
1477
1538
|
return {
|
|
1478
|
-
headers: headers.filter((h) => h !==
|
|
1539
|
+
headers: headers.filter((h) => h !== authHeader2),
|
|
1479
1540
|
auth: { type: "bearer", token: bearer[1].trim() }
|
|
1480
1541
|
};
|
|
1481
1542
|
}
|
|
@@ -3965,10 +4026,10 @@ function generateKarate(collection, environment) {
|
|
|
3965
4026
|
files.unshift({ path: "README.md", content: buildReadme(collection.name, files.map((f) => f.path)) });
|
|
3966
4027
|
return files;
|
|
3967
4028
|
}
|
|
3968
|
-
function mapOut(s) {
|
|
4029
|
+
function mapOut$1(s) {
|
|
3969
4030
|
return s.replace(/\{\{\s*(\$[A-Za-z]+)\s*\}\}/g, (_m, name) => `{{${SPECTOR_TO_HTTP[name] ?? name}}}`);
|
|
3970
4031
|
}
|
|
3971
|
-
function orderedRequests(collection) {
|
|
4032
|
+
function orderedRequests$1(collection) {
|
|
3972
4033
|
const out = [];
|
|
3973
4034
|
const walk = (folder) => {
|
|
3974
4035
|
for (const id of folder.requestIds) {
|
|
@@ -3998,7 +4059,7 @@ function authToHeader(auth) {
|
|
|
3998
4059
|
return null;
|
|
3999
4060
|
}
|
|
4000
4061
|
}
|
|
4001
|
-
function buildUrl(req) {
|
|
4062
|
+
function buildUrl$1(req) {
|
|
4002
4063
|
const query = (req.params ?? []).filter((p) => p.enabled && p.key && p.paramType !== "path");
|
|
4003
4064
|
if (req.auth.type === "apikey" && req.auth.apiKeyIn === "query" && req.auth.apiKeyName) {
|
|
4004
4065
|
query.push({ key: req.auth.apiKeyName, value: req.auth.apiKeyValue ?? "", enabled: true });
|
|
@@ -4036,33 +4097,141 @@ function generateHttpFile(collection, environment) {
|
|
|
4036
4097
|
Object.assign(vars, collection.collectionVariables ?? {});
|
|
4037
4098
|
const varKeys = Object.keys(vars);
|
|
4038
4099
|
if (varKeys.length) {
|
|
4039
|
-
for (const k of varKeys) lines.push(`@${k} = ${mapOut(vars[k])}`);
|
|
4100
|
+
for (const k of varKeys) lines.push(`@${k} = ${mapOut$1(vars[k])}`);
|
|
4040
4101
|
lines.push("");
|
|
4041
4102
|
}
|
|
4042
|
-
orderedRequests(collection).forEach((req, idx) => {
|
|
4103
|
+
orderedRequests$1(collection).forEach((req, idx) => {
|
|
4043
4104
|
if (idx > 0) lines.push("");
|
|
4044
4105
|
lines.push(`### ${req.name}`);
|
|
4045
4106
|
if (req.description?.trim()) {
|
|
4046
4107
|
for (const l of req.description.trim().split(/\r?\n/)) lines.push(`# ${l}`);
|
|
4047
4108
|
}
|
|
4048
|
-
lines.push(`${req.method} ${mapOut(buildUrl(req))}`);
|
|
4109
|
+
lines.push(`${req.method} ${mapOut$1(buildUrl$1(req))}`);
|
|
4049
4110
|
const headers = [...(req.headers ?? []).filter((h) => h.enabled && h.key)];
|
|
4050
|
-
const
|
|
4051
|
-
if (
|
|
4111
|
+
const authHeader2 = authToHeader(req.auth);
|
|
4112
|
+
if (authHeader2) headers.unshift(authHeader2);
|
|
4052
4113
|
const body = bodyLines(req);
|
|
4053
4114
|
const hasCT = headers.some((h) => h.key.toLowerCase() === "content-type");
|
|
4054
4115
|
if (body.text && body.contentType && !hasCT) {
|
|
4055
4116
|
headers.push({ key: "Content-Type", value: body.contentType, enabled: true });
|
|
4056
4117
|
}
|
|
4057
|
-
for (const h of headers) lines.push(`${h.key}: ${mapOut(h.value)}`);
|
|
4118
|
+
for (const h of headers) lines.push(`${h.key}: ${mapOut$1(h.value)}`);
|
|
4058
4119
|
if (body.text) {
|
|
4059
4120
|
lines.push("");
|
|
4060
|
-
lines.push(mapOut(body.text));
|
|
4121
|
+
lines.push(mapOut$1(body.text));
|
|
4061
4122
|
}
|
|
4062
4123
|
});
|
|
4063
4124
|
const slug2 = collection.name.replace(/\W+/g, "-").replace(/^-+|-+$/g, "").toLowerCase() || "collection";
|
|
4064
4125
|
return [{ path: `${slug2}.http`, content: lines.join("\n") + "\n" }];
|
|
4065
4126
|
}
|
|
4127
|
+
function mapOut(s) {
|
|
4128
|
+
return s.replace(/\{\{\s*([A-Za-z_][A-Za-z0-9_]*)\s*\}\}/g, (_m, name) => `\${${name}}`);
|
|
4129
|
+
}
|
|
4130
|
+
function shq(s) {
|
|
4131
|
+
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
4132
|
+
}
|
|
4133
|
+
function dq(s) {
|
|
4134
|
+
return `"${s.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
4135
|
+
}
|
|
4136
|
+
function orderedRequests(collection) {
|
|
4137
|
+
const out = [];
|
|
4138
|
+
const walk = (folder) => {
|
|
4139
|
+
for (const id of folder.requestIds) {
|
|
4140
|
+
const req = collection.requests[id];
|
|
4141
|
+
if (req) out.push(req);
|
|
4142
|
+
}
|
|
4143
|
+
for (const sub of folder.folders) walk(sub);
|
|
4144
|
+
};
|
|
4145
|
+
walk(collection.rootFolder);
|
|
4146
|
+
return out;
|
|
4147
|
+
}
|
|
4148
|
+
function authHeader(auth) {
|
|
4149
|
+
switch (auth.type) {
|
|
4150
|
+
case "bearer":
|
|
4151
|
+
return auth.token ? { key: "Authorization", value: `Bearer ${auth.token}`, enabled: true } : null;
|
|
4152
|
+
case "apikey":
|
|
4153
|
+
if (auth.apiKeyIn === "query") return null;
|
|
4154
|
+
return auth.apiKeyName ? { key: auth.apiKeyName, value: auth.apiKeyValue ?? "", enabled: true } : null;
|
|
4155
|
+
default:
|
|
4156
|
+
return null;
|
|
4157
|
+
}
|
|
4158
|
+
}
|
|
4159
|
+
function buildUrl(req) {
|
|
4160
|
+
const query = (req.params ?? []).filter((p) => p.enabled && p.key && p.paramType !== "path");
|
|
4161
|
+
if (req.auth.type === "apikey" && req.auth.apiKeyIn === "query" && req.auth.apiKeyName) {
|
|
4162
|
+
query.push({ key: req.auth.apiKeyName, value: req.auth.apiKeyValue ?? "", enabled: true });
|
|
4163
|
+
}
|
|
4164
|
+
if (!query.length) return req.url;
|
|
4165
|
+
const qs = query.map((p) => `${p.key}=${p.value}`).join("&");
|
|
4166
|
+
return req.url + (req.url.includes("?") ? "&" : "?") + qs;
|
|
4167
|
+
}
|
|
4168
|
+
function bodyOf(req) {
|
|
4169
|
+
const b = req.body;
|
|
4170
|
+
switch (b.mode) {
|
|
4171
|
+
case "json":
|
|
4172
|
+
return { contentType: "application/json", text: b.json ?? "" };
|
|
4173
|
+
case "graphql":
|
|
4174
|
+
return { contentType: "application/json", text: JSON.stringify({ query: b.graphql?.query ?? "", variables: b.graphql?.variables ? safeParse(b.graphql.variables) : void 0 }) };
|
|
4175
|
+
case "soap":
|
|
4176
|
+
return { contentType: "text/xml", text: b.soap?.envelope ?? "" };
|
|
4177
|
+
case "raw":
|
|
4178
|
+
return { contentType: b.rawContentType, text: b.raw ?? "" };
|
|
4179
|
+
case "form":
|
|
4180
|
+
return {
|
|
4181
|
+
contentType: "application/x-www-form-urlencoded",
|
|
4182
|
+
text: (b.form ?? []).filter((f) => f.enabled && f.key).map((f) => `${f.key}=${f.value}`).join("&")
|
|
4183
|
+
};
|
|
4184
|
+
default:
|
|
4185
|
+
return {};
|
|
4186
|
+
}
|
|
4187
|
+
}
|
|
4188
|
+
function safeParse(s) {
|
|
4189
|
+
try {
|
|
4190
|
+
return JSON.parse(s);
|
|
4191
|
+
} catch {
|
|
4192
|
+
return s;
|
|
4193
|
+
}
|
|
4194
|
+
}
|
|
4195
|
+
function generateCurl(collection, environment) {
|
|
4196
|
+
const lines = ["#!/usr/bin/env bash", "set -euo pipefail", ""];
|
|
4197
|
+
const vars = {};
|
|
4198
|
+
for (const v of environment?.variables ?? []) {
|
|
4199
|
+
if (v.enabled && !v.secret) vars[v.key] = v.value;
|
|
4200
|
+
}
|
|
4201
|
+
Object.assign(vars, collection.collectionVariables ?? {});
|
|
4202
|
+
const varKeys = Object.keys(vars);
|
|
4203
|
+
if (varKeys.length) {
|
|
4204
|
+
lines.push("# Variables (override via the environment before running)");
|
|
4205
|
+
for (const k of varKeys) lines.push(`${k}=${shq(vars[k])}`);
|
|
4206
|
+
lines.push("");
|
|
4207
|
+
}
|
|
4208
|
+
orderedRequests(collection).forEach((req, idx) => {
|
|
4209
|
+
if (idx > 0) lines.push("");
|
|
4210
|
+
lines.push(`# ${req.name}`);
|
|
4211
|
+
if (req.description?.trim()) {
|
|
4212
|
+
for (const l of req.description.trim().split(/\r?\n/)) lines.push(`# ${l}`);
|
|
4213
|
+
}
|
|
4214
|
+
const args = [`curl -sS -X ${req.method} ${dq(mapOut(buildUrl(req)))}`];
|
|
4215
|
+
if (req.auth.type === "basic") {
|
|
4216
|
+
const user = mapOut(req.auth.username ?? "");
|
|
4217
|
+
const pass = mapOut(req.auth.password ?? "");
|
|
4218
|
+
args.push(`-u ${dq(`${user}:${pass}`)}`);
|
|
4219
|
+
}
|
|
4220
|
+
const headers = [...(req.headers ?? []).filter((h) => h.enabled && h.key)];
|
|
4221
|
+
const ah = authHeader(req.auth);
|
|
4222
|
+
if (ah) headers.unshift(ah);
|
|
4223
|
+
const body = bodyOf(req);
|
|
4224
|
+
const hasCT = headers.some((h) => h.key.toLowerCase() === "content-type");
|
|
4225
|
+
if (body.text && body.contentType && !hasCT) {
|
|
4226
|
+
headers.push({ key: "Content-Type", value: body.contentType, enabled: true });
|
|
4227
|
+
}
|
|
4228
|
+
for (const h of headers) args.push(`-H ${dq(`${h.key}: ${mapOut(h.value)}`)}`);
|
|
4229
|
+
if (body.text) args.push(`--data ${dq(mapOut(body.text))}`);
|
|
4230
|
+
lines.push(args.join(" \\\n "));
|
|
4231
|
+
});
|
|
4232
|
+
const slug2 = collection.name.replace(/\W+/g, "-").replace(/^-+|-+$/g, "").toLowerCase() || "collection";
|
|
4233
|
+
return [{ path: `${slug2}.sh`, content: lines.join("\n") + "\n" }];
|
|
4234
|
+
}
|
|
4066
4235
|
function registerGenerateHandlers(ipc) {
|
|
4067
4236
|
handle.handleIpc(ipc, handle.IPC.generate.code, (_e, opts) => {
|
|
4068
4237
|
const { collection, environment, target } = opts;
|
|
@@ -4083,6 +4252,8 @@ function registerGenerateHandlers(ipc) {
|
|
|
4083
4252
|
return generateKarate(collection, environment);
|
|
4084
4253
|
case "http_file":
|
|
4085
4254
|
return generateHttpFile(collection, environment);
|
|
4255
|
+
case "curl":
|
|
4256
|
+
return generateCurl(collection, environment);
|
|
4086
4257
|
default:
|
|
4087
4258
|
throw new Error(`Unknown target: ${target}`);
|
|
4088
4259
|
}
|
|
@@ -4993,6 +5164,33 @@ function registerRecordHandlers(ipc, getWebContents) {
|
|
|
4993
5164
|
return recorder.entriesToMockServer(entries, upstream, name, port);
|
|
4994
5165
|
});
|
|
4995
5166
|
}
|
|
5167
|
+
const REGISTRY_URL = "https://registry.npmjs.org/@testsmith/api-spector/latest";
|
|
5168
|
+
function isNewer(a, b) {
|
|
5169
|
+
const core = (v) => v.split("-")[0].split(".").map((n) => parseInt(n, 10) || 0);
|
|
5170
|
+
const [a0, a1, a2] = core(a);
|
|
5171
|
+
const [b0, b1, b2] = core(b);
|
|
5172
|
+
if (a0 !== b0) return a0 > b0;
|
|
5173
|
+
if (a1 !== b1) return a1 > b1;
|
|
5174
|
+
return a2 > b2;
|
|
5175
|
+
}
|
|
5176
|
+
async function checkForUpdate() {
|
|
5177
|
+
const current = "0.4.1";
|
|
5178
|
+
try {
|
|
5179
|
+
const res = await fetch(REGISTRY_URL, { signal: AbortSignal.timeout(4e3) });
|
|
5180
|
+
if (!res.ok) return null;
|
|
5181
|
+
const data = await res.json();
|
|
5182
|
+
const latest = data.version;
|
|
5183
|
+
if (!latest) return null;
|
|
5184
|
+
return {
|
|
5185
|
+
current,
|
|
5186
|
+
latest,
|
|
5187
|
+
updateAvailable: isNewer(latest, current),
|
|
5188
|
+
command: "npm update -g @testsmith/api-spector"
|
|
5189
|
+
};
|
|
5190
|
+
} catch {
|
|
5191
|
+
return null;
|
|
5192
|
+
}
|
|
5193
|
+
}
|
|
4996
5194
|
if (process.env.ELECTRON_NO_SANDBOX === "1") {
|
|
4997
5195
|
electron.app.commandLine.appendSwitch("no-sandbox");
|
|
4998
5196
|
electron.app.commandLine.appendSwitch("disable-features", "RendererCodeIntegrity");
|
|
@@ -5097,6 +5295,7 @@ electron.app.whenReady().then(async () => {
|
|
|
5097
5295
|
registerGitHandlers(electron.ipcMain);
|
|
5098
5296
|
registerRecordHandlers(electron.ipcMain, () => electron.BrowserWindow.getAllWindows()[0]?.webContents ?? null);
|
|
5099
5297
|
handle.handleIpc(electron.ipcMain, handle.IPC.shell.openExternal, (_e, url) => electron.shell.openExternal(url));
|
|
5298
|
+
handle.handleIpc(electron.ipcMain, handle.IPC.app.checkUpdate, () => checkForUpdate());
|
|
5100
5299
|
createWindow();
|
|
5101
5300
|
electron.app.on("activate", () => {
|
|
5102
5301
|
if (electron.BrowserWindow.getAllWindows().length === 0) createWindow();
|
package/out/main/runner.js
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
const promises = require("fs/promises");
|
|
4
4
|
const path = require("path");
|
|
5
|
-
const requestExec = require("./chunks/request-exec-
|
|
5
|
+
const requestExec = require("./chunks/request-exec-DlvyG4rn.js");
|
|
6
6
|
const requestCollection = require("./chunks/request-collection-CJoXpvOw.js");
|
|
7
7
|
const environments = require("./chunks/environments-iM3SUM-4.js");
|
|
8
8
|
const cliCommon = require("./chunks/cli-common-CDQY1erJ.js");
|
|
9
9
|
require("undici");
|
|
10
|
-
require("./chunks/handle-
|
|
10
|
+
require("./chunks/handle-BGYDylL2.js");
|
|
11
11
|
require("crypto");
|
|
12
12
|
require("dayjs");
|
|
13
13
|
require("vm");
|
|
@@ -396,7 +396,7 @@ async function main() {
|
|
|
396
396
|
} else if (!envName && workspace.settings?.defaultEnvironment && !env) {
|
|
397
397
|
console.warn(cliCommon.color(`Warning: default environment "${workspace.settings.defaultEnvironment}" not found. Running without environment.`, cliCommon.C.yellow));
|
|
398
398
|
}
|
|
399
|
-
const version = `v${"0.
|
|
399
|
+
const version = `v${"0.4.1"}`;
|
|
400
400
|
console.log("");
|
|
401
401
|
console.log(cliCommon.color(" API Test Runner" + (version ? ` ${version}` : ""), cliCommon.C.bold, cliCommon.C.white));
|
|
402
402
|
console.log(cliCommon.color(` Workspace: ${wsPath}`, cliCommon.C.gray));
|
package/out/main/wsdl.js
CHANGED
|
@@ -4,10 +4,10 @@ const promises = require("fs/promises");
|
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const https = require("https");
|
|
6
6
|
const http = require("http");
|
|
7
|
-
const soapHandler = require("./chunks/soap-handler-
|
|
8
|
-
const _import = require("./chunks/import-
|
|
7
|
+
const soapHandler = require("./chunks/soap-handler-CAyUjzxB.js");
|
|
8
|
+
const _import = require("./chunks/import-CUcjlmSK.js");
|
|
9
9
|
const cliCommon = require("./chunks/cli-common-CDQY1erJ.js");
|
|
10
|
-
require("./chunks/handle-
|
|
10
|
+
require("./chunks/handle-BGYDylL2.js");
|
|
11
11
|
require("@xmldom/xmldom");
|
|
12
12
|
require("uuid");
|
|
13
13
|
function fetchUrl(url) {
|
package/out/preload/index.js
CHANGED
|
@@ -4,7 +4,9 @@ const IPC = {
|
|
|
4
4
|
// ─── Workspace / File ──────────────────────────────────────────────────────
|
|
5
5
|
file: {
|
|
6
6
|
openWorkspace: "file:openWorkspace",
|
|
7
|
+
openWorkspacePath: "file:openWorkspacePath",
|
|
7
8
|
getLastWorkspace: "file:getLastWorkspace",
|
|
9
|
+
getRecentWorkspaces: "file:getRecentWorkspaces",
|
|
8
10
|
saveWorkspace: "file:saveWorkspace",
|
|
9
11
|
newWorkspace: "file:newWorkspace",
|
|
10
12
|
closeWorkspace: "file:closeWorkspace",
|
|
@@ -154,12 +156,18 @@ const IPC = {
|
|
|
154
156
|
// ─── Shell ─────────────────────────────────────────────────────────────────
|
|
155
157
|
shell: {
|
|
156
158
|
openExternal: "shell:openExternal"
|
|
159
|
+
},
|
|
160
|
+
// ─── App ───────────────────────────────────────────────────────────────────
|
|
161
|
+
app: {
|
|
162
|
+
checkUpdate: "app:checkUpdate"
|
|
157
163
|
}
|
|
158
164
|
};
|
|
159
165
|
const api = {
|
|
160
166
|
// ─── Workspace / File ──────────────────────────────────────────────────────
|
|
161
167
|
openWorkspace: () => electron.ipcRenderer.invoke(IPC.file.openWorkspace),
|
|
162
168
|
getLastWorkspace: () => electron.ipcRenderer.invoke(IPC.file.getLastWorkspace),
|
|
169
|
+
getRecentWorkspaces: () => electron.ipcRenderer.invoke(IPC.file.getRecentWorkspaces),
|
|
170
|
+
openWorkspacePath: (path) => electron.ipcRenderer.invoke(IPC.file.openWorkspacePath, path),
|
|
163
171
|
saveWorkspace: (ws) => electron.ipcRenderer.invoke(IPC.file.saveWorkspace, ws),
|
|
164
172
|
newWorkspace: () => electron.ipcRenderer.invoke(IPC.file.newWorkspace),
|
|
165
173
|
closeWorkspace: () => electron.ipcRenderer.invoke(IPC.file.closeWorkspace),
|
|
@@ -297,6 +305,7 @@ const api = {
|
|
|
297
305
|
},
|
|
298
306
|
// ─── Shell ────────────────────────────────────────────────────────────────
|
|
299
307
|
openExternal: (url) => electron.ipcRenderer.invoke(IPC.shell.openExternal, url),
|
|
308
|
+
checkForUpdate: () => electron.ipcRenderer.invoke(IPC.app.checkUpdate),
|
|
300
309
|
// ─── Zoom ─────────────────────────────────────────────────────────────────
|
|
301
310
|
setZoomFactor: (factor) => electron.webFrame.setZoomFactor(factor),
|
|
302
311
|
// ─── Platform ─────────────────────────────────────────────────────────────
|