← All @molecule/* packages · App templates
@molecule/api-proxy-agentUtility · proxy-agent · API (Node) · v1.1.0 · Apache-2.0
CONNECT-capable HTTP(S) proxy agent built from the standard proxy environment (HTTPS_PROXY / HTTP_PROXY / NO_PROXY), for vendor SDKs that build their own HTTP agent and ignore it.
npm install @molecule/api-proxy-agent@molecule/api-proxy-agent is a utility package for the API (Node) side (proxy-agent).
import { getProxyAgent, getProxyAgents } from '@molecule/api-proxy-agent'
// Stripe: `httpAgent` is used for every request the client makes.
const stripe = new Stripe(key, { httpAgent: getProxyAgent('https://api.stripe.com') })
// AWS SDK v3 (any client): `requestHandler` takes NodeHttpHandler options,
// so no extra `@smithy/*` dependency is needed.
const proxy = getProxyAgents(`https://email.${region}.amazonaws.com`)
const ses = new SESv2Client({ region, ...(proxy ? { requestHandler: proxy } : {}) })Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
A CONNECT-capable proxy agent built from the standard proxy environment, for the vendor SDKs that ignore it.
Most HTTP clients already honour HTTPS_PROXY/HTTP_PROXY/NO_PROXY: Node's
global fetch does under NODE_USE_ENV_PROXY=1, and so do axios-based SDKs.
A handful do not — they build their own http.Agent or undici pool and dial
the vendor directly. On a workstation that direct connection succeeds, so the
difference is invisible; in an environment whose ONLY egress path is a proxy
(a molecule.dev sandbox, a deployed molecule.dev app, a locked-down VPC) the
same call fails with a bare connection error naming nothing.
Each of those SDKs does accept an agent — it just will not build one for you.
getProxyAgent(url) builds it, and returns undefined when no proxy applies
so the SDK keeps its own default and an app running outside a proxied
environment is completely unaffected.
import { getProxyAgent, getProxyAgents } from '@molecule/api-proxy-agent'
// Stripe: `httpAgent` is used for every request the client makes.
const stripe = new Stripe(key, { httpAgent: getProxyAgent('https://api.stripe.com') })
// AWS SDK v3 (any client): `requestHandler` takes NodeHttpHandler options,
// so no extra `@smithy/*` dependency is needed.
const proxy = getProxyAgents(`https://email.${region}.amazonaws.com`)
const ses = new SESv2Client({ region, ...(proxy ? { requestHandler: proxy } : {}) })
utility
npm install @molecule/api-proxy-agent http-proxy-agent https-proxy-agent proxy-from-env
npm install -D @types/proxy-from-env
ProxyAgentOptionsOptions for {@link getProxyAgent} / {@link getProxyUrl} / {@link shouldProxy}.
interface ProxyAgentOptions {
/**
* Keep the tunnelled socket alive between requests. Defaults to `true`,
* matching what every SDK in this class does with its own default agent —
* a proxy agent that closes the socket per request would silently make a
* chatty SDK (S3 multipart, SQS long-poll) far slower than it was before.
*/
keepAlive?: boolean
}
ProxyAgentAn agent this package can hand to a vendor SDK. http: targets get an
http.Agent, https: targets an https.Agent — both tunnel through the
configured proxy.
type ProxyAgent = HttpAgent | HttpsAgent
getProxyAgent(targetUrl, options)Returns an agent that tunnels targetUrl through the configured proxy via
CONNECT, or undefined when this target is not proxied.
undefined is the whole contract: a call site passes the result straight into
its SDK's own agent option, so with no proxy configured the SDK keeps its own
default agent and behaves exactly as it did before. Nothing is monkey-patched
and nothing changes for an app running outside a proxied environment.
function getProxyAgent(targetUrl: string, options?: ProxyAgentOptions): ProxyAgent | undefined
targetUrl — The absolute URL the SDK is about to call. It decides both which env var applies (https_proxy vs http_proxy) and whether NO_PROXY exempts the host, so pass the real vendor endpoint — not a placeholder.options — See {@link ProxyAgentOptions}.Returns: An http.Agent/https.Agent that tunnels through the proxy, or undefined when the target is not proxied.
getProxyAgents(targetUrl, options)Returns { httpAgent } or { httpsAgent } — whichever matches targetUrl's
protocol — or undefined when the target is not proxied.
This is the shape AWS SDK v3's requestHandler accepts directly (it takes
NodeHttpHandler OPTIONS, so no @smithy/node-http-handler dependency is
needed), and it is also what got and node-fetch take. Spread it, so that
an unproxied environment adds no key at all:
const proxy = getProxyAgents(endpoint)
new S3Client({ region, ...(proxy ? { requestHandler: proxy } : {}) })
function getProxyAgents(
targetUrl: string,
options?: ProxyAgentOptions,
): { httpAgent?: ProxyAgent; httpsAgent?: ProxyAgent } | undefined
targetUrl — The absolute URL the SDK is about to call.options — See {@link ProxyAgentOptions}.Returns: The agent pair, or undefined when the target is not proxied.
getProxyUrl(targetUrl)Returns the proxy URL that should serve targetUrl according to the standard
proxy environment (HTTPS_PROXY / HTTP_PROXY / ALL_PROXY, either case),
or undefined when the target is not proxied — either because no proxy is
configured, or because NO_PROXY exempts it.
function getProxyUrl(targetUrl: string): string | undefined
targetUrl — The absolute URL the SDK is about to call.Returns: The proxy URL, or undefined to connect directly.
resetProxyAgents()Drops every memoized agent, destroying its sockets.
Only useful when the proxy environment changes inside a live process — a test
that mutates process.env, or a secrets bond that resolves HTTPS_PROXY
after the first call. Ordinary application code never needs it.
function resetProxyAgents(): void
shouldProxy(targetUrl)Whether targetUrl should be sent through a proxy.
function shouldProxy(targetUrl: string): boolean
targetUrl — The absolute URL the SDK is about to call.Returns: true when a proxy is configured for this target.
http-proxy-agent
https-proxy-agent
proxy-from-env
Pass the REAL endpoint, not a placeholder. The target URL decides which
variable applies (https_proxy vs http_proxy) and whether NO_PROXY
exempts the host. getProxyAgent('https://example.com') standing in for an
S3 call would consult the wrong NO_PROXY entry.
Spread the result, never pass it unconditionally. Several SDKs treat a
present-but-undefined agent option as "use no agent" rather than "use the
default". ...(agent ? { httpAgent: agent } : {}) is the shape that is a
true no-op when nothing is proxied.
Agents are memoized per proxy URL, because an agent owns a connection pool — building a fresh one per call opens a new tunnel every request. Call it inside your lazy client getter and keep the client, not the agent.
This cannot rescue an SDK that vendors its own proxy handling. If a library bundles a copy of its HTTP client and offers no agent option, there is no hook to pass this into; the fix has to be upstream or in the proxy.
HTTP(S) only. A raw-TCP client — Postgres, MySQL, Redis, Mongo, AMQP, SMTP — cannot be tunnelled by an HTTP proxy at all. Those need a network path to the host, not an agent.
Built on https-proxy-agent/http-proxy-agent (the CONNECT tunnel) and
proxy-from-env (the env + NO_PROXY semantics, the same resolver axios
uses) rather than a hand-rolled parser: NO_PROXY has enough real edge
cases — leading dots, *, per-entry ports, IPv6 brackets — that a bespoke
one would be wrong in exactly the situations it matters.