@testsmith/api-spector 0.5.3 → 0.5.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.
@@ -2252,6 +2252,7 @@ exports.buildSchemaTestResults = buildSchemaTestResults;
2252
2252
  exports.buildUrl = buildUrl;
2253
2253
  exports.deriveRunStatus = deriveRunStatus;
2254
2254
  exports.executeRunnerRequest = executeRunnerRequest;
2255
+ exports.fetchOAuth2Token = fetchOAuth2Token;
2255
2256
  exports.getGlobals = getGlobals;
2256
2257
  exports.getSecret = getSecret;
2257
2258
  exports.hasSecretScheme = hasSecretScheme;
@@ -3,7 +3,7 @@ const promises = require("fs/promises");
3
3
  const path = require("path");
4
4
  const crypto = require("crypto");
5
5
  const undici = require("undici");
6
- const requestExec = require("./request-exec-igCwP-QK.js");
6
+ const requestExec = require("./request-exec-Dg-EHFX0.js");
7
7
  const Ajv = require("ajv");
8
8
  const jsYaml = require("js-yaml");
9
9
  require("http");
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
  const promises = require("fs/promises");
4
4
  const path = require("path");
5
- const snapshots = require("./chunks/snapshots-DWvEZ64W.js");
5
+ const snapshots = require("./chunks/snapshots-CN8g7lqA.js");
6
6
  const crypto = require("crypto");
7
7
  const undici = require("undici");
8
8
  const os = require("os");
@@ -10,7 +10,7 @@ const cliCommon = require("./chunks/cli-common-BKYgsbGB.js");
10
10
  const child_process = require("child_process");
11
11
  const jsYaml = require("js-yaml");
12
12
  const environments = require("./chunks/environments-iM3SUM-4.js");
13
- require("./chunks/request-exec-igCwP-QK.js");
13
+ require("./chunks/request-exec-Dg-EHFX0.js");
14
14
  require("tls");
15
15
  require("./chunks/handle-BFaeFA0A.js");
16
16
  require("node:fs");
package/out/main/index.js CHANGED
@@ -28,7 +28,7 @@ const fs$1 = require("fs");
28
28
  const promises = require("fs/promises");
29
29
  const crypto = require("crypto");
30
30
  const JSZip = require("jszip");
31
- const requestExec = require("./chunks/request-exec-igCwP-QK.js");
31
+ const requestExec = require("./chunks/request-exec-Dg-EHFX0.js");
32
32
  const ipcValidate = require("./chunks/ipc-validate-k6KI8adf.js");
33
33
  const uuid = require("uuid");
34
34
  const jsYaml = require("js-yaml");
@@ -45,7 +45,7 @@ const protoLoader = require("@grpc/proto-loader");
45
45
  const soapHandler = require("./chunks/soap-handler-DCCE344x.js");
46
46
  const promises$1 = require("node:fs/promises");
47
47
  const os$1 = require("os");
48
- const snapshots = require("./chunks/snapshots-DWvEZ64W.js");
48
+ const snapshots = require("./chunks/snapshots-CN8g7lqA.js");
49
49
  const simpleGit = require("simple-git");
50
50
  const recorder = require("./chunks/recorder-0Ij921El.js");
51
51
  require("tls");
@@ -4681,90 +4681,108 @@ function registerMockHandlers(ipc) {
4681
4681
  return JSON.parse(raw);
4682
4682
  });
4683
4683
  }
