Skip to content

fix(lib): CRDT list append, remove, move, unique merge, markdown LoroText - #1311

Open
joepio wants to merge 4 commits into
developfrom
cursor/crdt-array-push-8703
Open

fix(lib): CRDT list append, remove, move, unique merge, markdown LoroText#1311
joepio wants to merge 4 commits into
developfrom
cursor/crdt-array-push-8703

Conversation

@joepio

@joepio joepio commented Aug 27, 2026

Copy link
Copy Markdown
Member

Resource.push() used to rewrite the whole Loro list. This PR makes array membership, unique-set merge, markdown, canvas erase, and AI stream tokens use real CRDT ops.

Write APIs

  • push() / Resource::pushlist.append on the existing container
  • removeItems / remove_array_item — delete matching elements by CRDT position
  • moveListItemlist.delete + list.insert (InputResourceArray drag)
  • removeListItemsById — canvas erase by cid:…, not a stale-index rewrite
  • Unique arrays tag resourceArrayUnique and drop duplicate subjects after import
  • Empty lists persist a dummy push+delete so later appends share identity
  • Markdown / description is LoroText (prefix/suffix splice)
  • set() / replaceListItems() stay the explicit replace path

Call sites

  • Share rights, plugin permissions, tags, ontology lists, private-drive favorites use push/remove
  • Canvas erase deletes stroke containers by id
  • AI stream: persist assistant on first tokens, splice text as LoroText, onFinish upserts instead of minting a second message
  • Live LORO_SYNC of canvas, AI chat, and each message/part (useLoroDocSync / useLoroSyncForest)

Tests

  • resource.test.ts: concurrent push/remove, unique dedupe, empty-list persist, markdown merge, move, delete-by-id
  • loro.rs / resources.rs: same on the Rust side

Format-level leftovers (not this PR): Loro MovableList container type, PropVals dual-write / Flutter undo (loro-source-of-truth.md). Human chatrooms stay parent-pointer + query.

See planning/loro-crdt-write-paths.md.

Open in Web Open in Cursor 

push() rewrote the whole Loro list (TS deleted every item and re-inserted;
Rust minted a new container), so concurrent appends duplicated the shared
prefix. Append with list.push instead. set() / replaceListItems still
rewrite in place. Rust set_property reuses list identity so a full replace
does not fork a second list.

Co-authored-by: joepmeindertsma <joepmeindertsma@gmail.com>
@joepio
joepio marked this pull request as ready for review August 27, 2026 06:06
Membership remove was still set(filtered), JSON objects were LWW
strings, and live LORO_SYNC only ran in the document editor.

Resource.removeItems / remove_array_item delete matching Loro list
elements by CRDT id. set_property and TS object writes reuse LoroMap
identity. useArray exposes remove; share, tags, ontology, chat, and
private-drive lists use push/remove. Canvas and AI chat live-sync the
resource doc without TipTap cursors.

Tracked in planning/loro-crdt-write-paths.md.

Co-authored-by: joepmeindertsma <joepmeindertsma@gmail.com>
@cursor cursor Bot changed the title fix(lib): make Resource.push a CRDT list append fix(lib): CRDT list append/remove, map identity, live Loro sync Aug 27, 2026
Canvas erase deletes stroke containers by id instead of rewriting the
list from a stale snapshot. Resource-array drag uses moveListItem.
Unique arrays tag resourceArrayUnique and drop duplicates after import.
Empty lists persist a dummy op so later appends share identity.
Markdown and description write LoroText (prefix/suffix splice). AI
stream tokens persist on first chunk and onFinish updates that
resource instead of minting a second one.

Co-authored-by: joepmeindertsma <joepmeindertsma@gmail.com>
@cursor cursor Bot changed the title fix(lib): CRDT list append/remove, map identity, live Loro sync fix(lib): CRDT list append, remove, move, unique merge, markdown LoroText Aug 27, 2026
pushListItem wrote the new item into the cache first, so the first
getLoroDoc() seeded the list from that cache and then appended again.
Append first, matching push(). Also satisfy oxfmt/tsc on unique-dedupe
keys and list-move no-op padding.

Co-authored-by: joepmeindertsma <joepmeindertsma@gmail.com>
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.

2 participants