Skip to content

Fix web client crash after connect; persist browser sessions; show account identity#845

Merged
arul28 merged 2 commits into
mainfrom
ade/web-client-hotfix-c02f5c27
Jul 17, 2026
Merged

Fix web client crash after connect; persist browser sessions; show account identity#845
arul28 merged 2 commits into
mainfrom
ade/web-client-hotfix-c02f5c27

Conversation

@arul28

@arul28 arul28 commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Summary

Production hotfix for the hosted web client (found immediately after the v1.2.29 deploy):

  • Crash fix: the adapter's fallback proxy resolved unimplemented methods to null, so window.ade.account.status() returned null and the always-mounted LaunchGate crashed on status.signedIn right after a successful machine connect. The adapter now exposes a real account surface (status with email/name/avatar via Clerk userinfo, machine listing via the directory), and fetchAccountStatus coerces null → signed-out so the fallback-mismatch class can't crash the renderer again.
  • Persistent sessions: refresh token + OAuth identity persist in IndexedDB (beside the trust store), restore on boot with JWT-exp-aware refresh-first, clear on sign-out/confirmed expiry. Reloads no longer sign the user out.
  • Identity: machine picker shows email + avatar instead of the raw user_… Clerk id.
  • Copy: device-neutral ("Choose a machine").

Testing

98/98 webclient+account tests (new: adapter surface shape, null coercion, session persist/restore/clear, picker identity), tsc clean, webclient build green with bundle greps confirming new copy and no raw user-id render path, docs validated (194 files), quality re-review clean.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added browser account sign-in, sign-out, session restoration, token refresh, and profile support.
    • Account sessions now persist securely across browser restarts and clear correctly when signed out.
    • Added account identity displays with profile images or initials.
    • Added account controls and machine management to the web client.
  • Bug Fixes
    • Improved handling of expired sessions, unavailable directories, concurrent refreshes, and missing account status.
    • Updated machine-related messaging for broader device support.
  • Tests
    • Expanded coverage for account flows, persistence, refresh behavior, and storage upgrades.

Greptile Summary

This PR hardens the hosted web client account flow and machine picker. The main changes are:

  • Normalizes null account bridge status responses to a signed-out shape.
  • Adds a browser-backed window.ade.account adapter surface.
  • Persists OAuth refresh tokens and profile metadata in IndexedDB.
  • Restores sessions on boot and refreshes before using expired JWTs.
  • Shows account email/avatar identity in the machine picker.
  • Updates account-owned environment pruning and relay access handling.

Confidence Score: 5/5

Safe to merge with low risk.

The changed account and session flows validate persisted data, refresh before expired JWT use, filter trusted profile images, and handle storage cleanup failures without leaving the in-memory session active incorrectly.

No files require special attention.

T-Rex T-Rex Logs

What T-Rex did

  • Verified the real web client UI loaded successfully by Playwright, exiting with code 0 and displaying Sign in to ADE prompts.
  • Ran the five focused MachinePicker account-state tests and confirmed they all passed, including identity and no raw user-id render checks.
  • Observed the dev server command on port 5174 was terminated by the sandbox after Vite readiness, and the static server subsequently served the built UI on port 5174 for UI capture.
  • Collected and organized UI-related artifacts (images, a video, and logs) to support inspection of the UI load, sign-in flow, and server behavior.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
