# `validate` — tenant-label validation _(no submodules)_ ## Purpose Provides the default RFC-1035-style hostname-label validator (`defaultLabelValidator`) plus two pure string helpers (`normalizeHost`, `stripBaseDomain`) that the resolver uses to take an inbound `Host` header all the way down to a candidate tenant slug. Splitting these helpers out of the resolver body keeps the resolver readable and the host-parsing edge cases unit-testable in isolation. Tenant labels are persisted as `tenantId` and compared against by downstream RBAC / row-level filters, so the canonical form is enforced here: lower-case ASCII, 1..63 characters, `[a-z0-9-]`, no leading or trailing hyphen. ## Features - `defaultLabelValidator` — RFC 1035 §2.3.1 LDH-style validator. - `MAX_LABEL_LENGTH` constant exported for downstream schemas. - `normalizeHost(raw)` — strip `:port` suffix, lower-case, refuse the empty / starts-with-`:` cases. - `stripBaseDomain(host, baseDomain)` — tri-state return: `string` (labels), `null` (exact match — no tenant), `undefined` (mismatch — caller decides whether to raise). ## Usage: Basic ```ts import { defaultLabelValidator, normalizeHost, stripBaseDomain, } from "@suaveplan/api-tenant-resolver-subdomain/validate"; const host = normalizeHost("Acme.API.Example.com:443"); // → "acme.api.example.com" const labels = stripBaseDomain(host!, "api.example.com"); // → "acme" defaultLabelValidator(labels!); // → true ``` ## Usage: Advanced ```ts import { defaultLabelValidator } from "@suaveplan/api-tenant-resolver-subdomain/validate"; const RESERVED = new Set(["www", "admin", "api"]); const customValidator = (label: string): boolean => { if (!defaultLabelValidator(label)) return false; return !RESERVED.has(label); }; // → pass `customValidator` as `validate` in SubdomainTenantResolverOptions ``` ## API Reference - `LabelValidator` — `(label: string) => boolean`. - `defaultLabelValidator: LabelValidator`. - `MAX_LABEL_LENGTH: 63`. - `normalizeHost(raw: string | null | undefined): string | null`. - `stripBaseDomain(host, baseDomain): string | null | undefined`. ## Implementation Notes The label validator is hand-coded against the character-code range (`0x30..0x39`, `0x61..0x7a`, `0x2d`) rather than a regex so the hot-path has no allocator overhead. The tri-state `stripBaseDomain` return is the standard "missing vs absent vs malformed" pattern from the rest of the codebase: callers MUST distinguish "host is exactly the apex" (advance the chain — common for marketing pages) from "host has the wrong apex" (strict-mode error). `normalizeHost` does not honour IPv6 bracketed literals (`[::1]`) — tenant resolution by IPv6 host is not a supported deployment shape.