Document API
initRelationalText()
function initRelationalText(): Promise<void>Must be called once before any document operations. Safe to call multiple times — subsequent calls return immediately.
import { initRelationalText, Document } from 'relational-text'
await initRelationalText()
const doc = Document.fromText('Hello, world!')Document class
Factory methods
Document.fromText(text: string): Document
Document.fromJSON(json: DocumentJSON): Document
Document.parse(text: string): DocumentfromText creates a document with no facets. fromJSON deserializes from the wire format. parse detects mentions (@handle), URLs, and hashtags in plain text and stores them as facets.
const doc = Document.parse('Check out https://bsky.app and say hi to @alice.bsky.social!')
console.log(doc.features)
// [
// { $type: 'app.bsky.richtext.facet', name: 'link', byteStart: 10, byteEnd: 28, ... },
// { $type: 'app.bsky.richtext.facet', name: 'mention', byteStart: 37, byteEnd: 56, ... }
// ]Accessors
doc.features: FlatFeatureJSON[]Flat array of all features across all facets, with byteStart and byteEnd added to each entry.
Mutation methods
Each returns a new Document; the original is unchanged.
doc.insertText(byteOffset: number, text: string): Document
doc.deleteRange(byteStart: number, byteEnd: number): Document
doc.addMark(byteStart: number, byteEnd: number, feature: FeatureJSON): Document
doc.addBlock(byteOffset: number, feature: FeatureJSON): Document
doc.removeMark(byteStart: number, byteEnd: number, typeName: string): Document
doc.addLink(byteStart: number, byteEnd: number, url: string): Document
doc.addMention(byteStart: number, byteEnd: number, handle: string): Document
doc.addTag(byteStart: number, byteEnd: number, tag: string): DocumentAll byte offsets are UTF-8 byte positions, inclusive start / exclusive end.
let doc = Document.fromText('Hello world')
doc = doc.addMark(0, 5, {
$type: 'org.relationaltext.facet',
name: 'bold',
})
doc = doc.addLink(6, 11, 'https://example.com')
console.log(doc.toJSON())Output methods
doc.toHIR(): HIRNode[]
doc.toJSON(): DocumentJSON
doc.toString(): stringtoHIR() computes a render tree from the flat facet list; it is not stored in the wire format. toJSON() serializes to the wire format. toString() returns the plain text content.
Type Definitions
interface DocumentJSON {
text: string
facets: FacetJSON[]
}
interface FacetJSON {
index: ByteSlice
features: FeatureJSON[]
}
interface ByteSlice {
byteStart: number // inclusive, UTF-8 byte offset
byteEnd: number // exclusive, UTF-8 byte offset
}
type FeatureJSON = MarkFeatureJSON | BlockFeatureJSON | UnknownFeatureJSON
interface MarkFeatureJSON {
$type: string
name: string
attrs?: Record<string, unknown>
expandStart?: boolean
expandEnd?: boolean
}
interface BlockFeatureJSON {
$type: string
name: string
parents: string[]
attrs: Record<string, unknown>
}
interface UnknownFeatureJSON {
$type: string
[key: string]: unknown
}
interface FlatFeatureJSON extends MarkFeatureJSON {
byteStart: number
byteEnd: number
}HIR Types
toHIR() returns a tree of HIRNode values. Block nodes contain their children; container nodes group consecutive blocks sharing a parents[] prefix. Text nodes carry the inline content with associated marks.
type HIRNode = HIRBlockNode | HIRContainerNode | HIRTextNode
interface HIRBlockNode {
type: 'block'
name: string
attrs: Record<string, unknown>
children: HIRNode[]
}
interface HIRContainerNode {
type: 'container'
name: string
children: HIRNode[]
}
interface HIRTextNode {
type: 'text'
content: string
marks: HIRMark[]
}
interface HIRMark {
kind: string // full compound key, e.g. "org.commonmark.facet#strong"
attrs: Record<string, unknown>
}const doc = Document.fromJSON({
text: '\uFFFCHello',
facets: [
{ index: { byteStart: 0, byteEnd: 3 }, features: [{ $type: 'org.commonmark.facet', name: 'paragraph', parents: [], attrs: {} }] },
{ index: { byteStart: 3, byteEnd: 8 }, features: [{ $type: 'org.commonmark.facet', name: 'strong' }] },
],
})
const hir = doc.toHIR()
// [{ type: 'block', name: 'paragraph', attrs: {}, children: [
// { type: 'text', content: 'Hello', marks: [{ kind: 'org.commonmark.facet#strong', attrs: {} }] }
// ]}]