Concepts

Modes

Modes

Proxyline models two safety postures. The mode option selects one explicitly — there is no implicit fallback between them.

#Managed

Managed mode treats proxy routing as a security policy.

  • proxyUrl is required. Omitting it throws ProxylineError with code MANAGED_PROXY_URL_REQUIRED.
  • Only http:// and https:// proxy endpoints are accepted. Other schemes throw UNSUPPORTED_PROXY_PROTOCOL.
  • The managed proxy is forced for HTTP(S) and WS(S) requests on the patched surfaces.
  • bypassPolicy, registerBypass(), and withBypass() are the managed-mode direct-routing escape hatches. They match { surface, url } and intentionally send matching requests direct. registerBypass() is process-wide until unregistered; withBypass() is limited to the callback's async context.
  • Caller-supplied http.Agent or https.Agent values are replaced per request. TLS-relevant agent options (ca, cert, key, ciphers, minVersion, maxVersion, rejectUnauthorized, etc.) are copied onto the proxy request so destination TLS identity is preserved. See Surfaces — TLS identity preservation for the full list.
  • The undici global dispatcher is replaced with Proxyline's managed dispatcher, backed by undici.ProxyAgent instances pointed at proxyUrl.
  • Environment variables (HTTP_PROXY, HTTPS_PROXY, NO_PROXY, ...) are ignored.
  • explain() returns kind: "proxied" with reason: "managed-proxy-active" for supported URL schemes. Bypassed URLs return kind: "direct" with reason: "managed-proxy-bypass-policy". Unsupported schemes return kind: "direct" with reason: "managed-proxy-unsupported-url-scheme" because Proxyline has no safe proxy mapping for them.

Use managed mode when "go direct" must never be silent. If your network policy demands traffic egress through a specific gateway, this is the posture you want.

const proxy = installGlobalProxy({
  mode: "managed",
  proxyUrl: "https://proxy.corp.example:8443",
  proxyTls: { caFile: "/etc/proxy-ca.pem" },
  bypassPolicy: ({ url }) => new URL(url).hostname === "127.0.0.1",
});

#Ambient

Ambient mode mirrors the conventional "respect the environment" behavior used by most CLI tooling.

  • proxyUrl is ignored if supplied. Configuration comes from HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, and NO_PROXY (and their lowercase forms).
  • The runtime only installs patches when at least one of HTTP_PROXY, HTTPS_PROXY, or ALL_PROXY resolves to a supported http:// or https:// proxy endpoint. proxy.active is false otherwise and the handle behaves as a passive observer.
  • Per-request proxy resolution honors protocol-specific variables, falls back to ALL_PROXY, and applies NO_PROXY matching (suffix, wildcard, exact, IPv6).
  • Bare endpoints (no scheme) default to http:// — e.g. HTTPS_PROXY=proxy.corp:8080 becomes http://proxy.corp:8080.
  • The undici global dispatcher becomes Proxyline's ambient dispatcher so fetch sees the same routing rules.
  • explain() returns one of:
  • kind: "proxied", reason: "ambient-proxy-active" — a proxy applies.
  • kind: "direct", reason: "no-proxy-match"NO_PROXY exempted the host.
  • kind: "direct", reason: "ambient-proxy-not-configured" — no supported proxy variables are set, the configured proxy scheme is unsupported, or the URL scheme is unsupported.

Use ambient mode for tooling and CLIs that need best-effort compatibility with whatever the operator has configured.

const proxy = installGlobalProxy({ mode: "ambient" });
if (!proxy.active) {
  console.warn("no HTTP_PROXY/HTTPS_PROXY/ALL_PROXY set — direct egress");
}

#Comparison

Behaviormanagedambient
Requires proxyUrlyesno (ignored if passed)
Reads env variablesnoyes
Honors NO_PROXYnoyes
Supports bypassPolicyyesno
Forces traffic through proxyyesonly when env says so
Replaces caller-supplied agentsyesyes (when active)
Installs undici dispatcherProxyAgentProxyline ambient dispatcher
explain() direct reasonmanaged-proxy-bypass-policy or managed-proxy-unsupported-url-schemeno-proxy-match or ambient-proxy-not-configured
Setup failure modethrowsinactive but installed

#Why a strict managed mode

If you mix environment-based configuration with a security policy you get drift: a missing variable, a forgotten NO_PROXY entry, or a transient unset turns "always through the proxy" into "sometimes direct." Managed mode refuses to start without the URL and refuses to honor environment overrides, so the policy is encoded in code, not in shell state.