File size: 1,954 Bytes
67d18ac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
 * Node-only global-fetch normalization for the Android (Node.js bundle) build.
 *
 * Node's global fetch (undici) enforces default client timeouts that Bun's
 * fetch does not: `headersTimeout` and `bodyTimeout` both default to 300000 ms
 * (undici `client.js`, verified 2026-08-16). A non-streaming LLM upstream sends
 * response headers only after the ENTIRE generation completes — deep-reasoning
 * requests legitimately exceed 300s. Those requests work on the Bun desktop
 * build but die as `UND_ERR_HEADERS_TIMEOUT` → 502 `upstream_unreachable` on
 * the Node Android build. This module restores the project's intended
 * "no upstream timeout on LLM calls" invariant (root AGENTS.md anti-pattern
 * #7) by swapping the global dispatcher for an Agent with both timeouts
 * disabled.
 *
 * The npm `undici` package shares the global-dispatcher registration symbol
 * with Node's built-in fetch, so `setGlobalDispatcher` from the package
 * configures the GLOBAL fetch (verified empirically: a 1 ms Agent aborts
 * global fetch with `UND_ERR_HEADERS_TIMEOUT`). esbuild bundles the dynamic
 * import into the Android `server.cjs`; on Bun this function is a no-op and
 * the import never executes.
 */

let applied = false;

/**
 * Disable Node fetch's default 300s headers/body timeouts. Safe to call from
 * any runtime and any number of times: no-op under Bun, runs once under Node.
 * Errors are reported but never thrown — a default-timeout process still
 * works for the common (<300s) request path.
 */
export async function ensureNodeFetchNoTimeouts(): Promise<void> {
  if (typeof Bun !== "undefined") return;
  if (applied) return;
  applied = true;
  try {
    const { Agent, setGlobalDispatcher } = await import("undici");
    setGlobalDispatcher(new Agent({ headersTimeout: 0, bodyTimeout: 0 }));
  } catch (err) {
    console.error(`zcode-proxy: could not disable Node fetch default timeouts: ${(err as Error).message}`);
  }
}