π File detail
utils/apiPreconnect.ts
π― Use case
This file lives under βutils/β, which covers cross-cutting helpers (shell, tempfiles, settings, messages, process input, β¦). On the API surface it exposes preconnectAnthropicApi β mainly functions, hooks, or classes. It composes internal code from constants and envUtils (relative imports). What the file header says: Preconnect to the Anthropic API to overlap TCP+TLS handshake with startup. The TCP+TLS handshake is ~100-200ms that normally blocks inside the first API call. Kicking a fire-and-forget fetch during init lets the handshake happen in parallel with action-handler work (~100ms of set.
Generated from folder role, exports, dependency roots, and inline comments β not hand-reviewed for every path.
π§ Inline summary
Preconnect to the Anthropic API to overlap TCP+TLS handshake with startup. The TCP+TLS handshake is ~100-200ms that normally blocks inside the first API call. Kicking a fire-and-forget fetch during init lets the handshake happen in parallel with action-handler work (~100ms of setup/commands/mcp before the API request in -p mode; unbounded "user is typing" window in interactive mode). Bun's fetch shares a keep-alive connection pool globally, so the real API request reuses the warmed connection. Called from init.ts AFTER applyExtraCACertsFromConfig() + configureGlobalAgents() so settings.json env vars are applied and the TLS cert store is finalized. The early cli.tsx call site was removed β it ran before settings.json loaded, so ANTHROPIC_BASE_URL/proxy/mTLS in settings would be invisible and preconnect would warm the wrong pool (or worse, lock BoringSSL's cert store before NODE_EXTRA_CA_CERTS was applied). Skipped when: - proxy/mTLS/unix socket configured (preconnect would use wrong transport β the SDK passes a custom dispatcher/agent that doesn't share the global pool) - Bedrock/Vertex/Foundry (different endpoints, different auth)
π€ Exports (heuristic)
preconnectAnthropicApi
π₯οΈ Source preview
/**
* Preconnect to the Anthropic API to overlap TCP+TLS handshake with startup.
*
* The TCP+TLS handshake is ~100-200ms that normally blocks inside the first
* API call. Kicking a fire-and-forget fetch during init lets the handshake
* happen in parallel with action-handler work (~100ms of setup/commands/mcp
* before the API request in -p mode; unbounded "user is typing" window in
* interactive mode).
*
* Bun's fetch shares a keep-alive connection pool globally, so the real API
* request reuses the warmed connection.
*
* Called from init.ts AFTER applyExtraCACertsFromConfig() + configureGlobalAgents()
* so settings.json env vars are applied and the TLS cert store is finalized.
* The early cli.tsx call site was removed β it ran before settings.json loaded,
* so ANTHROPIC_BASE_URL/proxy/mTLS in settings would be invisible and preconnect
* would warm the wrong pool (or worse, lock BoringSSL's cert store before
* NODE_EXTRA_CA_CERTS was applied).
*
* Skipped when:
* - proxy/mTLS/unix socket configured (preconnect would use wrong transport β
* the SDK passes a custom dispatcher/agent that doesn't share the global pool)
* - Bedrock/Vertex/Foundry (different endpoints, different auth)
*/
import { getOauthConfig } from '../constants/oauth.js'
import { isEnvTruthy } from './envUtils.js'
let fired = false
export function preconnectAnthropicApi(): void {
if (fired) return
fired = true
// Skip if using a cloud provider β different endpoint + auth
if (
isEnvTruthy(process.env.CLAUDE_CODE_USE_BEDROCK) ||
isEnvTruthy(process.env.CLAUDE_CODE_USE_VERTEX) ||
isEnvTruthy(process.env.CLAUDE_CODE_USE_FOUNDRY)
) {
return
}
// Skip if proxy/mTLS/unix β SDK's custom dispatcher won't reuse this pool
if (
process.env.HTTPS_PROXY ||
process.env.https_proxy ||
process.env.HTTP_PROXY ||
process.env.http_proxy ||
process.env.ANTHROPIC_UNIX_SOCKET ||
process.env.CLAUDE_CODE_CLIENT_CERT ||
process.env.CLAUDE_CODE_CLIENT_KEY
) {
return
}
// Use configured base URL (staging, local, or custom gateway). Covers
// ANTHROPIC_BASE_URL env + USE_STAGING_OAUTH + USE_LOCAL_OAUTH in one lookup.
// NODE_EXTRA_CA_CERTS no longer a skip β init.ts applied it before this fires.
const baseUrl =
process.env.ANTHROPIC_BASE_URL || getOauthConfig().BASE_API_URL
// Fire and forget. HEAD means no response body β the connection is eligible
// for keep-alive pool reuse immediately after headers arrive. 10s timeout
// so a slow network doesn't hang the process; abort is fine since the real
// request will handshake fresh if needed.
// eslint-disable-next-line eslint-plugin-n/no-unsupported-features/node-builtins
void fetch(baseUrl, {
method: 'HEAD',
signal: AbortSignal.timeout(10_000),
}).catch(() => {})
}