4684
- function registerOAuth2Handlers(ipc) {
4685
- handle.handleIpc(ipc, handle.IPC.oauth2.startFlow, async (_e, auth, vars) => {
4686
- const port = auth.oauth2RedirectPort ?? 9876;
4687
- const redirectUri = `http://localhost:${port}/callback`;
4688
- const authUrl = requestExec.interpolate(auth.oauth2AuthUrl ?? "", vars);
4689
- const tokenUrl = requestExec.interpolate(auth.oauth2TokenUrl ?? "", vars);
4690
- const clientId = requestExec.interpolate(auth.oauth2ClientId ?? "", vars);
4691
- let clientSecret = auth.oauth2ClientSecret ?? "";
4692
- if (!clientSecret && auth.oauth2ClientSecretRef) {
4693
- clientSecret = await requestExec.getSecret(auth.oauth2ClientSecretRef) ?? "";
4694
- }
4695
- clientSecret = requestExec.interpolate(clientSecret, vars);
4696
- if (!authUrl) throw new Error("OAuth 2.0: authUrl is required for authorization_code flow.");
4697
- if (!tokenUrl) throw new Error("OAuth 2.0: tokenUrl is required for authorization_code flow.");
4698
- if (!clientId) throw new Error("OAuth 2.0: clientId is required.");
4699
- const state = Math.random().toString(36).slice(2);
4700
- const authUrlFull = new URL(authUrl);
4701
- authUrlFull.searchParams.set("response_type", "code");
4702
- authUrlFull.searchParams.set("client_id", clientId);
4703
- authUrlFull.searchParams.set("redirect_uri", redirectUri);
4704
- authUrlFull.searchParams.set("state", state);
4705
- if (auth.oauth2Scopes) authUrlFull.searchParams.set("scope", auth.oauth2Scopes);
4706
- const code = await new Promise((resolve2, reject) => {
4707
- const server = http.createServer((req, res) => {
4708
- const reqUrl = new URL(req.url ?? "/", `http://localhost:${port}`);
4709
- if (!reqUrl.pathname.startsWith("/callback")) {
4710
- res.writeHead(404);
4711
- res.end();
4712
- return;
4713
- }
4714
- const returnedState = reqUrl.searchParams.get("state");
4715
- const returnedCode = reqUrl.searchParams.get("code");
4716
- const error = reqUrl.searchParams.get("error");
4684
+ async function resolveClientSecret(auth, vars) {
4685
+ let secret = auth.oauth2ClientSecret ?? "";
4686
+ if (!secret && auth.oauth2ClientSecretRef) {
4687
+ secret = await requestExec.getSecret(auth.oauth2ClientSecretRef) ?? "";
4688
+ }
4689
+ return requestExec.interpolate(secret, vars);
4690
+ }
4691
+ async function browserFlow(auth, vars, flow) {
4692
+ const port = auth.oauth2RedirectPort ?? 9876;
4693
+ const redirectUri = `http://localhost:${port}/callback`;
4694
+ const authUrl = requestExec.interpolate(auth.oauth2AuthUrl ?? "", vars);
4695
+ const clientId = requestExec.interpolate(auth.oauth2ClientId ?? "", vars);
4696
+ if (!authUrl) throw new Error(`OAuth 2.0: authUrl is required for the ${flow} flow.`);
4697
+ if (!clientId) throw new Error("OAuth 2.0: clientId is required.");
4698
+ const state = Math.random().toString(36).slice(2);
4699
+ const authUrlFull = new URL(authUrl);
4700
+ authUrlFull.searchParams.set("response_type", flow === "implicit" ? "token" : "code");
4701
+ authUrlFull.searchParams.set("client_id", clientId);
4702
+ authUrlFull.searchParams.set("redirect_uri", redirectUri);
4703
+ authUrlFull.searchParams.set("state", state);
4704
+ if (auth.oauth2Scopes) authUrlFull.searchParams.set("scope", auth.oauth2Scopes);
4705
+ const captured = await new Promise((resolve2, reject) => {
4706
+ const server = http.createServer((req, res) => {
4707
+ const reqUrl = new URL(req.url ?? "/", `http://localhost:${port}`);
4708
+ if (flow === "implicit" && reqUrl.pathname === "/callback" && !reqUrl.searchParams.get("access_token") && !reqUrl.searchParams.get("error")) {
4717
4709
  res.writeHead(200, { "Content-Type": "text/html" });
4718
- res.end("<html><body><p>Authorization complete. You may close this tab.</p></body></html>");
4719
- server.close();
4720
- if (error) {
4721
- reject(new Error(`OAuth 2.0 authorization error: ${error}`));
4722
- return;
4723
- }
4724
- if (returnedState !== state) {
4725
- reject(new Error("OAuth 2.0: state mismatch."));
4726
- return;
4727
- }
4728
- if (!returnedCode) {
4729
- reject(new Error("OAuth 2.0: no code in callback."));
4730
- return;
4731
- }
4732
- resolve2(returnedCode);
4733
- });
4734
- server.on("error", reject);
4735
- server.listen(port, "127.0.0.1", () => {
4736
- electron.shell.openExternal(authUrlFull.toString()).catch(reject);
4737
- });
4738
- setTimeout(() => {
4739
- server.close();
4740
- reject(new Error("OAuth 2.0 authorization timed out (5 min)."));
4741
- }, 5 * 60 * 1e3);
4710
+ res.end('<!doctype html><html><body><p>Completing sign-in… you may close this tab.</p><script>location.replace("/callback/capture?" + (location.hash ? location.hash.substring(1) : ""));<\/script></body></html>');
4711
+ return;
4712
+ }
4713
+ if (reqUrl.pathname !== "/callback" && reqUrl.pathname !== "/callback/capture") {
4714
+ res.writeHead(404);
4715
+ res.end();
4716
+ return;
4717
+ }
4718
+ const params2 = Object.fromEntries(reqUrl.searchParams.entries());
4719
+ res.writeHead(200, { "Content-Type": "text/html" });
4720
+ res.end("<!doctype html><html><body><p>Authorization complete. You may close this tab.</p></body></html>");
4721
+ server.close();
4722
+ if (params2["error"]) {
4723
+ reject(new Error(`OAuth 2.0 authorization error: ${params2["error_description"] ?? params2["error"]}`));
4724
+ return;
4725
+ }
4726
+ if (params2["state"] !== state) {
4727
+ reject(new Error("OAuth 2.0: state mismatch."));
4728
+ return;
4729
+ }
4730
+ resolve2(params2);
4742
4731
  });
4743
- const { fetch: nodeFetch } = await import("undici");
4744
- const params = new URLSearchParams();
4745
- params.set("grant_type", "authorization_code");
4746
- params.set("code", code);
4747
- params.set("redirect_uri", redirectUri);
4748
- params.set("client_id", clientId);
4749
- if (clientSecret) params.set("client_secret", clientSecret);
4750
- const resp = await nodeFetch(tokenUrl, {
4751
- method: "POST",
4752
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
4753
- body: params.toString()
4732
+ server.on("error", reject);
4733
+ server.listen(port, "127.0.0.1", () => {
4734
+ electron.shell.openExternal(authUrlFull.toString()).catch(reject);
4754
4735
  });
4755
- if (!resp.ok) {
4756
- const body = await resp.text();
4757
- throw new Error(`OAuth 2.0 token exchange failed (${resp.status}): ${body}`);
4736
+ setTimeout(() => {
4737
+ server.close();
4738
+ reject(new Error("OAuth 2.0 authorization timed out (5 min)."));
4739
+ }, 5 * 60 * 1e3);
4740
+ });
4741
+ if (flow === "implicit") {
4742
+ const accessToken2 = captured["access_token"] ?? "";
4743
+ if (!accessToken2) throw new Error("OAuth 2.0: no access_token in implicit callback.");
4744
+ const expiresIn2 = Number(captured["expires_in"] ?? 3600);
4745
+ return { accessToken: accessToken2, expiresAt: Date.now() + expiresIn2 * 1e3 };
4746
+ }
4747
+ const code = captured["code"] ?? "";
4748
+ if (!code) throw new Error("OAuth 2.0: no code in callback.");
4749
+ const tokenUrl = requestExec.interpolate(auth.oauth2TokenUrl ?? "", vars);
4750
+ if (!tokenUrl) throw new Error("OAuth 2.0: tokenUrl is required for the authorization_code flow.");
4751
+ const clientSecret = await resolveClientSecret(auth, vars);
4752
+ const { fetch: nodeFetch } = await import("undici");
4753
+ const params = new URLSearchParams();
4754
+ params.set("grant_type", "authorization_code");
4755
+ params.set("code", code);
4756
+ params.set("redirect_uri", redirectUri);
4757
+ params.set("client_id", clientId);
4758
+ if (clientSecret) params.set("client_secret", clientSecret);
4759
+ const resp = await nodeFetch(tokenUrl, {
4760
+ method: "POST",
4761
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
4762
+ body: params.toString()
4763
+ });
4764
+ if (!resp.ok) {
4765
+ const body = await resp.text();
4766
+ throw new Error(`OAuth 2.0 token exchange failed (${resp.status}): ${body}`);
4767
+ }
4768
+ const json = await resp.json();
4769
+ const accessToken = String(json["access_token"] ?? "");
4770
+ if (!accessToken) throw new Error("OAuth 2.0: token response missing access_token.");
4771
+ const expiresIn = Number(json["expires_in"] ?? 3600);
4772
+ return {
4773
+ accessToken,
4774
+ expiresAt: Date.now() + expiresIn * 1e3,
4775
+ refreshToken: json["refresh_token"] ? String(json["refresh_token"]) : void 0
4776
+ };
4777
+ }
4778
+ function registerOAuth2Handlers(ipc) {
4779
+ handle.handleIpc(ipc, handle.IPC.oauth2.startFlow, async (_e, auth, vars) => {
4780
+ if (auth.type !== "oauth2") throw new Error("OAuth 2.0: auth is not an oauth2 config.");
4781
+ const flow = auth.oauth2Flow ?? "client_credentials";
4782
+ if (flow === "authorization_code" || flow === "implicit") {
4783
+ return browserFlow(auth, vars, flow);
4758
4784
  }
4759
- const json = await resp.json();
4760
- const accessToken = String(json["access_token"] ?? "");
4761
- if (!accessToken) throw new Error("OAuth 2.0: token response missing access_token.");
4762
- const expiresIn = Number(json["expires_in"] ?? 3600);
4763
- return {
4764
- accessToken,
4765
- expiresAt: Date.now() + expiresIn * 1e3,
4766
- refreshToken: json["refresh_token"] ? String(json["refresh_token"]) : void 0
4767
- };
4785
+ return requestExec.fetchOAuth2Token(auth, vars);
4768
4786
  });
4769
4787
  handle.handleIpc(ipc, handle.IPC.oauth2.refreshToken, async (_e, auth, vars, refreshToken) => {
4770
4788
  const tokenUrl = requestExec.interpolate(auth.oauth2TokenUrl ?? "", vars);
@@ -5923,7 +5941,7 @@ function isNewer(a, b) {
5923
5941
  return a2 > b2;
5924
5942
  }
5925
5943
  async function checkForUpdate() {
5926
- const current = "0.5.3";
5944
+ const current = "0.5.5";
5927
5945
  try {
5928
5946
  const res = await fetch(REGISTRY_URL, { signal: AbortSignal.timeout(4e3) });
5929
5947
  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-BxiXhP1m.js");
4
- const requestExec = require("./chunks/request-exec-igCwP-QK.js");
4
+ const requestExec = require("./chunks/request-exec-Dg-EHFX0.js");
5
5
  require("http");
6
6
  require("crypto");
7
7
  require("vm");
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
  const promises = require("fs/promises");
4
4
  const path = require("path");
5
- const requestExec = require("./chunks/request-exec-igCwP-QK.js");
5
+ const requestExec = require("./chunks/request-exec-Dg-EHFX0.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-BKYgsbGB.js");
@@ -402,7 +402,7 @@ async function main() {
402
402
  } else if (!envName && workspace.settings?.defaultEnvironment && !env) {
403
403
  console.warn(cliCommon.color(`Warning: default environment "${workspace.settings.defaultEnvironment}" not found. Running without environment.`, cliCommon.C.yellow));
404
404
  }
405
- const version = `v${"0.5.3"}`;
405
+ const version = `v${"0.5.5"}`;
406
406
  console.log("");
407
407
  console.log(cliCommon.color(" API Test Runner" + (version ? ` ${version}` : ""), cliCommon.C.bold, cliCommon.C.white));
408
408
  console.log(cliCommon.color(` Workspace: ${wsPath}`, cliCommon.C.gray));
@@ -1,4 +1,4 @@
1
- import { l as linter, E as EditorView, L as LanguageSupport, a as LRLanguage, s as styleTags, i as indentNodeProp, d as delimitedIndent, f as foldNodeProp, b as foldInside, S as StateField, c as LRParser, e as StateEffect, t as tags, r as reactExports, u as useStore, g as useActiveEnvironment, j as jsxRuntimeExports, R as ReactCodeMirror, o as oneDark, h as json } from "./index-Drj1BFmk.js";
1
+ import { l as linter, E as EditorView, L as LanguageSupport, a as LRLanguage, s as styleTags, i as indentNodeProp, d as delimitedIndent, f as foldNodeProp, b as foldInside, S as StateField, c as LRParser, e as StateEffect, t as tags, u as useT, r as reactExports, g as useStore, h as useActiveEnvironment, j as jsxRuntimeExports, R as ReactCodeMirror, o as oneDark, k as json } from "./index-e3ZM7oe9.js";
2
2
  function devAssert(condition, message) {
3
3
  const booleanCondition = Boolean(condition);
4
4
  if (!booleanCondition) {
@@ -12028,6 +12028,7 @@ function FieldNode({
12028
12028
  opType,
12029
12029
  onInsert
12030
12030
  }) {
12031
+ const t2 = useT();
12031
12032
  const [expanded, setExpanded] = reactExports.useState(false);
12032
12033
  const baseTypeName = getBaseTypeName(field.type);
12033
12034
  const baseKind = getBaseKind(field.type);
@@ -12067,8 +12068,8 @@ function FieldNode({
12067
12068
  {
12068
12069
  onClick: () => onInsert(field, path, opType, true),
12069
12070
  className: "opacity-0 group-hover:opacity-100 text-[10px] text-surface-600 hover:text-blue-400 px-1 transition-opacity flex-shrink-0",
12070
- title: "Insert with all of this type's fields",
12071
- children: "all"
12071
+ title: t2("Insert with all of this type's fields"),
12072
+ children: t2("all")
12072
12073
  }
12073
12074
  ),
12074
12075
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -12076,7 +12077,7 @@ function FieldNode({
12076
12077
  {
12077
12078
  onClick: () => onInsert(field, path, opType),
12078
12079
  className: "opacity-0 group-hover:opacity-100 text-[10px] text-surface-600 hover:text-blue-400 px-1 transition-opacity ml-0.5 flex-shrink-0",
12079
- title: "Insert into query",
12080
+ title: t2("Insert into query"),
12080
12081
  children: "+"
12081
12082
  }
12082
12083
  )
@@ -12093,6 +12094,7 @@ function RootTypeSection({
12093
12094
  listOnly,
12094
12095
  onInsert
12095
12096
  }) {
12097
+ const t2 = useT();
12096
12098
  const [expanded, setExpanded] = reactExports.useState(true);
12097
12099
  const type2 = typeMap.get(typeName);
12098
12100
  const opType = opTypeForLabel(label);
@@ -12107,10 +12109,7 @@ function RootTypeSection({
12107
12109
  children: [
12108
12110
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px]", children: expanded ? "▾" : "▸" }),
12109
12111
  label,
12110
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-400 normal-case tracking-normal font-normal ml-auto", children: [
12111
- fields.length,
12112
- " fields"
12113
- ] })
12112
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-400 normal-case tracking-normal font-normal ml-auto", children: t2(":count field|:count fields", { count: fields.length }) })
12114
12113
  ]
12115
12114
  }
12116
12115
  ),
@@ -12121,6 +12120,7 @@ function SchemaExplorer({
12121
12120
  schema,
12122
12121
  onInsert
12123
12122
  }) {
12123
+ const t2 = useT();
12124
12124
  const [search, setSearch] = reactExports.useState("");
12125
12125
  const [listOnly, setListOnly] = reactExports.useState(false);
12126
12126
  const filter = search.trim().toLowerCase();
@@ -12143,20 +12143,16 @@ function SchemaExplorer({
12143
12143
  {
12144
12144
  value: search,
12145
12145
  onChange: (e) => setSearch(e.target.value),
12146
- placeholder: "Search fields…",
12146
+ placeholder: t2("Search fields…"),
12147
12147
  className: "w-full bg-surface-800 border border-surface-700 rounded px-2 py-0.5 text-[11px] focus:outline-none focus:border-blue-500 placeholder-surface-700"
12148
12148
  }
12149
12149
  ),
12150
- /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-1 text-[10px] text-surface-500 cursor-pointer", title: "Hide the by-id lookups (e.g. product(id!)); show list/collection fields", children: [
12150
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-1 text-[10px] text-surface-500 cursor-pointer", title: t2("Hide the by-id lookups (e.g. product(id!)); show list/collection fields"), children: [
12151
12151
  /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "checkbox", checked: listOnly, onChange: (e) => setListOnly(e.target.checked) }),
12152
- "Hide fields that require arguments"
12152
+ t2("Hide fields that require arguments")
12153
12153
  ] })
12154
12154
  ] }),
12155
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto py-1", children: filter ? allFields.length > 0 ? allFields.map(({ rootLabel, field }) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: /* @__PURE__ */ jsxRuntimeExports.jsx(FieldNode, { field, typeMap: schema.typeMap, depth: 0, path: [], opType: opTypeForLabel(rootLabel), onInsert }) }, `${rootLabel}-${field.name}`)) : /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] text-surface-400 px-3 py-4 text-center", children: [
12156
- 'No fields match "',
12157
- search,
12158
- '"'
12159
- ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
12155
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto py-1", children: filter ? allFields.length > 0 ? allFields.map(({ rootLabel, field }) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: /* @__PURE__ */ jsxRuntimeExports.jsx(FieldNode, { field, typeMap: schema.typeMap, depth: 0, path: [], opType: opTypeForLabel(rootLabel), onInsert }) }, `${rootLabel}-${field.name}`)) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-surface-400 px-3 py-4 text-center", children: t2('No fields match ":query"', { query: search }) }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
12160
12156
  schema.queryType && /* @__PURE__ */ jsxRuntimeExports.jsx(RootTypeSection, { label: "Query", typeName: schema.queryType, typeMap: schema.typeMap, listOnly, onInsert }),
12161
12157
  schema.mutationType && /* @__PURE__ */ jsxRuntimeExports.jsx(RootTypeSection, { label: "Mutation", typeName: schema.mutationType, typeMap: schema.typeMap, listOnly, onInsert }),
12162
12158
  schema.subscriptionType && /* @__PURE__ */ jsxRuntimeExports.jsx(RootTypeSection, { label: "Subscription", typeName: schema.subscriptionType, typeMap: schema.typeMap, listOnly, onInsert })
@@ -12165,6 +12161,7 @@ function SchemaExplorer({
12165
12161
  }
12166
12162
  const EMPTY_GQL = { query: "", variables: "" };
12167
12163
  function GraphQLEditor({ request, onChange }) {
12164
+ const t2 = useT();
12168
12165
  const gql = reactExports.useMemo(
12169
12166
  () => request.body.graphql ?? EMPTY_GQL,
12170
12167
  [request.body.graphql]
@@ -12277,7 +12274,7 @@ function GraphQLEditor({ request, onChange }) {
12277
12274
  {
12278
12275
  value: gql.operationName ?? "",
12279
12276
  onChange: (e) => updateGql({ operationName: e.target.value }),
12280
- placeholder: "operationName (optional)",
12277
+ placeholder: t2("operationName (optional)"),
12281
12278
  className: "bg-surface-800 border border-surface-700 rounded px-2 py-0.5 text-xs font-mono focus:outline-none focus:border-blue-500 placeholder-surface-700 w-44"
12282
12279
  }
12283
12280
  ),
@@ -12287,7 +12284,7 @@ function GraphQLEditor({ request, onChange }) {
12287
12284
  onClick: loadSchema,
12288
12285
  disabled: schemaState === "loading" || !request.url.trim(),
12289
12286
  className: "px-2.5 py-0.5 text-[11px] bg-surface-800 hover:bg-surface-700 disabled:text-surface-400 rounded transition-colors",
12290
- children: schemaState === "loading" ? "Loading…" : "Fetch schema"
12287
+ children: schemaState === "loading" ? t2("Loading…") : t2("Fetch schema")
12291
12288
  }
12292
12289
  ),
12293
12290
  schemaError && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[11px] text-red-400 truncate max-w-xs", title: schemaError, children: [
@@ -12299,13 +12296,13 @@ function GraphQLEditor({ request, onChange }) {
12299
12296
  {
12300
12297
  onClick: () => setShowExplorer((v) => !v),
12301
12298
  className: `px-2 py-0.5 text-[11px] rounded transition-colors ml-auto ${showExplorer ? "bg-blue-700 text-white" : "bg-surface-800 hover:bg-surface-700"}`,
12302
- children: "Explorer"
12299
+ children: t2("Explorer")
12303
12300
  }
12304
12301
  )
12305
12302
  ] }),
12306
12303
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-1 min-h-0 gap-2", children: [
12307
12304
  hasSchema && showExplorer && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-56 flex-shrink-0 min-h-0 border border-surface-700 rounded overflow-hidden flex flex-col", children: [
12308
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-2 py-1 border-b border-surface-800 flex-shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold uppercase tracking-wider text-surface-600", children: "Schema" }) }),
12305
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-2 py-1 border-b border-surface-800 flex-shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold uppercase tracking-wider text-surface-600", children: t2("Schema") }) }),
12309
12306
  /* @__PURE__ */ jsxRuntimeExports.jsx(SchemaExplorer, { schema, onInsert: handleInsert })
12310
12307
  ] }),
12311
12308
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col min-h-0 gap-2", children: [
@@ -12313,15 +12310,14 @@ function GraphQLEditor({ request, onChange }) {
12313
12310
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between px-2 py-0.5 bg-surface-800/50 border-b border-surface-700 shrink-0", children: [
12314
12311
  !gql.query.trim() ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", {}) : errors.length ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] text-red-400", title: errors.map((e) => e.message).join("\n"), children: [
12315
12312
  "✗ ",
12316
- errors.length,
12317
- " error",
12318
- errors.length !== 1 ? "s" : ""
12313
+ t2(":count error|:count errors", { count: errors.length })
12319
12314
  ] }) : warnings.length ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] text-amber-400", title: warnings.map((w) => w.message).join("\n"), children: [
12320
12315
  "▲ ",
12321
- warnings.length,
12322
- " warning",
12323
- warnings.length !== 1 ? "s" : ""
12324
- ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-emerald-400", children: "✓ valid" }),
12316
+ t2(":count warning|:count warnings", { count: warnings.length })
12317
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] text-emerald-400", children: [
12318
+ " ",
12319
+ t2("valid")
12320
+ ] }),
12325
12321
  /* @__PURE__ */ jsxRuntimeExports.jsx(
12326
12322
  "button",
12327
12323
  {
@@ -12339,8 +12335,8 @@ function GraphQLEditor({ request, onChange }) {
12339
12335
  }
12340
12336
  },
12341
12337
  className: "text-[10px] text-surface-500 hover:text-white transition-colors",
12342
- title: "Format GraphQL query (comments will not be preserved)",
12343
- children: "Format"
12338
+ title: t2("Format GraphQL query (comments will not be preserved)"),
12339
+ children: t2("Format")
12344
12340
  }
