The package exported six functions, four of them shaped by one SDK's
transport each: a dispatcher factory, a `node:http` agent factory, a
proxy-URL lookup, and a policy accessor. Review asked whether the call
sites could converge instead of the package growing an export per SDK.
They could, and each removal took a whole shape with it:
- The OTLP exporter moves to the SDK's `fetch` delegate, retiring
`createNodeHttpAgent`. Its Node-version floor goes too: `proxyEnv` on
an `http.Agent` needs 22.21 or 24.5, inside the engines range, so
telemetry was direct on 22.19, 22.20, and 24.0-24.4. The cost is
`compression`, a Node-transport option; the plugin now refuses it,
`keepAlive`, and `httpAgentOptions` at load instead of ignoring them.
- `web-fetch-http` builds its own address-pinning agent under an
annotated `proxy-exempt:` exemption, retiring `createDispatcher`.
Pinning is per-request state a process-wide dispatcher cannot hold.
- E2B reads `route.proxy`, retiring `proxyUrlFor`.
What remains is `installProxyFromEnvironment`, `proxyRouteFor`,
`proxyEnvironmentForChild`, and `clearedProxyEnv` — one per way a caller
can need the policy. Installation absorbs resolution and diagnostic
reporting, which no caller needed apart.
`proxyRouteFor` also closes a defect the old accessor made expressible:
`web-fetch-http` read the policy to decide whether to pin, then read it
again to build a transport, so an unmount between the two returned a
direct, unpinned agent for a URL the first read had cleared as proxied.
A route carries the answer and the transport that answer assumed.
Every egress spec now installs through `installProxyFromEnvironment`, so
no test asserts a policy object a real launch could not produce.
`AGENTS.md` sat at exactly its 1950-word ceiling on master, so the one line this
branch adds to the repository layout — a new top-level package group — cannot
fit at any length: even a one-word description overflows. The description is
condensed to five words and the ceiling raised by ten, the smallest change that
keeps every package group listed. Omitting only `net/` from a list that names
every other group was the alternative.
One new test drove an IPv4-mapped literal through a full fetch. An IPv6 literal
sends `resolvePublicAddresses` looking for a NAT64 prefix before it refuses
anything, and that is a real DNS query — 5s under load, 6ms here, which is why
it passed alone and timed out in the full suite. The three IPv4 cases already
prove the branch end to end without touching the network, so the mapped form is
asserted on the predicate instead.
Review found `127.0.0.2` routed through the proxy. The bypass list carries four
literal loopback entries because that is all a consumer reading an environment
can match, and `proxyForUrl` matched only those — leaving the rest of
`127.0.0.0/8`, `0.0.0.0`, and the IPv4-mapped spellings routed through a proxy
that could then reach them. Loopback is now recognised structurally, which a
list entry cannot express; the published entries stay for the environment
readers.
The same review case exposed a wider one. `web_fetch` skips its address checks
on a proxied hop, because the proxy resolves the origin — but a literal needs no
resolution, so the skip bought nothing and let a proxy on this machine reach
every private range those checks refuse, `169.254.169.254` included. A literal
the checks would refuse now takes the validated path, where the existing
refusal already covers it.
Tests that proved a tunnelled hop used a loopback origin, which no policy can
route through a proxy any more. They name a host only the proxy can answer for
instead — closer to what a proxied request actually looks like.
The user guide promised the proxy carried every outbound request including
telemetry. It carries neither on an older Node, nor anything a model-authored
script sends, so the promise is narrowed and the exceptions listed. A password
in a proxy URL reaching every tool DSH runs is documented there too: it is how
the variable already behaves, and worth knowing before putting one in.
Node's built-in fetch ignores HTTP_PROXY, so every harness request connected
directly regardless of what the user exported. Resolve one policy from the
launch environment and install it as undici's global dispatcher, then wire the
four surfaces a global dispatcher cannot reach: web_fetch's pinned transport,
the OTLP exporter's node:http agent, the E2B SDK's own proxy option, and the
environment a child process or worker thread is given.
Each outbound call site carries an egress test that drives its real code path
through a fake proxy; that measurement is what found the OTLP and E2B gaps.