Unlinking a device is one flow in the core: link::unlink

The desktop's sync_unlink and the ffi's unlink were both written out in full: try
the revoke, clear the link either way, and log the outcome. link::unlink(db, held)
now does that. Each client reads its link with state::credentials (with its seal)
before the await and passes it in.

DRY pass #2, batch 1, F3 (#5372).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 14:16:59 -04:00
co-authored by Claude Opus 5.5
parent 91c47245ab
commit 1f2ddd70d3
3 changed files with 31 additions and 27 deletions
+2 -11
View File
@@ -121,21 +121,12 @@ pub struct UnlinkResult {
/// honestly, and the link cleared either way.
#[tauri::command]
pub async fn sync_unlink(db: State<'_, Db>) -> Result<UnlinkResult, String> {
// Read and release before the network call: a std MutexGuard isn't Send, and
// holding the store across a round-trip would freeze every note operation in
// the UI.
let link = {
let held = {
let conn = db.conn()?;
state::credentials(&conn, None).map_err(|e| e.to_string())?
};
let revoked = match &link {
Some((base_url, token)) => client::revoke_self(base_url, token).await,
None => client::RevokeOutcome::Skipped,
};
let revoked = link::unlink(&db, held).await?;
let conn = db.conn()?;
state::clear_link(&conn).map_err(|e| e.to_string())?;
log::info!("unlinked from server (server-side token: {revoked:?})");
Ok(UnlinkResult {
status: state::status(&conn).map_err(|e| e.to_string())?,
revoked,