/** * `normalizeIpForBucketKey` — THE cross-repo normalizer for turning a raw * client-IP candidate (`x-forwarded-for` hop, socket remote address, proxy * header) into a stable rate-limit / dedup bucket key. * * WHY IT LIVES HERE: producer and consumer sit in DIFFERENT repos (the app * emits the candidate, the hub buckets it) and each had grown its own * normalizer. They disagreed — one unwrapped `::ffff:1.2.3.4` to the bare * IPv4 and stripped `%zone`, the other kept the zone and only lower-cased the * mapped form — so ONE visitor could land in TWO buckets depending on which * side normalized. Both repos already depend on this package, and * `./chat-protocol` is its server-safe subpath (no React, no browser APIs), * so this is the one place both sides can share. * * Contract: * - input longer than `IP_BUCKET_KEY_MAX_LENGTH` → `null` (an unbounded * header must never become an unbounded map key); * - `[…]` brackets and a trailing `]:port` are stripped, as is a bare * `:port` on an IPv4 (`203.0.113.4:8080`) — an unbracketed IPv6 with a * bare port stays ambiguous and is not stripped; * - a `%zone` suffix is stripped (link-local scope is per-host, not part of * the peer's identity); * - IPv4-mapped IPv6 (`::ffff:203.0.113.4`) collapses to the bare IPv4, so * the same peer buckets identically over either stack; * - IPv6 is lower-cased; * - IPv4 octets are range-checked and REJECTED when zero-padded (`.04` * would otherwise bucket separately from `.4`), and IPv6 is * charset/shape-checked (one `::` at most, ≤8 groups, an embedded IPv4 * only in the last group, no dangling separator); anything else returns * `null` rather than a junk bucket key. * * It does NOT canonicalize IPv6 zero-compression (`2001:db8::1` vs * `2001:0db8:0:0:0:0:0:1`) — peers do not spell their own address two ways * within one deployment, and a full expander is more surface than the bucket * key warrants. */ /** Longest accepted candidate. A full IPv6 + zone fits well inside this. */ export declare const IP_BUCKET_KEY_MAX_LENGTH = 64; /** * Normalize one IP candidate to its canonical bucket key, or `null` when the * value is not a usable address. */ export declare function normalizeIpForBucketKey(value: string): string | null; //# sourceMappingURL=ip-normalize.d.ts.map