# `service/normalize-domain.ts` ## Purpose Pure helper that mirrors the SurrealDB `fn::site::domain::normalize` function in TypeScript so application-tier code (the resolver, the route layer, the site service's `addDomain` / `removeDomain` paths) and database-tier code (the surql function) agree on the canonical form of a domain. Without this parity, a site stored with `"acme.example.com"` would be unreachable when an integrator naively passed `"HTTPS://WWW.Acme.Example.Com/"` from a `Host` header. ## Features - Lower-cases, trims whitespace, strips `http://`/`https://`, strips `www.`, strips a single trailing slash. - Pure function, zero deps, zero side effects. - Single source of truth for normalisation — services and middleware call this exclusively. ## Usage: Basic ```ts import { normalizeDomain } from "@suaveplan/api-plugin-site/service/normalize-domain"; normalizeDomain("HTTPS://WWW.Acme.Example.Com/"); // → "acme.example.com" ``` ## Usage: Advanced ```ts import { normalizeDomain } from "@suaveplan/api-plugin-site/service/normalize-domain"; // Use inside a middleware to canonicalise the request domain before // hitting the DomainResolverService. const host = c.req.header("host") ?? c.req.header("x-forwarded-host") ?? ""; const domain = normalizeDomain(host.split(":")[0] ?? host); const resolved = await resolver.resolve(domain); ``` ## API Reference - `normalizeDomain(domain: string): string` ## Implementation Notes - The order matters: `http(s)://` MUST be stripped before `www.` so that `https://www.example.com` reduces correctly. - The trailing-slash strip is a single character — paths beyond the host are preserved by the caller's split (the middleware uses `host.split(":")` and the route layer uses the URL parser). - Internationalised domains (`xn--`) are passed through untouched; callers needing IDNA normalisation must run punycode normalisation separately. - The function is intentionally tolerant of leading whitespace and mixed case; in practice the `Host` header is canonical at the wire layer, but reverse proxies and edge workers occasionally pass through a value pulled from a configuration file that has neither been trimmed nor downcased. Normalisation here means the rest of the plugin can assume a single form. - Because the function is pure and synchronous, it is safe to call inside hot paths (e.g. inside the Hono middleware) without any concern over async ordering or external I/O.