(opts?: {
tokenPath?: string
systemCaPath?: string
caBundlePath?: string
ccrBaseUrl?: string
})
| 77 | * Overridable paths are for tests; production uses the defaults. |
| 78 | */ |
| 79 | export async function initUpstreamProxy(opts?: { |
| 80 | tokenPath?: string |
| 81 | systemCaPath?: string |
| 82 | caBundlePath?: string |
| 83 | ccrBaseUrl?: string |
| 84 | }): Promise<UpstreamProxyState> { |
| 85 | if (!isEnvTruthy(process.env.CLAUDE_CODE_REMOTE)) { |
| 86 | return state |
| 87 | } |
| 88 | // CCR evaluates ccr_upstream_proxy_enabled server-side (where GrowthBook is |
| 89 | // warm) and injects this env var via StartupContext.EnvironmentVariables. |
| 90 | // Every CCR session is a fresh container with no GB cache, so a client-side |
| 91 | // GB check here always returned the default (false). |
| 92 | if (!isEnvTruthy(process.env.CCR_UPSTREAM_PROXY_ENABLED)) { |
| 93 | return state |
| 94 | } |
| 95 | |
| 96 | const sessionId = process.env.CLAUDE_CODE_REMOTE_SESSION_ID |
| 97 | if (!sessionId) { |
| 98 | logForDebugging( |
| 99 | '[upstreamproxy] CLAUDE_CODE_REMOTE_SESSION_ID unset; proxy disabled', |
| 100 | { level: 'warn' }, |
| 101 | ) |
| 102 | return state |
| 103 | } |
| 104 | |
| 105 | const tokenPath = opts?.tokenPath ?? SESSION_TOKEN_PATH |
| 106 | const token = await readToken(tokenPath) |
| 107 | if (!token) { |
| 108 | logForDebugging('[upstreamproxy] no session token file; proxy disabled') |
| 109 | return state |
| 110 | } |
| 111 | |
| 112 | setNonDumpable() |
| 113 | |
| 114 | // CCR injects ANTHROPIC_BASE_URL via StartupContext (sessionExecutor.ts / |
| 115 | // sessionHandler.ts). getOauthConfig() is wrong here: it keys off |
| 116 | // USER_TYPE + USE_{LOCAL,STAGING}_OAUTH, none of which the container sets, |
| 117 | // so it always returned the prod URL and the CA fetch 404'd. |
| 118 | const baseUrl = |
| 119 | opts?.ccrBaseUrl ?? |
| 120 | process.env.ANTHROPIC_BASE_URL ?? |
| 121 | 'https://api.anthropic.com' |
| 122 | const caBundlePath = |
| 123 | opts?.caBundlePath ?? join(homedir(), '.ccr', 'ca-bundle.crt') |
| 124 | |
| 125 | const caOk = await downloadCaBundle( |
| 126 | baseUrl, |
| 127 | opts?.systemCaPath ?? SYSTEM_CA_BUNDLE, |
| 128 | caBundlePath, |
| 129 | ) |
| 130 | if (!caOk) return state |
| 131 | |
| 132 | try { |
| 133 | const wsUrl = baseUrl.replace(/^http/, 'ws') + '/v1/code/upstreamproxy/ws' |
| 134 | const relay = await startUpstreamProxyRelay({ wsUrl, sessionId, token }) |
| 135 | registerCleanup(async () => relay.stop()) |
| 136 | state = { enabled: true, port: relay.port, caBundlePath } |
no test coverage detected