12345
12341
  )
12346
12342
  ] }),
@@ -12366,7 +12362,8 @@ function GraphQLEditor({ request, onChange }) {
12366
12362
  className: "text-[10px] text-surface-600 hover:text-surface-300 uppercase tracking-wider font-medium flex items-center gap-1",
12367
12363
  children: [
12368
12364
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: showVars ? "▾" : "▸" }),
12369
- " Variables",
12365
+ " ",
12366
+ t2("Variables"),
12370
12367
  gql.variables?.trim() && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-blue-400 ml-1", children: "●" })
12371
12368
  ]
12372
12369
  }
@@ -12381,8 +12378,8 @@ function GraphQLEditor({ request, onChange }) {
12381
12378
  }
12382
12379
  },
12383
12380
  className: "text-[10px] text-surface-500 hover:text-white transition-colors",
12384
- title: "Format JSON variables",
12385
- children: "Format"
12381
+ title: t2("Format JSON variables"),
12382
+ children: t2("Format")
12386
12383
  }
12387
12384
  )
12388
12385
  ] }),
@@ -1,4 +1,4 @@
1
- import { r as reactExports, j as jsxRuntimeExports, R as ReactCodeMirror, k as commentKeymap, o as oneDark, x as xml } from "./index-Drj1BFmk.js";
1
+ import { u as useT, r as reactExports, j as jsxRuntimeExports, R as ReactCodeMirror, m as commentKeymap, o as oneDark, x as xml } from "./index-e3ZM7oe9.js";
2
2
  const SOAP_11_CONTENT_TYPE = "text/xml; charset=utf-8";
