Rich-text links + isLocalizable is now immutable once content exists
A new inline mark for rich text and a content-modeling guardrail landed this round.
Links in rich text
Rich text gained a link mark, so a run of text can now carry a hyperlink end to
end — from the TipTap editor through storage, validation, and both delivery
projections.
The mark sits alongside the existing formatting marks and adds two fields:
{ "type": "link", "href": "/about", "title": "About us" }
hrefis required. It must be an absolutehttp/httpsURL, amailto:/tel:link, or a relative path. Unsafe schemes likejavascript:are rejected on write, and sanitized again at render time as defense in depth.titleis optional and maps to the anchor'stitleattribute.
The html projection renders <a href="…">, adding rel="noopener noreferrer"
on external links (and a title attribute when present). This works identically
on the GraphQL and REST delivery paths. The HTML-paste cleaner (from-html)
preserves anchors, so pasting from Word / Google Docs keeps links intact.
The href is a plain string today; the AST shape leaves room for a future
entry-reference link variant without breaking stored content.
React
@krios/react's KriosRichText handles the link mark out of the
box — the default renderer receives href + optional title, sanitizes the href,
and adds rel="noopener noreferrer" on external links. Override it like any other
mark renderer for full control.
See Rich Text for the full AST reference.
isLocalizable is now immutable once a field has content
Shared and per-locale values use different storage keys, so flipping
isLocalizable after a field already has data would orphan the existing values.
The field-update API now guards against this: changing the flag once any value has
been written returns 409 is_localizable_immutable. Set it correctly at field
creation time.
isSortable and isFilterable remain mutable. See Flags
for the full matrix.