Skip to content

Conversation

@Shervanator
Copy link

Fixes #468

Problem

When merging arrays in mergeIntoObservable, the code only iterated over source array indices. If the source array was shorter than the target, extra elements in the target were never removed.

This caused real-time sync issues across multiple devices/browsers - removing array items would update correctly in the database and locally, but other connected clients would not see the removal.

Why it only affected multi-device sync

With a single browser, the local optimistic update masks the bug. The second browser relies solely on the incoming realtime update, exposing the failure to apply array changes.

Example

// Before fix (broken):
const target = observable({ arr: ['a', 'b', 'c'] });
mergeIntoObservable(target, { arr: ['a'] });
target.arr.get(); // ['a', 'b', 'c'] ❌ extra elements remain

// After fix:
target.arr.get(); // ['a'] ✅## Solution

  • Dense arrays: Replace entirely with set() to ensure correct length
  • Sparse arrays: Continue merging element-by-element to support partial index updates

Sparse array detection: Object.keys(arr).length < arr.length

Backwards compatibility

Sparse array behavior is preserved - partial index updates (e.g., arr[5] = 'x') still merge correctly without affecting other indices.

Fixes LegendApp#468

When merging arrays in mergeIntoObservable, the code only iterated over
source array indices. If the source array was shorter than the target,
extra elements in the target were never removed.

Solution:
- Dense arrays: Replace entirely with set()
- Sparse arrays: Merge element-by-element (for partial index updates)
@Shervanator Shervanator reopened this Nov 27, 2025
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