3
3
  const SOAP_12_CONTENT_TYPE = "application/soap+xml; charset=utf-8";
4
4
  function contentTypeForSoap(version) {
@@ -12,8 +12,9 @@ function withContentType(headers, value) {
12
12
  }
13
13
  const { electron } = window;
14
14
  function ParamTree({ params, depth = 0 }) {
15
+ const t = useT();
15
16
  if (params.length === 0) {
16
- return /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-surface-600 italic", children: "No parameters declared in WSDL." });
17
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-surface-600 italic", children: t("No parameters declared in WSDL.") });
17
18
  }
18
19
  return /* @__PURE__ */ jsxRuntimeExports.jsx("ul", { className: depth === 0 ? "flex flex-col gap-0.5" : "flex flex-col gap-0.5 ml-4 border-l border-surface-800 pl-3 mt-1", children: params.map((p, i) => /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { className: "text-[11px] font-mono", children: [
19
20
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-200", children: p.name }),
@@ -23,6 +24,7 @@ function ParamTree({ params, depth = 0 }) {
23
24
  ] }, `${p.name}-${i}`)) });
24
25
  }
25
26
  function SoapEditor({ request, onChange }) {
27
+ const t = useT();
26
28
  const soap = request.body.soap ?? { wsdlUrl: "", envelope: "" };
27
29
  const [operations, setOperations] = reactExports.useState([]);
28
30
  const [endpoints, setEndpoints] = reactExports.useState([]);
@@ -100,7 +102,7 @@ function SoapEditor({ request, onChange }) {
100
102
  const showEmpty = !showFullUi && !showFallback;
101
103
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3 h-full min-h-0", children: [
102
104
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 items-center", children: [
103
- /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] uppercase tracking-wider text-surface-500 font-medium whitespace-nowrap", children: "WSDL" }),
105
+ /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] uppercase tracking-wider text-surface-500 font-medium whitespace-nowrap", children: t("WSDL") }),
104
106
  /* @__PURE__ */ jsxRuntimeExports.jsx(
105
107
  "input",
106
108
  {
@@ -119,22 +121,22 @@ function SoapEditor({ request, onChange }) {
119
121
  onClick: fetchWsdl,
120
122
  disabled: fetching || !soap.wsdlUrl.trim(),
121
123
  className: "px-3 py-1.5 text-xs bg-blue-700 hover:bg-blue-600 disabled:bg-surface-800 disabled:text-surface-600 rounded transition-colors whitespace-nowrap",
122
- children: fetching ? "Fetching…" : operations.length > 0 ? "Refresh" : "Fetch WSDL"
124
+ children: fetching ? t("Fetching…") : operations.length > 0 ? t("Refresh") : t("Fetch WSDL")
123
125
  }
124
126
  )
125
127
  ] }),
