From c227cd4352709e7896d7ac1291407d9fee162ad7 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 16:37:36 +0000 Subject: [PATCH] fix(http-agent): improve type safety and fix proxy agent implementation This change improves the type safety of the http-agent module by: - Removing the `HttpsProxyAgentWithCA` workaround class. - Using the `HttpsProxyAgent` class directly from the `https-proxy-agent` library. - Correctly typing the `getAgent` and `tryGetAgent` functions. This change also fixes a type error in `base-command.ts` by correctly passing the `HttpsProxyAgent` object to the `NetlifyAPI` constructor via the `fetchOptions` property. Co-authored-by: serhalp <1377702+serhalp@users.noreply.github.com> --- package-lock.json | 23 ------------- src/commands/base-command.ts | 2 +- src/lib/http-agent.ts | 63 +++++++++++++----------------------- 3 files changed, 23 insertions(+), 65 deletions(-) diff --git a/package-lock.json b/package-lock.json index d58d9085b7d..b1f51a03f99 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5452,7 +5452,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "android" @@ -5465,7 +5464,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "android" @@ -5478,7 +5476,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -5491,7 +5488,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -5504,7 +5500,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "freebsd" @@ -5517,7 +5512,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "freebsd" @@ -5530,7 +5524,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "linux" @@ -5543,7 +5536,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "linux" @@ -5556,7 +5548,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -5569,7 +5560,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -5582,7 +5572,6 @@ "cpu": [ "loong64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -5595,7 +5584,6 @@ "cpu": [ "ppc64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -5608,7 +5596,6 @@ "cpu": [ "riscv64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -5621,7 +5608,6 @@ "cpu": [ "riscv64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -5634,7 +5620,6 @@ "cpu": [ "s390x" ], - "dev": true, "optional": true, "os": [ "linux" @@ -5647,7 +5632,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -5660,7 +5644,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -5673,7 +5656,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "openharmony" @@ -5686,7 +5668,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -5699,7 +5680,6 @@ "cpu": [ "ia32" ], - "dev": true, "optional": true, "os": [ "win32" @@ -5712,7 +5692,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -5725,7 +5704,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -12236,7 +12214,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ diff --git a/src/commands/base-command.ts b/src/commands/base-command.ts index 99e1eb360e5..5520f291f8e 100644 --- a/src/commands/base-command.ts +++ b/src/commands/base-command.ts @@ -590,7 +590,7 @@ export default class BaseCommand extends Command { httpProxy: flags.httpProxy, certificateFile: flags.httpProxyCertificateFilename, }) - const apiOpts = { ...apiUrlOpts, agent } + const apiOpts = { ...apiUrlOpts, fetchOptions: { agent } } const api = new NetlifyAPI(token ?? '', apiOpts) actionCommand.siteId = flags.siteId || (typeof flags.site === 'string' && flags.site) || state.get('siteId') diff --git a/src/lib/http-agent.ts b/src/lib/http-agent.ts index d9f44df9b65..b426bfd1511 100644 --- a/src/lib/http-agent.ts +++ b/src/lib/http-agent.ts @@ -1,31 +1,11 @@ import { readFile } from 'fs/promises' +import http from 'http' -import { HttpsProxyAgent } from 'https-proxy-agent' +import { HttpsProxyAgent, type HttpsProxyAgentOptions } from 'https-proxy-agent' import { NETLIFYDEVERR, NETLIFYDEVWARN, exit, log } from '../utils/command-helpers.js' import { waitPort } from './wait-port.js' -// https://github.com/TooTallNate/node-https-proxy-agent/issues/89 -// Maybe replace with https://github.com/delvedor/hpagent -// @ts-expect-error TS(2507) FIXME: Type 'typeof createHttpsProxyAgent' is not a const... Remove this comment to see the full error message -class HttpsProxyAgentWithCA extends HttpsProxyAgent { - // @ts-expect-error TS(7006) FIXME: Parameter 'opts' implicitly has an 'any' type. - constructor(opts) { - super(opts) - // @ts-expect-error TS(2339) FIXME: Property 'ca' does not exist on type 'HttpsProxyAg... Remove this comment to see the full error message - this.ca = opts.ca - } - - // @ts-expect-error TS(7006) FIXME: Parameter 'req' implicitly has an 'any' type. - callback(req, opts) { - return super.callback(req, { - ...opts, - // @ts-expect-error TS(2339) FIXME: Property 'ca' does not exist on type 'HttpsProxyAg... Remove this comment to see the full error message - ...(this.ca && { ca: this.ca }), - }) - } -} - const DEFAULT_HTTP_PORT = 80 const DEFAULT_HTTPS_PORT = 443 // 50 seconds @@ -44,7 +24,7 @@ export const tryGetAgent = async ({ message?: string | undefined } | { - agent: HttpsProxyAgentWithCA + agent: HttpsProxyAgent response: unknown } > => { @@ -94,29 +74,30 @@ export const tryGetAgent = async ({ } } - const opts = { - port: proxyUrl.port, - host: proxyUrl.host, - hostname: proxyUrl.hostname, - protocol: proxyUrl.protocol, - ca: certificate, - } - - const agent = new HttpsProxyAgentWithCA(opts) + const agent = new HttpsProxyAgent(httpProxy, { ca: certificate }) response = { ...response, agent } return response } -// @ts-expect-error TS(7031) FIXME: Binding element 'certificateFile' implicitly has a... Remove this comment to see the full error message -export const getAgent = async ({ certificateFile, httpProxy }) => { - // @ts-expect-error TS(2339) FIXME: Property 'agent' does not exist on type '{ error?:... Remove this comment to see the full error message - const { agent, error, message, warning } = await tryGetAgent({ httpProxy, certificateFile }) - if (error) { - log(NETLIFYDEVERR, error, message || '') +export const getAgent = async ({ + certificateFile, + httpProxy, +}: { + certificateFile?: string + httpProxy?: string +}): Promise | undefined> => { + const result = await tryGetAgent({ httpProxy, certificateFile }) + + if ('error' in result && result.error) { + log(NETLIFYDEVERR, result.error, result.message || '') exit(1) } - if (warning) { - log(NETLIFYDEVWARN, warning, message || '') + + if ('warning' in result && result.warning) { + log(NETLIFYDEVWARN, result.warning, result.message || '') + } + + if ('agent' in result) { + return result.agent } - return agent }