harden oneliner session backend recovery

This commit is contained in:
kris
2026-03-28 09:13:46 +08:00
parent f05a43fee3
commit dff369aafd
2 changed files with 39 additions and 4 deletions

View File

@@ -562,6 +562,17 @@ function setLastSeenAt(value) {
appState.lastSeenAt = SESSION_STORE.setLastSeenAt(value); appState.lastSeenAt = SESSION_STORE.setLastSeenAt(value);
} }
function normalizeBackendUrlValue(value) {
return String(value || "").trim().replace(/\/$/, "");
}
function hasSessionBackendMismatch(expectedBackendUrl = DEFAULT_BACKEND_URL) {
if (!appState.session) return false;
const expected = normalizeBackendUrlValue(expectedBackendUrl);
const current = normalizeBackendUrlValue(appState.session.backendUrl);
return Boolean(expected && current && expected !== current);
}
function compareDateDesc(leftValue, rightValue) { function compareDateDesc(leftValue, rightValue) {
return new Date(rightValue || 0).getTime() - new Date(leftValue || 0).getTime(); return new Date(rightValue || 0).getTime() - new Date(leftValue || 0).getTime();
} }
@@ -1139,6 +1150,10 @@ async function loginWithAutoSession(backendUrl = DEFAULT_BACKEND_URL) {
async function ensureAutoSession(options = {}) { async function ensureAutoSession(options = {}) {
const backendUrl = options.backendUrl || readAuthForm().backendUrl || DEFAULT_BACKEND_URL; const backendUrl = options.backendUrl || readAuthForm().backendUrl || DEFAULT_BACKEND_URL;
const force = Boolean(options.force); const force = Boolean(options.force);
const backendMismatch = hasSessionBackendMismatch(backendUrl);
if (backendMismatch) {
persistSession(null);
}
if (appState.session && !force) { if (appState.session && !force) {
return true; return true;
} }
@@ -1689,10 +1704,11 @@ async function loadPlatformAccount(platform, accountId, requestToken = 0) {
async function bootstrap() { async function bootstrap() {
renderAll(); renderAll();
if (!appState.session) { const backendMismatch = hasSessionBackendMismatch();
setBusy(true, "正在自动连接后端..."); if (!appState.session || backendMismatch) {
setBusy(true, backendMismatch ? "正在切换到当前工作区后端..." : "正在自动连接后端...");
try { try {
await ensureAutoSession(); await ensureAutoSession({ force: backendMismatch });
} finally { } finally {
setBusy(false, ""); setBusy(false, "");
} }
@@ -8279,7 +8295,8 @@ document.addEventListener("submit", async (event) => {
openOneLinerPanel(); openOneLinerPanel();
renderAll(); renderAll();
} catch (error) { } catch (error) {
alert("OneLiner 调度失败: " + error.message); presentActionFailure(error, "OneLiner 调度失败");
openOneLinerPanel();
} finally { } finally {
setBusy(false, ""); setBusy(false, "");
} }

View File

@@ -75,3 +75,21 @@ test("ensureAutoSession re-renders immediately when auto-connect starts", () =>
assert.match(source, /appState\.autoConnectAttempted = true;/); assert.match(source, /appState\.autoConnectAttempted = true;/);
assert.match(source, /renderAll\(\);/); assert.match(source, /renderAll\(\);/);
}); });
test("bootstrap does not trust a stored session from a different backend", () => {
const helpers = extractBetween(APP, "function loadStoredSession()", "function compareDateDesc(");
const ensure = extractBetween(APP, "async function ensureAutoSession(options = {})", "async function refreshFromAuthModal()");
const bootstrap = extractBetween(APP, "async function bootstrap()", "async function markTrackingDigestRead()");
assert.match(helpers, /function normalizeBackendUrlValue\(/);
assert.match(helpers, /function hasSessionBackendMismatch\(/);
assert.match(ensure, /const backendMismatch = hasSessionBackendMismatch\(backendUrl\);/);
assert.match(ensure, /persistSession\(null\);/);
assert.match(bootstrap, /const backendMismatch = hasSessionBackendMismatch\(\);/);
assert.match(bootstrap, /await ensureAutoSession\(\{ force: backendMismatch \}\);/);
});
test("oneliner submit failures stay inside the app instead of using a browser alert", () => {
assert.doesNotMatch(APP, /alert\("OneLiner 调度失败:/);
assert.match(APP, /presentActionFailure\(error,\s*"OneLiner 调度失败"\)/);
});