2.0.0-alpha.7
Fixed
- DOCX round trips keep every modeled mark and block. A new
export → import matrix (every formatting mark in every text context,
every paragraph, list, table, cell, image, code, math, note, header,
footer, and page-layout attribute, plus a second-pass fixed-point
check) found and pinned a set of losses: lists inside table cells
were dropped on export; hanging indents exported as zero and
w:hangingwas ignored on import; headings came back as Word’s blue 16pt built-ins (export now writes the editor’s heading sizes with inherited color); unscoped header/footer blocks were not exported; hyperlinks discarded an explicit text color; links inside footnotes were lost on import; header and footer runs used a reduced codec in both directions and now share the body run codec, links and inline code included; inline code and code blocks flattened to Courier text and now travel asCodeInline/CodeBlock_<language>styles and return as the original nodes; todo items exported as literal[x]text and now use checkbox glyphs that re-import as todo lists with their checked state; code-block line breaks doubled on re-import; and a single run in another font restamped the whole document (the inferred document font is now the character-weighted majority). - Table borders export and re-import faithfully. Export no longer
throws on non-hex colors such as
TRANSPARENT,rgba(), or CSS names — unresolvable values are omitted or written asauto. The uniformborderWidth/borderColorpair is honored (width 0 means no borders), width-0 spec edges export asnoneinstead of a hairline, and an explicitw:sz="0"imports as hidden rather than a 1px line. Table Settings border changes now rewrite the structured table spec and clear per-cell overrides, so hiding borders on an imported table takes effect. - Byte-preserving DOCX export degrades instead of failing. A carrier that fails to load falls back to the regenerated package like every other graft failure; the graft option reports its outcome (exact, grafted, regenerated, and the fallback code) through an isolated callback that can never break an export. Untouched imports of rich documents now export byte-identical: note-body font inheritance, header/footer zone ids, and legacy chrome no longer drift the fidelity signatures; watermark and settings edits graft instead of restoring carrier values; body grafting is invalidated when wrapper or style sidecars change; single-quoted and non-numeric relationship ids parse; and a changed header image is replaced even when its media filename collides.
- Formatting suggestions preserve footnotes. Accepting a
style_blockssuggestion keeps footnote references and bodies. - Large documents no longer stall on batch edits. Styling 205 blocks in a 10,000-block document, applying 100 replacements, and large multi-block insertions run without re-decoding the document per action; suggestion projection latency is bounded; batch paragraph formatting suggestions behave identically through preview, acceptance, and rejection.
- Semantic tool errors and inputs. Errors distinguish Markdown find
syntax from stored plain text; metric CSS paragraph indentation
(
cm,mm) is accepted; number-dot prose can be parsed as inline text instead of a list when requested. - Comments render AI citations. Structured citations persist on replies and render in the panel; unsupported provider citation markers are hidden, including on legacy comments.
- Agent image rehosting. Wikimedia thumbnail URLs are recovered by rehosting the original image, and rate-limited rehosts surface the backend reason and status.
- Revision timeline never collapses to zero. A stale or missing server update counter no longer disables history or pins every frame to the first update; loaded frames are authoritative.
- Pasted images write once. A pasted image no longer inserts a temporary base64 placeholder that is replaced later; the final hosted URL is written at the captured paste position when the upload completes.
Changed
- Comment margin geometry is direction-aware. Chip, floating-stack, and insert-chip positions are computed along an outward axis with a single conversion to physical coordinates. The embedded document surface itself is still laid out left-to-right: the margin chrome stays on the page’s right regardless of the host page’s direction. Mirroring the embed for right-to-left hosts is not part of this release.
2.0.0-alpha.6
Fixed
- A healed seed race now recovers full fidelity — and never loses a comment. Three repair refinements: the winner is the seed whose metadata survived the merge (each seed stamps a ballot in the same transaction), so the kept content matches the surviving import capture; a shared deterministic id keeps the WINNER’s element, not an arbitrary one; and map records under a shared key (deterministic comment ids) are never deleted — the merge already deduplicated them, and alpha.5’s repair removed the only surviving record. A raced, repaired room now reports “exact” and exports byte-identically.
2.0.0-alpha.5
The 2.0.0 alphas are prereleases for evaluation — not yet the default
install.
npm install @reviseio/sdk continues to resolve to the 1.x
line; install with the alpha dist-tag. Guides elsewhere on this site
describe 1.x until 2.0.0 ships.Fixed
- Seed-race repair kept a duplicate footnote. Deterministic ids that every seed generates identically (docx footnotes) were protected from repair as a collision safeguard, leaving one copy per seed. Repair now keeps exactly one occurrence of a shared id. Supersedes 2.0.0-alpha.4, which was deprecated minutes after publish.
2.0.0-alpha.4
Fixed
- Double-seed connect race no longer duplicates the document. Two
peers that each found an empty room and seeded the same file before
syncing used to merge into a perfectly-synced, perfectly-duplicated
document. Every seed now records a claim in the same transaction as
its content, and any peer that sees two claims deterministically
removes the losing seed’s content — idempotent, convergent, and
content added after a seed is never touched.
seedYDocFromFileis now genuinely safe to call on every connection: a later call also heals an already-raced room, and every live editor session repairs one the moment the second claim syncs in. - Editing no longer rewrites document properties. A structural edit
(or a rejected tracked change) permanently dropped the imported core
properties from the live model, so every later export regenerated
docProps/core.xmlwith an “Un-named” creator, the title removed, and the creation date reset to export time. Core properties now survive every model rebuild, and when core.xml is legitimately regenerated it is a faithful merge:cp:revisionround-trips and fields the original never had are not invented. docProps/app.xmlpasses through untouched. It is never regenerated (preserving Application/Company/TotalTime) and never added to a package that did not have one.
Added
repairSeedRace(ydoc)on the backend entry (withSeedRaceRepairResult): detect and repair a double-seed race on demand. Editor sessions andseedYDocFromFilerun it for you.
Changed
- New reserved top-level key in shared documents:
"seed-claims"(seeRESERVED_DOCUMENT_KEYS) — where seed claims live.
2.0.0-alpha.3
Fixed
- Backspace before a chip deleted the chip. A preserved-object chip has two caret stops — before and after — and a delete now respects which side the caret is on, like a caret between two characters: backspace at the before-stop targets the block before the chip (an atomic neighbor is deleted whole, a text neighbor loses its last character), and forward delete at the after-stop targets the block after. Deletes pointing at the chip still remove it.
- Up/down arrows at a chip slid the caret to the chip’s other side instead of changing lines. Vertical movement now leaves the chip’s line and lands on the neighboring block’s stop nearest the caret’s column — arrowing through a stack of chips keeps the caret on the same side all the way down.
2.0.0-alpha.2
Fixed
- Exporting .docx could crash in production builds of the host app
(
Cannot destructure property 'default' … as it is undefinedfrom the converter’s zip loader). The SDK’s build emitted duplicate interop chunks for its zip dependency behind dynamic imports, and some consumer bundlers resolved one family toundefinedwhen producing production builds — development builds were unaffected, which is why the crash only appeared after deployment. The dependency is now a static import inside the (still lazily loaded) converter modules: the load profile is unchanged and the chunk graph no longer depends on the host bundler’s interop handling. - Backspace in an empty paragraph directly after a chip deleted the chip instead of the paragraph. Preserved payloads are content the source file owns, not editor furniture: the empty paragraph dies, the chip survives. (Page and section breaks keep their old consume-on-backspace behavior.)
- Chips gained real before/after caret stops. The caret can now be placed on either side of a chip — arrow keys walk across it, and clicking the left or right half of the chip places the caret on the matching side.
2.0.0-alpha.1
The 2.0 line’s headline is DOCX source fidelity: a document imported from .docx can leave the editor as the file it came from, not a reconstruction of it.Added
- DOCX source-fidelity mode (default on). Importing a .docx keeps the original package inside the document (the “carrier” — shared documents included, capped at 25MB). On export, content you did not touch is emitted as the exact bytes that arrived — byte-for-byte, unannotated — and only changed content is regenerated. A verification stage inspects every composed package and falls back to full regeneration rather than ship anything it cannot verify.
handle.getSourceFidelity()— plusydocSourceFidelity(ydoc)anddocumentToDocx(doc, { originalDocx })on the backend entry — reports the relationship of the next export to the original file:"exact"(byte-identical),"grafted"(original bytes plus your edits), or"converted"(no usable original; the report says why).- Unmodeled Word formatting survives editing. Run, paragraph, table,
row, cell, and section properties the editor does not model (vendor
effects such as
w14:glow, revision-save ids, row heights, table look flags, page borders, note-numbering properties…) are carried through the model and re-emitted — an edited paragraph keeps them too, with or without the carrier. - Preserved objects render as labeled chips. OLE embeds (Excel,
Visio), SmartArt without a raster fallback, and unknown OOXML
constructs import as atomic blocks labeled with their source tag
(for example
w:object · Excel.Sheet.12), render as chips on canvas and in PDF export, and re-export verbatim. In agent HTML they appear as<docx-raw id tag />: an agent can keep, move, or omit one (omission deletes it), but can never inject raw OOXML of its own. - Editable-region permissions preserved.
w:permStart/w:permEndpairs survive import, editing, and export with balance guaranteed by construction: typing inside extends the region, deleting its text retires it, and unbalanced pairs in source files are repaired at import.
Changed
- BREAKING: two new reserved top-level keys in shared documents —
"docx-carrier"and"oxml-ranges"(seeRESERVED_DOCUMENT_KEYS). A host-built Y.Doc already using these names is rejected byassertUsableSharedDocument. - BREAKING: docx-sourced exports are byte-preserving by default. 1.x regenerated every export from the model; 2.0 reproduces original bytes for untouched content. Hosts that depended on exports being normalized into the generated dialect should convert explicitly.
ReviseDocumentblock children may now include the"docx-raw"node type (opaque — convert rather than inspect, as ever).- Shared documents built from a .docx are larger by roughly the size of the source file (the carrier). It is stored once, chunked, and synced like any other document state.
1.3.1
Fixed
- Delegated page inspection now reaches the embedded editor canvas. The
SDK connects the delegated agent’s
render_document_pagestool to the mounted document renderer, so appearance and layout requests return the actual pages instead of reporting that canvas inspection is unavailable. - Agent-tool documentation now matches the generated SDK catalogue. The
public docs use the canonical
remove_blocksname, distinguish the deterministic document-local tool subset from delegated-agent-only tools, and explain where visual page inspection is available.
1.3.0
Added
- The built-in editor UI now localizes itself in English, Spanish, and German. Ribbon controls, menus, dialogs, comments, Review mode, and agent chrome follow the browser language or the persisted Revise UI-language preference, while English remains the fallback if a locale chunk cannot be loaded.
- The delegated browser agent can inspect the document’s rendered pages. It can request bounded appearance contact sheets or layout diagnostics from the real canvas renderer, including page geometry, tables, images, math, headers, footers, and safe placeholders for unavailable visual assets.
Changed
- Tab editing and layout now follow Word-style paragraph behavior. Tab and Shift+Tab at the start of a block keep indenting or outdenting, while either key inside paragraph text inserts a tab. Long tabbed lines wrap at word boundaries, restart their ruler on each visual line, and preserve custom, aligned, leader, and right-to-left tab stops.
Fixed
- DOCX named styles remain stable through editing and repeated round trips. Imported paragraph styles and document defaults now drive newly created headings and agent-created styled blocks, survive Yjs persistence, suppress redundant direct formatting on export, and converge without accumulating unused generated Word styles. Explicit formatting resets, borders, spacing, fonts, and styles inside table cells remain intact.
- Agent document measurements reconcile pending Review changes. Primary totals consistently measure the final, as-if-accepted document and include the original review projection when pending suggestions make the visible word or character count differ.
1.2.0
Added
- International text support now extends across the editing and conversion pipeline. Unicode-aware line breaking, search, list numbering, font fallback, and IME composition preserve multilingual text more reliably, and text import now detects UTF-8 and UTF-16 files. HTML, DOCX, RTF, ODT, and plain-text conversions keep the expanded script coverage intact.
- Orange and purple join the SDK highlight palette. The editor UI,
find_highlights,style_blocks, agent HTML, and DOCX round trips now share the same seven canonical highlight colors. - Agent styling covers richer document structures.
style_blocksadds span, descendant-wildcard, first-row, and named-paragraph-style selectors, with durable mappings for image sizing and alignment, paragraph borders, nested tables and lists, per-edge cell borders, cell fills, padding, and table-cell text styles.
Fixed
- DOCX import follows Word’s effective paragraph and table styling. Unstyled paragraphs inherit the document’s default style; exact and at-least line rules use the resolved font size; paragraph before/after and contextual spacing replace the editor’s fallback gap; missing table borders remain borderless; and non-uniform cell margins survive import. The imported spacing persists through Yjs, paragraph splits and merges, HTML, DOCX, and PDF output, keeping compact Word layouts from growing onto extra pages.
- Unavailable Word fonts use the document’s own substitution hints. DOCX
import reads
fontTable.xmlalternate names and PANOSE/family/pitch metadata, persists them with the document, and chooses metric-compatible fallbacks before resorting to a generic family. - Multilingual PDF export embeds and shapes the scripts it needs. Chinese, Japanese, Korean, Indic, Southeast Asian, Tibetan, Ethiopic, Armenian, Georgian, Syriac, Thaana, symbols, emoji, and rare Han use bundled lazy fallback faces, while a hidden logical-text layer preserves search and text extraction.
- Agent edits preserve complex formatting and pending review state. Styled tables, nested content, list-item formatting, explicit text overrides, comments, and edits layered over pending insertions now survive preview, acceptance, and rejection without duplicating or flattening structure.
- Borderless layout tables stay visually borderless while editing. The canvas now reveals only the specific invisible vertical edge under a resize pointer instead of ghosting the table’s entire grid on hover or focus.
- Imported pale-yellow highlights remain highlights. HTML clipboard import no longer remaps Word’s pale yellow to the editor’s green palette entry.
1.1.0
Added
- First-class right-to-left editing. The built-in toolbar can set paragraph and list direction to automatic, LTR, or RTL. Mixed Hebrew, Arabic, and left-to-right text now uses bidi-aware line layout, visual arrow-key movement, stable caret and selection geometry, direction-aware alignment and indents, mirrored list markers, and RTL tab stops. Direction survives Yjs, clipboard and agent edits, HTML, and DOCX round trips; PDF export preserves mixed-direction reading order and positioning.
- Multi-column sections. Page layout now supports one, two, or three
newspaper-style columns with a configurable gap. Continuous section breaks
balance their final columns, while page and next-page sections keep ordinary
pagination. The canvas editor and PDF export share the flow rules, DOCX and
HTML import/export preserve the settings, and
set_page_layoutexposescolumnCount,columnGap, and section-scoped updates to browser and server agent sessions. - Native document-structure tools.
insert_blockcan create a live table of contents with<toc levels="3"></toc>. The canonicalremove_blockstool can delete a counted range, exact IDs, a saved search result, or an explicitly authorized document tail withthrough_end.
Changed
- Agent tool sessions avoid unproductive read cycles. Sequential reads now
reject windows containing only blocks already returned in the same request
with
no_new_read_context;read_specific_blocksremains available for intentional revisits.remove_blocksis now the model-facing name, while the previousremove_blockname remains an executable compatibility alias.
Fixed
- Strict-provider nulls behave like omitted optional tool fields. Browser
and server tool execution normalize provider-materialized
nullvalues from the generated schema before dispatch, without stripping required or deliberately nullable values. Optional layout and mutation inputs therefore no longer take invalid branches merely because a provider filled them in. - Agent-generated Unicode escapes become the intended text. Literal
\uXXXXsequences in agent HTML and replacement paths are decoded without disturbing escaped backslashes or code spans, preventing visible escape text in edited documents. - Review decisions preserve the reader’s place. Accepting or rejecting a tracked change no longer forces the embedded editor to scroll back to the active suggestion.
- SDK PDF export keeps Hebrew and Arabic text self-contained. The package now bundles the Noto fallback faces used by RTL export, so embedding hosts do not need to mirror Revise’s public font directory to avoid dropped glyphs.
1.0.1
Fixed
- Malformed model input can no longer crash a host’s agent loop. A bare
string where
search_documentexpects aqueriesarray — the most common model slip — threw a rawTypeErrorout ofexecute()/executeDynamic()instead of returning a structured failure. Bare strings are now coerced to one-element arrays (also forread_specific_blocks’block_ids), anything uncoercible fails structurally, and both surfaces gained a safety net that converts an unexpected handler throw into aninternal_errorresult. The documented contract — expected failures as results, only environment errors reject — now holds for arbitrary input. - Invalid enum values no longer mutate the wrong target silently. An
insert tool called with
position: "above"placed content after the reference block while reporting success, andset_header_footerwith a misspelled or missingsideedited the header. Both now return a structured failure naming the valid values.
1.0.0
One package, one tool contract. The browser and server surfaces now speak the same canonical envelope, so host result-handling code is shared verbatim between web and Node. That convergence is breaking on the browser side — every change is listed below.Breaking
tools.execute()returns the canonical discriminated envelope. The flat{ toolCallId, name, success, error?, agentFeedback?, output?, documentContent? }result is gone. Both surfaces now return{ ok: true, value: { callId, tool, message, data, context, suggestionIds } }or{ ok: false, error: { callId, tool, code, message } }(ReviseToolResult). Field mapping:toolCallId → value.callId,name → value.tool,agentFeedback → value.message,output → value.data,documentContent → value.context.html;view_image’s attachment lives onvalue.image.ReviseEditorToolExecutionResultno longer exists.tools.execute()is typed and no longer routesdocument_id.execute()/call()take the generated per-tool input types and cover the shared 24-tool contract; untrusted model calls — including the browser-onlyget_selection,view_image, andrevise_run_agent, and model-facingdocument_idrouting — go through the newexecuteDynamic(), exactly as on the server.- Unknown tools and role denials are results, not throws.
execute()returns{ ok: false }withcode: "unknown_tool"or"role_not_permitted"instead of throwing; the newtools.call()throws a typedReviseToolErrorfor hosts that prefer exceptions.ReviseRoleErroris still thrown byagent.run()and UI controllers. - ID-keyed suggestion decisions return per-ID outcomes.
review.acceptSuggestions/rejectSuggestions,review.acceptCommentSuggestions/rejectCommentSuggestions, andtools.acceptAllSuggestions/rejectAllSuggestions, and the server session’sacceptSuggestions/rejectSuggestionsreturn{ resolved, missing, unresolved }(ReviseSuggestionDecision) instead of a bare count. Stale IDs land inmissing; a role that may not resolve reports everythingunresolved.review.acceptAll()/rejectAll()keep their boolean UI-gesture contract. - Server sessions default to suggesting mode.
createServerDocumentSessionwithoutmodenow proposes tracked changes instead of applying edits directly — the same default posture as the browser surface, and the safe one. Passmode: "editing"(or per-calldirectMode: true) for direct application.
Added
-
Browser mutation results report created suggestion IDs. Successful
mutations carry
suggestionIds— the tracked records that call created (empty for direct edits,nullfor read/search/measure tools) — with a concurrent human suggestion never attributed to the tool call. Feed them straight toreview.acceptSuggestions(). -
The tool contract types ship from both entries.
ReviseToolResult,ReviseToolResponse,ReviseToolFailure,ReviseToolError,ReviseSuggestionDecision, the generatedReviseToolInputMap, and friends are exported by@reviseio/sdkand@reviseio/sdk/backendalike. -
Server mutation results report the tracked records they created.
Successful mutation calls from
createServerDocumentSessionnow carrysuggestionIds— the tracked suggestion records that call created (empty for direct edits,nullfor read/search/measure tools) — so a host can persist per-edit IDs with its review workflow instead of diffing the document-global pending set. -
listSuggestions()returns every pending suggestion as a reviewable record with authorship metadata (authorType,agentName,agentModel,source,label,createdAt), so hosts can decide on their own agent’s suggestions and leave collaborators’ pending work alone. -
acceptAllSuggestions()/rejectAllSuggestions()make the whole-document decision an explicit, greppable call instead of theacceptSuggestions(getPendingSuggestionIds())idiom.
Fixed
- Server tool types now resolve for
moduleResolution: "NodeNext"consumers. The packaged declarations re-exported the server tool contract through extensionless relative specifiers, which NodeNext cannot resolve — every tool input/output type silently degraded toany, and importing a contract type by name (e.g.ServerDocumentSession) failed to compile. The declarations now use explicit.jsspecifiers, which every supported resolution mode maps to the sibling.d.tsfiles. - Importing a document with code blocks no longer risks crashing a Node
host. The canvas syntax highlighter tried to fetch its tree-sitter wasm
under Node (the server DOM shims install a jsdom
window, defeating its browser check), failing as an unhandled promise rejection. Highlighting now recognizes the server runtime explicitly and stays off, and a failed highlighter init in the browser no longer poisons later attempts. - Table and list mutations no longer spam
Invalid accesswarnings. Building table rows, cells, and list items called Yjspush()on elements not yet integrated into a document, which logs a warning per child. Construction now inserts children at explicit indices — dozens of stderr lines per table insert in server logs, gone. - Editing mode applies server edits directly again. A server session in
"editing"mode quietly recorded every mutation as a pending tracked suggestion instead of applying it. Editing-mode calls now run in the runtime’s direct mode and settle within the call, matching the documented behavior; an explicit per-calldirectModestill overrides in either direction.
0.9.0
Added
review.listChanges()now reports linked moves as moves. A move pair surfaces as ONEReviseTrackedChangewithkind: "move",moveSourceBlockIds/moveDestinationBlockIdslocating each half, anddeletedText/insertedTextcarrying the text as it left and as it arrived. Previously both halves were folded into a single change labeled"delete", leaving a host review panel no way to distinguish a move from a replacement. Accept/reject semantics are unchanged: resolving the change settles both locations atomically.
0.8.0
Added
- Cut and paste now creates native linked moves in Suggesting mode. Cutting text from supported paragraphs and pasting that same internal clipboard payload elsewhere in the document produces one atomic “Moved from”/“Moved here” pair. Accepting or rejecting either half resolves both locations, undo cannot strand an orphaned half, and DOCX export/reimport preserves native linked move markup. Copy/paste, editing mode, reused or mismatched clipboard payloads, and unsupported structural selections continue to use ordinary insertion/deletion behavior.
0.7.0
Added
- Server-side semantic tools.
await createServerDocumentSession(ydoc, { documentId, mode })in@reviseio/sdk/backendbinds the canonical document-local agent tools — read, search, measure, mutate, layout, footnotes, tables, comments — to a host-owned Y.Doc under plain Node.mode: "suggesting"produces Word-compatible tracked changes with accept/reject; concurrent calls are serialized; literal tool calls infer their schema inputs and structured outputs. See the README’s “Server semantic tools” section. - Linked Word moves now round-trip as atomic move suggestions. DOCX import
pairs native
w:moveFromandw:moveToranges across runs, paragraphs, and table cells. Accepting either half keeps the text at its destination; rejecting either half restores its original location; export re-emits native paired move markup. Suggestion cards distinguish “Moved from” and “Moved here”, and focusing either half highlights its partner even across paragraphs.
Fixed
- Node-side DOCX imports preserve tracked table-row revisions without a
browser
FileReader. The backend DOM shims and table-revision postprocessor now work fromBlob.arrayBuffer(), retaining row insertion and deletion metadata in server integrations. - Word comment anchors preserve their identity and semantic range. Safe native numeric IDs no longer shift, cross-paragraph and table-cell ranges emit one anchor triple instead of duplicates, and collapsed, overlapping, threaded, and resolved comments survive repeated round trips.
- Visible drawing text survives DOCX import when shape geometry is
flattened. Inline and anchored DrawingML, grouped shapes, legacy VML,
headers, and standards-valid
mc:AlternateContentChoice/Fallback content become editable paragraphs in reading order without duplicate fallback text. - DOCX archives no longer inflate and large imports avoid repeated work. Generated packages use DEFLATE compression, parse the main document XML once, and skip move indexing when a file has no moves, preventing the reported multi-fold output growth and superlinear no-move scan.
0.6.0
Added
- Horizontal rules and ornamental dividers are now supported throughout the
editor. Insert thin, thick, double, dashed, dotted, star, or diamond
dividers from the toolbar or context menu, or create them with text triggers
such as
---,===,-**-, and-<>-. DOCX, HTML, Markdown, agent HTML, PDF, and plain-text output preserve the divider where the format permits; DOCX, HTML, Markdown, RTF, and ODT imports recognize their native divider or paragraph-border representations.
Changed
- Em-dash autocorrection now waits for a word boundary. Typing
--remains literal until Space or Enter, allowing---to be used for horizontal-rule insertion and preserving word-initial values such as--flag.
Fixed
- Words no longer wrap in the middle at formatting or tracked-change run boundaries. A word split across differently styled text nodes now wraps as one unit and keeps a stable layout when suggestions are accepted.
- Suggestion editing produces stable runs and caret placement. Continued typing or backspacing merges into the existing suggestion instead of creating one run per keystroke, replacement normalization no longer leaves the caret inside hidden deleted text, and Enter after a pending deletion creates the expected paragraph or list item without moving the deleted content.
- Structural editing keeps the expected document shape and keyboard focus. Backspace exits or splits empty list items correctly, compatible lists rejoin when their separating empty paragraph is removed, Enter at the start of a leading heading or code block creates a body paragraph above it, and toolbar commands no longer steal keyboard focus from the editor.
0.5.1
Fixed
- PDF table-of-contents page numbers stay accurate when a heading moves to the next page. Export now records a heading’s destination after paragraph pagination, so a keep-with-next or end-of-page preflight cannot leave the TOC pointing at the page the heading would have occupied before it moved.
0.5.0
Added
- Comments now work on list items, including nested items. Selecting list
text, expanding a word from the caret, and commenting on a whole item all
create item-local anchors. Returning the caret to that text activates the
thread, list-item threads survive agent-HTML round trips, and the
leave_commentagent tool accepts list-item IDs.
Changed
- PDF export now follows the editor’s layout and print semantics much more closely. It shares wrapping and pagination rules for tab stops and leaders, hyphenation, keep-with-next, keep-lines, widows and orphans, code blocks, nested tables, footnotes, page and section breaks, live TOC page numbers, line numbers, and watermarks. Editor-only placeholders and review chrome are not printed, and Word hidden text remains hidden in ordinary PDF output. The SDK now carries its metric-compatible PDF fonts itself, so an embedding host does not need to mirror Revise’s public font directory.
- Agent tool sessions reject redundant full-document read loops. After a
session has read the complete document, another sequential
read_documentreturnsno_new_read_context; agents can still revisit known content withread_specific_blocks.
Fixed
- DOCX formatting exceptions survive a complete edit and export cycle. Explicit run-property clears over named styles, zero paragraph indents, paragraph border and shading clears, decimal font sizes, and mixed small-cap and all-cap overrides now remain distinct from inherited formatting and do not leak into adjacent text.
- Complex Word structures no longer lose modeled content on re-export. Internal bookmark links stay internal; exact table widths, columns, alignment, cell padding, and vertical alignment survive; nested tables keep the paragraphs around them; display equations are not flattened when a file is immediately re-exported; and multi-block footnotes and endnotes can retain their lists and tables.
- Accepting or rejecting a compound agent edit is atomic. Mixed text, formatting, and structural suggestions are resolved together, so accepting a rewrite no longer retains deleted fragments and rejecting it restores the original content and formatting.
- Comment cards stay where users put them. A previously active card no longer drifts with the viewport, and selecting text inside a card no longer jumps focus back to the document or clears the selection. Inline code in comment bodies is also styled as code.
- Package managers can no longer omit the Yjs runtime. Every editor session
is Yjs-backed even without a collaboration provider, so
yjsandy-protocolsare now required peers instead of optional peers. This makes package managers install or validate them instead of letting bundlers substitute empty optional-peer modules and fail the consumer build.
0.4.5
Fixed
- Starting a list no longer drops the font. Typing a list trigger
(
-,1.,[]) in a paragraph set in a non-default font produced a list item that fell back to the default font: clearing the trigger text left an empty item with nowhere to carry its formatting. The formatting at the trigger’s trailing edge — the font family included — is now preserved on the empty item and applies to the next character typed.
0.4.4
Fixed
- Suggestion cards now hang from the suggested text. The floating accept/reject card anchored to the caret; it now follows the suggested fragment (or your selection) and sits centered below its line, the same placement the revise.io app uses, falling back to the caret only when the fragment cannot be measured. Wide cards are clamped to the page edges instead of a fixed margin.
0.4.3
Identical in content to 0.4.2; republished.0.4.2
Fixed
- Word-level diffs misplaced edits next to repeated words. When the text adjacent to an edit repeated a word from the edit itself (replacing “[Berkshire County / appropriate Massachusetts county],” with “Suffolk County, Massachusetts,” just before “Massachusetts will”), the unchanged suffix could be drawn as deleted and retyped. Unchanged repeated words now stay anchored as unchanged, in tracked changes and the diff view alike.
- Writing a comment no longer collapses the comments margin. Finishing a draft that had itself opened the margin always collapsed it — even when submitting had just created a thread, so the pages jerked sideways in both directions and hid the card the user just wrote. The margin now stays open on the new thread; only an abandoned draft with no other open thread collapses it.
- Comment card placement around drafts and tracked changes. A comment draft started while hovering the card stack could pin its card — and drag the viewport — to the top of page 1; it now anchors where the draft was made. A caret inside a resolved thread’s highlight, or inside an imported thread’s replies, activated no card at all; it now activates the right open thread. And when a commented paragraph also contains tracked changes, the card describes the change under the cursor instead of jumping to the top of the paragraph.
- The selection card no longer chases the pointer mid-drag. While the mouse button is down nothing pops up under the pointer; the card appears on release, anchored below the selection the user meant.
0.4.1
Fixed
- Opening the export menu crashed. An icon component in the export menu referenced React without importing it, which the packaged build has no global to fall back on.
0.4.0
Changed
- The default entry no longer ships Tree-sitter syntax highlighting or the embedded WASM payload. Code blocks still render as code, and every WASM hot path has a TypeScript implementation. This keeps the normal integration smaller and compatible with strict Content Security Policies. Optional features now load as async chunks inside the package.
Added
@reviseio/sdk/full— an opt-in entry point that keeps token-coloured code blocks and the WASM hot paths. The API and stylesheet are identical between the two entries.
0.3.4
Fixed
- The SDK no longer attempts any telemetry. Earlier builds emitted editor health metrics toward a Revise backend that does not exist in your deployment, which could only fail — loudly, as console CORS errors — and represented network calls you never asked for. Telemetry is now something only the revise.io application itself can switch on; embedded editors send nothing anywhere: no metric POSTs, no analytics vendor code, no beacons.
Added
onAnalyticsEvent— the editor’s own instrumentation, delivered to the host instead:<ReviseEditor onAnalyticsEvent={(event, properties) => ...} />. Forward events to your own analytics service; a throwing handler never breaks the editor. Event names and property shapes are internal and version-unstable.
0.3.3
Four suggesting-mode fixes, two of them content corruption. If your users edit insuggesting mode — the mode this SDK exists for — take this
release.
Fixed
- Pasting in suggesting mode corrupted the document. The paste path predated suggesting mode: it duplicated the rest of the paragraph and inserted the pasted text without tracked-change marks, so the paste was invisible to review and survived reject. Pasting is now recorded exactly as if the pasted characters had been typed — an insertion suggestion, plus a deletion suggestion for any replaced selection.
- Formatting across a pending change destroyed it. Applying bold (or any
inline format) over a range touching a pending insertion or deletion
overwrote the change’s identity; resolving the format then silently turned
a pending insertion into accepted text, or resurrected deleted text.
Formatting now leaves deletion spans alone, folds into insertion spans (as
Word nests run properties inside
w:ins), and records a reviewable format change only on unmarked text. - Accepting a deletion that crossed a paragraph boundary left the paragraphs unmerged. The boundary is now part of the suggestion, as the pilcrow is in Word: accepting merges the paragraphs, in any resolution order, for any number of paragraphs in the selection.
- Copying a selection inside your own pending insertion copied nothing. It now copies the selected text. Clipboard payloads are also sanitized so tracked-change marks never travel with copied content.
Console
- Opening a document no longer logs to the console (previously one Yjs
warning per block plus two internal debug lines).
console.warnandconsole.errorremain for genuinely actionable problems.
0.3.2
Fixed
editor.whenReady()was missing from the published type declarations. It worked at runtime, but TypeScript rejected the call the documentation tells you to make.
0.3.1
Fixed
- Using the editor handle from
onReadyno longer throws.onReadyfires before any document exists, and “subscribe to everything on ready” is the first thing a host writes — a subscription placed then now waits and attaches when a document arrives.selection.observe()was affected too. Methods that act on a document still fail loudly, and the message now names the fix.
Added
editor.whenReady()— resolves once a document is open and its controllers are usable.REVISE_SDK_VERSIONandREVISE_SDK_BUILDexports, and abugsentry in the manifest: a support ticket can name the exact build it came from.
0.3.0
Collaboration
Multi-user editing over a Yjs transport you own. The editor builds the document; you attach the connection:editor.collaboration), seed-or-join
semantics, and validation of any document you supply. See the collaboration
guide.
Roles
role="editor" | "suggester" | "viewer", editor-wide or per document, and
enforced on every surface: typing, the built-in chrome, the handle, and agent
tool calls. A suggester cannot leave suggesting mode, apply anything directly,
or accept and reject.
Tracked changes you can list
review.listChanges() and review.getChange(id) return each pending change
with its kind, author, timestamp, affected blocks, and text — enough to build
your own review panel. Imported Word redlines keep their original reviewers.
Server-side primitives
New subpath export@reviseio/sdk/backend (Node only): parseDocument,
fileToYDoc, seedYDocFromFile, ydocToDocx, encodeYDoc/decodeYDoc.
Your server can create a collaborative room from a .docx before any browser
connects, and export a live room without one. Requires jsdom.
Breaking
yjsandy-protocolsare now peer dependencies and are no longer bundled. Install them yourself, and make sure your bundler resolves ONE copy — Yjs identifies its own types withinstanceof, so a second copy breaks a shared document. Only collaboration needs them; they are optional peers.ReviseDocumentInput.docxis now optional, since a document joining a collaborative room needs no source file. Inputs must supplydocx,collaboration, or both.
Fixed
search_result_id, which the agent tool schemas advertise for bulk edits, was unusable: tool state did not survive betweentools.execute()calls.exportDocx()omitted TOC page numbers, which only the live layout knows.- Exports lost imported named styles and reset core property dates in any non-browser environment.
collaboration.syncedwas read once at mount, so a host reporting sync later was ignored and the document never opened.- The margin insert-comment chip was missing from the embedded editor.
- Presence colours: an explicit
currentUser.colorwas ignored whenever the user had an id.