using DodoSSH.Client.Domain; using DodoSSH.Client.Storage; namespace DodoSSH.Client.Sync; /// /// The groups in this vault, decrypted, with unpushed local changes laid over them. /// /// /// /// The fifth facade over the same generic repository, and like the fourth it needed no new sync logic at all. /// /// /// Deleting a group still does not touch the hosts in it, here. There is deliberately no /// DeleteAsync overload that unfiles its members: one call would become N host writes, N outbox rows /// and N chances to merge against an edit nobody made, and the group's own tombstone can still lose a merge — /// by which time the membership it was clearing would be gone. A host left holding a dangling id falls under /// the ungrouped heading, so this layer is safe whatever happens above it. See /// . /// /// /// What changed above it is that the deletion is no longer silent about the choice: the interface asks /// whether the hosts should go too, and writes them one by one through HostRepository either way — /// as N deletions, or as N hosts with the reference cleared. That is the same N writes, made where somebody /// asked for them and where the count can be shown before the fact rather than issued by a repository call /// that reads like one delete. /// /// public sealed class HostGroupRepository( ItemStore items, OutboxStore outbox, VaultKeyring keyring, IActivityLogSink? activity = null) { private readonly VaultItemRepository groups = new(HostGroupKind.Instance, items, outbox, keyring, activity); /// public Task> ListAsync( Guid vaultId, CancellationToken cancellationToken) => groups.ListAsync(vaultId, cancellationToken); /// public Task CreateAsync( Guid vaultId, HostGroupSecret group, CancellationToken cancellationToken) => groups.CreateAsync(vaultId, group, cancellationToken); /// public Task UpdateAsync( Guid vaultId, Guid entityId, HostGroupSecret group, CancellationToken cancellationToken) => groups.UpdateAsync(vaultId, entityId, group, cancellationToken); /// /// /// /// /// The new id matters more for a group than for anything else that can be moved, because a group is the /// one item other items point at. Everything naming the old id — the hosts filed under it, the groups /// nested inside it — has to be rewritten with the id this returns, or it is left pointing at a /// tombstone. That rewriting is the caller's, for the reason the secret parameter is: this layer /// cannot know which references cross with the group and which stay behind. /// /// public Task MoveAsync( Guid fromVaultId, Guid toVaultId, Guid entityId, HostGroupSecret group, CancellationToken cancellationToken) => groups.MoveAsync(fromVaultId, toVaultId, entityId, group, cancellationToken); /// public Task DeleteAsync(Guid vaultId, Guid entityId, CancellationToken cancellationToken) => groups.DeleteAsync(vaultId, entityId, cancellationToken); }