@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.
@@ -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-B1Huudj7.js");
5
- require("./handle-Coax8Nz1.js");
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-Coax8Nz1.js");
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-C0DnGKdd.js");
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-Coax8Nz1.js");
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-Bilo697Z.js"));
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 });
@@ -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-CatB4zLh.js");
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-C0DnGKdd.js");
34
- require("./chunks/handle-Coax8Nz1.js");
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-Coax8Nz1.js");
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-C0DnGKdd.js");
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-B1Huudj7.js");
40
+ const soapHandler = require("./chunks/soap-handler-CAyUjzxB.js");
41
41
  const os = require("os");
42
- const snapshots = require("./chunks/snapshots-CatB4zLh.js");
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 authHeader = headers.find((h) => h.key.toLowerCase() === "authorization");
1474
- if (authHeader) {
1475
- const bearer = /^Bearer\s+(.+)$/i.exec(authHeader.value.trim());
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 !== authHeader),
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 authHeader = authToHeader(req.auth);
4051
- if (authHeader) headers.unshift(authHeader);
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();
@@ -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-C0DnGKdd.js");
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-Coax8Nz1.js");
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.3.9"}`;
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-B1Huudj7.js");
8
- const _import = require("./chunks/import-Bilo697Z.js");
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-Coax8Nz1.js");
10
+ require("./chunks/handle-BGYDylL2.js");
11
11
  require("@xmldom/xmldom");
12
12
  require("uuid");
13
13
  function fetchUrl(url) {
@@ -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 ─────────────────────────────────────────────────────────────