Something went wrong. Try again.
source dump of claude code forked from oppi.li/claude-code
Something went wrong. Try again.
4.6 kB · 141 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142import axios from 'axios'import isEqual from 'lodash-es/isEqual.js'import { getAnthropicApiKey, getClaudeAIOAuthTokens, hasProfileScope,} from 'src/utils/auth.js'import { z } from 'zod'import { getOauthConfig, OAUTH_BETA_HEADER } from '../../constants/oauth.js'import { getGlobalConfig, saveGlobalConfig } from '../../utils/config.js'import { logForDebugging } from '../../utils/debug.js'import { withOAuth401Retry } from '../../utils/http.js'import { lazySchema } from '../../utils/lazySchema.js'import { logError } from '../../utils/log.js'import { getAPIProvider } from '../../utils/model/providers.js'import { isEssentialTrafficOnly } from '../../utils/privacyLevel.js'import { getClaudeCodeUserAgent } from '../../utils/userAgent.js'
const bootstrapResponseSchema = lazySchema(() => z.object({ client_data: z.record(z.unknown()).nullish(), additional_model_options: z .array( z .object({ model: z.string(), name: z.string(), description: z.string(), }) .transform(({ model, name, description }) => ({ value: model, label: name, description, })), ) .nullish(), }),)
type BootstrapResponse = z.infer<ReturnType<typeof bootstrapResponseSchema>>
async function fetchBootstrapAPI(): Promise<BootstrapResponse | null> { if (isEssentialTrafficOnly()) { logForDebugging('[Bootstrap] Skipped: Nonessential traffic disabled') return null }
if (getAPIProvider() !== 'firstParty') { logForDebugging('[Bootstrap] Skipped: 3P provider') return null }
// OAuth preferred (requires user:profile scope — service-key OAuth tokens // lack it and would 403). Fall back to API key auth for console users. const apiKey = getAnthropicApiKey() const hasUsableOAuth = getClaudeAIOAuthTokens()?.accessToken && hasProfileScope() if (!hasUsableOAuth && !apiKey) { logForDebugging('[Bootstrap] Skipped: no usable OAuth or API key') return null }
const endpoint = `${getOauthConfig().BASE_API_URL}/api/claude_cli/bootstrap`
// withOAuth401Retry handles the refresh-and-retry. API key users fail // through on 401 (no refresh mechanism — no OAuth token to pass). try { return await withOAuth401Retry(async () => { // Re-read OAuth each call so the retry picks up the refreshed token. const token = getClaudeAIOAuthTokens()?.accessToken let authHeaders: Record<string, string> if (token && hasProfileScope()) { authHeaders = { Authorization: `Bearer ${token}`, 'anthropic-beta': OAUTH_BETA_HEADER, } } else if (apiKey) { authHeaders = { 'x-api-key': apiKey } } else { logForDebugging('[Bootstrap] No auth available on retry, aborting') return null }
logForDebugging('[Bootstrap] Fetching') const response = await axios.get<unknown>(endpoint, { headers: { 'Content-Type': 'application/json', 'User-Agent': getClaudeCodeUserAgent(), ...authHeaders, }, timeout: 5000, }) const parsed = bootstrapResponseSchema().safeParse(response.data) if (!parsed.success) { logForDebugging( `[Bootstrap] Response failed validation: ${parsed.error.message}`, ) return null } logForDebugging('[Bootstrap] Fetch ok') return parsed.data }) } catch (error) { logForDebugging( `[Bootstrap] Fetch failed: ${axios.isAxiosError(error) ? (error.response?.status ?? error.code) : 'unknown'}`, ) throw error }}
/** * Fetch bootstrap data from the API and persist to disk cache. */export async function fetchBootstrapData(): Promise<void> { try { const response = await fetchBootstrapAPI() if (!response) return
const clientData = response.client_data ?? null const additionalModelOptions = response.additional_model_options ?? []
// Only persist if data actually changed — avoids a config write on every startup. const config = getGlobalConfig() if ( isEqual(config.clientDataCache, clientData) && isEqual(config.additionalModelOptionsCache, additionalModelOptions) ) { logForDebugging('[Bootstrap] Cache unchanged, skipping write') return }
logForDebugging('[Bootstrap] Cache updated, persisting to disk') saveGlobalConfig(current => ({ ...current, clientDataCache: clientData, additionalModelOptionsCache: additionalModelOptions, })) } catch (error) { logError(error) }}