diff --git a/NucleicRemote/NucleicRemote/Models/IdentityStore.swift b/NucleicRemote/NucleicRemote/Models/IdentityStore.swift index ecfbe49..fa26ed4 100644 --- a/NucleicRemote/NucleicRemote/Models/IdentityStore.swift +++ b/NucleicRemote/NucleicRemote/Models/IdentityStore.swift @@ -112,6 +112,26 @@ enum IdentityStore { savePairedHosts(pairedHosts().filter { $0.fingerprint != hostID }) } + /// Merge a Mac learned via mesh roster gossip (mesh "join"): append it if new, else refresh its + /// hints **in place** — unlike `upsertPairedHost`, this must NOT reorder (which would hijack the + /// active host) and must not clobber a relay token or our established device id with the + /// gossiped nils. + static func mergePairedHost(_ host: PairedHost) { + var hosts = pairedHosts() + if let index = hosts.firstIndex(where: { $0.fingerprint == host.fingerprint }) { + var merged = host + let existing = hosts[index] + merged.deviceID = existing.deviceID // keep our established id for this host + merged.relayMembershipToken = host.relayMembershipToken ?? existing.relayMembershipToken + merged.relayRoomID = host.relayRoomID ?? existing.relayRoomID + merged.relayURL = host.relayURL ?? existing.relayURL + hosts[index] = merged + } else { + hosts.append(host) + } + savePairedHosts(hosts) + } + /// Mutate one host's record **in place**, preserving registry order — unlike /// `upsertPairedHost`, this must not make the host active (it backs background /// refreshes like the relay-membership push, which can arrive from a non-active Mac).