apps/desktop/src/renderer/lib/account.ts Normalizes null account bridge responses to the signed-out account shape to avoid renderer crashes.
apps/desktop/src/renderer/webclient/account/client.ts Adds browser account session persistence, refresh-first restore, userinfo profile loading, and machine removal support.
apps/desktop/src/renderer/webclient/account/sessionStore.ts Introduces validated IndexedDB-backed persistence for browser account refresh tokens and profile metadata.
apps/desktop/src/renderer/webclient/adapter/account.ts Maps BrowserAccountClient snapshots and operations onto the web adapter account namespace.
apps/desktop/src/renderer/webclient/shell/WebClientRoot.tsx Bootstraps persisted account sessions, wires account-aware relay access, and preserves account privacy for stored environments.
apps/desktop/src/renderer/webclient/shell/MachinePicker.tsx Updates the machine picker to show account identity and device-neutral machine selection copy.
apps/desktop/src/renderer/webclient/sync/envStore.ts Adds an account IndexedDB store and account-owner pruning helpers for browser trust records.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
  participant Browser as WebClientRoot
  participant Account as BrowserAccountClient
  participant Store as IndexedDB SessionStore
  participant Clerk as Clerk OAuth/Userinfo
  participant Directory as Account Directory
  participant Adapter as window.ade.account

  Browser->>Account: bootstrap()
  Account->>Store: load persisted refresh token/profile
  alt OAuth callback
    Account->>Clerk: exchange authorization code
  else persisted session
    Account->>Clerk: refresh token
  end
  Account->>Clerk: userinfo(access token)
  Account->>Store: save rotated refresh token/profile
  Account->>Directory: list account machines
  Account-->>Browser: BrowserAccountSnapshot
  Browser->>Adapter: createAdeWebAdapter(accountClient)
  Adapter-->>Browser: status/listMachines/signOut surface
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
  participant Browser as WebClientRoot
  participant Account as BrowserAccountClient
  participant Store as IndexedDB SessionStore
  participant Clerk as Clerk OAuth/Userinfo
  participant Directory as Account Directory
  participant Adapter as window.ade.account

  Browser->>Account: bootstrap()
  Account->>Store: load persisted refresh token/profile
  alt OAuth callback
    Account->>Clerk: exchange authorization code
  else persisted session
    Account->>Clerk: refresh token
  end
  Account->>Clerk: userinfo(access token)
  Account->>Store: save rotated refresh token/profile
  Account->>Directory: list account machines
  Account-->>Browser: BrowserAccountSnapshot
  Browser->>Adapter: createAdeWebAdapter(accountClient)
  Adapter-->>Browser: status/listMachines/signOut surface
Loading

Reviews (2): Last reviewed commit: "Fix snapshot test literals, UTF-8 JWT cl..." | Re-trigger Greptile

The web adapter's fallback proxy resolved any unimplemented namespace method
to null, so window.ade.account.status() returned null and the always-mounted
LaunchGate crashed on status.signedIn right after connecting. The adapter now
exposes a real account surface backed by the browser session (status with
email/name/imageUrl from Clerk userinfo, machine listing via the directory),
and fetchAccountStatus coerces null to signed-out as defense in depth.

Browser sessions now persist: the refresh token and OAuth identity live in
IndexedDB beside the trust store, restore on boot with a JWT-exp-aware refresh
first, and clear on sign-out or confirmed auth expiry — reloading no longer
signs the user out.

The machine picker shows the account email and avatar instead of the raw
Clerk user id, and web copy is device-neutral ("Choose a machine").

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
ade Ignored Ignored Preview Jul 17, 2026 7:03am

@arul28 arul28 changed the title web-client-hotfix -> Primary Fix web client crash after connect; persist browser sessions; show account identity Jul 17, 2026
@arul28

arul28 commented Jul 17, 2026

Copy link
Copy Markdown
Owner Author

@copilot review but do not make fixes

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@arul28, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 16 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 82c8cf16-89e2-4436-bbce-ebf302024f49

📥 Commits

Reviewing files that changed from the base of the PR and between 8493762 and b512d79.

📒 Files selected for processing (3)
  • apps/desktop/src/renderer/webclient/account/client.test.ts
  • apps/desktop/src/renderer/webclient/account/client.ts
  • apps/desktop/src/renderer/webclient/sync/__tests__/sync.test.ts
📝 Walkthrough

Walkthrough

Changes

Browser account flow

Layer / File(s) Summary
Account status normalization
apps/desktop/src/renderer/lib/account.ts, apps/desktop/src/renderer/lib/account.test.ts
Nullish account status results are normalized to the signed-out account shape and tested.
Session storage and IndexedDB schema
apps/desktop/src/renderer/webclient/account/sessionStore.ts, apps/desktop/src/renderer/webclient/sync/envStore.ts, apps/desktop/src/renderer/webclient/sync/envStore.test.ts
Persisted account sessions, an IndexedDB account area, schema upgrades, blocked-upgrade handling, and storage edge cases are added.
Browser account lifecycle and profile handling
apps/desktop/src/renderer/webclient/account/client.ts, apps/desktop/src/renderer/webclient/account/client.test.ts, apps/desktop/src/renderer/webclient/account/leaseMonitor.ts
Account profiles, trusted image URLs, expiration, refresh coordination, persistence restoration, asynchronous sign-out, and session tests are expanded.
Account adapter surface
apps/desktop/src/renderer/webclient/adapter/account.ts, apps/desktop/src/renderer/webclient/adapter/index.ts, apps/desktop/src/renderer/webclient/adapter/__tests__/adapter.test.ts
Browser account snapshots and machine states are mapped into ADE account APIs, with injectable client wiring.
Account identity and machine UI
apps/desktop/src/renderer/webclient/shell/*, apps/desktop/src/renderer/webclient/public/_headers, apps/desktop/src/renderer/webclient/sync/relayPolicy.ts
Shared account identity rendering, signed-in checks, machine terminology, adapter bootstrapping, image CSP sources, and related UI fixtures are updated.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • arul28/ADE#819: Shares the account status caching and normalization flow.
  • arul28/ADE#825: Overlaps with browser account state and machine-directory integration.

Suggested labels: desktop, docs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.55% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: crash fix, browser session persistence, and account identity display.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ade/web-client-hotfix-c02f5c27

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/desktop/src/renderer/webclient/account/client.ts (1)

390-395: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Validate the session generation before applying asynchronous account results.

Late operations from account A can mutate, restore, or expire account B after sign-out or reauthentication.

  • apps/desktop/src/renderer/webclient/account/client.ts#L390-L395: capture the session/generation before fetching machines and discard stale results.
  • apps/desktop/src/renderer/webclient/account/client.ts#L609-L660: capture an operation generation before loading persistence and stop restoration after any account transition.
  • apps/desktop/src/renderer/webclient/account/client.ts#L664-L697: verify the originating session before handling authorization failures or updating machines.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/renderer/webclient/account/client.ts` around lines 390 -
395, Guard asynchronous account operations with the existing session/generation
mechanism: in apps/desktop/src/renderer/webclient/account/client.ts:390-395,
capture the originating generation before fetchAccountMachines and discard the
result if it changed before applyDirectoryResult; in :609-660, capture the
operation generation before loading persistence and stop restoration after any
account transition; in :664-697, verify the originating session before handling
authorization failures or updating machines.
🧹 Nitpick comments (2)
apps/desktop/src/renderer/webclient/shell/AccountIdentity.tsx (1)

1-58: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Avoid using useEffect to derive state from props.

Resetting the imageFailed state inside a useEffect causes a second render after paint, which can briefly flash the fallback initials before the new image starts loading. You can completely avoid this effect cycle by storing the URL of the failed image instead of a boolean.

This simplifies the state management and aligns with React's recommendation to calculate derived state directly during render.

♻️ Proposed refactor
-import React, { useEffect, useState } from "react";
+import React, { useState } from "react";
 import type { BrowserAccountSnapshot } from "../account/client";
 import { COLORS, SANS_FONT } from "./shellTokens";
 
 export function accountIdentityLabel(account: BrowserAccountSnapshot): string {
   return account.email ?? account.name ?? "ADE account";
 }
 
 function accountIdentityInitials(account: BrowserAccountSnapshot): string {
   const name = account.name?.trim();
   if (name) {
     const parts = name.split(/\s+/).filter(Boolean);
     if (parts.length > 1) return `${parts[0]![0]}${parts.at(-1)![0]}`.toUpperCase();
     return parts[0]!.slice(0, 2).toUpperCase();
   }
   return account.email?.trim()[0]?.toUpperCase() ?? "A";
 }
 
 export function AccountIdentity({
   account,
   size = 24,
 }: {
   account: BrowserAccountSnapshot;
   size?: number;
 }) {
-  const [imageFailed, setImageFailed] = useState(false);
-  useEffect(() => setImageFailed(false), [account.imageUrl]);
-  const showImage = Boolean(account.imageUrl) && !imageFailed;
+  const [failedUrl, setFailedUrl] = useState<string | null>(null);
+  const showImage = Boolean(account.imageUrl) && account.imageUrl !== failedUrl;
 
   return (
     <div style={{ display: "flex", alignItems: "center", gap: 8, minWidth: 0 }}>
       <span
         aria-hidden="true"
         style={{
           width: size,
           height: size,
           flex: `0 0 ${size}px`,
           display: "inline-flex",
           alignItems: "center",
           justifyContent: "center",
           overflow: "hidden",
           borderRadius: "50%",
           border: `1px solid ${COLORS.border}`,
           background: "color-mix(in srgb, var(--color-fg) 8%, transparent)",
           color: COLORS.textSecondary,
           fontFamily: SANS_FONT,
           fontSize: Math.max(9, Math.round(size * 0.42)),
           fontWeight: 600,
         }}
       >
         {showImage ? (
           <img
             src={account.imageUrl!}
             alt=""
-            onError={() => setImageFailed(true)}
+            onError={() => setFailedUrl(account.imageUrl)}
             style={{ width: "100%", height: "100%", objectFit: "cover" }}
           />
         ) : accountIdentityInitials(account)}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/renderer/webclient/shell/AccountIdentity.tsx` around lines 1
- 58, Refactor AccountIdentity to store the failed image URL rather than a
boolean imageFailed state, and remove the useEffect import and reset logic.
Derive showImage during render by requiring account.imageUrl to differ from the
stored failed URL, and update the img onError handler to record the current URL
so changing image URLs immediately attempts the new image without an
effect-driven render.
apps/desktop/src/renderer/webclient/account/client.test.ts (1)

414-415: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert every static origin allowed by the avatar policy.

This passes even if CSP omits images.clerk.dev or storage.googleapis.com, although trustedProfileImageUrl accepts both.

Proposed test expansion
 expect(hostedHeaders).toContain("img-src 'self' data: blob: https://img.clerk.com");
+expect(hostedHeaders).toContain("https://images.clerk.dev");
+expect(hostedHeaders).toContain("https://storage.googleapis.com");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/renderer/webclient/account/client.test.ts` around lines 414
- 415, Expand the CSP assertion in the hostedHeaders test to verify every static
origin accepted by trustedProfileImageUrl, including images.clerk.dev and
storage.googleapis.com alongside the existing img.clerk.com origin. Keep the
current directive assertion and add checks that each required origin is present
in img-src.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/desktop/src/renderer/webclient/account/client.ts`:
- Around line 525-580: Make authentication state transitions failure-atomic in
setSession, sign-out, and auth-expiry flows: persist or clear the refresh
credential before exposing the corresponding session state, and roll back or
keep state consistent when storage operations reject. In
apps/desktop/src/renderer/webclient/account/client.ts lines 525-580, update
setSession to handle save/clear failures without leaving session and snapshot
partially committed; lines 361-378, commit the signed-out snapshot in finally
and explicitly handle credential-removal failure; lines 703-719, commit the
auth-expired snapshot even when IndexedDB clearing fails. Add rejection tests
covering save() and clear() during sign-in, sign-out, and expiry.
- Around line 131-137: Update decodeJwtPayload to interpret the atob-decoded JWT
payload bytes as UTF-8 before JSON.parse, preserving correct non-ASCII claim
values while retaining the existing base64url normalization and isRecord
validation.

---

Outside diff comments:
In `@apps/desktop/src/renderer/webclient/account/client.ts`:
- Around line 390-395: Guard asynchronous account operations with the existing
session/generation mechanism: in
apps/desktop/src/renderer/webclient/account/client.ts:390-395, capture the
originating generation before fetchAccountMachines and discard the result if it
changed before applyDirectoryResult; in :609-660, capture the operation
generation before loading persistence and stop restoration after any account
transition; in :664-697, verify the originating session before handling
authorization failures or updating machines.

---

Nitpick comments:
In `@apps/desktop/src/renderer/webclient/account/client.test.ts`:
- Around line 414-415: Expand the CSP assertion in the hostedHeaders test to
verify every static origin accepted by trustedProfileImageUrl, including
images.clerk.dev and storage.googleapis.com alongside the existing img.clerk.com
origin. Keep the current directive assertion and add checks that each required
origin is present in img-src.

In `@apps/desktop/src/renderer/webclient/shell/AccountIdentity.tsx`:
- Around line 1-58: Refactor AccountIdentity to store the failed image URL
rather than a boolean imageFailed state, and remove the useEffect import and
reset logic. Derive showImage during render by requiring account.imageUrl to
differ from the stored failed URL, and update the img onError handler to record
the current URL so changing image URLs immediately attempts the new image
without an effect-driven render.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ca7f304f-6308-45ec-82b8-57e563a4693d

📥 Commits

Reviewing files that changed from the base of the PR and between d9ba221 and 8493762.

⛔ Files ignored due to path filters (1)
  • docs/features/web-client/README.md is excluded by !docs/**
📒 Files selected for processing (19)
  • apps/desktop/src/renderer/lib/account.test.ts
  • apps/desktop/src/renderer/lib/account.ts
  • apps/desktop/src/renderer/webclient/account/client.test.ts
  • apps/desktop/src/renderer/webclient/account/client.ts
  • apps/desktop/src/renderer/webclient/account/leaseMonitor.ts
  • apps/desktop/src/renderer/webclient/account/sessionStore.ts
  • apps/desktop/src/renderer/webclient/adapter/__tests__/adapter.test.ts
  • apps/desktop/src/renderer/webclient/adapter/account.ts
  • apps/desktop/src/renderer/webclient/adapter/index.ts
  • apps/desktop/src/renderer/webclient/public/_headers
  • apps/desktop/src/renderer/webclient/shell/AccountIdentity.tsx
  • apps/desktop/src/renderer/webclient/shell/MachinePicker.tsx
  • apps/desktop/src/renderer/webclient/shell/WebClientRoot.tsx
  • apps/desktop/src/renderer/webclient/shell/WebShell.tsx
  • apps/desktop/src/renderer/webclient/shell/__tests__/MachinePicker.test.tsx
  • apps/desktop/src/renderer/webclient/shell/__tests__/WebClientRoot.test.tsx
  • apps/desktop/src/renderer/webclient/sync/envStore.test.ts
  • apps/desktop/src/renderer/webclient/sync/envStore.ts
  • apps/desktop/src/renderer/webclient/sync/relayPolicy.ts

Comment thread apps/desktop/src/renderer/webclient/account/client.ts
Comment thread apps/desktop/src/renderer/webclient/account/client.ts
…persistence

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@arul28

arul28 commented Jul 17, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@arul28
arul28 merged commit d6b7a96 into main Jul 17, 2026
35 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b512d796c9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

};
},
cancelLogin: async () => browserAccountStatus(accountClient.getSnapshot()),
signOut: async () => browserAccountStatus(await accountClient.signOut()),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Route bridge sign-out through root cleanup

When the mounted Account page calls this bridge method, it only clears BrowserAccountClient; it bypasses WebClientRoot.onAccountSignOut, which is the path that disconnects the sync client and prunes account-owned environments. If a user signs out from /account while connected to an account machine, the relay connection and shell account state remain active/stale until the lease monitor eventually runs, so explicit sign-out does not immediately revoke access.

Useful? React with 👍 / 👎.

return {
status: async () => browserAccountStatus(accountClient.getSnapshot()),
startLogin: async () => {
const authorizeUrl = await accountClient.startSignIn();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 Badge Avoid opening a second OAuth flow from the bridge

This bridge method is also used by the shared Account page's useAccountLogin, which expects startLogin to return an authorization URL and then calls openExternalUrl itself. Because accountClient.startSignIn() already does location.assign(url), clicking sign-in from the mounted web Account page both navigates the current tab and opens a second OAuth tab; with the adapter's noopener window open, that second tab does not have the PKCE verifier in sessionStorage, so completing auth there fails state verification.

Useful? React with 👍 / 👎.

@arul28
arul28 deleted the ade/web-client-hotfix-c02f5c27 branch July 17, 2026 07:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant