You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: stop routing all traffic through EnvHttpProxyAgent by default (#359)
* chore(deps): bump undici to 7.x
Our engines field requires Node >=20.20.0, which already satisfies undici
7.x (>=20.18.1). The 6.x pin was over-conservative — the original pin
message referenced Node 18 support, but we don't actually support 18.
8.x would require Node >=22.19.0, which would exclude Node 20 users.
* fix(proxy): only install EnvHttpProxyAgent when proxy env vars are set
PR #338 set EnvHttpProxyAgent as the default dispatcher unconditionally
so that Node's fetch (which ignores HTTP_PROXY/HTTPS_PROXY/NO_PROXY by
default) would pick up standard proxy env vars for managed-network users.
The tradeoff: we also took over the HTTP stack for every user, including
those whose shell has a stale or incidental proxy var (from a VPN client,
old dev setup, or inherited env) that wasn't meant to apply to Figma API
traffic. Those users silently routed through an intermediary that returned
403, and our error message still blamed Figma (issue #358).
Gate the swap on at least one of HTTP_PROXY/HTTPS_PROXY/NO_PROXY being
set. Corporate users get the zero-config behavior they had before; users
with no proxy vars keep Node's native dispatcher untouched.
* fix(fetch): attach truncated response body to HTTP errors
Throwing \`Fetch failed with status 403\` and discarding the body makes
it impossible to tell a real Figma 403 from a proxy/intermediary 403.
Read up to 500 chars of the body, collapse whitespace, and attach it
to both the error message and the \`responseBody\` property on HttpError.
Callers can pass \`redactFromErrorBody\` to scrub secrets from the body
before it's exposed — defense in depth against chatty intermediaries
that sometimes mirror request metadata into error pages.
FigmaService passes its API key and OAuth token through this channel
so they're scrubbed even in the unlikely case a proxy echoes them back.
* fix(figma): include response body in 403 error message
The canned \"Figma API returned 403 Forbidden\" message lied when the 403
actually came from an HTTP intermediary (proxy, firewall, VPN) rather
than Figma itself. Surface the response body so the LLM and user can see
what actually rejected the request, and add the intermediary case to the
list of common causes.
* feat(telemetry): add proxy_env_set common property
PR #338 made proxy configuration load-bearing for every user's HTTP
stack. Without a telemetry dimension for proxy-env presence we can't
answer "do auth-category 403s correlate with proxy env vars" empirically
across the user base — we can only respond to individual tickets.
Add \`proxy_env_set\` to the common properties attached to every PostHog
event. Boolean, so no proxy URL is logged. Shared helper in
\`src/utils/proxy-env.ts\` so server.ts (dispatcher gating) and
telemetry/client.ts (reporting) agree on the definition.
* feat(telemetry): replace proxy_env_set with proxy_mode, surface bypass hint on 403
\`proxy_mode: none | explicit | env\` distinguishes --proxy/FIGMA_PROXY
from env-derived proxies, which the boolean couldn't. Lets us correlate
#358-style failures with the specific configuration that produced them.
When a 403 surfaces and a proxy is configured, the error now hints at
the right bypass: unset --proxy for explicit mode, or set
NO_PROXY=api.figma.com for env mode. Users already have NO_PROXY as a
standard escape hatch (EnvHttpProxyAgent respects it) — no new flag.
* feat(proxy): support --proxy=none to bypass env-var proxies
Users with a system-level HTTPS_PROXY that misbehaves for api.figma.com
specifically couldn't easily opt out via the CLI — NO_PROXY worked but
required knowing the convention and the right hostname. Accept 'none' as
a special value for --proxy (also via FIGMA_PROXY) to explicitly skip
both ProxyAgent and EnvHttpProxyAgent, leaving Node's default dispatcher
in place regardless of what's in the environment.
No new flag surface; reuses the existing knob.
* chore: code cleanup pass + follow-ups
Incorporates an automated cleanup pass across the proxy/dispatcher code,
plus two manual follow-ups on top:
- server.ts: consolidate proxy branches, unify commentary, drop the
emitWarning suppression (undici 7.x no longer emits UNDICI-EHPA).
- fetch-json.ts: push optional-handling for redactFromErrorBody to the
boundary (destructure default + filter(Boolean)), tighten signatures.
- proxy-env.ts: reorder (type first), extract PROXY_ENV_VARS constant.
Restored a short note on hasProxyEnv so future readers know it's
shared across three files and shouldn't be re-inlined.
- figma.ts: split ternary into explicit per-mode branches, add rationale
JSDoc on buildForbiddenMessage. Aligned HttpError cast style between
buildForbiddenMessage and buildRateLimitMessage — both now use
(error as HttpError).field ?? fallback with no optional chain, safe
because both only run from the requestWithSize catch block.
Copy file name to clipboardExpand all lines: src/bin.ts
+2-1Lines changed: 2 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -44,7 +44,8 @@ const argv = cli({
44
44
},
45
45
proxy: {
46
46
type: String,
47
-
description: "HTTP proxy URL for networks that require a proxy (e.g. http://proxy:8080)",
47
+
description:
48
+
"HTTP proxy URL for networks that require a proxy (e.g. http://proxy:8080). Pass 'none' to ignore HTTP_PROXY/HTTPS_PROXY from the environment and connect directly.",
"Note: this server is configured to route requests through an explicit proxy (--proxy/FIGMA_PROXY). If the proxy may be the source of the 403, unset it, change it to --proxy=none, or bypass it for this host.",
363
+
);
364
+
}elseif(mode==="env"){
365
+
parts.push(
366
+
"",
367
+
"Note: this server picked up a proxy from HTTP_PROXY/HTTPS_PROXY in your environment. If the proxy may be the source of the 403, set NO_PROXY=api.figma.com, pass --proxy=none, or unset HTTP_PROXY/HTTPS_PROXY.",
368
+
);
369
+
}
370
+
returnparts.join("\n");
355
371
}
356
372
373
+
/**
374
+
* Build a user-facing 429 message from the Figma rate-limit response headers.
375
+
* Figma includes plan tier, seat-level limit type, retry-after, and an upgrade
376
+
* link — all of which let us give targeted guidance instead of a generic
377
+
* "try again later."
378
+
*
379
+
* See https://developers.figma.com/docs/rest-api/rate-limits/
0 commit comments