Skip to content

Add multi-account auth support with quick account switcher UI#355

Merged
Kief5555 merged 36 commits intodevfrom
priyanshrv1-oss/main
Apr 25, 2026
Merged

Add multi-account auth support with quick account switcher UI#355
Kief5555 merged 36 commits intodevfrom
priyanshrv1-oss/main

Conversation

@Kief5555
Copy link
Copy Markdown
Collaborator

@Kief5555 Kief5555 commented Apr 25, 2026

FIXES FOR #344

🚀 Multi-Account Switcher (Quick Account Switching)

Overview

This PR introduces a multi-account system that allows users to manage and switch between multiple accounts seamlessly without re-entering credentials.


✨ Features

  • Multi-account support

    • Store multiple authenticated sessions
    • Track and switch active account
  • Quick account switching

    • Instantly switch accounts using stored refresh tokens
    • No password re-entry required
  • Account management UI

    • Dropdown menu in navbar
    • View all saved accounts with profile info
    • Active account indicator
    • Remove individual accounts
    • Add new accounts
    • Sign out of all accounts

🛠️ Technical Changes

Backend (AuthService)

  • Migrated from single session → multiple sessions (Map<string, AuthSession>)

  • Added:

    • getSavedAccounts()
    • switchAccount(userId)
    • removeAccount(userId)
    • logoutAll()
  • Added session persistence with activeUserId

  • Implemented backward compatibility for old session format

IPC & API

  • New IPC channels:

    • auth:get-saved-accounts
    • auth:switch-account
    • auth:remove-account
  • Extended preload API for account operations

Frontend

  • Navbar dropdown for account switching
  • Integrated state management in App.tsx
  • Handlers for switching, adding, and removing accounts

Styling

  • Added dropdown UI with dark theme support
  • Tier badges and interactive states

🔁 Behavior

  • New logins are added (not replaced)
  • Switching accounts validates/refreshes tokens
  • Invalid sessions are automatically removed
  • “Sign out all” clears all stored sessions

✅ Testing

  • Verified multi-account login flow
  • Tested switching without password prompts
  • Confirmed account removal and full logout
  • Build, typecheck, and tests all passing

📌 Notes

This implementation is backward-compatible and migrates existing single-session users automatically.

zortos293 and others added 30 commits April 9, 2026 19:58
Merge Developer branch into main branch
Add multi-account auth support with quick account switcher UI
…nfirmation

Add confirmation modal for account removal
* Fix account switch session validation during refresh

* Fail switch-account refresh when user identity cannot be verified

* Update opennow-stable/src/main/gfn/auth.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: PriyanshAg-1 <204138848+PriyanshAg-1@users.noreply.github.com>
Co-authored-by: priyanshrv1-oss <priyanshrv1@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…o refreshNavbarActiveSession to avoid stale auth token

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Fix async session state in handleSwitchAccount
…rror recovery state sync, ARIA semantics, SavedAccount type usage

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…after logout

Agent-Logs-Url: https://github.com/priyanshrv1-oss/OpenNOW1/sessions/bc9cb33e-8e97-4cf8-8986-2a9a584abddc

Co-authored-by: PriyanshAg-1 <204138848+PriyanshAg-1@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…ne numbers in TS files

Agent-Logs-Url: https://github.com/priyanshrv1-oss/OpenNOW1/sessions/f707cd73-f431-41cf-96a8-c5e0c34ab939

Co-authored-by: PriyanshAg-1 <204138848+PriyanshAg-1@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds multi-account authentication to OpenNOW (main process AuthService + shared IPC/contract + preload API) and exposes it in the renderer via a quick account switcher dropdown in the navbar, enabling switching/removing accounts and signing out of all accounts without re-entering credentials.

Changes:

  • Extend shared IPC channels and OpenNowApi contract to support saved accounts, switching, removal, and logout-all.
  • Implement multi-session persistence and account switching/removal logic in AuthService, wired through main IPC handlers and preload.
  • Add renderer state + navbar dropdown UI (with styling) for switching/managing accounts, including new confirmation flow for removing an account.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
