Skip to content

fix(core): avoid torn Yjs plugin state during fork merge - #3136

Open
nperez0111 wants to merge 1 commit into
mainfrom
fix-issue-3135-collaboration-cursor-merge-crash
Open

nperez0111 wants to merge 1 commit into
mainfrom
fix-issue-3135-collaboration-cursor-merge-crash

Conversation

@nperez0111

@nperez0111 nperez0111 commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes #3135. This closes the cursor crash left after #2952.

  • Give the replacement ySync and yUndo plugins fresh state during an off-view reconfiguration, then update the view once. This keeps the sync type, doc, and binding consistent when y-prosemirror rerenders synchronously and the remote cursor plugin initializes.
  • Preserve original-document undo and redo stacks across fork/merge while isolating fork undo history. Remove the post-swap ySync rebinding transaction.
  • Add regression coverage for Accept and Discard with a remote awareness cursor, plus undo/redo history isolation. Both cursor cases reproduced the reported nodeSize exception without this change.

Verification

  • vp run test in packages/core: 792 passed, 9 skipped
  • vp run lint in packages/core: clean

Out of scope

Undoing an accepted merge is a separate existing behavior: Y.applyUpdate uses the editor as the update origin, which the Yjs undo manager does not track. This PR leaves that origin unchanged.

Summary by CodeRabbit

  • Bug Fixes
    • Merging a fork while a remote cursor is present no longer causes an error, and the cursor remains visible.
    • Undo and redo history now behaves consistently when editing, merging, or discarding fork changes, preserving the expected document content.

@vercel

vercel Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
blocknote Ready Ready Preview Sep 28, 2026 4:02pm UTC
blocknote-website Ready Ready Preview Sep 28, 2026 4:02pm UTC

Request Review

@coderabbitai

coderabbitai Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: a940b80d-5f99-46f1-945e-0683c6f07f33

📥 Commits

Reviewing files that changed from the base of the PR and between 660f8a2 and 591b983.

📒 Files selected for processing (3)
  • packages/core/src/editor/managers/ExtensionManager/index.ts
  • packages/core/src/yjs/extensions/ForkYDoc.test.ts
  • packages/core/src/yjs/extensions/ForkYDoc.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

replaceExtension now supports resetting selected ProseMirror plugin state during replacement. ForkYDocExtension uses this when switching between original and forked documents, preserves undo and redo stacks, and adds tests for remote cursors and history.

Changes

Forked document plugin state

Layer / File(s) Summary
Selected plugin state reset
packages/core/src/editor/managers/ExtensionManager/index.ts
replaceExtension accepts an optional list of plugin keys to reset. The update removes matching keyed plugins from an intermediate state before reconfiguring with the updated plugins.
Fork and merge plugin state
packages/core/src/yjs/extensions/ForkYDoc.ts, packages/core/src/yjs/extensions/ForkYDoc.test.ts
Fork and merge reset ySync and yUndo plugin state. ForkYDoc saves the original undo and redo stacks and restores them after merge. Tests cover merging with remote cursors for both keepChanges values and restoring history after undo.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant ForkYDocExtension
  participant ExtensionManager
  participant EditorState
  participant UndoManager
  ForkYDocExtension->>UndoManager: Save original undo and redo stacks
  ForkYDocExtension->>ExtensionManager: replaceExtension with resetPluginStateFor
  ExtensionManager->>EditorState: Reconfigure plugins with selected state reset
  ForkYDocExtension->>ExtensionManager: replaceExtension during merge with resetPluginStateFor
  ExtensionManager->>EditorState: Reconfigure plugins with selected state reset
  ForkYDocExtension->>UndoManager: Restore saved undo and redo stacks
Loading

Merge Risk: ⚪ Minimal · up to 591b9

The fork and merge changes are mergeable after normal checks; the saved undo and redo history remains available when the old manager is destroyed.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 591b9

The change improves collaboration-state consistency without an established new security exposure. Failure recovery and concurrent-edit behavior remain insufficiently verified.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The directly affected state is the editor’s fork and its configured original collaboration document; accept retains the pre-existing path for propagating changes to that document. No broader service or tenant exposure is established by the available evidence.

