fix(offline): logout reopens the Qobuz gate; auth endpoints exempt from it

Logging out of an offline session left offline_session set and the gate
closed, refusing the very OAuth exchange that could end the offline state
(user-reproduced: sign-in failed with OfflineMode after logout). teardown()
now ends the session-scoped offline state (offline_session and the cached
induced flag reset; the persisted preference reloads on the next
activation) and recomputes, reopening the gate when connectivity allows.
Two regression tests added.

The three login methods (login, login_with_oauth_code, login_with_token)
are exempt from the offline gate: user-initiated sign-in is explicit
intent to reach Qobuz; the gate governs services. Verified none of them
reach gated sub-calls; bundle cold-start stays gated on purpose. New unit
test pins the exemption. The recovery sign-in falls back to the full
browser OAuth flow when the saved token is gone or rejected, and
offline_session is lifted only on success paths.

cc
This commit is contained in:
vicrodh committed 2026-06-10 01:32:14 -06:00
1 parent 5fd41e8026
commit c207f232c5
3 files changed
+141 -7

No files matched your search

+13
View File
@@ -33,6 +33,19 @@ where
{
let core = runtime.core();
// Belt-and-suspenders: signing in is an explicit intent to reach Qobuz.
// If a session-scoped offline session is still active (e.g. invoked from
// the login screen after a logout that raced the engine reset), end it so
// the still-gated parts of the pipeline (cold bundle init, post-login
// activation) work. The persisted `induced` preference is NOT touched —
// a successful login reloads it via init_for_user and the app correctly
// lands back in induced offline.
let offline_engine = crate::offline_mode::engine();
if offline_engine.status().offline_session {
log::info!("[qbz-slint] sign-in requested with an offline session active — ending it");
offline_engine.set_offline_session(false);
}
// Ensure the Qobuz client is initialized (bundle tokens).
if !core.is_api_initialized().await {
core.try_init_api().await.map_err(|e| e.to_string())?;