opennow-stable/src/shared/ipc.ts Adds new IPC channel constants for multi-account operations.
opennow-stable/src/shared/gfn.ts Extends shared types (SavedAccount) and OpenNowApi with multi-account methods.
opennow-stable/src/preload/index.ts Exposes new auth/account APIs to the renderer via window.openNow.
opennow-stable/src/main/index.ts Registers new IPC handlers that delegate to AuthService.
opennow-stable/src/main/gfn/auth.ts Migrates auth state from single-session to multi-session with persistence and account operations.
opennow-stable/src/renderer/src/components/Navbar.tsx Implements account switcher dropdown UI and wires callbacks.
opennow-stable/src/renderer/src/App.tsx Adds saved-account state, account switching/removal flows, and logout-all integration.
opennow-stable/src/renderer/src/styles.css Adds styles for the account switcher dropdown and interactions.
opennow-stable/package.json Bumps app version.
README.md Adds TestFlight badge and lists iOS as a packaging target.
Comments suppressed due to low confidence (2)

opennow-stable/src/renderer/src/App.tsx:2452

  • After removing an account, refreshNavbarActiveSession(sessionResult.session, sessionResult.session.provider.streamingServiceUrl) forces the provider base URL and can ignore a user-selected settings.region. This can make the navbar active-session query inconsistent with the rest of the app when a region override is set.

Suggestion: call refreshNavbarActiveSession(sessionResult.session) without passing streamingServiceUrl as an override (or compute an override that respects settings.region).

    setSelectedGameId("");
  }, [resetLaunchRuntime]);

  // Logout handler

opennow-stable/src/renderer/src/App.tsx:2463

  • confirmRemoveAccount performs multiple awaited IPC calls but doesn’t have any error handling. Since it’s triggered via void confirmRemoveAccount() (button click / Enter key handler), any thrown error will become an unhandled promise rejection and the UI state has already been mutated (modal closed, accountToRemove cleared).

Suggestion: add a try/catch around the removal + refresh sequence, and consider restoring the modal/state or surfacing an error message when removal fails.

    setGames([]);
    setLibraryGames([]);
    setVariantByGameId({});
    resetLaunchRuntime();
    setNavbarActiveSession(null);
    setIsResumingNavbarSession(false);
    setSubscriptionInfo(null);
    setCurrentPage("home");
    setCatalogFilterGroups([]);
    setCatalogSortOptions([]);
    setCatalogSelectedSortId("relevance");
    setCatalogSelectedFilterIds([]);
    setCatalogTotalCount(0);
    setCatalogSupportedCount(0);
    setSelectedGameId("");
  }, [resetLaunchRuntime]);

  // Logout handler
  const handleLogout = useCallback(() => {
    setLogoutConfirmOpen(true);
  }, []);

  // Load games handler
  const loadGames = useCallback(async (targetSource: "main" | "library") => {
    setIsLoadingGames(true);
    try {
      const token = authSession?.tokens.idToken ?? authSession?.tokens.accessToken;
      const baseUrl = effectiveStreamingBaseUrl;
      if (!token) {

Comment on lines +1018 to 1059
const latestSession = this.getSession() ?? currentSession;
let refreshedUser: AuthUser | null = null;
let userInfoError: string | undefined;
try {
user = await fetchUserInfo(refreshedTokens);
console.debug("auth: fetched user info on token refresh", { userId: user.userId, email: user.email, avatarUrl: user.avatarUrl });
refreshedUser = await fetchUserInfo(refreshedTokens);
console.debug("auth: fetched user info on token refresh", {
userId: refreshedUser.userId,
email: refreshedUser.email,
avatarUrl: refreshedUser.avatarUrl,
});
} catch (error) {
console.warn("Token refresh succeeded but user info refresh failed. Keeping cached user:", error);
userInfoError = error instanceof Error ? error.message : "Unknown error while fetching user info";
}

const resolvedUser = refreshedUser ?? latestSession.user;
if (expectedUserId && resolvedUser.userId !== expectedUserId) {
return {
session: latestSession,
refresh: {
attempted: true,
forced: forceRefresh,
outcome: "failed",
message: refreshedUser
? "Token refresh returned a different account than expected."
: "Token refresh kept a cached account identity that did not match the expected account.",
error: refreshedUser
? `expected_user_id:${expectedUserId} actual_user_id:${refreshedUser.userId}`
: userInfoError
? `expected_user_id:${expectedUserId} cached_user_id:${resolvedUser.userId} user_info_error:${userInfoError}`
: `expected_user_id:${expectedUserId} cached_user_id:${resolvedUser.userId}`,
},
};
}

this.session = {
provider: this.session!.provider,
const updatedSession: AuthSession = {
provider: latestSession.provider,
tokens: refreshedTokens,
user: user ?? this.session!.user,
user: resolvedUser,
};
this.sessions.set(updatedSession.user.userId, updatedSession);

Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

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

In ensureValidSessionWithStatus, applyRefreshedTokens writes the refreshed session back into this.sessions keyed by updatedSession.user.userId, but it never updates activeUserId if fetchUserInfo returns a different user than the currently-active session (when expectedUserId is not provided). That can leave activeUserId pointing at an entry whose tokens were never updated, while the refreshed tokens are stored under a different key, causing this.getSession() (and the returned session) to remain stale/expired.

Consider always enforcing that resolvedUser.userId matches the current session’s userId (or default expectedUserId to currentSession.user.userId), and/or updating activeUserId to the refreshed user when you intentionally allow identity changes.

Copilot uses AI. Check for mistakes.
Comment on lines +2403 to +2406
window.openNow.getSavedAccounts(),
window.openNow.getAuthSession(),
]);
setSavedAccounts(accounts);
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

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

handleSwitchAccount calls refreshNavbarActiveSession(session, session.provider.streamingServiceUrl). Passing the provider URL as an override bypasses the user-selected settings.region (since refreshNavbarActiveSession will always use the override), so the navbar active-session query may hit the wrong base URL when a custom region is set.

Suggestion: call refreshNavbarActiveSession(session) without the override (or pass an override that respects settings.region), since refreshNavbarActiveSession already derives the correct base URL from settings.region + the provided session.

Copilot uses AI. Check for mistakes.
Comment on lines +2413 to +2416
}
setRegions([]);
setGames([]);
setLibraryGames([]);
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

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

In the handleSwitchAccount failure path, refreshNavbarActiveSession(sessionResult.session, sessionResult.session.provider.streamingServiceUrl) has the same issue as the success path: the explicit override forces the provider base URL and ignores a user-selected settings.region, so the navbar active-session refresh may query the wrong endpoint.

Suggestion: call refreshNavbarActiveSession(sessionResult.session) without the override (or compute an override that respects settings.region).

Copilot uses AI. Check for mistakes.
Comment on lines +2406 to +2427
setSavedAccounts(accounts);
setAuthSession(sessionResult.session);
if (sessionResult.session) {
setProviderIdpId(sessionResult.session.provider.idpId);
await loadSessionRuntimeData(sessionResult.session);
await refreshNavbarActiveSession(sessionResult.session, sessionResult.session.provider.streamingServiceUrl);
return;
}
setRegions([]);
setGames([]);
setLibraryGames([]);
setSubscriptionInfo(null);
setNavbarActiveSession(null);
setCatalogFilterGroups([]);
setCatalogSortOptions([]);
setCatalogTotalCount(0);
setCatalogSupportedCount(0);
}, [accountToRemove, loadSessionRuntimeData, refreshNavbarActiveSession]);