Security Findings and Attack Paths

  • inferred — Tracing the supplied update through fork and merge found no PR-added route into the original document: discard does not apply it, while accept uses the existing explicit update path. Caller authorization is not defined in this source.

Trust Boundaries and Controls

  • observed — Fork omits the awareness cursor plugin; merge reinstalls it with the original collaboration options. The remote-cursor regression checks its restoration, not provider-level identity or authorization.

Resilience and Maintainability Implications

  • inferred — An exception between plugin replacement and final store-state updates could leave the visible fork status inconsistent with plugin or document ownership. This is an unverified recovery limitation, not an established new security finding.

Hardening Proposals

  • proposed — Exercise replacement and merge-update failures, retries, and concurrent remote content edits; define how plugin, history, and fork-status ownership is restored after an interrupted transition.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 3 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the primary change: preventing torn Yjs plugin state during fork merge.
Description check ✅ Passed The description provides a clear summary, rationale, implementation details, testing results, and out-of-scope behavior. It does not use all template headings and omits the checklist, but the required…
Linked Issues check ✅ Passed The PR addresses [#3135]. replaceExtension can reset ySyncPluginKey and yUndoPluginKey state during the single plugin reconfiguration. ForkYDocExtension uses this option for both fork and merg…
Out of Scope Changes check ✅ Passed The changes stay within [#3135]. The ExtensionManager option provides the atomic state reset required by the fork and merge fix. The ForkYDoc changes remove the torn-state rebinding step and prese…
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit checks the cursor’s place,
Then watches forked changes race.
The plugins reset; the stacks stay near,
Undo and redo both appear.
The remote cursor finds its way,
And hops through merge without delay.

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

@blocknote/ariakit

npm i https://pkg.pr.new/@blocknote/ariakit@3136

@blocknote/code-block

npm i https://pkg.pr.new/@blocknote/code-block@3136

@blocknote/core

npm i https://pkg.pr.new/@blocknote/core@3136

@blocknote/diagram-block

npm i https://pkg.pr.new/@blocknote/diagram-block@3136

@blocknote/mantine

npm i https://pkg.pr.new/@blocknote/mantine@3136

@blocknote/math-block

npm i https://pkg.pr.new/@blocknote/math-block@3136

@blocknote/react

npm i https://pkg.pr.new/@blocknote/react@3136

@blocknote/server-util

npm i https://pkg.pr.new/@blocknote/server-util@3136

@blocknote/shadcn

npm i https://pkg.pr.new/@blocknote/shadcn@3136

@blocknote/xl-ai

npm i https://pkg.pr.new/@blocknote/xl-ai@3136

@blocknote/xl-docx-exporter

npm i https://pkg.pr.new/@blocknote/xl-docx-exporter@3136

@blocknote/xl-email-exporter

npm i https://pkg.pr.new/@blocknote/xl-email-exporter@3136

@blocknote/xl-multi-column

npm i https://pkg.pr.new/@blocknote/xl-multi-column@3136

@blocknote/xl-odt-exporter

npm i https://pkg.pr.new/@blocknote/xl-odt-exporter@3136

@blocknote/xl-pdf-exporter

npm i https://pkg.pr.new/@blocknote/xl-pdf-exporter@3136

@blocknote/xl-typst-exporter

npm i https://pkg.pr.new/@blocknote/xl-typst-exporter@3136

commit: 591b983

@github-actions

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://TypeCellOS.github.io/BlockNote/pr-preview/pr-3136/

Built to branch gh-pages at 2026-09-28 16:14 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

This branch was successfully deployed

2 active deployments
Preview – blocknote-website — 591b9831 Deployed Sep 28, 2026 by vercel[bot]
Preview – blocknote — 591b9831 Deployed Sep 28, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Collaboration: accepting/rejecting AI changes throws "reading 'nodeSize'" when another client has a cursor (ForkYDoc merge)

1 participant