fix: enhance account management by updating existing accounts and improving session handling

This commit is contained in:
Linus Rath
2026-03-19 17:47:18 +01:00
parent 34e495dde3
commit 95af61c4be
2 changed files with 58 additions and 21 deletions
+21 -4
View File
@@ -58,13 +58,30 @@ export const useAccountStore = create<AccountState>()(
addAccount: (entry) => {
const state = get();
if (state.accounts.length >= MAX_ACCOUNTS) {
throw new Error(`Maximum of ${MAX_ACCOUNTS} accounts reached`);
}
const id = generateAccountId(entry.username, entry.serverUrl);
if (state.accounts.some((a) => a.id === id)) {
return id; // already exists, return existing id
// Already exists — update mutable fields and return existing id
set((s) => ({
accounts: s.accounts.map((a) =>
a.id === id
? {
...a,
rememberMe: entry.rememberMe,
isConnected: entry.isConnected,
hasError: entry.hasError,
errorMessage: undefined,
lastLoginAt: entry.lastLoginAt,
authMode: entry.authMode,
}
: a
),
}));
return id;
}
if (state.accounts.length >= MAX_ACCOUNTS) {
throw new Error(`Maximum of ${MAX_ACCOUNTS} accounts reached`);
}
const cookieSlot = state.getNextCookieSlot();
+37 -17
View File
@@ -288,6 +288,33 @@ export const useAuthStore = create<AuthState>()(
});
accountStore.setActiveAccount(accountId);
// Update account entry in case it already existed (addAccount is a no-op for existing accounts)
accountStore.updateAccount(accountId, {
rememberMe: !!rememberMe,
isConnected: true,
hasError: false,
errorMessage: undefined,
lastLoginAt: Date.now(),
});
// Store session cookie BEFORE setting isAuthenticated to avoid a race
// condition: setting isAuthenticated triggers navigation to the main page,
// whose checkAuth() would try to read the cookie before it was stored.
if (rememberMe) {
try {
const res = await fetch(`/api/auth/session?slot=${cookieSlot}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ serverUrl, username, password: effectivePassword, slot: cookieSlot }),
});
if (!res.ok) {
debug.error('Failed to store session: server returned', res.status);
}
} catch (err) {
debug.error('Failed to store session:', err);
}
}
set({
isAuthenticated: true,
isLoading: false,
@@ -297,6 +324,7 @@ export const useAuthStore = create<AuthState>()(
identities,
primaryIdentity,
authMode: 'basic',
rememberMe: !!rememberMe,
accessToken: null,
tokenExpiresAt: null,
connectionLost: false,
@@ -312,23 +340,6 @@ export const useAuthStore = create<AuthState>()(
});
}).catch(() => {});
if (rememberMe) {
try {
const res = await fetch(`/api/auth/session?slot=${cookieSlot}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ serverUrl, username, password: effectivePassword, slot: cookieSlot }),
});
if (res.ok) {
set({ rememberMe: true });
} else {
debug.error('Failed to store session: server returned', res.status);
}
} catch (err) {
debug.error('Failed to store session:', err);
}
}
return true;
} catch (error) {
debug.error('Login error:', error);
@@ -537,6 +548,7 @@ export const useAuthStore = create<AuthState>()(
username: nextAccount.username,
client: nextClient,
authMode: nextAccount.authMode,
rememberMe: nextAccount.rememberMe,
connectionLost: false,
error: null,
activeAccountId: nextAccount.id,
@@ -740,6 +752,11 @@ export const useAuthStore = create<AuthState>()(
}
if (!targetClient) {
accountStore.updateAccount(accountId, {
isConnected: false,
hasError: true,
errorMessage: 'Unable to restore session',
});
set({ isLoading: false });
return;
}
@@ -756,6 +773,7 @@ export const useAuthStore = create<AuthState>()(
username: targetAccount.username,
client: targetClient,
authMode: targetAccount.authMode,
rememberMe: targetAccount.rememberMe,
connectionLost: false,
error: null,
activeAccountId: accountId,
@@ -872,6 +890,7 @@ export const useAuthStore = create<AuthState>()(
identities,
primaryIdentity,
authMode: targetAccount.authMode,
rememberMe: targetAccount.rememberMe,
connectionLost: false,
error: null,
activeAccountId: targetId,
@@ -903,6 +922,7 @@ export const useAuthStore = create<AuthState>()(
identities,
primaryIdentity,
authMode: acc.authMode,
rememberMe: acc.rememberMe,
connectionLost: false,
error: null,
activeAccountId: id,