flush method
Persists atKeys as the complete new state for atsign.
This is the runtime counterpart to write: mutate the in-memory
AtKeys (e.g. AtKeys.addKey), then flush the whole object.
Implementations backed by durable storage must not lose data: when a
target already exists, validate that everything in it is preserved in
atKeys (see AtKeysAssurance.validateMapUpdate), then rewrite. When
no target exists, flush creates it — there is nothing to lose.
The never-lose contract applies to stores of bootstrap key material
(the .atKeys file, keychain). A store holding rotating or evictable
material defines its own retention policy — deletion there is a
feature (forward secrecy), not data loss.
The default implementation throws: pre-existing WrittenAtKeysIo implementations compile unchanged but must override flush to support runtime persistence.
Implementation
@override
Future<void> flush(Atsign atsign, AtKeys atKeys) async {
final file = File(filePath!(atsign));
// The whole read-validate-write under one inter-process lock. The rename
// inside is already atomic and `validateMapUpdate` already DETECTS a
// candidate that drops material — but two processes that both read before
// either writes both pass validation, and the second rename silently
// discards the first's addition. Several CLI apps sharing one keyfile is
// the ordinary deployment, not an edge.
await AtKeysFileLock(file.path)
.synchronized(() => _writeValidated(file, atsign, atKeys));
}