126
128
  fetchError && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-red-400 bg-red-950/30 border border-red-900 rounded px-2.5 py-1.5", children: fetchError }),
127
129
  operations.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-surface-900/40 border border-surface-800 rounded-md px-3 py-2 text-[11px] flex flex-col gap-1", children: [
128
130
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-surface-500", children: [
129
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "uppercase tracking-wider text-[9px] font-semibold text-surface-600 w-20 shrink-0", children: "Endpoint" }),
130
- /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-surface-200 font-mono truncate", children: primaryEndpoint ?? "(not declared)" })
131
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "uppercase tracking-wider text-[9px] font-semibold text-surface-600 w-20 shrink-0", children: t("Endpoint") }),
132
+ /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-surface-200 font-mono truncate", children: primaryEndpoint ?? t("(not declared)") })
131
133
  ] }),
132
134
  targetNs && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-surface-500", children: [
133
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "uppercase tracking-wider text-[9px] font-semibold text-surface-600 w-20 shrink-0", children: "Namespace" }),
135
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "uppercase tracking-wider text-[9px] font-semibold text-surface-600 w-20 shrink-0", children: t("Namespace") }),
134
136
  /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-surface-200 font-mono truncate", children: targetNs })
135
137
  ] }),
136
138
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-surface-500", children: [
137
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "uppercase tracking-wider text-[9px] font-semibold text-surface-600 w-20 shrink-0", children: "Operations" }),
139
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "uppercase tracking-wider text-[9px] font-semibold text-surface-600 w-20 shrink-0", children: t("Operations") }),
138
140
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-300", children: [
139
141
  operations.length,
140
142
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-600", children: [
@@ -146,7 +148,7 @@ function SoapEditor({ request, onChange }) {
146
148
  ] }),
147
149
  showFullUi && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3 min-h-0 flex-1", children: [
148
150
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-44 shrink-0 flex flex-col bg-surface-900/40 border border-surface-800 rounded-md overflow-hidden", children: [
149
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-2.5 py-1.5 text-[9px] uppercase tracking-wider font-semibold text-surface-600 border-b border-surface-800", children: "Operations" }),
151
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-2.5 py-1.5 text-[9px] uppercase tracking-wider font-semibold text-surface-600 border-b border-surface-800", children: t("Operations") }),
150
152
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "overflow-y-auto flex-1", children: operations.map((op) => {
151
153
  const active = selected && op.name === selected.name && op.soapVersion === selected.soapVersion && (op.binding ?? "") === (selected.binding ?? "");
152
154
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(
@@ -176,24 +178,26 @@ function SoapEditor({ request, onChange }) {
176
178
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-300", children: selected.soapAction })
177
179
  ] }),
178
180
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-surface-900/40 border border-surface-800 rounded-md px-3 py-2", children: [
179
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[9px] uppercase tracking-wider font-semibold text-surface-600 mb-1.5", children: "Inputs" }),
181
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[9px] uppercase tracking-wider font-semibold text-surface-600 mb-1.5", children: t("Inputs") }),
180
182
  /* @__PURE__ */ jsxRuntimeExports.jsx(ParamTree, { params: selected.params ?? [] })
181
183
  ] }),
