Files
2026-05-27 23:29:53 +01:00

2.7 KiB

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

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

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.