Coverage Summary for Class: AbandonAuthSessionUseCase (com.georgeci.moneysurfer.domain.usecase)
| Class |
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| AbandonAuthSessionUseCase |
100%
(2/2)
|
100%
(2/2)
|
100%
(10/10)
|
100%
(87/87)
|
| AbandonAuthSessionUseCase$Companion |
|
| AbandonAuthSessionUseCase$invoke$1 |
|
| Total |
100%
(2/2)
|
100%
(2/2)
|
100%
(10/10)
|
100%
(87/87)
|
package com.georgeci.moneysurfer.domain.usecase
import arrow.core.Either
import co.touchlab.kermit.Logger
import com.georgeci.moneysurfer.domain.auth.SessionMutator
import com.georgeci.moneysurfer.domain.repositories.AuthRemoteRepository
import org.koin.core.annotation.Single
/**
* Undoes a half-finished sign-in: the auth provider accepted the credentials and the session
* pointers were already pinned, but [PostAuthBootstrapUseCase] failed afterwards.
*
* Without this the app is left "signed in" with no workspace, and `resolveStartRoute` sends the
* next cold start straight to the workspace selector — the sign-in screen is skipped, and the
* bootstrap has no retry path of its own (issue #342). Clearing the pointers puts the user back
* on the sign-in form, where retrying re-runs the whole flow.
*
* Deliberately *not* [LogoutUseCase]: nothing was hydrated yet, so there is no local data to
* wipe and no shutdown gate to trip. The `users` row written by
* [com.georgeci.moneysurfer.domain.auth.AuthLocalRepository] is left in place — it is an idempotent
* upsert that the retry rewrites anyway, and deleting it would cascade into rows a later attempt
* still wants.
*/
@Single
class AbandonAuthSessionUseCase(
private val sessionMutator: SessionMutator,
private val authRemoteRepository: AuthRemoteRepository,
) {
private val log = Logger.withTag(TAG)
/**
* [isAnon] must be `true` for an anonymous sign-in. An anonymous account has no credential to
* sign back in with: `signInAnonymously()` reuses `auth.currentUser` when there is one and
* mints a brand-new uid otherwise. Signing out would therefore make the *previous* anonymous
* account — and whatever it already owns on Firestore — permanently unreachable, over what may
* be a transient bootstrap failure. Clearing the local pointers is enough to put the user back
* on the sign-in screen; the provider session is left alone so a retry lands on the same uid.
*/
suspend operator fun invoke(isAnon: Boolean) {
log.w { "[rollback] clearing session pointers after a failed post-auth bootstrap" }
// One store edit, so a crash mid-rollback cannot leave a half-cleared session behind —
// which is the state this use case exists to get out of.
sessionMutator.clearSession()
if (isAnon) {
log.i { "[rollback] keeping the anonymous provider session — signing out would orphan it" }
return
}
// Best-effort: a provider session that outlives the pointers is harmless — the next
// sign-in overwrites it — but a throw here would mask the original bootstrap failure.
Either.catch { authRemoteRepository.signOut() }
.onLeft { log.w(it) { "[rollback] signOut failed — pointers are cleared regardless" } }
}
private companion object {
const val TAG = "AbandonAuthSession"
}
}