182
184
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
183
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] uppercase tracking-wider font-semibold text-surface-600", children: "Envelope" }),
185
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] uppercase tracking-wider font-semibold text-surface-600", children: t("Envelope") }),
184
186
  /* @__PURE__ */ jsxRuntimeExports.jsx(
185
187
  "button",
186
188
  {
187
189
  onClick: () => setShowXml((v) => !v),
188
190
  className: "text-[10px] text-surface-500 hover:text-surface-300 transition-colors",
189
- children: showXml ? "▾ Hide XML" : "▸ Edit XML"
191
+ children: showXml ? t("▾ Hide XML") : t("▸ Edit XML")
190
192
  }
191
193
  )
192
194
  ] }),
193
195
  !showXml && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[10px] text-surface-600 leading-relaxed", children: [
194
- "Envelope auto-generated from the operation's input parameters. Method (POST), endpoint URL, and Content-Type are managed for you. Click ",
195
- /* @__PURE__ */ jsxRuntimeExports.jsx("em", { children: "Edit XML" }),
196
- " to tweak."
196
+ t("Envelope auto-generated from the operation's input parameters. Method (POST), endpoint URL, and Content-Type are managed for you. Click"),
197
+ " ",
198
+ /* @__PURE__ */ jsxRuntimeExports.jsx("em", { children: t("Edit XML") }),
199
+ " ",
200
+ t("to tweak.")
197
201
  ] }),
