Skip to content

fix: correct the onLoadDocument callback type and skip the document self-apply - #1155

Merged
janthurau merged 1 commit into
ueberdosis:mainfrom
ramin-010:fix/on-load-document-self-apply
Sep 10, 2026
Merged

janthurau merged 1 commit into
ueberdosis:mainfrom
ramin-010:fix/on-load-document-self-apply

Conversation

@ramin-010

Copy link
Copy Markdown
Contributor

The callback that handles onLoadDocument return values has two problems.

The parameter is annotated Uint8ArrayConstructor instead of Uint8Array. It only
typechecks because the instanceof check narrows it at runtime. 667e145 added that
branch and describes the hook as accepting "a yjs update (Uint8Array or Buffer) or a
Y.Doc", so the annotation says the opposite of what the branch is for.

The same callback also applies a document to itself. When a hook returns the document
it was given, loadDocument runs applyUpdate(document, encodeStateAsUpdate(document)).
Encoding a document's own state and applying it back can never add content, but it costs
a full encode and apply on the first connection to every document.

The bundled Database extension used to return the document, and c4c6094 removed that
return for this reason (#849, closing #848). The core was never guarded, so any hook that
still returns its document keeps paying the round trip.

This skips the apply when the returned instance is the same one. Returning a different
Y.Doc or a Uint8Array is unchanged.

Two tests:

  • does not apply the document to itself when onLoadDocument returns it — records
    transaction origins after the hook returns and asserts none is null. The self-apply
    calls applyUpdate with no origin, while the client sync carries a
    ConnectionTransactionOrigin, so a null origin can only be the self-apply. Fails on
    main with 1.
  • applies a document returned by the onLoadDocument callback — no existing test returned
    a different Y.Doc, so the merge branch had no coverage once the skip is in place.
    This pins it.

…elf-apply

The callback that consumes onLoadDocument return values annotates its
parameter as Uint8ArrayConstructor rather than Uint8Array. It only
typechecks because the instanceof check narrows it at runtime. 667e145,
which added that branch, describes the hook as accepting "a yjs update
(Uint8Array or Buffer) or a Y.Doc", so the annotation contradicts what
the branch is for.

The same callback also re-applies a document to itself. When a hook
returns the document it was given, loadDocument runs
applyUpdate(document, encodeStateAsUpdate(document)). Encoding a
document's own state and applying it back can never add content, but it
costs a full encode and apply on the first connection to every document.

The bundled Database extension used to return the document and had that
return removed in c4c6094 (ueberdosis#849, closing ueberdosis#848). The core was never
guarded, so any hook that still returns its document keeps paying the
round trip. Skip it when the instance is the same; returning a different
Y.Doc or a Uint8Array is unchanged, and the new test for that path covers
the merge branch, which no existing test exercised.
@coderabbitai

coderabbitai Bot commented Sep 9, 2026 •

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Advanced

Run ID: 380987c0-61da-4551-a44e-9c7013fb1750

📥 Commits

Reviewing files that changed from the base of the PR and between 6ddc757 and 13bba9b.

📒 Files selected for processing (2)
  • packages/server/src/Hocuspocus.ts
  • tests/server/onLoadDocument.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Summary

Summary

  • Corrected the onLoadDocument callback type to use Uint8Array.
  • Skipped self-applying a document when the callback returns the same Y.Doc.
  • Added tests for same-document and different-document returns.

Walkthrough

Changes

The document loading callback now uses the correct Uint8Array type and skips state reapplication when it returns the existing document. Tests cover both same-document and replacement-document results.

Document loading

Layer / File(s) Summary
Load document callback behavior
packages/server/src/Hocuspocus.ts
The callback type now uses Uint8Array. The loader returns early when the hook returns the existing Document.
Document loading validation
tests/server/onLoadDocument.ts
Tests verify that the existing document is not reapplied and that a separate Y.Doc is applied to the provider document.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to 13bba

Document loading now avoids redundant self-application while preserving application of separately returned documents, with coverage for both paths. No merge-blocking risk remains.

Suggested labels: complexity: easy

Suggested reviewers: janthurau

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description check ✅ Passed The description clearly explains the callback type correction, the self-apply optimization, and the added tests.
Title check ✅ Passed The title clearly summarizes both main changes: correcting the callback type and skipping self-application.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

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

@coderabbitai coderabbitai Bot added the complexity: easy Small effort, well-defined scope label Sep 9, 2026
@janthurau
janthurau merged commit 136816d into ueberdosis:main Sep 10, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

complexity: easy Small effort, well-defined scope

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants