/** * Closed rich-text AST for provider content (proposal ยง4.5 "rich content * contract"). Nothing outside these node types can be rendered: there is no * node that carries raw HTML, attributes, styles or arbitrary URLs. * * URL-bearing fields are only ever produced by `parseSafeHttpUrl` / * `toProxiedMediaUrl`, and the renderer re-validates them, so an AST that was * round-tripped through storage or the network cannot smuggle a bad scheme. */ export const RICH_TEXT_VERSION = 1 as const; export type TextNode = { readonly type: "text"; readonly text: string }; export type LineBreakNode = { readonly type: "linebreak" }; /** Custom emoji / emote. `src` is always a media-proxy URL, never the origin URL. */ export type EmojiNode = { readonly type: "emoji"; readonly shortcode: string; readonly src: string }; export type LinkNode = { readonly type: "link"; /** Absolute http(s) URL, credential-free. */ readonly href: string; /** ASCII (punycode) host of `href`, shown to the operator next to the label. */ readonly host: string; readonly children: readonly (TextNode | EmojiNode)[]; }; export type MentionNode = { readonly type: "mention"; /** Handle without the leading "@", e.g. `alice` or `alice@example.social`. */ readonly handle: string; readonly href?: string; }; export type HashtagNode = { readonly type: "hashtag"; /** Tag without the leading "#". */ readonly tag: string; readonly href?: string; }; export type InlineNode = TextNode | LineBreakNode | EmojiNode | LinkNode | MentionNode | HashtagNode; export type ParagraphNode = { readonly type: "paragraph"; readonly children: readonly InlineNode[] }; export type RichTextDocument = { readonly type: "doc"; readonly version: typeof RICH_TEXT_VERSION; readonly children: readonly ParagraphNode[]; /** True when input exceeded a length/node/depth limit and was cut. */ readonly truncated: boolean; }; export type LinkPreview = { readonly type: "linkPreview"; readonly href: string; readonly host: string; readonly title?: string; readonly description?: string; readonly siteName?: string; /** Media-proxy URL for the preview image. */ readonly image?: string; };