Skip to content

Commit 969b071

Browse files
Add https-proxy-agent support for HTTP-only proxies in dts-plugin
Co-authored-by: ScriptedAlchemy <25274700+ScriptedAlchemy@users.noreply.github.com>
1 parent 7796414 commit 969b071

3 files changed

Lines changed: 148 additions & 1 deletion

File tree

packages/dts-plugin/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"adm-zip": "^0.5.10",
5252
"ansi-colors": "^4.1.3",
5353
"axios": "^1.11.0",
54+
"https-proxy-agent": "^7.0.5",
5455
"rambda": "^9.1.0",
5556
"@module-federation/sdk": "workspace:*",
5657
"@module-federation/managers": "workspace:*",

packages/dts-plugin/src/core/lib/utils.spec.ts

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { it, expect, vi } from 'vitest';
22
import http from 'http';
3+
import https from 'https';
4+
import { HttpsProxyAgent } from 'https-proxy-agent';
35
import { axiosGet } from './utils';
46

57
vi.mock('axios', () => ({
@@ -8,22 +10,146 @@ vi.mock('axios', () => ({
810
},
911
}));
1012

13+
vi.mock('https-proxy-agent', () => ({
14+
HttpsProxyAgent: vi.fn(),
15+
}));
16+
1117
it('axiosGet should use agents with family set to 4', async () => {
1218
const httpSpy = vi.spyOn(http, 'Agent');
19+
const httpsSpy = vi.spyOn(https, 'Agent');
1320

1421
await axiosGet('http://localhost');
1522

1623
expect(httpSpy).toHaveBeenCalledWith({ family: 4 });
24+
expect(httpsSpy).toHaveBeenCalledWith({ family: 4 });
1725

1826
httpSpy.mockRestore();
27+
httpsSpy.mockRestore();
1928
});
2029

2130
it('axiosGet should allow to use agents with family set to 6', async () => {
2231
const httpSpy = vi.spyOn(http, 'Agent');
32+
const httpsSpy = vi.spyOn(https, 'Agent');
2333

2434
await axiosGet('http://localhost', { family: 6 });
2535

2636
expect(httpSpy).toHaveBeenCalledWith({ family: 6 });
37+
expect(httpsSpy).toHaveBeenCalledWith({ family: 6 });
38+
39+
httpSpy.mockRestore();
40+
httpsSpy.mockRestore();
41+
});
42+
43+
it('axiosGet should use HttpsProxyAgent when HTTP_PROXY is set', async () => {
44+
const originalHttpProxy = process.env.HTTP_PROXY;
45+
process.env.HTTP_PROXY = 'http://proxy.company.com:8080';
46+
47+
const httpSpy = vi.spyOn(http, 'Agent');
48+
const httpsProxyAgentSpy = vi.mocked(HttpsProxyAgent);
49+
50+
await axiosGet('https://example.com');
51+
52+
expect(httpSpy).toHaveBeenCalledWith({ family: 4 });
53+
expect(httpsProxyAgentSpy).toHaveBeenCalledWith('http://proxy.company.com:8080', { family: 4 });
54+
55+
// Restore environment variable
56+
if (originalHttpProxy !== undefined) {
57+
process.env.HTTP_PROXY = originalHttpProxy;
58+
} else {
59+
delete process.env.HTTP_PROXY;
60+
}
61+
62+
httpSpy.mockRestore();
63+
});
64+
65+
it('axiosGet should use HttpsProxyAgent when HTTPS_PROXY is set', async () => {
66+
const originalHttpsProxy = process.env.HTTPS_PROXY;
67+
process.env.HTTPS_PROXY = 'http://proxy.company.com:8080';
68+
69+
const httpSpy = vi.spyOn(http, 'Agent');
70+
const httpsProxyAgentSpy = vi.mocked(HttpsProxyAgent);
71+
72+
await axiosGet('https://example.com');
73+
74+
expect(httpSpy).toHaveBeenCalledWith({ family: 4 });
75+
expect(httpsProxyAgentSpy).toHaveBeenCalledWith('http://proxy.company.com:8080', { family: 4 });
76+
77+
// Restore environment variable
78+
if (originalHttpsProxy !== undefined) {
79+
process.env.HTTPS_PROXY = originalHttpsProxy;
80+
} else {
81+
delete process.env.HTTPS_PROXY;
82+
}
83+
84+
httpSpy.mockRestore();
85+
});
86+
87+
it('axiosGet should prefer HTTPS_PROXY over HTTP_PROXY when both are set', async () => {
88+
const originalHttpProxy = process.env.HTTP_PROXY;
89+
const originalHttpsProxy = process.env.HTTPS_PROXY;
90+
91+
process.env.HTTP_PROXY = 'http://proxy1.company.com:8080';
92+
process.env.HTTPS_PROXY = 'http://proxy2.company.com:8080';
93+
94+
const httpSpy = vi.spyOn(http, 'Agent');
95+
const httpsProxyAgentSpy = vi.mocked(HttpsProxyAgent);
96+
97+
await axiosGet('https://example.com');
98+
99+
expect(httpSpy).toHaveBeenCalledWith({ family: 4 });
100+
expect(httpsProxyAgentSpy).toHaveBeenCalledWith('http://proxy2.company.com:8080', { family: 4 });
101+
102+
// Restore environment variables
103+
if (originalHttpProxy !== undefined) {
104+
process.env.HTTP_PROXY = originalHttpProxy;
105+
} else {
106+
delete process.env.HTTP_PROXY;
107+
}
108+
if (originalHttpsProxy !== undefined) {
109+
process.env.HTTPS_PROXY = originalHttpsProxy;
110+
} else {
111+
delete process.env.HTTPS_PROXY;
112+
}
113+
114+
httpSpy.mockRestore();
115+
});
116+
117+
it('axiosGet should use standard https.Agent when no proxy is configured', async () => {
118+
const originalHttpProxy = process.env.HTTP_PROXY;
119+
const originalHttpsProxy = process.env.HTTPS_PROXY;
120+
const originalHttpProxyLower = process.env.http_proxy;
121+
const originalHttpsProxyLower = process.env.https_proxy;
122+
123+
// Clear all proxy environment variables
124+
delete process.env.HTTP_PROXY;
125+
delete process.env.HTTPS_PROXY;
126+
delete process.env.http_proxy;
127+
delete process.env.https_proxy;
128+
129+
const httpSpy = vi.spyOn(http, 'Agent');
130+
const httpsSpy = vi.spyOn(https, 'Agent');
131+
const httpsProxyAgentSpy = vi.mocked(HttpsProxyAgent);
132+
133+
await axiosGet('https://example.com');
134+
135+
expect(httpSpy).toHaveBeenCalledWith({ family: 4 });
136+
expect(httpsSpy).toHaveBeenCalledWith({ family: 4 });
137+
expect(httpsProxyAgentSpy).not.toHaveBeenCalled();
138+
139+
// Restore environment variables
140+
if (originalHttpProxy !== undefined) {
141+
process.env.HTTP_PROXY = originalHttpProxy;
142+
}
143+
if (originalHttpsProxy !== undefined) {
144+
process.env.HTTPS_PROXY = originalHttpsProxy;
145+
}
146+
if (originalHttpProxyLower !== undefined) {
147+
process.env.http_proxy = originalHttpProxyLower;
148+
}
149+
if (originalHttpsProxyLower !== undefined) {
150+
process.env.https_proxy = originalHttpsProxyLower;
151+
}
27152

28153
httpSpy.mockRestore();
154+
httpsSpy.mockRestore();
29155
});

packages/dts-plugin/src/core/lib/utils.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import path from 'path';
33
import axios, { type AxiosRequestConfig } from 'axios';
44
import http from 'http';
55
import https from 'https';
6+
import { HttpsProxyAgent } from 'https-proxy-agent';
67
import { moduleFederationPlugin, getProcessEnv } from '@module-federation/sdk';
78
import ansiColors from 'ansi-colors';
89
import { retrieveRemoteConfig } from '../configurations/remotePlugin';
@@ -152,10 +153,29 @@ const getEnvHeaders = (): Record<string, string> => {
152153

153154
export async function axiosGet(url: string, config?: AxiosRequestConfig) {
154155
const httpAgent = new http.Agent({ family: config?.family ?? 4 });
155-
const httpsAgent = new https.Agent({ family: config?.family ?? 4 });
156+
157+
// Check for proxy environment variables
158+
const httpProxy = process.env.HTTP_PROXY || process.env.http_proxy;
159+
const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy;
160+
const proxyUrl = httpsProxy || httpProxy;
161+
162+
let httpsAgent: https.Agent | HttpsProxyAgent;
163+
let axiosConfig: any = {};
164+
165+
if (proxyUrl) {
166+
// Use HttpsProxyAgent for HTTPS requests when proxy is configured
167+
httpsAgent = new HttpsProxyAgent(proxyUrl, { family: config?.family ?? 4 });
168+
// Disable axios built-in proxy to let our custom agent handle it
169+
axiosConfig.proxy = false;
170+
} else {
171+
// Use standard HTTPS agent when no proxy is configured
172+
httpsAgent = new https.Agent({ family: config?.family ?? 4 });
173+
}
174+
156175
return axios.get(url, {
157176
httpAgent,
158177
httpsAgent,
178+
...axiosConfig,
159179
...{
160180
headers: getEnvHeaders(),
161181
},

0 commit comments

Comments
 (0)