fix(auth): 修复重启后无法对话 — restoreSession 优先验证 SaaS token
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
根因: 心跳降级将 'tauri' 持久化到 localStorage,重启后盲信该值。 修复: token refresh 成功时强制恢复 'saas' 模式;connectionMode 携带时间戳。
This commit is contained in:
@@ -157,16 +157,41 @@ export async function clearSaaSSession(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Persist the connection mode to localStorage.
|
* Persist the connection mode to localStorage with timestamp.
|
||||||
*/
|
*/
|
||||||
export function saveConnectionMode(mode: string): void {
|
export function saveConnectionMode(mode: string): void {
|
||||||
localStorage.setItem(SAASMODE_KEY, mode);
|
const data = JSON.stringify({ mode, timestamp: Date.now() });
|
||||||
|
localStorage.setItem(SAASMODE_KEY, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the connection mode from localStorage.
|
* Load the connection mode from localStorage.
|
||||||
|
* Handles both new JSON format and legacy plain string format.
|
||||||
* Returns null if not set.
|
* Returns null if not set.
|
||||||
*/
|
*/
|
||||||
export function loadConnectionMode(): string | null {
|
export function loadConnectionMode(): string | null {
|
||||||
return localStorage.getItem(SAASMODE_KEY);
|
const raw = localStorage.getItem(SAASMODE_KEY);
|
||||||
|
if (!raw) return null;
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(raw);
|
||||||
|
if (typeof parsed === 'string') return parsed; // legacy format
|
||||||
|
return parsed.mode ?? null;
|
||||||
|
} catch {
|
||||||
|
return raw; // legacy format (plain string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the timestamp of the persisted connection mode.
|
||||||
|
* Returns null if not set or format is legacy.
|
||||||
|
*/
|
||||||
|
export function loadConnectionModeTimestamp(): number | null {
|
||||||
|
const raw = localStorage.getItem(SAASMODE_KEY);
|
||||||
|
if (!raw) return null;
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(raw);
|
||||||
|
return parsed.timestamp ?? null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -818,8 +818,11 @@ export const useSaaSStore = create<SaaSStore>((set, get) => {
|
|||||||
account,
|
account,
|
||||||
saasUrl: restored.saasUrl,
|
saasUrl: restored.saasUrl,
|
||||||
authToken: newToken,
|
authToken: newToken,
|
||||||
connectionMode: loadConnectionMode() === 'saas' ? 'saas' : 'tauri',
|
// If token refresh succeeded, always restore to 'saas' mode
|
||||||
|
// regardless of what was persisted (heartbeat may have degraded to 'tauri')
|
||||||
|
connectionMode: 'saas',
|
||||||
});
|
});
|
||||||
|
saveConnectionMode('saas');
|
||||||
get().fetchAvailableModels().catch(() => {});
|
get().fetchAvailableModels().catch(() => {});
|
||||||
get().fetchAvailableTemplates().catch(() => {});
|
get().fetchAvailableTemplates().catch(() => {});
|
||||||
get().fetchAssignedTemplate().catch(() => {});
|
get().fetchAssignedTemplate().catch(() => {});
|
||||||
|
|||||||
Reference in New Issue
Block a user