Repository navigation
[pull] main from loro-dev:main - #208
Merged
Merged
Conversation
, #1151; #1149 documented) (#1171) * fix: reject imports that reuse local op ids with different content (#1118) Importing history from a client that shared a peer id trimmed the "known" part by version vector and applied the tail on top of different local history: it panicked in state apply (poisoning the doc, aborting on drop) or silently scrambled text. Compare the overlap with local history before anything is mutated and return UsedOpID; also reject changes that skip counters of their peer instead of tripping a DAG assertion. Rationale: context/import-peer-id-reuse.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: drop subscriber callbacks outside the subscriber set lock (#1162) Dropping a subscriber's callback runs arbitrary code; when it owns another Subscription or an UndoManager on the same doc, their drop re-entered the set's mutex on the same thread and deadlocked. The unsubscribe closure, retain's dropped-subscriber sweep, and remove() now move the removed subscribers out and drop them after releasing the lock. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: export several non-contiguous spans of one peer in updates_in_range (#1155) export_blocks_in_range inserted every selected change into one temporary change store, which requires each peer's counters to be contiguous, so two non-contiguous spans of one peer panicked under the op log lock. Merge the ranges per peer and put the k-th range of every peer into the k-th store; the blocks of all stores are written one after another. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: accept a style start without its end in snapshots (#1165) A version addressed with op-level frontiers can hold a mark's StyleStart but not its StyleEnd. checkout keeps the lone start anchor, but the fast state decoder rejected it, and the first read of a fork or snapshot panicked under the doc locks. Decode it the way checkout keeps it (no style range until the end arrives), relax the debug-only pair checks accordingly, leave it alone in dead-style redaction, and only advance a shallow root past a StyleStart when the StyleEnd exists in the op log. Rationale: context/shallow-snapshot-style-redaction.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: migration advice for legacy text delete start_ids (#1149) Deletes written by WASM loro-crdt <= 1.16.3 can name the wrong characters in start_id. The ops are immutable and the affected readers (shallow-snapshot placeholders, cursors on deleted text) have nothing but start_id, so the history is not repaired in code. Document which paths stay correct and how to avoid the wrong ones, and pin that advice with a test on a forged legacy history (plus the still-divergent shallow root before the delete). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: show empty root containers touched by imported history (#1156) A root is visible when the state store has it. The writing peer creates it with its first local op, but an import only did so when the root's net diff was non-empty, so text inserted then deleted showed {"t": ""} live and {} in a replay. After an attached import, and after a checkout to the latest version, create the state of every non-mergeable root the diff calculator touched. Getting a root handle also makes it visible, by design; that half of the issue's random workload is an API decision and is documented, not changed. Rationale: context/root-container-visibility.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: keep arena indices when a failed import is rolled back (#1164) A failed import's arena rollback freed the indices of containers registered during the import, while DocState store entries, the dead-container cache and handlers on other threads still referred to them. The next container registered at a freed index inherited the old state. The rollback now keeps every index and drops only what the failed import may have told the arena (parent links of new normal containers, cached depths), plus values and text; every rollback path also clears the dead-container cache. Rationale: context/failed-import-arena-indices.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: emit tree events for revived subtrees on import (#1157) In the Linear and ImportGreaterUpdates diff modes the tree diff is the raw ops, and TreeState::apply_diff_and_convert labeled a move that brought a node out of a deleted subtree as a single Create. The nodes below it got no Create, so a tree rebuilt from events lost them. In Linear mode a move of an alive node under a deleted one also emitted no Delete, and in ImportGreaterUpdates mode Create ops skipped the cycle check that apply_diff applies. Raw Create/Move ops are now classified by whether the target is alive before and after the op, and a revived node is followed by a Create for each node of its subtree. Checkout-mode diffs are unchanged. Rationale and the local-event gap: context/tree-events.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: make apply_diff/revert_to all-or-nothing (#1154) A batch that fails is rolled back: its ops are taken out of the transaction (uncommitted edits before it stay), undone from the state by a checkout through a temporary change under an import rollback scope, and removed from the DAG. No event is emitted. A stale tree diff naming a missing parent now returns an error instead of panicking. Rationale, reused op ids and the multi-thread fallback: context/apply-diff-atomicity.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(loro-crdt): keep the known keys of a map event with an unknown child (#1151) A map event that set a key to a container of an unknown type (created by a newer loro-crdt) failed to convert as a whole, so edits to known keys in the same event never reached subscribers. Leave out only the unknown child's entry. List events holding an unknown child are still left out whole, and delivering the unknown child itself needs a public representation (an API decision); see context/unknown-containers.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The two "major" changesets (rich-text anchors, text interop) bumped loro.js from 0.2.1 to 1.0.0. Keep it on 0.x: mark them minor and refer to the release as 0.3 in the changesets and the README upgrade guide. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…t stored data (#1172) * fix: export an unprunable shallow root verbatim Re-exporting a shallow doc at its own root filtered the cached root state and returned an error when the state was inconsistent. The error was not cached, so every export failed again and only fork() worked. Fall back to the verbatim root, as exporters before #1123 did: nothing referenced is dropped. See context/internal-encoding.md. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: report an unparsable change block instead of panicking in the creator resolver The resolver runs under the state lock from queries that cannot return an error. It now records the block and answers CreatorOp::Corrupt; import, export and checkout then return a DecodeError. See context/arena-parent-links.md. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: check an unparsable change block only where an error can be returned The check sat in _checkout_without_emitting, so once a block was recorded, undo, checkout_to_latest and a detached fork panicked on the new error (they unwrap it). Check it in checkout, diff, revert_to, import and export instead; merge propagates the export error. Every reader of the change store now records a block it cannot parse, not only the creator resolver, and export checks again when it is done, so it cannot return updates that silently miss the block. See context/arena-parent-links.md, "A block that cannot be parsed". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )