Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,19 @@ fun App(deepLinkUri: String? = null) {
) {
ApplyAndroidSystemBars(state.isDarkTheme)

if (state.showRateLimitDialog && state.rateLimitInfo != null) {
// Suppress the rate-limit dialog while the user is on the auth
// screen. They already accepted the prompt and are mid-sign-in;
// re-emitting the same dialog over the auth UI is noise that
// also blocks them from finishing the device-flow steps. Also
// flush any pending flag set by background API calls during
// auth, so it doesn't ghost back when the user returns home.
val onAuthScreen = currentScreen is GithubStoreGraph.AuthenticationScreen
LaunchedEffect(onAuthScreen, state.showRateLimitDialog) {
if (onAuthScreen && state.showRateLimitDialog) {
viewModel.onAction(MainAction.DismissRateLimitDialog)
}
}
if (state.showRateLimitDialog && state.rateLimitInfo != null && !onAuthScreen) {
RateLimitDialog(
rateLimitInfo = state.rateLimitInfo!!,
isAuthenticated = state.isLoggedIn,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -422,9 +422,28 @@ class AuthenticationViewModel(
}

if (outcome.path != authPath) {
logger.debug("Auth path escalated from $authPath to ${outcome.path}")
authPath = outcome.path
savedStateHandle[KEY_AUTH_PATH] = authPath.name
// Mid-session transitions are strictly one-way: only the
// Backend → Direct escalation that AuthenticationRepositoryImpl
// performs on infrastructure errors (timeouts, connect/socket
// failures, 5xx) is legitimate. Direct → Backend is not a path
// the repository ever returns; treat any such outcome as a
// defensive no-op rather than silently flipping back to a
// probably-broken Backend mid-flow. The infrastructure-failure
// gate itself lives at the repository (single source of
// truth — see `pollDeviceTokenOnce` and
// `Throwable.isAuthInfrastructureError()`); the VM only
// enforces direction.
val isLegalEscalation =
authPath == AuthPath.Backend && outcome.path == AuthPath.Direct
if (isLegalEscalation) {
logger.debug("Auth path escalated from $authPath to ${outcome.path}")
authPath = outcome.path
savedStateHandle[KEY_AUTH_PATH] = authPath.name
} else {
logger.warn(
"Refusing invalid auth path transition $authPath → ${outcome.path}",
)
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

when (val result = outcome.result) {
Expand Down