mirror of
https://github.com/Routstr/routstrd.git
synced 2026-10-05 20:38:22 +00:00
`routstrd update` gave the whole release download the same 30 s budget as the connection: `AbortSignal.timeout(FETCH_TIMEOUT_MS)` was attached to the fetch, then the 38 MB archive was read with `arrayBuffer()` under that same signal. Anything slower than ~1.3 MB/s failed with "The operation timed out." — including the 540 KB/s / 70 s connection this was reproduced on. Split the deadline in two: - connect + response headers: 30 s, unchanged. The releases API and SHA256SUMS are a few KB, and a hang there is a real failure worth surfacing quickly. - release archive body: 300 s. That is 38 MB / 300 s ≈ 127 KB/s ≈ 1 Mbit/s, about 4x headroom over the reproduction, while still bounding the silent failure (the command prints no progress) at five minutes. `fetchOrThrow` now owns an AbortController and reschedules the deadline once headers arrive, taking a `consume` callback so the body read is covered by the transfer budget. Aborts report the phase and URL instead of a bare "The operation timed out." Also bound `getLatestNpmVersion`, which called `fetch` with no timeout at all on the same `routstrd update` path; it already returns null on error, so a stalled registry now degrades to "latest version unknown" instead of hanging. Adds regression tests: a body slower than the connect budget must still install, and a body overrunning the transfer budget must fail with the phase-aware message.