Files
enricobuehler a3a6444e6e
ci / bun-nix (pull_request) Successful in 23s
ci / docs-site (pull_request) Successful in 1m10s
ci / rust-arm64 (pull_request) Successful in 5m59s
ci / web (pull_request) Successful in 6m25s
android / android (pull_request) Successful in 4m20s
ci / rust (pull_request) Successful in 16m23s
feat(host,web): unpair every device from one button, over a collection DELETE per plane
Clearing a host's trust store meant clicking the row trash icon once per
device and confirming each time — tedious with a handful of clients, and
easy to leave half-done.

The "Paired devices" card header now carries an "Unpair all" action behind
a single confirmation. It is backed by two new endpoints rather than a loop
over the per-fingerprint deletes:

    DELETE /api/v1/clients          -> {"unpaired": N}
    DELETE /api/v1/native/clients   -> {"unpaired": N}

one per pairing plane, because the two planes own separate trust stores
with separate persistence and separate revocation duties. Each empties its
store in ONE persisted write. Doing it as N deletes would rewrite (and
atomically rename) the store once per client, and a failure partway would
leave the operator with a half-emptied store and no way to tell which half.

They are collection deletes, so they carry the single delete's revocation
guarantees across the whole set: a live session owned by any removed
certificate is ended, and on the Moonlight side the ENet control port
closes, because no pairing is left to hold it open.

200 with a count rather than the single delete's 204/404: "unpair
everything" is idempotent, an already-empty store satisfies it, and the
count still tells the operator whether that meant three devices or none.

Both gates match on (method, path), so the roster's plugin-readable GET
does not carry over to emptying it — both new routes are admin-token only,
like every other pairing-administration route, with explicit rows in the
route-classification table.

The console calls only the planes that actually have a row: the native
endpoint answers 503 on a host built without that plane, which would
otherwise report a failure for devices that were never there.
2026-08-14 00:35:33 +02:00
..