apiPreconnect.ts
utils/apiPreconnect.ts
72
Lines
2843
Bytes
1
Exports
2
Imports
10
Keywords
What this is
This page documents one file from the repository and includes its full source so you can read it without leaving the docs site.
Beginner explanation
This file is one piece of the larger system. Its name, directory, imports, and exports show where it fits. Start by reading the exports and related files first.
How it is used
Start from the exports list and related files. Those are the easiest clues for where this file fits into the system.
Expert explanation
Architecturally, this file intersects with integrations. It contains 72 lines, 2 detected imports, and 1 detected exports.
Important relationships
Detected exports
preconnectAnthropicApi
Keywords
processpoolhandshakebeforeisenvtruthypreconnectfetchinitrequestconnection
Detected imports
../constants/oauth.js./envUtils.js
Source notes
This page embeds the full file contents. Small or leaf files are still indexed honestly instead of being over-explained.
Full source
/**
* 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(() => {})
}