198
202
  showXml && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded overflow-hidden border border-surface-700 h-72 shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
199
203
  ReactCodeMirror,
@@ -216,7 +220,7 @@ function SoapEditor({ request, onChange }) {
216
220
  "SOAPAction: ",
217
221
  soap.soapAction
218
222
  ] }),
219
- !soap.operationName && !soap.soapAction && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-surface-500", children: soap.wsdlUrl?.trim() ? "WSDL not loaded - the saved envelope below is still sent on Send." : "No WSDL - hand-crafted SOAP envelope." })
223
+ !soap.operationName && !soap.soapAction && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-surface-500", children: soap.wsdlUrl?.trim() ? t("WSDL not loaded - the saved envelope below is still sent on Send.") : t("No WSDL - hand-crafted SOAP envelope.") })
220
224
  ] }),
221
225
  soap.wsdlUrl?.trim() && /* @__PURE__ */ jsxRuntimeExports.jsx(
222
226
  "button",
@@ -224,7 +228,7 @@ function SoapEditor({ request, onChange }) {
224
228
  onClick: fetchWsdl,
225
229
  disabled: fetching,
226
230
  className: "px-2.5 py-1 text-[11px] bg-surface-800 hover:bg-surface-700 disabled:opacity-50 rounded transition-colors whitespace-nowrap",
227
- children: fetching ? "Loading…" : "Reload WSDL"
231
+ children: fetching ? t("Loading…") : t("Reload WSDL")
228
232
  }
229
233
  )
230
234
  ] }),
@@ -242,11 +246,12 @@ function SoapEditor({ request, onChange }) {
242
246
  ] }),
243
247
  showEmpty && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center text-center gap-2 border border-dashed border-surface-800 rounded-md py-8 px-4", children: [
244
248
  /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-surface-400", children: [
245
- "Paste a WSDL URL above and click ",
246
- /* @__PURE__ */ jsxRuntimeExports.jsx("em", { children: "Fetch WSDL" }),
249
+ t("Paste a WSDL URL above and click"),
250
+ " ",
251
+ /* @__PURE__ */ jsxRuntimeExports.jsx("em", { children: t("Fetch WSDL") }),
247
252
  "."
248
253
  ] }),
249
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-surface-600 max-w-sm", children: "The endpoint, SOAP version, Content-Type header, and per-operation envelope are derived from the WSDL - you only pick the operation and fill the parameters." })
254
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-surface-600 max-w-sm", children: t("The endpoint, SOAP version, Content-Type header, and per-operation envelope are derived from the WSDL - you only pick the operation and fill the parameters.") })
250
255
  ] })
251
256
  ] });
252
257
  }