Skip to content

Commit 6423a8d

Browse files
committed
fix(SyncProcess): Avoid recreating items that already have a mapping to an existing target tree item
Signed-off-by: Marcel Klehr <mklehr@gmx.net>
1 parent 37cf786 commit 6423a8d

1 file changed

Lines changed: 38 additions & 0 deletions

File tree

src/lib/strategies/Default.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,44 @@ export default class SyncProcess {
947947
return
948948
}
949949

950+
// The scan flagged this as a creation, but a surviving mapping may already point it at an item
951+
// that still exists on the target. This happens when the common-ancestor cache was reset
952+
// (account.init() wipes cache+mappings) or rolled back (an interrupted atomic sync persists
953+
// cache+mappings while the server discards its working copy): the scan re-sees an
954+
// already-synced item as "new". Re-creating it would duplicate it on the target and the later
955+
// addMapping would evict the surviving mapping, orphaning one copy → a silent drop. Instead,
956+
// reconcile the source subtree against the existing target item and only create genuinely-new
957+
// descendants.
958+
const mappedTargetId = Mappings.mapId(mappingsSnapshot, action.payload, targetLocation)
959+
const existingTargetItem = (typeof mappedTargetId !== 'undefined' && mappedTargetId !== null)
960+
? targetTree.findItem(action.payload.type, mappedTargetId)
961+
: null
962+
// Only treat it as already-present if it is still genuinely mergeable. A URL change, for
963+
// instance, keeps the local id (so the mapping survives) but is intentionally recreated
964+
// rather than merged (Scanner refuses to merge bookmarks whose url changed) — that must fall
965+
// through to a real CREATE, not be swallowed here.
966+
if (existingTargetItem && action.payload.canMergeWith(existingTargetItem)) {
967+
const subScanner = new Scanner(
968+
this.mappings,
969+
existingTargetItem, // target tree
970+
action.payload, // source tree
971+
(oldItem, newItem) => (
972+
oldItem.type === newItem.type &&
973+
oldItem.canMergeWith(newItem) &&
974+
!Mappings.wouldEvictUnrelatedMapping(mappingsSnapshot, oldItem, newItem)
975+
),
976+
this.hashSettings,
977+
false,
978+
true,
979+
true,
980+
)
981+
const scanResult = await subScanner.run()
982+
scanResult.CREATE.getActions().forEach(a =>
983+
targetPlan.CREATE.commit({type: a.type, payload: a.payload})
984+
)
985+
return
986+
}
987+
950988
const concurrentRemoval = targetScanResult.REMOVE.getActions().find(targetRemoval =>
951989
// target removal removed this creation's target (via some chain)
952990
Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, sourceTree, action.payload, targetRemoval, findChainCacheForCreations)

0 commit comments

Comments
 (0)