Repository navigation
3.0.0
Breaking: ACE-only hostnames and trie labels
Hostnames passed to PublicSuffixList.isUnrestricted(_:) and match(_:) must now be in ACE (Punycode) form. Raw Unicode hostnames like example.香港 are rejected by syntax validation — encode IDN labels as xn--… before calling:
// ❌ rejected since v3.0
list.isUnrestricted("example.香港")
// ✅ correct
list.isUnrestricted("example.xn--j6w193g")This aligns with DNS wire format and RFC 5321 hostname syntax, and eliminates the silent UTF-8-vs-ACE mismatch that was possible in v2.
Changed
- Breaking:
isValidHostnow rejects any byte ≥ 0x80. - Breaking: The embedded trie stores labels in ACE form only. Caches built from v2.0.x rules loaded via
.filePath(_:)remain structurally valid but IDN labels won't match — rebuild caches on upgrade. TrieBuilder.buildAndSerialize(rules:)auto-converts each label via Punycode before insertion, so callers can continue to pass the PSL .dat's native UTF-8 form in[[String]]rules.- Per-label cap tightened from 255 to 63 bytes (DNS RFC 1035).
Added
Punycode(internal) — self-contained RFC 3492 encoder. No external IDNA dependency.walkForValidationenforces ASCII LDH on every stored label byte. NewTrieValidationError.nonLDHLabelByte(at:byte:)case.- Structural check: label length ≤ 63 bytes. New
TrieValidationError.labelTooLong(at:length:)case.
Trie format version unchanged at 2 — only the byte content of stored labels changed, not the binary layout.