Conversation
…/Upstash sync mergeWithUpdate had two bugs that prevented local customModels (and any other Config/Access field synced via mergeWithUpdate) from reaching the cloud: 1. remoteUpdateTime was mistakenly read from localState.lastUpdateTime, making the timestamp comparison ineffective. 2. Both branches swapped the merge direction, so when remote was treated as older it still overwrote local with remote, then the empty local value was uploaded to the cloud. Now the comparison uses remoteState.lastUpdateTime and the newer side is merged in-place into localState (which is what setLocalAppState and client.set later upload). Local wins on ties to avoid clobbering new local edits with stale remote values. Verified with 4 scenarios (local newer, remote newer, local changed again, equal timestamps) and yarn test:ci (34 suites / 157 tests).
Moise225
approved these changes
Sep 14, 2026
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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Fixes a WebDAV/Upstash sync bug where locally edited
customModels(and any other field merged viamergeWithUpdate) never reached the cloud, so other devices never received the change.Root cause
app/utils/sync.ts→mergeWithUpdatehad two compounding bugs:remoteUpdateTimewas mistakenly read fromlocalState.lastUpdateTimeinstead ofremoteState.lastUpdateTime, so the timestamp comparison was effectivelylocalUpdateTime < localUpdateTimeand always fell into theelsebranch.if(remote newer) branch calledmerge(remoteState, localState)and returned{ ...remoteState }(solocalStatewas never updated), while theelsebranch calledmerge(localState, remoteState)(remote overwrote local).Combined, the effective behavior was: remote always overwrote local, after which
sync()uploadedlocalState(which now held the stale remote value). Locally edited fields such ascustomModelswere therefore lost on every sync round-trip.Fix
remoteUpdateTimefromremoteState.lastUpdateTime.localState(which is whatsetLocalAppStateandclient.setsubsequently upload):merge(localState, remoteState)so local adopts the remote value and uploads it.Affected fields
Not limited to
customModels.mergeWithUpdateis used by both theConfigandAccessstores, so the same bug affectedmodelConfig,ttsConfig,realtimeConfig,theme/fontSize/fontFamily, and every provider URL/Key/Secret stored inaccess.Validation
yarn test:ci: 34 suites / 157 tests passed, including the existingtest/merge.test.ts.Files changed
app/utils/sync.ts(mergeWithUpdateonly; +10/-6)Notes
No behavioral change for users whose remote was always older than local (they already kept local). The fix specifically restores the intended "newer wins" semantics for the round-trip upload.