IpAddressKey reads the socket peer from ConnectInfo. Behind a reverse
proxy / load balancer (e.g. an AWS ALB) that peer is the proxy, so every
caller collapses into one global rate-limit bucket — per-client limiting
is impossible.
Add ForwardedIpKey, a RateLimitKey that derives the client IP from the
X-Forwarded-For header. Because XFF is oldest-first and each proxy appends
the address it saw, the right-most entries are added by trusted infra and
the left-most are client-spoofable. The key takes the entry trusted_hops
positions from the right (configurable, default 1 = single ALB), and falls
back to the ConnectInfo peer when the header is absent, too short, or
malformed — coarse but never spoofable.
11 unit tests cover rightmost-for-one-hop, spoofed-left ignored, multi-hop,
multi-header flattening, fallback (absent/short/malformed), IPv6 + ip:port
forms, no-key, and zero-hops clamping. IpAddressKey refactored to share the
peer-IP helper. Bumps workspace 0.1.4 -> 0.1.5 + CHANGELOG.