Public Suffix
The Public Suffix List (PSL) is Mozilla's published catalog of "effective top-level domains" — labels under which independent parties can register names (com, co.uk, s3.amazonaws.com, …). It is the canonical reference for deriving the "organizational domain" of a hostname: the registrable label one level below its public suffix. Several upstream specs lean on it directly:
- DMARCbis (IETF DMARC WG) replaces RFC 7489's heuristic organizational-domain derivation with a PSL lookup, including new psd= (public-suffix-domain policy) and np= (non-public-suffix policy) tags - BIMI (RFC 9669 + draft) uses the same organizational-domain logic to scope brand indicators - Same-site cookie scoping (RFC 6265bis) refers to the PSL when deciding whether Domain=co.uk is a "public suffix" attempt
This module ships the PSL as a vendored data file (lib/vendor/public-suffix-list.dat) and parses it once at module-load. The algorithm is the canonical one published at https://publicsuffix.org/list/ (exact > exception > wildcard).
Surface:
b.publicSuffix.publicSuffix("example.co.uk") // → "co.uk"
b.publicSuffix.organizationalDomain("foo.bar.example.co.uk") // → "example.co.uk"
b.publicSuffix.isPublicSuffix("co.uk") // → true
b.publicSuffix.lookupSource() // → { vendoredAt: "2026-05-09", entries:
IDN inputs are punycode-normalized via Node's url.domainToASCII before lookup. Bad inputs throw PublicSuffixError.
b.publicSuffix.publicSuffix(domain) #
Returns the longest matching public suffix for domain, per the Mozilla PSL algorithm (https://publicsuffix.org/list/). Exception rules outrank exact rules, exact rules outrank wildcards, wildcards outrank the implicit "*" rule. Input is lowercased and IDN- normalized (punycode) before lookup. Returns null for inputs that have no registrable parent (single-label TLDs, public-suffix-only inputs).
Throws PublicSuffixError (public-suffix/invalid-domain) for non-string / empty / overlong / control-byte-bearing inputs.
var b = require("@blamejs/core");
b.publicSuffix.publicSuffix("example.co.uk");
// → "co.uk"
b.publicSuffix.publicSuffix("foo.bar.example.com");
// → "com"
b.publicSuffix.organizationalDomain(domain) #
Returns the registrable "organizational domain" — the public suffix plus exactly one label to its left. This is the value DMARCbis, BIMI, and cookie-scope policies operate on when they decide whether two hostnames belong to the same registered party.
Returns null when domain IS a public suffix (no organizational parent exists — co.uk has no registrable owner, only the labels registered under it do).
Throws PublicSuffixError (public-suffix/invalid-domain) on bad input shape.
var b = require("@blamejs/core");
b.publicSuffix.organizationalDomain("foo.bar.example.co.uk");
// → "example.co.uk"
b.publicSuffix.organizationalDomain("example.com");
// → "example.com"
b.publicSuffix.organizationalDomain("co.uk");
// → null
b.publicSuffix.isPublicSuffix(domain) #
Returns true when domain is itself a public suffix (e.g. "co.uk", "com", "s3.amazonaws.com"), false otherwise. DMARCbis uses this distinction for its psd= (public-suffix- domain) policy: a TLD operator publishing a record on co.uk itself is a different actor than example.co.uk publishing one.
Throws PublicSuffixError (public-suffix/invalid-domain) on bad input shape.
var b = require("@blamejs/core");
b.publicSuffix.isPublicSuffix("co.uk");
// → true
b.publicSuffix.isPublicSuffix("example.co.uk");
// → false
b.publicSuffix.lookupSource() #
Returns transparency metadata for the loaded PSL: the date the file was vendored (vendoredAt, ISO 8601 from lib/vendor/MANIFEST.json), the parsed-rule count (entries), and the SHA-256 hash of the raw file contents (sha256, hex). Use to surface in operator dashboards / forensic logs so a snapshot of the PSL the framework was making decisions against is reproducible after the fact.
var b = require("@blamejs/core");
var src = b.publicSuffix.lookupSource();
// → { vendoredAt: "2026-05-09", entries: 9000, sha256: "a008..." }
b.publicSuffix.canonicalDomain(domain) #
Returns the bare canonical host form of domain for identity comparison: lowercase, a single trailing dot stripped, and IDN labels normalized to their A-label (punycode) form. Unlike organizationalDomain it does NOT walk the public-suffix list — it returns the input host itself in canonical form.
Two values that denote the same host in different encodings (case, trailing dot, U-label vs A-label) return the SAME string, so an equality compare is encoding-stable — the building block for DMARC alignment and certificate SAN-vs-domain authorization checks, where one side normalizing differently from the other is a bypass.
Non-throwing: returns "" for any input that is not a valid host (control bytes, empty labels, over the 253-octet limit), so a hostile or garbage value canonicalizes to "" and matches nothing.
var b = require("@blamejs/core");
b.publicSuffix.canonicalDomain("Example.COM."); // → "example.com"
b.publicSuffix.canonicalDomain("a..b"); // → ""
Last updated 2026-08-08T16:39:49.652Z by seeder.