Repository navigation
feat: run node requests through undici's own fetch (0.4.0) - #2
Conversation
32047b3 to
4bdac32
Compare
ildella
left a comment
There was a problem hiding this comment.
REWORK
Medium: Env-proxy support silently dropped
globalThis.fetch on Node 22.19+/24+ honors NODE_USE_ENV_PROXY=1 and HTTP_PROXY/HTTPS_PROXY/NO_PROXY; npm undici's fetch does not (it needs an explicit EnvHttpProxyAgent dispatcher). A user behind a corporate proxy who sets NODE_USE_ENV_PROXY=1 and upgrades will get connection failures with no code change on their side. Either document this limitation or default the Agent's dispatcher to EnvHttpProxyAgent when proxy env vars are present.
Low: Dead code in tests
tests/platform-node.test.js:30-32 — afterEach calls vi.unstubAllGlobals() but no test in the file uses vi.stubGlobal. Leftover from the previous version where stubFetch used vi.stubGlobal('fetch', mock).
platform-node now imports both fetch and Agent from the same undici package instead of dispatching into the Node-bundled undici via globalThis.fetch. The builtin fetch builds dispatch handlers whose callback shape is tied to the undici major bundled in the runtime (node 22 -> undici 6, 24 -> 7, 26 -> 8), and undici 8 dropped the tolerant handler bridge, so an Agent of a different major than the builtin one is rejected with UND_ERR_INVALID_ARG. Calling undici's own fetch removes the cross-major pair entirely. - undici range ^7 || ^8: consumers already on either major dedupe to one copy, nobody is forced to jump to 8 - engines floor ^22.19.0, matching undici 8's own requirement - CI matrix runs node 22/24/26 crossed with undici 7 and 8 - tests mock the undici module, plus an offline proof requests bypass globalThis.fetch - README documents the env-proxy limitation (the adapter installs its own dispatcher) and the explicit-dispatcher escape hatch; env-proxy support was prototyped but undici 7 does not proxy plain http targets while undici 8 does, so a version-divergent feature was rejected
4bdac32 to
3f2295b
Compare
|
Rework pushed ( 1. Env-proxy (Medium). I prototyped the suggested fix rather than only documenting: Root cause, verified in isolation with a bare undici 8 proxies plain
2. Dead code (Low). Removed the unused Suite: 83/83 on node 22.23 / 24.21 / 26.10 for both undici 7.30 and 8.11, lint clean. |
ildella
left a comment
There was a problem hiding this comment.
APPROVED
Both findings addressed: env-proxy limitation documented with workaround in README, dead vi.unstubAllGlobals() removed from tests.
What changed
platform-nodenow imports bothfetchandAgentfrom the same npm undici package, instead of dispatchingglobalThis.fetch(the Node-bundled undici) into an npm Agent. Undici range becomes^7.0.0 || ^8.0.0; engines floor rises to^22.19.0; CI tests the node x undici matrix.Why
The builtin fetch builds dispatch handlers whose callback shape is tied to the undici major bundled in the runtime (verified locally): node 22 -> undici 6, node 24 -> undici 7, node 26 -> undici 8. Undici 8's
assertRequestHandlerstrictly requires the new-style callbacks (onRequestStart/onResponseError) — so a mismatched Agent/builtin pair throwsUND_ERR_INVALID_ARGat dispatch time (hard fail, not degraded). Undici 7 tolerated both shapes, which is what made it the unique bridge major.Calling undici's own
fetchremoves the cross-major pair entirely: handler and Agent always come from one module, whichever major resolved.Why the range, not
^8An earlier iteration pinned
^8.0.0. Rejected: it forces a second undici copy (~2 MB, duplicate socket pools, double instrumentation) on every consumer that already uses undici 7 happily. With^7 || ^8:The engines floor stays at 22.19 because that is where undici 8 itself starts; undici 7 would allow lower, but the floor tracks our Node support, not the lower major's.
Consequences
connectTimeout/dispatcher/caching semantics unchanged;client.jsuntouched. No live bug fixed — the 10s connect wall died in 0.3.1; this is architecture + future-proofing.platformFetchusers now get undici'sResponseclass (not Node builtin) —instanceof Responsediffers.createHttpClientconsumers unaffected (plain{data, status, headers}). Documented in README.dispatchermust come from the same undici major the app resolved. Documented in README.Verification
TimeoutError/TIMEOUT(survives the old builtin 10s cap)TimeoutError/CONNECT_TIMEOUTReview notes
v0.4.0to publish (tag triggers the publish workflow; it gates on the suite).0.4.0exact — only real check there is Codemagic's Node >= 22.19.