Repository navigation
Split isSteamShell() from isDesktopShell() so the Android shell skips Steam paths - #6408
Conversation
The Android app defines window.openfrontDesktop too, with no `steam` namespace. isDesktopShell() is true there, so every Steam-only path (Steam sign-in and link flow, the Turnstile exemption, Steam presence and invites, the "(Steam v...)" label, the Steam session gate) would have fired in a shell that cannot do any of it. Add isSteamShell(), true when the bridge carries `steam`, and move the Steam-dependent call sites to it. Sites about being in any native shell (ads off, the shell's updater, the shell-served document) keep isDesktopShell(). The Steam preload exposes `steam` unconditionally, so on Steam the two predicates are always equal and the Steam build is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
006b29d to
d1bfa09
Compare
|
No actionable comments were generated in the recent review. WalkthroughThe client now identifies Steam shells separately from other desktop shells. Authentication, session handling, platform features, and selected interface behavior use the Steam-shell check. Android shells continue to use web authentication. ChangesSteam and Android Shell Behavior
Estimated code review effort: 3 (Moderate) | ~25 minutes Change: Bug fix Sequence Diagram(s)sequenceDiagram
actor AndroidPlayer
participant AccountModal
participant Auth
participant Browser
AndroidPlayer->>AccountModal: Select Discord or Google sign-in
AccountModal->>Auth: Start sign-in
Auth->>Browser: Navigate to OAuth URL with web-page redirect_uri
Suggested reviewers: Merge Risk:
|
🤖 Claude Code ReviewVerdict: No issues found. Checked for bugs and CLAUDE.md compliance. Findings: 0 critical · 0 major · 0 minor Checked:
The Android behaviour changes left over ( |
Description:
The Android app defines
window.openfrontDesktoptoo, but its bridge has nosteamnamespace (and nolinkGate,presence,invite,displayorquit).isDesktopShell()is true there, so every Steam-only path would fire in a shell that can't do any of it. That covers the Steam sign-in and link flow, the Turnstile exemption, Steam presence and invites, the "(Steam v…)" label and the Steam session gate.This adds
isSteamShell()next toisDesktopShell(). It is true when the bridge carriessteam, the same testSteamSDK.isOnSteam()andPayments.steamBridge()already make. EveryisDesktopShell()call site was audited:isSteamShell().isDesktopShell(): ads off, the shell's own updater, a document the shell serves.isDesktopShellis not renamed, and nothing Android-specific is added beyond the split.Why the Steam build is unchanged
On Steam,
isSteamShell() === isDesktopShell()always holds:steamunconditionally, whether or not a Steam client is running. So whenever the bridge exists on Steam,steamis in it.replay.*hosts the preload withholds the whole bridge, so both predicates are false there.Every moved site therefore takes the same branch on Steam as before. The three sites that combined an update gate and a session gate are now split: update on
isDesktopShell(), session onisSteamShell(). On Steam both halves are still on.Audit
Moved to
isSteamShell()(19)Auth.ts:90startDesktopLinkFlowshowLinkGategets an update prompt instead of the OAuth redirectapp://. Android is served at the site's own origin, so the web redirect works there.Auth.ts:152linkGoogleapp://reasonAccountModal.ts:865linkGoogleAccountModal.ts:883renderSteamLinkAccountModal.ts:1022viaBrowserstartDesktopLinkFlowAccountSettingsPanel.ts:324linkGoogleClientPlatform.ts:13"steam""web"(see open questions).Footer.ts:117FreePlayPerks.ts:34WebGLGate.ts:105quit, which only Steam has. Tells the player to use Steam.DesktopSessionRecovery.ts:101online/ reachabilityDesktopStatusBar.ts:221Main.ts:575provider="steam"JWT (JoinVerify.planJoinVerify), not the shell. Android has to send a token.Main.ts:2350getTurnstileTokenMain.ts:957steamNoticeDueMain.ts:1778blockedJoin(session half)isDesktopShell().GameModeSelector.ts:415(session half)DetailedGameViewModal.ts:223(session half)DesktopPresence.ts:62isAvailableshell.api >= 2. That number space is shared with Android, which is past 2 but has no presence or invites, so it would have shown a dead Invite Friends button.Also
index.html:215: the first-paintdesktop-layoutclass is now Steam only. Android lays out the way the site does in a mobile browser. That script also definesBOOTSTRAP_CONFIG, so it uses&&rather than optional chaining.Kept on
isDesktopShell()(26)Main.ts:837FeaturedStream.ts:198PurchaseNudgeModal.ts:38CosmeticCard.ts:619WinModal.ts:590UserSettings.ts:984Main.ts:942,Main.ts:1012bootInterruptsAllowed/index.html(Android navigates there too)Main.ts:1733Transport.ts:618ServerList.ts:199serverHostServerList.ts:804, 942, 973ClientGameRunner.ts:398GameModeSelector.ts:351GameModeSelector.ts:414,DetailedGameViewModal.ts:222,Main.ts:1777GameModeSelector.ts:234DesktopStatusBar.ts:233UserSettingModal.ts:807desktopDisplay(), which Android lacks, so it stays hidden there anywayCosmetics.ts:373promptManageBillingSubscriptionPanel.ts:456onDesktopGameRightSidebar.ts:65,ReplayControls.ts:94Direct bridge reads that already key on their own namespace (
SteamSDK,Payments,DesktopDisplay) are untouched.Ambiguous sites (decided from the code)
Cosmetics.ts:373,SubscriptionPanel.ts:456): kept as "no external payment link-outs from an app shell". The comment says the guard that kills the button lives in the shell. On Android, Play's anti-steering policy points the same way. The strings say "on the OpenFront website", not Steam. Keeping this is the conservative choice.GameRightSidebar.ts:65,ReplayControls.ts:94): kept hidden. A native app owns its own window.Open questions
clientPlatform()now reports"web". There is no"android"value inClientPlatform.paymentsProvider()is"stripe"on Android (nosteambridge), while the link-out guards above still hide Stripe's buttons. That needs settling with Google Play billing.Tests
isDesktopShell/isSteamShell: web is false/false, Steam is true/true, an Android-shaped bridge is true/false.DesktopPresence.isAvailable()is false at api 7clientPlatform()is"web"{}bridge now carrysteam: {}, matching what the real preload always exposes.npm test,npm run lint,npm run typecheckandoxfmt --checkpass locally.Please complete the following:
Please put your Discord username so you can be contacted if a bug or regression is found:
evan
🤖 Generated with Claude Code