feat: add certs and proxy config to bru.sendRequest API (#6988)

* feat: add certs and proxy config to bru.sendRequest API

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: handle URL string argument in bru.sendRequest

When bru.sendRequest is called with a plain URL string instead of a
config object, the function now normalizes it to { url: string } before
processing. This fixes the case where spreading a string created an
invalid config object.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: add variable interpolation to bru.sendRequest certs and proxy config

Interpolate environment variables in clientCertificates and proxy
configuration for bru.sendRequest API, enabling use of variables like
{{CERT_PATH}} or {{PROXY_HOST}} in certificate paths and proxy settings.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: use interpolateObject for certs and proxy config interpolation

- Add interpolateObject to electron's interpolate-string.js using
  buildCombinedVars pattern (matches CLI implementation)
- Simplify cert-utils.js by using interpolateObject instead of
  manual field-by-field interpolation
- Add interpolation for clientCertificates and proxy config in CLI's
  run-single-request.js for bru.sendRequest

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: add all variable types to sendRequest interpolation options

- Add globalEnvVars, collectionVariables, folderVariables, requestVariables
  to sendRequestInterpolationOptions for complete variable support
- Use cached system proxy instead of redundant getSystemProxy() call
- Remove duplicate getOptions() call

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: skip CA cert loading when TLS verification is disabled

Only load CA certificates when shouldVerifyTls is true, since they
are not used for validation when TLS verification is disabled.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
lohit
2026-02-02 12:29:46 +00:00
committed by GitHub
parent 06dd5c14d5
commit bafb235e72
14 changed files with 461 additions and 50 deletions

View File

@@ -76,6 +76,8 @@ const STATIC_API_HINTS = {
'bru.setNextRequest(requestName)',
'bru.getRequestVar(key)',
'bru.runRequest(requestPathName)',
'bru.sendRequest(requestConfig)',
'bru.sendRequest(requestConfig, callback)',
'bru.getAssertionResults()',
'bru.getTestResults()',
'bru.sleep(ms)',

View File

@@ -170,6 +170,37 @@ const runSingleRequest = async function (
const scriptingConfig = get(brunoConfig, 'scripts', {});
scriptingConfig.runtime = runtime;
// Build certsAndProxyConfig for bru.sendRequest
const options = getOptions();
const systemProxyConfig = options['cachedSystemProxy'];
const sendRequestInterpolationOptions = {
envVars: envVariables,
runtimeVariables,
processEnvVars,
globalEnvVars,
collectionVariables: request.collectionVariables || {},
folderVariables: request.folderVariables || {},
requestVariables: request.requestVariables || {}
};
const rawClientCertificates = get(brunoConfig, 'clientCertificates');
const rawProxyConfig = get(brunoConfig, 'proxy', {});
const certsAndProxyConfig = {
collectionPath,
options: {
noproxy: get(options, 'noproxy', false),
shouldVerifyTls: !get(options, 'insecure', false),
shouldUseCustomCaCertificate: !!options['cacert'],
customCaCertificateFilePath: options['cacert'],
shouldKeepDefaultCaCertificates: !options['ignoreTruststore']
},
clientCertificates: rawClientCertificates ? interpolateObject(rawClientCertificates, sendRequestInterpolationOptions) : undefined,
collectionLevelProxy: transformProxyConfig(interpolateObject(rawProxyConfig, sendRequestInterpolationOptions)),
systemProxyConfig
};
// Add certsAndProxyConfig to request object for bru.sendRequest
request.certsAndProxyConfig = certsAndProxyConfig;
// run pre request script
const requestScriptFile = get(request, 'script.req');
const collectionName = collection?.brunoConfig?.name;
@@ -237,7 +268,6 @@ const runSingleRequest = async function (
request.url = `http://${request.url}`;
}
const options = getOptions();
const insecure = get(options, 'insecure', false);
const noproxy = get(options, 'noproxy', false);
const cachedSystemProxy = get(options, 'cachedSystemProxy', null);

View File

@@ -5,7 +5,7 @@ const { getCACertificates } = require('@usebruno/requests');
const { preferencesUtil } = require('../../store/preferences');
const { getBrunoConfig } = require('../../store/bruno-config');
const { getCachedSystemProxy } = require('../../store/system-proxy');
const { interpolateString } = require('./interpolate-string');
const { interpolateString, interpolateObject } = require('./interpolate-string');
/**
* Gets certificates and proxy configuration for a request
@@ -155,4 +155,68 @@ const getCertsAndProxyConfig = async ({
return { proxyMode, proxyConfig, httpsAgentRequestFields, interpolationOptions };
};
module.exports = { getCertsAndProxyConfig };
/**
* Builds the certsAndProxyConfig object for bru.sendRequest
* This allows bru.sendRequest to use the same proxy/certs config as the main request
*/
const buildCertsAndProxyConfig = async ({
collectionUid,
collection,
collectionPath,
envVars,
runtimeVariables,
processEnvVars,
request
}) => {
const brunoConfig = getBrunoConfig(collectionUid, collection);
// Build interpolation options (same pattern as getCertsAndProxyConfig)
const globalEnvironmentVariables = collection.globalEnvironmentVariables || {};
const { promptVariables } = collection;
const collectionVariables = request?.collectionVariables || {};
const folderVariables = request?.folderVariables || {};
const requestVariables = request?.requestVariables || {};
const interpolationOptions = {
globalEnvironmentVariables,
collectionVariables,
envVars,
folderVariables,
requestVariables,
runtimeVariables,
promptVariables,
processEnvVars
};
// Build options for getHttpHttpsAgents
const options = {
noproxy: false,
shouldVerifyTls: preferencesUtil.shouldVerifyTls(),
shouldUseCustomCaCertificate: preferencesUtil.shouldUseCustomCaCertificate(),
customCaCertificateFilePath: preferencesUtil.getCustomCaCertificateFilePath(),
shouldKeepDefaultCaCertificates: preferencesUtil.shouldKeepDefaultCaCertificates()
};
// Get client certificates from bruno config and interpolate
const rawClientCertificates = get(brunoConfig, 'clientCertificates');
const clientCertificates = rawClientCertificates
? interpolateObject(rawClientCertificates, interpolationOptions)
: undefined;
// Get proxy config from bruno config and interpolate
const collectionProxyConfig = get(brunoConfig, 'proxy', {});
const collectionLevelProxy = interpolateObject(collectionProxyConfig, interpolationOptions);
// Get system proxy config
const systemProxyConfig = getCachedSystemProxy();
return {
collectionPath,
options,
clientCertificates,
collectionLevelProxy,
systemProxyConfig
};
};
module.exports = { getCertsAndProxyConfig, buildCertsAndProxyConfig };

View File

@@ -34,7 +34,7 @@ const { isRequestTagsIncluded } = require('@usebruno/common');
const { cookiesStore } = require('../../store/cookies');
const registerGrpcEventHandlers = require('./grpc-event-handlers');
const { registerWsEventHandlers } = require('./ws-event-handlers');
const { getCertsAndProxyConfig } = require('./cert-utils');
const { getCertsAndProxyConfig, buildCertsAndProxyConfig } = require('./cert-utils');
const { buildFormUrlEncodedPayload, isFormData } = require('@usebruno/common').utils;
const ERROR_OCCURRED_WHILE_EXECUTING_REQUEST = 'Error occurred while executing the request!';
@@ -680,6 +680,20 @@ const registerNetworkIpc = (mainWindow) => {
request.signal = abortController.signal;
saveCancelToken(cancelTokenUid, abortController);
// Build certsAndProxyConfig for bru.sendRequest
const certsAndProxyConfig = await buildCertsAndProxyConfig({
collectionUid,
collection,
collectionPath,
envVars,
runtimeVariables,
processEnvVars,
request
});
// Add certsAndProxyConfig to request object for bru.sendRequest
request.certsAndProxyConfig = certsAndProxyConfig;
let preRequestScriptResult = null;
let preRequestError = null;
try {
@@ -1288,6 +1302,20 @@ const registerNetworkIpc = (mainWindow) => {
}
try {
// Build certsAndProxyConfig for bru.sendRequest
const certsAndProxyConfig = await buildCertsAndProxyConfig({
collectionUid,
collection,
collectionPath,
envVars,
runtimeVariables,
processEnvVars,
request
});
// Add certsAndProxyConfig to request object for bru.sendRequest
request.certsAndProxyConfig = certsAndProxyConfig;
let preRequestScriptResult;
let preRequestError = null;
try {

View File

@@ -1,7 +1,7 @@
const { forOwn, cloneDeep } = require('lodash');
const { interpolate } = require('@usebruno/common');
const { interpolate, interpolateObject: interpolateObjectCommon } = require('@usebruno/common');
const interpolateString = (str, {
const buildCombinedVars = ({
globalEnvironmentVariables,
collectionVariables,
envVars,
@@ -11,10 +11,6 @@ const interpolateString = (str, {
processEnvVars,
promptVariables
}) => {
if (!str || !str.length || typeof str !== 'string') {
return str;
}
processEnvVars = processEnvVars || {};
runtimeVariables = runtimeVariables || {};
globalEnvironmentVariables = globalEnvironmentVariables || {};
@@ -38,8 +34,7 @@ const interpolateString = (str, {
});
});
// runtimeVariables take precedence over envVars
const combinedVars = {
return {
...globalEnvironmentVariables,
...collectionVariables,
...envVars,
@@ -53,10 +48,26 @@ const interpolateString = (str, {
}
}
};
};
const interpolateString = (str, interpolationOptions) => {
if (!str || !str.length || typeof str !== 'string') {
return str;
}
const combinedVars = buildCombinedVars(interpolationOptions);
return interpolate(str, combinedVars);
};
module.exports = {
interpolateString
/**
* Recursively interpolates all string values in an object
*/
const interpolateObject = (obj, interpolationOptions) => {
const combinedVars = buildCombinedVars(interpolationOptions);
return interpolateObjectCommon(obj, combinedVars);
};
module.exports = {
interpolateString,
interpolateObject
};

View File

@@ -1,13 +1,33 @@
const { cloneDeep } = require('lodash');
const xmlFormat = require('xml-formatter');
const { interpolate: _interpolate } = require('@usebruno/common');
const { sendRequest } = require('@usebruno/requests').scripting;
const { sendRequest, createSendRequest } = require('@usebruno/requests').scripting;
const { jar: createCookieJar } = require('@usebruno/requests').cookies;
const variableNameRegex = /^[\w-.]*$/;
class Bru {
constructor(runtime, envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables, oauth2CredentialVariables, collectionName, promptVariables) {
/**
* @param {string} runtime - The runtime environment ('quickjs' or 'nodevm')
* @param {object} envVariables - Environment variables
* @param {object} runtimeVariables - Runtime variables
* @param {object} processEnvVars - Process environment variables
* @param {string} collectionPath - Path to the collection
* @param {object} collectionVariables - Collection-level variables
* @param {object} folderVariables - Folder-level variables
* @param {object} requestVariables - Request-level variables
* @param {object} globalEnvironmentVariables - Global environment variables
* @param {object} oauth2CredentialVariables - OAuth2 credential variables
* @param {string} collectionName - Name of the collection
* @param {object} promptVariables - Prompt variables
* @param {object} certsAndProxyConfig - Configuration for bru.sendRequest (proxy, certs, TLS)
* @param {string} certsAndProxyConfig.collectionPath - Path to the collection
* @param {object} certsAndProxyConfig.options - TLS and proxy options
* @param {object} [certsAndProxyConfig.clientCertificates] - Client certificate configuration
* @param {object} [certsAndProxyConfig.collectionLevelProxy] - Collection-level proxy settings
* @param {object} [certsAndProxyConfig.systemProxyConfig] - System proxy configuration
*/
constructor(runtime, envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables, oauth2CredentialVariables, collectionName, promptVariables, certsAndProxyConfig) {
this.envVariables = envVariables || {};
this.runtimeVariables = runtimeVariables || {};
this.promptVariables = promptVariables || {};
@@ -19,7 +39,8 @@ class Bru {
this.oauth2CredentialVariables = oauth2CredentialVariables || {};
this.collectionPath = collectionPath;
this.collectionName = collectionName;
this.sendRequest = sendRequest;
// Use createSendRequest with config if provided, otherwise use default sendRequest
this.sendRequest = certsAndProxyConfig ? createSendRequest(certsAndProxyConfig) : sendRequest;
this.runtime = runtime;
this.cookies = {
jar: () => {

View File

@@ -256,6 +256,7 @@ class AssertRuntime {
}
const promptVariables = request?.promptVariables || {};
const certsAndProxyConfig = request?.certsAndProxyConfig;
const bru = new Bru(
this.runtime,
envVariables,
@@ -268,7 +269,8 @@ class AssertRuntime {
globalEnvironmentVariables,
{},
undefined,
promptVariables
promptVariables,
certsAndProxyConfig
);
const req = new BrunoRequest(request);
const res = createResponseParser(response);

View File

@@ -33,7 +33,8 @@ class ScriptRuntime {
const requestVariables = request?.requestVariables || {};
const promptVariables = request?.promptVariables || {};
const assertionResults = request?.assertionResults || [];
const bru = new Bru(this.runtime, envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables, oauth2CredentialVariables, collectionName, promptVariables);
const certsAndProxyConfig = request?.certsAndProxyConfig;
const bru = new Bru(this.runtime, envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables, oauth2CredentialVariables, collectionName, promptVariables, certsAndProxyConfig);
const req = new BrunoRequest(request);
// extend bru with result getter methods
@@ -128,7 +129,8 @@ class ScriptRuntime {
const requestVariables = request?.requestVariables || {};
const promptVariables = request?.promptVariables || {};
const assertionResults = request?.assertionResults || {};
const bru = new Bru(this.runtime, envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables, oauth2CredentialVariables, collectionName, promptVariables);
const certsAndProxyConfig = request?.certsAndProxyConfig;
const bru = new Bru(this.runtime, envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables, oauth2CredentialVariables, collectionName, promptVariables, certsAndProxyConfig);
const req = new BrunoRequest(request);
const res = new BrunoResponse(response);

View File

@@ -32,7 +32,8 @@ class TestRuntime {
const requestVariables = request?.requestVariables || {};
const promptVariables = request?.promptVariables || {};
const assertionResults = request?.assertionResults || [];
const bru = new Bru(this.runtime, envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables, {}, collectionName, promptVariables);
const certsAndProxyConfig = request?.certsAndProxyConfig;
const bru = new Bru(this.runtime, envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables, {}, collectionName, promptVariables, certsAndProxyConfig);
const req = new BrunoRequest(request);
const res = new BrunoResponse(response);

View File

@@ -36,7 +36,8 @@ class VarsRuntime {
}
const promptVariables = request?.promptVariables || {};
const bru = new Bru(this.runtime, envVariables, runtimeVariables, processEnvVars, undefined, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables, oauth2CredentialVariables, undefined, promptVariables);
const certsAndProxyConfig = request?.certsAndProxyConfig;
const bru = new Bru(this.runtime, envVariables, runtimeVariables, processEnvVars, undefined, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables, oauth2CredentialVariables, undefined, promptVariables, certsAndProxyConfig);
const req = new BrunoRequest(request);
const res = createResponseParser(response);

View File

@@ -1 +1 @@
export { default as sendRequest } from './send-request';
export { default as sendRequest, createSendRequest } from './send-request';

View File

@@ -0,0 +1,198 @@
import sendRequest, { createSendRequest } from './send-request';
jest.mock('../network', () => ({
makeAxiosInstance: jest.fn()
}));
jest.mock('../utils/http-https-agents', () => ({
getHttpHttpsAgents: jest.fn()
}));
import { makeAxiosInstance } from '../network';
import { getHttpHttpsAgents } from '../utils/http-https-agents';
const mockMakeAxiosInstance = makeAxiosInstance as jest.Mock;
const mockGetHttpHttpsAgents = getHttpHttpsAgents as jest.Mock;
describe('sendRequest', () => {
let mockAxios: jest.Mock;
beforeEach(() => {
jest.clearAllMocks();
mockAxios = jest.fn();
mockMakeAxiosInstance.mockReturnValue(mockAxios);
mockGetHttpHttpsAgents.mockResolvedValue({ httpAgent: null, httpsAgent: null });
});
describe('without callback', () => {
test('should return response directly', async () => {
const mockResponse = { data: 'test', status: 200 };
mockAxios.mockResolvedValue(mockResponse);
const result = await sendRequest({ url: 'http://example.com' });
expect(result).toBe(mockResponse);
});
test('should reject on request error', async () => {
const error = new Error('Network error');
mockAxios.mockRejectedValue(error);
await expect(sendRequest({ url: 'http://example.com' })).rejects.toThrow('Network error');
});
test('should handle URL string instead of config object', async () => {
const mockResponse = { data: 'pong', status: 200 };
mockAxios.mockResolvedValue(mockResponse);
const result = await sendRequest('http://example.com/ping');
expect(result).toBe(mockResponse);
expect(mockAxios).toHaveBeenCalledWith(
expect.objectContaining({
url: 'http://example.com/ping'
})
);
});
});
describe('with callback', () => {
test('should call callback with response and return response', async () => {
const mockResponse = { data: 'test', status: 200 };
mockAxios.mockResolvedValue(mockResponse);
const callback = jest.fn();
const result = await sendRequest({ url: 'http://example.com' }, callback);
expect(callback).toHaveBeenCalledWith(null, mockResponse);
expect(result).toBe(mockResponse);
});
test('should call callback with error on request failure', async () => {
const error = new Error('Network error');
mockAxios.mockRejectedValue(error);
const callback = jest.fn();
await sendRequest({ url: 'http://example.com' }, callback);
expect(callback).toHaveBeenCalledWith(error, null);
});
test('should reject if callback throws on success', async () => {
const mockResponse = { data: 'test', status: 200 };
mockAxios.mockResolvedValue(mockResponse);
const callbackError = new Error('Callback error');
const callback = jest.fn().mockRejectedValue(callbackError);
await expect(sendRequest({ url: 'http://example.com' }, callback)).rejects.toThrow(
'Callback error'
);
});
test('should reject if callback throws on error', async () => {
const requestError = new Error('Network error');
mockAxios.mockRejectedValue(requestError);
const callbackError = new Error('Callback error');
const callback = jest.fn().mockRejectedValue(callbackError);
await expect(sendRequest({ url: 'http://example.com' }, callback)).rejects.toThrow(
'Callback error'
);
});
});
});
describe('createSendRequest', () => {
let mockAxios: jest.Mock;
beforeEach(() => {
jest.clearAllMocks();
mockAxios = jest.fn();
mockMakeAxiosInstance.mockReturnValue(mockAxios);
});
test('should apply agents from config', async () => {
const mockHttpAgent = { name: 'httpAgent' };
const mockHttpsAgent = { name: 'httpsAgent' };
mockGetHttpHttpsAgents.mockResolvedValue({
httpAgent: mockHttpAgent,
httpsAgent: mockHttpsAgent
});
const mockResponse = { data: 'test' };
mockAxios.mockResolvedValue(mockResponse);
const customSendRequest = createSendRequest({ proxyConfig: {} });
await customSendRequest({ url: 'https://example.com' });
expect(mockGetHttpHttpsAgents).toHaveBeenCalledWith({
proxyConfig: {},
requestUrl: 'https://example.com'
});
expect(mockAxios).toHaveBeenCalledWith(
expect.objectContaining({
httpAgent: mockHttpAgent,
httpsAgent: mockHttpsAgent
})
);
});
test('should not override agents if already set in requestConfig', async () => {
const configHttpAgent = { name: 'configAgent' };
const configHttpsAgent = { name: 'configHttpsAgent' };
mockGetHttpHttpsAgents.mockResolvedValue({
httpAgent: { name: 'ignored' },
httpsAgent: { name: 'ignored' }
});
mockAxios.mockResolvedValue({ data: 'test' });
const customSendRequest = createSendRequest({ proxyConfig: {} });
await customSendRequest({
url: 'https://example.com',
httpAgent: configHttpAgent,
httpsAgent: configHttpsAgent
});
expect(mockAxios).toHaveBeenCalledWith(
expect.objectContaining({
httpAgent: configHttpAgent,
httpsAgent: configHttpsAgent
})
);
});
test('should not call getHttpHttpsAgents when no config provided', async () => {
mockAxios.mockResolvedValue({ data: 'test' });
const customSendRequest = createSendRequest();
await customSendRequest({ url: 'https://example.com' });
expect(mockGetHttpHttpsAgents).not.toHaveBeenCalled();
});
test('should handle URL string and apply agents from config', async () => {
const mockHttpAgent = { name: 'httpAgent' };
const mockHttpsAgent = { name: 'httpsAgent' };
mockGetHttpHttpsAgents.mockResolvedValue({
httpAgent: mockHttpAgent,
httpsAgent: mockHttpsAgent
});
const mockResponse = { data: 'pong' };
mockAxios.mockResolvedValue(mockResponse);
const customSendRequest = createSendRequest({ collectionPath: '/test' });
const result = await customSendRequest('https://example.com/ping');
expect(result).toBe(mockResponse);
expect(mockGetHttpHttpsAgents).toHaveBeenCalledWith({
collectionPath: '/test',
requestUrl: 'https://example.com/ping'
});
expect(mockAxios).toHaveBeenCalledWith(
expect.objectContaining({
url: 'https://example.com/ping',
httpAgent: mockHttpAgent,
httpsAgent: mockHttpsAgent
})
);
});
});

View File

@@ -1,27 +1,76 @@
import { AxiosRequestConfig } from 'axios';
import { makeAxiosInstance } from '../network';
import { getHttpHttpsAgents } from '../utils/http-https-agents';
import type { GetHttpHttpsAgentsParams } from '../utils/http-https-agents';
type T_SendRequestCallback = (error: any, response: any) => void;
const sendRequest = async (requestConfig: AxiosRequestConfig, callback: T_SendRequestCallback) => {
const axiosInstance = makeAxiosInstance();
if (!callback) {
return await axiosInstance(requestConfig);
}
try {
const response = await axiosInstance(requestConfig);
/**
* Configuration for creating a sendRequest function with proxy/certs support.
* This is the same config used by getHttpHttpsAgents, minus requestUrl which is
* extracted from the actual request.
*/
type SendRequestConfig = Omit<GetHttpHttpsAgentsParams, 'requestUrl'>;
/**
* Creates a sendRequest function configured with proxy and certificate settings.
* This allows bru.sendRequest to use the same proxy/certs config as the main request.
*
* @param config - Configuration for proxy, certs, and TLS options (same as getHttpHttpsAgents)
* @returns A sendRequest function that applies the config to each request
*/
const createSendRequest = (config?: SendRequestConfig) => {
return async (requestConfig: AxiosRequestConfig | string, callback?: T_SendRequestCallback) => {
// Handle case where requestConfig is a URL string
const normalizedConfig: AxiosRequestConfig = typeof requestConfig === 'string'
? { url: requestConfig }
: { ...requestConfig };
// If config is provided, create agents with the request URL for proper proxy bypass
if (config) {
const requestUrl = normalizedConfig.url;
const { httpAgent, httpsAgent } = await getHttpHttpsAgents({
...config,
requestUrl
});
// Apply agents if not explicitly set in normalizedConfig
if (httpAgent && !normalizedConfig.httpAgent) {
normalizedConfig.httpAgent = httpAgent;
}
if (httpsAgent && !normalizedConfig.httpsAgent) {
normalizedConfig.httpsAgent = httpsAgent;
}
}
const axiosInstance = makeAxiosInstance();
if (!callback) {
return await axiosInstance(normalizedConfig);
}
try {
await callback(null, response);
const response = await axiosInstance(normalizedConfig);
try {
await callback(null, response);
return response;
} catch (error) {
return Promise.reject(error);
}
} catch (error) {
return Promise.reject(error);
try {
await callback(error, null);
} catch (err) {
return Promise.reject(err);
}
}
} catch (error) {
try {
await callback(error, null);
} catch (err) {
return Promise.reject(err);
}
}
};
};
// Default sendRequest without config (for backward compatibility)
const sendRequest = createSendRequest();
export default sendRequest;
export { createSendRequest };
export type { SendRequestConfig };

View File

@@ -214,18 +214,18 @@ const getCertsAndProxyConfig = ({
}: GetCertsAndProxyConfigParams): GetCertsAndProxyConfigResult => {
const certsConfig: CertsConfig = {};
const caCertFilePath = options.shouldUseCustomCaCertificate && options.customCaCertificateFilePath ? options.customCaCertificateFilePath : undefined;
const caCertificatesData = getCACertificates({
caCertFilePath,
shouldKeepDefaultCerts: options.shouldKeepDefaultCaCertificates
});
// Only load CA certificates when TLS verification is enabled
if (options.shouldVerifyTls) {
const caCertFilePath = options.shouldUseCustomCaCertificate && options.customCaCertificateFilePath ? options.customCaCertificateFilePath : undefined;
const caCertificatesData = getCACertificates({
caCertFilePath,
shouldKeepDefaultCerts: options.shouldKeepDefaultCaCertificates
});
const caCertificates = caCertificatesData.caCertificates;
const caCertificatesCount = caCertificatesData.caCertificatesCount;
// configure HTTPS agent with aggregated CA certificates
certsConfig.caCertificatesCount = caCertificatesCount;
certsConfig.ca = caCertificates || [];
// configure HTTPS agent with aggregated CA certificates
certsConfig.caCertificatesCount = caCertificatesData.caCertificatesCount;
certsConfig.ca = caCertificatesData.caCertificates || [];
}
// client certificate config
const clientCertConfig = get(clientCertificates, 'certs', []) as ClientCertificate[];
@@ -443,3 +443,5 @@ const getHttpHttpsAgents = async ({
};
export { getHttpHttpsAgents };
export type { GetHttpHttpsAgentsParams };