Skip to content

Commit eac65ca

Browse files
authored
Merge pull request ericc-ch#92 from lroolle/feat/proxy-dispatch-no-proxy-logs
proxy: respect env proxy via undici
2 parents 573a90c + 17fe0a6 commit eac65ca

File tree

4 files changed

+78
-5
lines changed

4 files changed

+78
-5
lines changed

bun.lock

Lines changed: 8 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,11 @@
4444
"consola": "^3.4.2",
4545
"fetch-event-stream": "^0.1.5",
4646
"gpt-tokenizer": "^3.0.1",
47-
"hono": "^4.9.6",
48-
"srvx": "^0.8.7",
49-
"tiny-invariant": "^1.3.3"
47+
"hono": "^4.9.4",
48+
"proxy-from-env": "^1.1.0",
49+
"srvx": "^0.8.6",
50+
"tiny-invariant": "^1.3.3",
51+
"undici": "^6.19.8"
5052
},
5153
"devDependencies": {
5254
"@echristian/eslint-config": "^0.0.54",

src/lib/proxy.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import consola from "consola"
2+
import { getProxyForUrl } from "proxy-from-env"
3+
import { Agent, ProxyAgent, setGlobalDispatcher, type Dispatcher } from "undici"
4+
5+
export function initProxyFromEnv(): void {
6+
if (typeof Bun !== "undefined") return
7+
8+
try {
9+
const direct = new Agent()
10+
const proxies = new Map<string, ProxyAgent>()
11+
12+
const dispatcher: Dispatcher = {
13+
dispatch(
14+
options: Dispatcher.RequestOptions,
15+
handler: Dispatcher.DispatchHandlers,
16+
) {
17+
try {
18+
const origin =
19+
typeof options.origin === "string" ?
20+
new URL(options.origin)
21+
: (options.origin as URL)
22+
const get = getProxyForUrl as unknown as (
23+
u: string,
24+
) => string | undefined
25+
const raw = get(origin.toString())
26+
const proxyUrl = raw && raw.length > 0 ? raw : undefined
27+
if (!proxyUrl) {
28+
consola.debug(`HTTP proxy bypass: ${origin.hostname}`)
29+
return (direct as unknown as Dispatcher).dispatch(options, handler)
30+
}
31+
let agent = proxies.get(proxyUrl)
32+
if (!agent) {
33+
agent = new ProxyAgent(proxyUrl)
34+
proxies.set(proxyUrl, agent)
35+
}
36+
let label = proxyUrl
37+
try {
38+
const u = new URL(proxyUrl)
39+
label = `${u.protocol}//${u.host}`
40+
} catch {
41+
/* noop */
42+
}
43+
consola.debug(`HTTP proxy route: ${origin.hostname} via ${label}`)
44+
return (agent as unknown as Dispatcher).dispatch(options, handler)
45+
} catch {
46+
return (direct as unknown as Dispatcher).dispatch(options, handler)
47+
}
48+
},
49+
close() {
50+
return direct.close()
51+
},
52+
destroy() {
53+
return direct.destroy()
54+
},
55+
}
56+
57+
setGlobalDispatcher(dispatcher)
58+
consola.debug("HTTP proxy configured from environment (per-URL)")
59+
} catch (err) {
60+
consola.debug("Proxy setup skipped:", err)
61+
}
62+
}

src/main.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { defineCommand, runMain } from "citty"
55
import { auth } from "./auth"
66
import { checkUsage } from "./check-usage"
77
import { debug } from "./debug"
8+
import { initProxyFromEnv } from "./lib/proxy"
89
import { start } from "./start"
910

1011
const main = defineCommand({
@@ -16,4 +17,6 @@ const main = defineCommand({
1617
subCommands: { auth, start, "check-usage": checkUsage, debug },
1718
})
1819

20+
initProxyFromEnv()
21+
1922
await runMain(main)

0 commit comments

Comments
 (0)