mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-08-01 20:35:09 +00:00
The pricing fetch (loadPricing -> fetchAndCachePricing) runs on every CLI invocation, and the macOS menubar shells out to the CLI and blocks on its exit. fetch() had no timeout, so a half-open network after wake-from-sleep made it hang forever once the 24h pricing cache expired — wedging the menubar on its loading spinner until relaunch. Add a shared fetchWithTimeout helper (8s default, AbortSignal.timeout) and apply it to the two daily-critical-path fetches: pricing (models.ts) and the currency rate (currency.ts). On timeout the existing catch falls back to the bundled price snapshot / cached or USD rate. Reproduced on main (stale cache + black-holed host -> hangs indefinitely); with the timeout the same scenario aborts in 8s and renders via fallback.
22 lines
1.1 KiB
TypeScript
22 lines
1.1 KiB
TypeScript
// Default ceiling for outbound HTTP. Every CLI command awaits loadPricing(),
|
|
// and the macOS menubar shells out to the CLI and blocks on its exit — so an
|
|
// unbounded fetch() on a half-open network (e.g. Wi-Fi/DNS not yet up after
|
|
// wake-from-sleep) wedges the menubar on its loading spinner indefinitely.
|
|
// 8s is generous for these small JSON endpoints while still failing fast.
|
|
export const DEFAULT_FETCH_TIMEOUT_MS = 8000
|
|
|
|
/// fetch() with a hard timeout. On timeout the returned promise rejects with a
|
|
/// TimeoutError (an AbortError subtype), which callers already handle via their
|
|
/// existing try/catch + bundled-snapshot fallback. A caller-supplied signal is
|
|
/// combined with the timeout so either can abort the request.
|
|
export async function fetchWithTimeout(
|
|
url: string,
|
|
init: RequestInit = {},
|
|
timeoutMs: number = DEFAULT_FETCH_TIMEOUT_MS,
|
|
): Promise<Response> {
|
|
const timeoutSignal = AbortSignal.timeout(timeoutMs)
|
|
const signal = init.signal
|
|
? AbortSignal.any([init.signal, timeoutSignal])
|
|
: timeoutSignal
|
|
return fetch(url, { ...init, signal })
|
|
}
|