@testsmith/api-spector 0.2.2 → 0.2.4

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.
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const Ajv = require("ajv");
4
+ const ajv = new Ajv({
5
+ allErrors: true,
6
+ strict: false,
7
+ coerceTypes: false,
8
+ allowUnionTypes: true
9
+ });
10
+ function compile(schema) {
11
+ const fn = ajv.compile(schema);
12
+ return function validate(data) {
13
+ if (!fn(data)) {
14
+ const err = (fn.errors ?? []).map((e) => `${e.instancePath || "<root>"} ${e.message ?? "invalid"}`).join("; ");
15
+ throw new Error(`Invalid IPC payload: ${err || "unknown"}`);
16
+ }
17
+ };
18
+ }
19
+ const apiRequestSchema = {
20
+ type: "object",
21
+ properties: {
22
+ id: { type: "string" },
23
+ name: { type: "string" },
24
+ method: { type: "string" },
25
+ url: { type: "string" },
26
+ headers: { type: "array" },
27
+ params: { type: "array" },
28
+ auth: {
29
+ type: "object",
30
+ properties: { type: { type: "string" } },
31
+ required: ["type"],
32
+ additionalProperties: true
33
+ },
34
+ body: {
35
+ type: "object",
36
+ properties: { mode: { type: "string" } },
37
+ required: ["mode"],
38
+ additionalProperties: true
39
+ }
40
+ },
41
+ required: ["id", "name", "method", "url", "headers", "params"],
42
+ additionalProperties: true
43
+ };
44
+ const stringMap = {
45
+ type: "object",
46
+ additionalProperties: { type: "string" }
47
+ };
48
+ const validateSendRequestPayload = compile({
49
+ type: "object",
50
+ properties: {
51
+ request: apiRequestSchema,
52
+ collectionVars: stringMap,
53
+ globals: stringMap,
54
+ piiMaskPatterns: { type: "array", items: { type: "string" } }
55
+ // `environment`, `proxy`, `tls` are accepted as anything — they're
56
+ // covered by the IPC handler's own type-narrow + defaults.
57
+ },
58
+ required: ["request"],
59
+ additionalProperties: true
60
+ });
61
+ const validateContractRunPayload = compile({
62
+ type: "object",
63
+ properties: {
64
+ mode: { type: "string", enum: ["consumer", "provider", "bidirectional"] },
65
+ requests: { type: "array", items: apiRequestSchema },
66
+ envVars: stringMap,
67
+ collectionVars: stringMap,
68
+ specUrl: { type: "string" },
69
+ specPath: { type: "string" },
70
+ specSnapshotRelPath: { type: "string" },
71
+ requestBaseUrl: { type: "string" }
72
+ },
73
+ required: ["mode", "requests"],
74
+ additionalProperties: true
75
+ });
76
+ const validateWsdlFetchUrl = (url) => {
77
+ if (typeof url !== "string" || !url.trim()) throw new Error("Invalid IPC payload: url must be a non-empty string");
78
+ if (!/^https?:\/\//i.test(url)) throw new Error("Invalid IPC payload: url must start with http:// or https://");
79
+ };
80
+ const validateWsdlImport = compile({
81
+ type: "object",
82
+ properties: {
83
+ url: { type: "string" },
84
+ xml: { type: "string" },
85
+ name: { type: "string" },
86
+ extraHeaders: stringMap,
87
+ existingMockPorts: { type: "array", items: { type: "number" } }
88
+ },
89
+ additionalProperties: true
90
+ });
91
+ exports.validateContractRunPayload = validateContractRunPayload;
92
+ exports.validateSendRequestPayload = validateSendRequestPayload;
93
+ exports.validateWsdlFetchUrl = validateWsdlFetchUrl;
94
+ exports.validateWsdlImport = validateWsdlImport;
@@ -169,6 +169,10 @@ async function handleRequest(serverId, req, res, reqStart) {
169
169
  vm__namespace.runInNewContext(route.script, {
170
170
  request: requestCtx,
171
171
  response: responseDraft,
172
+ // Free-form per-route data the importer/user can stash (e.g. SOAP
173
+ // envelopes by operation, lookup tables, fixtures). Frozen so a script
174
+ // can't mutate it across calls.
175
+ metadata: route.metadata ? Object.freeze({ ...route.metadata }) : {},
172
176
  faker: faker2,
173
177
  dayjs,
174
178
  console: { log: (...args) => console.log("[mock-script]", ...args) }
@@ -23,14 +23,16 @@ 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 authBuilder = require("./auth-builder-B7-LgcGr.js");
27
+ const vm = require("vm");
26
28
  const crypto = require("crypto");
27
- const path = require("path");
28
29
  const dayjs = require("dayjs");
29
- const vm = require("vm");
30
30
  const tv4 = require("tv4");
31
31
  const jsonpathPlus = require("jsonpath-plus");
32
32
  const xmldom = require("@xmldom/xmldom");
33
+ const path = require("path");
33
34
  const Ajv = require("ajv");
35
+ const ipcValidate = require("./ipc-validate-CscN4HfG.js");
34
36
  function _interopNamespaceDefault(e) {
35
37
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
36
38
  if (e) {
@@ -47,8 +49,8 @@ function _interopNamespaceDefault(e) {
47
49
  n.default = e;
48
50
  return Object.freeze(n);
49
51
  }
50
- const crypto__namespace = /* @__PURE__ */ _interopNamespaceDefault(crypto);
51
52
  const vm__namespace = /* @__PURE__ */ _interopNamespaceDefault(vm);
53
+ const crypto__namespace = /* @__PURE__ */ _interopNamespaceDefault(crypto);
52
54
  let globals = {};
53
55
  let currentDir = null;
54
56
  function globalsPath(dir) {
@@ -77,171 +79,6 @@ function setGlobals(next) {
77
79
  function patchGlobals(patch) {
78
80
  globals = { ...globals, ...patch };
79
81
  }
80
- const MASTER_KEY_ENV = "API_SPECTOR_MASTER_KEY";
81
- let secretStore = {};
82
- let secretStorePath = null;
83
- async function initSecretStore(userDataPath) {
84
- secretStorePath = path.join(userDataPath, "secrets.json");
85
- try {
86
- const raw = await promises.readFile(secretStorePath, "utf8");
87
- secretStore = JSON.parse(raw);
88
- } catch {
89
- secretStore = {};
90
- }
91
- }
92
- async function persistSecretStore() {
93
- if (!secretStorePath) return;
94
- await promises.writeFile(secretStorePath, JSON.stringify(secretStore, null, 2), "utf8");
95
- }
96
- function getSafeStorage() {
97
- try {
98
- const { safeStorage } = require("electron");
99
- if (typeof safeStorage?.isEncryptionAvailable === "function") return safeStorage;
100
- return null;
101
- } catch {
102
- return null;
103
- }
104
- }
105
- function registerSecretHandlers(ipc) {
106
- ipc.handle("secret:checkMasterKey", () => {
107
- return { set: Boolean(process.env[MASTER_KEY_ENV]) };
108
- });
109
- ipc.handle("secret:setMasterKey", (_e, value) => {
110
- process.env[MASTER_KEY_ENV] = value;
111
- });
112
- ipc.handle("secret:set", async (_e, ref, value) => {
113
- const ss = getSafeStorage();
114
- if (!ss || !ss.isEncryptionAvailable()) {
115
- throw new Error("OS encryption is not available — set the secret via environment variable instead");
116
- }
117
- secretStore[ref] = ss.encryptString(value).toString("base64");
118
- await persistSecretStore();
119
- });
120
- }
121
- function decryptSecret(encrypted, salt, iv, password) {
122
- const saltBuf = Buffer.from(salt, "base64");
123
- const ivBuf = Buffer.from(iv, "base64");
124
- const encBuf = Buffer.from(encrypted, "base64");
125
- const key = crypto.pbkdf2Sync(password, saltBuf, 1e5, 32, "sha256");
126
- const authTag = encBuf.subarray(encBuf.length - 16);
127
- const ciphertext = encBuf.subarray(0, encBuf.length - 16);
128
- const decipher = crypto.createDecipheriv("aes-256-gcm", key, ivBuf);
129
- decipher.setAuthTag(authTag);
130
- return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
131
- }
132
- async function getSecret(ref) {
133
- const stored = secretStore[ref];
134
- if (stored) {
135
- const ss = getSafeStorage();
136
- if (ss && ss.isEncryptionAvailable()) {
137
- try {
138
- return ss.decryptString(Buffer.from(stored, "base64"));
139
- } catch {
140
- }
141
- }
142
- }
143
- return process.env[ref] ?? null;
144
- }
145
- let _fakerCache$1 = null;
146
- async function getFaker$1() {
147
- if (!_fakerCache$1) _fakerCache$1 = await import("@faker-js/faker");
148
- return _fakerCache$1.faker;
149
- }
150
- let _exprContext = null;
151
- async function buildDynamicVars() {
152
- const faker = await getFaker$1();
153
- const now = dayjs();
154
- _exprContext = { faker, dayjs };
155
- return {
156
- $uuid: faker.string.uuid(),
157
- $timestamp: String(Date.now()),
158
- $isoTimestamp: now.toISOString(),
159
- $randomInt: String(faker.number.int({ min: 0, max: 1e3 })),
160
- $randomFloat: String(faker.number.float({ min: 0, max: 1e3, fractionDigits: 2 })),
161
- $randomBoolean: String(faker.datatype.boolean()),
162
- $randomEmail: faker.internet.email(),
163
- $randomUsername: faker.internet.username(),
164
- $randomPassword: faker.internet.password(),
165
- $randomFullName: faker.person.fullName(),
166
- $randomFirstName: faker.person.firstName(),
167
- $randomLastName: faker.person.lastName(),
168
- $randomWord: faker.lorem.word(),
169
- $randomPhrase: faker.lorem.sentence(),
170
- $randomUrl: faker.internet.url(),
171
- $randomIp: faker.internet.ip(),
172
- $randomHexColor: faker.color.rgb({ format: "hex", casing: "lower" })
173
- };
174
- }
175
- function interpolate(str, vars) {
176
- return str.replace(/\{\{([^}]+)\}\}/g, (match, key) => {
177
- const trimmed = key.trim();
178
- if (trimmed in vars) return vars[trimmed];
179
- if (_exprContext && (trimmed.includes(".") || trimmed.includes("("))) {
180
- try {
181
- const result = vm__namespace.runInNewContext(trimmed, _exprContext);
182
- if (result !== void 0 && result !== null) return String(result);
183
- } catch {
184
- }
185
- }
186
- return match;
187
- });
188
- }
189
- function buildUrl(baseUrl, params, vars) {
190
- const templateTokens = /* @__PURE__ */ new Set();
191
- baseUrl.replace(/\{\{([^}]+)\}\}/g, (_m, name) => {
192
- templateTokens.add(String(name).trim());
193
- return "";
194
- });
195
- const enabled = (params ?? []).filter((p) => p.enabled && p.key);
196
- const pathRows = [];
197
- const queryRows = [];
198
- for (const p of enabled) {
199
- const isPath = p.paramType === "path" || templateTokens.has(p.key);
200
- if (isPath) pathRows.push(p);
201
- else queryRows.push(p);
202
- }
203
- const mergedVars = pathRows.length ? {
204
- ...vars,
205
- ...Object.fromEntries(pathRows.map((p) => [p.key, interpolate(p.value, vars)]))
206
- } : vars;
207
- const url = interpolate(baseUrl, mergedVars);
208
- if (!queryRows.length) return url;
209
- const sep = url.includes("?") ? "&" : "?";
210
- const qs = queryRows.map((p) => `${encodeURIComponent(interpolate(p.key, vars))}=${encodeURIComponent(interpolate(p.value, vars))}`).join("&");
211
- return url + sep + qs;
212
- }
213
- async function buildEnvVars(environment) {
214
- const vars = {};
215
- if (!environment) return vars;
216
- const masterKey = process.env["API_SPECTOR_MASTER_KEY"];
217
- for (const v of environment.variables) {
218
- if (!v.enabled) continue;
219
- if (v.envRef) {
220
- const envValue = process.env[v.envRef];
221
- if (envValue !== void 0) vars[v.key] = envValue;
222
- } else if (v.secret && v.secretEncrypted && v.secretSalt && v.secretIv) {
223
- if (masterKey) {
224
- try {
225
- vars[v.key] = decryptSecret(v.secretEncrypted, v.secretSalt, v.secretIv, masterKey);
226
- } catch {
227
- }
228
- }
229
- if (vars[v.key] === void 0 && process.env[v.key] !== void 0) {
230
- vars[v.key] = process.env[v.key];
231
- }
232
- } else if (v.secret) {
233
- if (process.env[v.key] !== void 0) {
234
- vars[v.key] = process.env[v.key];
235
- }
236
- } else {
237
- vars[v.key] = v.value;
238
- }
239
- }
240
- return vars;
241
- }
242
- function mergeVars(envVars, collectionVars, globals2, localVars = {}, dynamicVars = {}) {
243
- return { ...dynamicVars, ...globals2, ...collectionVars, ...envVars, ...localVars };
244
- }
245
82
  function xmlFindAll(node, tag, nth) {
246
83
  const results = [];
247
84
  const siblings = Array.from(node.childNodes).filter((c) => c.nodeType === 1 && c.tagName === tag);
@@ -600,156 +437,6 @@ async function runScript(code, ctx, timeoutMs = 5e3) {
600
437
  updatedLocalVars: localVarsCopy
601
438
  };
602
439
  }
603
- async function buildAuthHeaders(auth, vars) {
604
- const headers = {};
605
- if (auth.type === "bearer") {
606
- let token = auth.token ?? "";
607
- if (!token && auth.tokenSecretRef) token = await getSecret(auth.tokenSecretRef) ?? "";
608
- token = interpolate(token, vars);
609
- if (token) headers["Authorization"] = `Bearer ${token}`;
610
- }
611
- if (auth.type === "basic") {
612
- let password = auth.password ?? "";
613
- if (!password && auth.passwordSecretRef) password = await getSecret(auth.passwordSecretRef) ?? "";
614
- password = interpolate(password, vars);
615
- const username = interpolate(auth.username ?? "", vars);
616
- headers["Authorization"] = `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
617
- }
618
- if (auth.type === "apikey" && auth.apiKeyIn === "header") {
619
- let value = auth.apiKeyValue ?? "";
620
- if (!value && auth.apiKeySecretRef) value = await getSecret(auth.apiKeySecretRef) ?? "";
621
- value = interpolate(value, vars);
622
- headers[auth.apiKeyName ?? "X-API-Key"] = value;
623
- }
624
- if (auth.type === "oauth2") {
625
- const now = Date.now();
626
- if (auth.oauth2CachedToken && auth.oauth2TokenExpiry && auth.oauth2TokenExpiry > now + 5e3) {
627
- headers["Authorization"] = `Bearer ${auth.oauth2CachedToken}`;
628
- }
629
- }
630
- return headers;
631
- }
632
- async function buildApiKeyParam(auth, vars) {
633
- if (auth.type !== "apikey" || auth.apiKeyIn !== "query") return null;
634
- let value = auth.apiKeyValue ?? "";
635
- if (!value && auth.apiKeySecretRef) value = await getSecret(auth.apiKeySecretRef) ?? "";
636
- value = interpolate(value, vars);
637
- return { key: auth.apiKeyName ?? "apikey", value };
638
- }
639
- function parseDigestChallenge(wwwAuth) {
640
- const extract = (key) => {
641
- const m = new RegExp(`${key}="([^"]*)"`, "i").exec(wwwAuth);
642
- return m ? m[1] : "";
643
- };
644
- const extractUnquoted = (key) => {
645
- const m = new RegExp(`${key}=([^,\\s]+)`, "i").exec(wwwAuth);
646
- return m ? m[1] : "";
647
- };
648
- return {
649
- realm: extract("realm"),
650
- nonce: extract("nonce"),
651
- qop: extract("qop") || extractUnquoted("qop") || void 0,
652
- algorithm: extract("algorithm") || extractUnquoted("algorithm") || "MD5",
653
- opaque: extract("opaque") || void 0
654
- };
655
- }
656
- function md5(s) {
657
- return crypto.createHash("md5").update(s).digest("hex");
658
- }
659
- function buildDigestAuthHeader(challenge, username, password, method, uri) {
660
- const { realm, nonce, qop, algorithm, opaque } = challenge;
661
- const algo = (algorithm ?? "MD5").toUpperCase();
662
- const ha1 = algo === "MD5-SESS" ? md5(`${md5(`${username}:${realm}:${password}`)}:${nonce}:`) : md5(`${username}:${realm}:${password}`);
663
- const ha2 = md5(`${method}:${uri}`);
664
- let response;
665
- let nc;
666
- let cnonce;
667
- if (qop === "auth" || qop === "auth-int") {
668
- nc = "00000001";
669
- cnonce = crypto.randomBytes(8).toString("hex");
670
- response = md5(`${ha1}:${nonce}:${nc}:${cnonce}:${qop}:${ha2}`);
671
- } else {
672
- response = md5(`${ha1}:${nonce}:${ha2}`);
673
- }
674
- let header = `Digest username="${username}", realm="${realm}", nonce="${nonce}", uri="${uri}", response="${response}"`;
675
- if (qop) header += `, qop=${qop}`;
676
- if (nc) header += `, nc=${nc}`;
677
- if (cnonce) header += `, cnonce="${cnonce}"`;
678
- if (opaque) header += `, opaque="${opaque}"`;
679
- if (algo !== "MD5") header += `, algorithm=${algo}`;
680
- return header;
681
- }
682
- async function performDigestAuth(url, method, auth, vars, fetchFn) {
683
- const probeResp = await fetchFn(url, { method, headers: {} });
684
- if (probeResp.status !== 401) return null;
685
- const wwwAuth = probeResp.headers.get("www-authenticate") ?? "";
686
- if (!wwwAuth.toLowerCase().startsWith("digest")) return null;
687
- const challenge = parseDigestChallenge(wwwAuth);
688
- let password = auth.password ?? "";
689
- if (!password && auth.passwordSecretRef) password = await getSecret(auth.passwordSecretRef) ?? "";
690
- password = interpolate(password, vars);
691
- const username = interpolate(auth.username ?? "", vars);
692
- let uri = "/";
693
- try {
694
- uri = new URL(url).pathname + (new URL(url).search ?? "");
695
- } catch {
696
- }
697
- return buildDigestAuthHeader(challenge, username, password, method, uri);
698
- }
699
- async function performNtlmRequest(_url, _method, _auth, _vars) {
700
- throw new Error(
701
- 'NTLM auth is not yet implemented. Add "httpntlm" to package.json dependencies and implement performNtlmRequest in auth-builder.ts.'
702
- );
703
- }
704
- async function fetchOAuth2Token(auth, vars) {
705
- const flow = auth.oauth2Flow ?? "client_credentials";
706
- if (flow === "authorization_code") {
707
- throw new Error("authorization_code flow requires the oauth2:startFlow IPC call from the renderer.");
708
- }
709
- if (flow === "implicit") {
710
- throw new Error("implicit flow cannot be performed server-side — tokens must be obtained via the browser redirect.");
711
- }
712
- const tokenUrl = interpolate(auth.oauth2TokenUrl ?? "", vars);
713
- if (!tokenUrl) throw new Error("OAuth 2.0: tokenUrl is required.");
714
- const clientId = interpolate(auth.oauth2ClientId ?? "", vars);
715
- let clientSecret = auth.oauth2ClientSecret ?? "";
716
- if (!clientSecret && auth.oauth2ClientSecretRef) {
717
- clientSecret = await getSecret(auth.oauth2ClientSecretRef) ?? "";
718
- }
719
- clientSecret = interpolate(clientSecret, vars);
720
- const params = new URLSearchParams();
721
- params.set("grant_type", flow === "password" ? "password" : "client_credentials");
722
- params.set("client_id", clientId);
723
- params.set("client_secret", clientSecret);
724
- if (auth.oauth2Scopes) params.set("scope", auth.oauth2Scopes);
725
- if (flow === "password") {
726
- let password = auth.password ?? "";
727
- if (!password && auth.passwordSecretRef) password = await getSecret(auth.passwordSecretRef) ?? "";
728
- password = interpolate(password, vars);
729
- params.set("username", interpolate(auth.username ?? "", vars));
730
- params.set("password", password);
731
- }
732
- const { fetch: nodeFetch } = await import("undici");
733
- const resp = await nodeFetch(tokenUrl, {
734
- method: "POST",
735
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
736
- body: params.toString()
737
- });
738
- if (!resp.ok) {
739
- const body = await resp.text();
740
- throw new Error(`OAuth 2.0 token request failed (${resp.status}): ${body}`);
741
- }
742
- const json = await resp.json();
743
- const accessToken = String(json["access_token"] ?? "");
744
- if (!accessToken) throw new Error("OAuth 2.0: token response missing access_token.");
745
- const expiresIn = Number(json["expires_in"] ?? 3600);
746
- const expiresAt = Date.now() + expiresIn * 1e3;
747
- return {
748
- accessToken,
749
- expiresAt,
750
- refreshToken: json["refresh_token"] ? String(json["refresh_token"]) : void 0
751
- };
752
- }
753
440
  function buildProxyUri(proxy) {
754
441
  const raw = proxy.url.trim();
755
442
  if (!raw) throw new Error("Proxy URL is empty");
@@ -956,6 +643,7 @@ async function buildDispatcher(proxy, tls) {
956
643
  }
957
644
  function registerRequestHandler(ipc) {
958
645
  ipc.handle("request:send", async (_e, payload) => {
646
+ ipcValidate.validateSendRequestPayload(payload);
959
647
  const {
960
648
  request: req,
961
649
  environment,
@@ -972,7 +660,7 @@ function registerRequestHandler(ipc) {
972
660
  const start = Date.now();
973
661
  const liveGlobals = getGlobals();
974
662
  const mergedGlobals = { ...payloadGlobals, ...liveGlobals };
975
- const envVars = await buildEnvVars(environment);
663
+ const envVars = await authBuilder.buildEnvVars(environment);
976
664
  let localVars = {};
977
665
  const decryptionWarnings = [];
978
666
  if (environment) {
@@ -986,14 +674,14 @@ function registerRequestHandler(ipc) {
986
674
  }
987
675
  }
988
676
  }
989
- const dynamicVars = await buildDynamicVars();
990
- let vars = mergeVars(envVars, collectionVars, mergedGlobals, localVars, dynamicVars);
677
+ const dynamicVars = await authBuilder.buildDynamicVars();
678
+ let vars = authBuilder.mergeVars(envVars, collectionVars, mergedGlobals, localVars, dynamicVars);
991
679
  let preScriptMeta = { consoleOutput: [] };
992
680
  let updatedCollectionVars = { ...collectionVars };
993
681
  let updatedEnvVars = { ...envVars };
994
682
  let updatedGlobals = { ...mergedGlobals };
995
683
  if (req.preRequestScript?.trim()) {
996
- const result = await runScript(interpolate(req.preRequestScript, vars), {
684
+ const result = await runScript(authBuilder.interpolate(req.preRequestScript, vars), {
997
685
  envVars: { ...envVars },
998
686
  collectionVars: { ...collectionVars },
999
687
  globals: { ...mergedGlobals },
@@ -1006,11 +694,11 @@ function registerRequestHandler(ipc) {
1006
694
  updatedGlobals = result.updatedGlobals;
1007
695
  patchGlobals(result.updatedGlobals);
1008
696
  await persistGlobals();
1009
- vars = mergeVars(updatedEnvVars, updatedCollectionVars, updatedGlobals, localVars, dynamicVars);
697
+ vars = authBuilder.mergeVars(updatedEnvVars, updatedCollectionVars, updatedGlobals, localVars, dynamicVars);
1010
698
  }
1011
699
  let response;
1012
700
  let sentRequest = { method: req.method, url: "", headers: {} };
1013
- const resolvedUrl = buildUrl(req.url, req.params, vars);
701
+ const resolvedUrl = authBuilder.buildUrl(req.url, req.params, vars);
1014
702
  const secretValues = /* @__PURE__ */ new Set();
1015
703
  if (environment) {
1016
704
  for (const v of environment.variables) {
@@ -1047,13 +735,13 @@ function registerRequestHandler(ipc) {
1047
735
  const tokenMissing = !req.auth.oauth2CachedToken;
1048
736
  const tokenExpired = req.auth.oauth2TokenExpiry ? req.auth.oauth2TokenExpiry <= now + 5e3 : true;
1049
737
  if (tokenMissing || tokenExpired) {
1050
- const result = await fetchOAuth2Token(req.auth, vars);
738
+ const result = await authBuilder.fetchOAuth2Token(req.auth, vars);
1051
739
  req.auth.oauth2CachedToken = result.accessToken;
1052
740
  req.auth.oauth2TokenExpiry = result.expiresAt;
1053
741
  }
1054
742
  }
1055
- const authHeaders = await buildAuthHeaders(req.auth, vars);
1056
- const apiKeyParam = await buildApiKeyParam(req.auth, vars);
743
+ const authHeaders = await authBuilder.buildAuthHeaders(req.auth, vars);
744
+ const apiKeyParam = await authBuilder.buildApiKeyParam(req.auth, vars);
1057
745
  let finalUrl = resolvedUrl;
1058
746
  if (apiKeyParam) {
1059
747
  const sep = finalUrl.includes("?") ? "&" : "?";
@@ -1063,7 +751,7 @@ function registerRequestHandler(ipc) {
1063
751
  const h = new undici.Headers();
1064
752
  for (const header of req.headers) {
1065
753
  if (header.enabled && header.key) {
1066
- h.set(interpolate(header.key, vars), interpolate(header.value, vars));
754
+ h.set(authBuilder.interpolate(header.key, vars), authBuilder.interpolate(header.value, vars));
1067
755
  }
1068
756
  }
1069
757
  for (const [k, v] of Object.entries(authHeaders)) h.set(k, v);
@@ -1071,18 +759,18 @@ function registerRequestHandler(ipc) {
1071
759
  };
1072
760
  let body;
1073
761
  if (req.body.mode === "json" && req.body.json) {
1074
- body = interpolate(req.body.json, vars);
762
+ body = authBuilder.interpolate(req.body.json, vars);
1075
763
  } else if (req.body.mode === "form" && req.body.form) {
1076
- body = req.body.form.filter((p) => p.enabled && p.key).map((p) => `${encodeURIComponent(interpolate(p.key, vars))}=${encodeURIComponent(interpolate(p.value, vars))}`).join("&");
764
+ body = req.body.form.filter((p) => p.enabled && p.key).map((p) => `${encodeURIComponent(authBuilder.interpolate(p.key, vars))}=${encodeURIComponent(authBuilder.interpolate(p.value, vars))}`).join("&");
1077
765
  } else if (req.body.mode === "raw" && req.body.raw) {
1078
- body = interpolate(req.body.raw, vars);
766
+ body = authBuilder.interpolate(req.body.raw, vars);
1079
767
  } else if (req.body.mode === "graphql" && req.body.graphql) {
1080
768
  const gql = req.body.graphql;
1081
- const gqlBody = { query: interpolate(gql.query, vars) };
769
+ const gqlBody = { query: authBuilder.interpolate(gql.query, vars) };
1082
770
  const rawVars = gql.variables?.trim();
1083
771
  if (rawVars) {
1084
772
  try {
1085
- gqlBody.variables = JSON.parse(interpolate(rawVars, vars));
773
+ gqlBody.variables = JSON.parse(authBuilder.interpolate(rawVars, vars));
1086
774
  } catch {
1087
775
  }
1088
776
  }
@@ -1090,7 +778,7 @@ function registerRequestHandler(ipc) {
1090
778
  body = JSON.stringify(gqlBody);
1091
779
  } else if (req.body.mode === "soap" && req.body.soap) {
1092
780
  const soap = req.body.soap;
1093
- body = interpolate(soap.envelope, vars);
781
+ body = authBuilder.interpolate(soap.envelope, vars);
1094
782
  }
1095
783
  const methodHasBody = !["GET", "HEAD"].includes(req.method);
1096
784
  const doFetch = async (overrideHeaders) => {
@@ -1120,7 +808,7 @@ function registerRequestHandler(ipc) {
1120
808
  };
1121
809
  let fetchResp;
1122
810
  if (req.auth.type === "ntlm") {
1123
- await performNtlmRequest(finalUrl, req.method, req.auth, vars);
811
+ await authBuilder.performNtlmRequest(finalUrl, req.method, req.auth, vars);
1124
812
  fetchResp = await doFetch();
1125
813
  } else if (req.auth.type === "digest") {
1126
814
  const probeFetch = async (url, init) => {
@@ -1129,7 +817,7 @@ function registerRequestHandler(ipc) {
1129
817
  dispatcher
1130
818
  });
1131
819
  };
1132
- const digestHeader = await performDigestAuth(finalUrl, req.method, req.auth, vars, probeFetch);
820
+ const digestHeader = await authBuilder.performDigestAuth(finalUrl, req.method, req.auth, vars, probeFetch);
1133
821
  const h = buildHeaders();
1134
822
  if (digestHeader) h.set("Authorization", digestHeader);
1135
823
  fetchResp = await doFetch(h);
@@ -1176,7 +864,7 @@ function registerRequestHandler(ipc) {
1176
864
  let postConsole = [];
1177
865
  let postError;
1178
866
  if (req.postRequestScript?.trim() && !response.error) {
1179
- const result = await runScript(interpolate(req.postRequestScript, vars), {
867
+ const result = await runScript(authBuilder.interpolate(req.postRequestScript, vars), {
1180
868
  envVars: { ...updatedEnvVars },
1181
869
  collectionVars: { ...updatedCollectionVars },
1182
870
  globals: { ...updatedGlobals },
@@ -1291,29 +979,17 @@ function resolveInheritedAuthAndHeaders(requestId, collection) {
1291
979
  }
1292
980
  return { auth: inheritedAuth, headers: inheritedHeaders };
1293
981
  }
1294
- exports.buildAuthHeaders = buildAuthHeaders;
1295
982
  exports.buildDispatcher = buildDispatcher;
1296
- exports.buildDynamicVars = buildDynamicVars;
1297
- exports.buildEnvVars = buildEnvVars;
1298
983
  exports.buildSchemaTestResults = buildSchemaTestResults;
1299
- exports.buildUrl = buildUrl;
1300
984
  exports.collectTagged = collectTagged;
1301
- exports.fetchOAuth2Token = fetchOAuth2Token;
1302
985
  exports.getAllApplicableHooks = getAllApplicableHooks;
1303
986
  exports.getGlobals = getGlobals;
1304
- exports.getSecret = getSecret;
1305
- exports.initSecretStore = initSecretStore;
1306
- exports.interpolate = interpolate;
1307
987
  exports.loadGlobals = loadGlobals;
1308
988
  exports.maskHeaders = maskHeaders;
1309
989
  exports.maskPii = maskPii;
1310
- exports.mergeVars = mergeVars;
1311
990
  exports.patchGlobals = patchGlobals;
1312
- exports.performDigestAuth = performDigestAuth;
1313
- exports.performNtlmRequest = performNtlmRequest;
1314
991
  exports.persistGlobals = persistGlobals;
1315
992
  exports.registerRequestHandler = registerRequestHandler;
1316
- exports.registerSecretHandlers = registerSecretHandlers;
1317
993
  exports.resolveInheritedAuthAndHeaders = resolveInheritedAuthAndHeaders;
1318
994
  exports.runScript = runScript;
1319
995
  exports.setGlobals = setGlobals;