const handleAddAccount = useCallback(() => {
setAuthSession(null);
setLoginError(null);
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

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

handleSwitchAccount is passed down to Navbar as onSwitchAccount, and the navbar calls it without awaiting. In the catch block here, several awaited operations (getAuthSession, loadSessionRuntimeData, refreshNavbarActiveSession) can still throw; if they do, the resulting rejected promise will be unhandled in the renderer.

Suggestion: wrap the recovery logic in its own try/catch (and ensure this handler always resolves), or handle the returned promise at the call site (e.g., void onSwitchAccount(...) plus centralized error handling).

Copilot uses AI. Check for mistakes.
Comment on lines +365 to +397
<button
type="button"
className="navbar-user navbar-user--clickable"
onClick={() => setAccountDropdownOpen((previous) => !previous)}
aria-haspopup="dialog"
aria-expanded={accountDropdownOpen}
aria-controls="navbar-account-dropdown"
>
{user.avatarUrl ? (
<img src={user.avatarUrl} alt={user.displayName} className="navbar-avatar" />
) : (
<div className="navbar-avatar-fallback">
<User size={14} />
</div>
)}
<div className="navbar-user-info">
<span className="navbar-username">{user.displayName}</span>
{tierInfo && (
<span className={`navbar-tier ${tierInfo.className}`}>{tierInfo.label}</span>
)}
</div>
<ChevronDown
size={14}
className={`navbar-user-chevron${accountDropdownOpen ? " is-open" : ""}`}
/>
</button>
{accountDropdownOpen && (
<div
id="navbar-account-dropdown"
className="navbar-account-dropdown"
role="dialog"
aria-modal="false"
aria-labelledby="navbar-account-dropdown-header"
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

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

The account switcher trigger/dropdown is implemented as a menu-like control, but it uses aria-haspopup="dialog" and the popup uses role="dialog". This is likely to be announced incorrectly by assistive tech (it’s not a modal dialog, and the contents are a list of choices + actions).

Suggestion: use menu semantics (aria-haspopup="menu", role="menu" / role="menuitem") or otherwise align ARIA roles/attributes with the actual interaction pattern.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@capy-ai capy-ai Bot left a comment

Choose a reason for hiding this comment

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

Added 1 comment

Comment thread opennow-stable/src/main/gfn/auth.ts
Kief5555 and others added 2 commits April 24, 2026 19:33
…pp components; update Navbar accessibility roles
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
@Kief5555 Kief5555 merged commit 081b6ce into dev Apr 25, 2026
8 checks passed
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

opennow-stable/src/renderer/src/App.tsx:2454

  • confirmLogout now calls window.openNow.logoutAll() but does not handle failures. Since it is invoked via void confirmLogout() (click/Enter handler), a thrown error will surface as an unhandled promise rejection and the UI/state will already have dismissed the modal. Consider wrapping the IPC call + state resets in try/catch and only clearing local state after the IPC succeeds (or restore state / show an error if it fails).
  const confirmLogout = useCallback(async () => {
    setLogoutConfirmOpen(false);
    await window.openNow.logoutAll();
    setAuthSession(null);
    setSavedAccounts([]);
    setGames([]);
    setLibraryGames([]);
    setVariantByGameId({});
    resetLaunchRuntime();
    setNavbarActiveSession(null);
    setIsResumingNavbarSession(false);
    setSubscriptionInfo(null);
    setCurrentPage("home");
    setCatalogFilterGroups([]);
    setCatalogSortOptions([]);
    setCatalogSelectedSortId("relevance");
    setCatalogSelectedFilterIds([]);
    setCatalogTotalCount(0);
    setCatalogSupportedCount(0);
    setSelectedGameId("");
  }, [resetLaunchRuntime]);

Comment on lines +2267 to +2273
// Load providers and session (refresh only if token is near expiry)
setStartupStatusMessage("Restoring saved session...");
const [providerList, sessionResult] = await Promise.all([
window.openNow.getLoginProviders(),
window.openNow.getAuthSession(),
]);
const accounts = await window.openNow.getSavedAccounts();
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

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

During initialization, getSavedAccounts() is awaited after the Promise.all that loads providers/session. This makes startup slower than necessary because the accounts fetch could run in parallel with the other two IPC calls. Consider including window.openNow.getSavedAccounts() in the same Promise.all and destructuring all three results.

Suggested change
// Load providers and session (refresh only if token is near expiry)
setStartupStatusMessage("Restoring saved session...");
const [providerList, sessionResult] = await Promise.all([
window.openNow.getLoginProviders(),
window.openNow.getAuthSession(),
]);
const accounts = await window.openNow.getSavedAccounts();
// Load providers, session, and saved accounts in parallel (refresh only if token is near expiry)
setStartupStatusMessage("Restoring saved session...");
const [providerList, sessionResult, accounts] = await Promise.all([
window.openNow.getLoginProviders(),
window.openNow.getAuthSession(),
window.openNow.getSavedAccounts(),
]);

Copilot uses AI. Check for mistakes.
Comment on lines +365 to +399
<button
type="button"
className="navbar-user navbar-user--clickable"
onClick={() => setAccountDropdownOpen((previous) => !previous)}
aria-haspopup="menu"
aria-expanded={accountDropdownOpen}
aria-controls="navbar-account-dropdown"
>
{user.avatarUrl ? (
<img src={user.avatarUrl} alt={user.displayName} className="navbar-avatar" />
) : (
<div className="navbar-avatar-fallback">
<User size={14} />
</div>
)}
<div className="navbar-user-info">
<span className="navbar-username">{user.displayName}</span>
{tierInfo && (
<span className={`navbar-tier ${tierInfo.className}`}>{tierInfo.label}</span>
)}
</div>
<ChevronDown
size={14}
className={`navbar-user-chevron${accountDropdownOpen ? " is-open" : ""}`}
/>
</button>
{accountDropdownOpen && (
<div
id="navbar-account-dropdown"
className="navbar-account-dropdown"
role="menu"
aria-labelledby="navbar-account-dropdown-header"
>
<div id="navbar-account-dropdown-header" className="navbar-account-dropdown-header">
Switch Account
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

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

The account dropdown is exposed as an ARIA menu (aria-haspopup="menu", role="menu"), but there is no keyboard handling to dismiss it (e.g., Escape) or manage focus within the menu. This makes the new switcher hard to use with keyboard-only navigation and diverges from expected menu behavior. Consider adding an onKeyDown handler (Escape to close, arrow-key navigation if keeping role="menu") and/or simplifying the semantics (e.g., treat it as a list of buttons without role="menu").

Copilot uses AI. Check for mistakes.
Comment on lines +586 to +608
setSession(session: AuthSession | null): void {
if (!session) {
this.sessions.clear();
this.activeUserId = null;
this.selectedProvider = defaultProvider();
this.clearSubscriptionCache();
this.clearVpcCache();
void this.persist();
return;
}

const normalized: AuthSession = {
...session,
provider: normalizeProvider(session.provider),
};
this.sessions.set(normalized.user.userId, normalized);
this.activeUserId = normalized.user.userId;
this.selectedProvider = normalized.provider;
this.clearSubscriptionCache();
this.clearVpcCache();
void this.persist();
}

Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

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

AuthService.setSession() is added as a public method but doesn't appear to be used anywhere in the codebase. If it isn't part of an intended external API, consider removing it or making it private to avoid carrying unused surface area (especially now that setSession(null) clears all stored sessions).

Suggested change
setSession(session: AuthSession | null): void {
if (!session) {
this.sessions.clear();
this.activeUserId = null;
this.selectedProvider = defaultProvider();
this.clearSubscriptionCache();
this.clearVpcCache();
void this.persist();
return;
}
const normalized: AuthSession = {
...session,
provider: normalizeProvider(session.provider),
};
this.sessions.set(normalized.user.userId, normalized);
this.activeUserId = normalized.user.userId;
this.selectedProvider = normalized.provider;
this.clearSubscriptionCache();
this.clearVpcCache();
void this.persist();
}

Copilot uses AI. Check for mistakes.
Kief5555 added a commit that referenced this pull request Apr 25, 2026
* Fix Epic ownership guard and owned store glow (#334)

* Add Windows ARM64 release builds to pipeline (#340)

* Restore Windows ARM64 build artifacts in release pipeline

* fix(ci): match linux x64 artifact upload names

* Add 'Hide Server Selector' setting to skip free-tier queue modal

* Add Discord activity clearing functionality to rich presence (#349)

* Remove Game Hub media handling and refactor ControllerLibraryPage (#350)

* Remove Game Hub media handling from ControllerLibraryPage

* Refactor initial category index logic in ControllerLibraryPage for clarity

* Replace useEffect with useLayoutEffect for improved layout handling in ControllerLibraryPage

* Merge branch 'dev' into Jayian1890/controller-mode-patch-042226

* Add flake.nix again (#343)

* Fix Nix npm packaging

* Update

* Add nix instruction in README.md

* Delete symbolic Link

* change requested changes and add desktop items

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update flake.nix

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Zortos <zortosdev@proton.me>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Kiefer <67562560+Kief5555@users.noreply.github.com>
Co-authored-by: Kiefer <kieferlin1001@gmail.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Co-authored-by: DINEXXL <dinexxl@noreply.codeberg.org>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Switch macOS jobs to Blacksmith runners (#352)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* feat: implement DiscordStatusMonitor to periodically sync RPC activity with active cloud gaming sessions

* feat: add initial sync handling in DiscordStatusMonitor to clear stale status on startup

* Fix Settings search to show relevant sections only (scope-aware filtering + sidebar UX polish) (#353)

* settings

* Update opennow-stable/src/renderer/src/components/SettingsPage.tsx

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* do capy's suggestion

Co-authored-by: Copilot <copilot@github.com>

* Auto-recover active sessions after signaling disconnects (#321)

* Implement bounded auto-recovery for active sessions after signaling disconnects

* Enhance signaling recovery mechanism by introducing generation tracking. Added generation state to manage recovery attempts and prevent stale session applications. Updated relevant functions to utilize generation checks for improved session handling.

* Refactor claimed session handling to improve recovery logic. Introduced a helper function to determine if a claimed reconnect can proceed based on recovery generation and explicit shutdown status, enhancing session management and logging clarity.

* Enhance signaling recovery logic by adding checks for explicit shutdown and non-recoverable stream statuses. This prevents unnecessary error handling and improves logging clarity during disconnect scenarios.

* Remove explicit shutdown check from signaling connection logic to streamline recovery process. This change simplifies the connection flow during recovery attempts.

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Co-authored-by: Jared <jared@interlacedpixel.com>

* Add multi-account auth support with quick account switcher UI (#355)

* chore(release): prepare v0.3.3

* chore(release): prepare v0.3.4

* chore(release): prepare v1.3.5

* chore(release): prepare v0.3.5

* Update README.md to include TestFlight badge and iOS packaging target

* update AGENTS.md

* chore(release): prepare v0.3.6

* Add multi-account auth support with quick account switcher UI

* Add confirmation modal for account removal

* Fix account switch session validation during refresh (#4)

* Fix account switch session validation during refresh

* Fail switch-account refresh when user identity cannot be verified

* Update opennow-stable/src/main/gfn/auth.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: PriyanshAg-1 <204138848+PriyanshAg-1@users.noreply.github.com>
Co-authored-by: priyanshrv1-oss <priyanshrv1@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix async session state in handleSwitchAccount - pass fresh session to refreshNavbarActiveSession to avoid stale auth token

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Fix all remaining Copilot review issues: auth session null returns, error recovery state sync, ARIA semantics, SavedAccount type usage

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix: use menu ARIA roles in account dropdown and return getSession() after logout

Agent-Logs-Url: https://github.com/priyanshrv1-oss/OpenNOW1/sessions/bc9cb33e-8e97-4cf8-8986-2a9a584abddc

Co-authored-by: PriyanshAg-1 <204138848+PriyanshAg-1@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix: add role=none to structural wrappers in menu and fix embedded line numbers in TS files

Agent-Logs-Url: https://github.com/priyanshrv1-oss/OpenNOW1/sessions/f707cd73-f431-41cf-96a8-c5e0c34ab939

Co-authored-by: PriyanshAg-1 <204138848+PriyanshAg-1@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Change logoutAll to logout in auth service

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Update opennow-stable/src/main/gfn/auth.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fixed errors and improved session auth flows

* fix: improve session handling and error recovery in AuthService and App components; update Navbar accessibility roles

* Update opennow-stable/src/main/gfn/auth.ts

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Resolve styling issues

* Resolve startup issues

---------

Co-authored-by: Zortos <zortosdev@proton.me>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Co-authored-by: PriyanshAg-1 <204138848+PriyanshAg-1@users.noreply.github.com>
Co-authored-by: priyanshrv1-oss <priyanshrv1@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Priyansh Agarwal <2k22.cse.32203@gmail.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>

* Improve stream pointer responsiveness under load. (#354)

* Improve stream pointer responsiveness under load.

Reduce mouse input hot-path overhead with residual delta accumulation, adaptive flush scheduling, cached scale conversion, and tuned raw-input filtering while adding diagnostics and targeted tests.

Made-with: Cursor

* Refactor mouse input handling in GfnWebRtcClient to maintain pending deltas until a non-zero packet is sent. This change prevents loss of quantized integer deltas during server scaling, improving responsiveness and accuracy of mouse movements.

* Enhance mouse input handling in GfnWebRtcClient by preventing re-arming of the mouse flush timer during teardown. This change ensures that the timer does not continue to operate after it has been cleared, improving resource management and stability.

* Refactor App and StreamView components to remove Esc hold release indicator functionality. This includes the removal of related state management, CSS styles, and UI elements, streamlining the codebase and improving maintainability.

* Refactor setActivity function in discordRpc.ts to update lastActivity only after successful RPC call, improving state management.

* Update flake.nix to reference the correct path for opennow-logo.png and enhance Discord RPC state management by introducing pendingActivity for improved activity handling.

* Enhance Discord RPC state management by consuming pendingActivity after processing, preventing reprocessing of failed attempts. Simplify activity title and start time assignment in DiscordStatusMonitor for improved clarity.

* Reset pendingActivity to null on setActivity failure in discordRpc.ts to ensure proper state management during error handling.

---------

Co-authored-by: Zortos <zortosdev@proton.me>
Co-authored-by: Jared Terrance <jared@interlacedpixel.com>
Co-authored-by: DINEXXL <105819287+DINEXXL@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Co-authored-by: DINEXXL <dinexxl@noreply.codeberg.org>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: zaloguj12 <patrik.ostafin@gmail.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: PriyanshAg-1 <204138848+PriyanshAg-1@users.noreply.github.com>
Co-authored-by: priyanshrv1-oss <priyanshrv1@gmail.com>
Co-authored-by: Priyansh Agarwal <2k22.cse.32203@gmail.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
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.

6 participants