feat(proxy): forward the client's address on every call to Gauzy (0.1.12)
Problem
Since ever-co/ever-gauzy#11505, the proxy mounted inside the Gauzy API calls Gauzy over loopback. Gauzy therefore sees 127.0.0.1 as the client of every proxied call, so every pm.gauzy.co user shares one rate-limit bucket on public routes (login, email-check) and one sign-in-attempt bucket. Before #11505 they shared the homelab's egress IP instead, so this isn't a regression, but it's still wrong. Tracked as Gauzy task Ever Gauzy #645.
Fix
request-context.ts:clientAddressHeaders(req)captures the headers Gauzy reads the client's address from:X-Forwarded-For, or the socket address when the request came without one;CF-Connecting-IP.
mount.ts: integrated mode stores them in the per-request context (createContext(req)).apiFetch: sends them unchanged on every call to Gauzy.customHeaderscan still override them.- Standalone mode (
main.ts) creates its context without a request, so it sends nothing new.
Why the forwarded headers are correct and safe:
- Gauzy resolves the client as (1) a signed
X-Ever-Client-IP, (2)CF-Connecting-IPwhenTHROTTLE_TRUST_CF_CONNECTING_IP=true(as on prod), or (3) Expressreq.ipwithTRUST_PROXY= 1 hop by default. - With the headers passed on unchanged, the loopback hop stands in for the hop the request came through, so Gauzy resolves the same client for the proxied call as for the browser's own request.
- A client gains nothing: it could send the same headers to Gauzy directly.
- With
TRUST_PROXY=false, Gauzy keeps seeing127.0.0.1, as it trusts no forwarded address at all.
Tests
New request-context.spec.ts (9 tests):
- Header capture: unchanged pass-through, the socket address when
X-Forwarded-Foris missing, a repeated header joined, nothing sent when nothing is known. apiFetch: sends the headers inside a request and none in standalone mode.- End to end with a real Express server (
trust proxy= 1, the same derivation Gauzy uses): ingress request ā client; a client-writtenX-Forwarded-Forentry ā still the real client; direct request ā the socket address. The control without the headers resolves127.0.0.1.
jest --runInBand: 10 suites, 54 tests pass. tsc -p tsconfig.build.json: clean.
Release
The version is bumped to 0.1.12 (plugin only; models unchanged). After merge: release PR develop ā main, tag v0.1.12, npm publish, then bump in ever-gauzy.
š¤ Generated with Claude Code