统一 AGC 平台会话转移状态

让登录、refresh 和退出共享 auth-transition operation 投影

保留 generation、Runner phase、成功、失败和不确定状态
This commit is contained in:
2026-09-14 12:54:09 +08:00
parent 21efc4cdc4
commit 1445d1b1ab
@@ -6,6 +6,11 @@ import {
refreshClientAuthAccessToken,
} from './clientAuth';
import { getClientServerBaseUrl } from './clientHttp';
import {
type ClientOperation,
createClientOperation,
transitionClientOperation,
} from './clientOperation';
const ACCESS_TOKEN_STORAGE_KEY = 'genarrative.auth.access-token.v1';
@@ -34,12 +39,20 @@ let committedPlatformSession: CommittedPlatformSession | null = null;
let desiredPlatformSession: CommittedPlatformSession | null = null;
let platformSessionRefreshPromise: Promise<PlatformSessionRefreshResult> | null =
null;
let platformSessionOperation: ClientOperation<
'auth-transition',
{ userId: string | null }
> | null = null;
let platformSessionNativeMutationTail: Promise<void> = Promise.resolve();
const platformSessionRefreshListeners =
new Set<PlatformSessionRefreshListener>();
const platformSessionGenerationListeners =
new Set<PlatformSessionGenerationListener>();
export function getPlatformSessionOperation() {
return platformSessionOperation;
}
function restoreCommittedAccessToken() {
if (committedPlatformSession?.accessToken) {
window.localStorage.setItem(
@@ -259,15 +272,44 @@ export async function commitAuthenticatedPlatformSession(
if (!accessToken) {
throw new Error('陶泥儿登录凭据缺失,请重新登录');
}
const operation = createClientOperation(
'auth-transition',
{ userId: user.id },
{
scope: { apiBaseUrl, sessionGeneration: expectedGeneration },
deadlineMs: 45_000,
cancellable: false,
},
);
platformSessionOperation = transitionClientOperation(operation, 'runner');
return enqueuePlatformSessionNativeMutation(async () => {
const session = await commitPlatformSession(
user,
accessToken,
apiBaseUrl,
expectedGeneration,
);
if (!session) return null;
return session.generation;
try {
const session = await commitPlatformSession(
user,
accessToken,
apiBaseUrl,
expectedGeneration,
);
if (!session) {
platformSessionOperation = transitionClientOperation(
operation,
'unknown',
);
return null;
}
platformSessionOperation = transitionClientOperation(
operation,
'success',
{ scope: { sessionGeneration: session.generation } },
);
return session.generation;
} catch (error) {
platformSessionOperation = transitionClientOperation(
operation,
'retryable-failure',
);
throw error;
}
});
}
@@ -375,30 +417,64 @@ export function subscribePlatformSessionGeneration(
}
export async function clearCommittedPlatformSession(generation: number) {
const operation = createClientOperation(
'auth-transition',
{ userId: null },
{
scope: { sessionGeneration: generation },
deadlineMs: 45_000,
cancellable: false,
},
);
platformSessionOperation = transitionClientOperation(operation, 'runner');
return enqueuePlatformSessionNativeMutation(async () => {
if (platformAuthGeneration !== generation) {
await reconcileNativePlatformSessionToCurrentAuthority();
return;
}
desiredPlatformSession = null;
const nativeGeneration = await reserveNativePlatformSessionGeneration();
try {
await clearNativePlatformSession(nativeGeneration);
} catch {
if (platformAuthGeneration === generation) {
desiredPlatformSession = null;
if (platformAuthGeneration !== generation) {
await reconcileNativePlatformSessionToCurrentAuthority();
platformSessionOperation = transitionClientOperation(
operation,
'unknown',
);
return;
}
await reconcileNativePlatformSessionToCurrentAuthority();
return;
desiredPlatformSession = null;
const nativeGeneration = await reserveNativePlatformSessionGeneration();
try {
await clearNativePlatformSession(nativeGeneration);
} catch {
if (platformAuthGeneration === generation) {
desiredPlatformSession = null;
}
await reconcileNativePlatformSessionToCurrentAuthority();
platformSessionOperation = transitionClientOperation(
operation,
'retryable-failure',
);
return;
}
if (platformAuthGeneration !== generation) {
await reconcileNativePlatformSessionToCurrentAuthority();
platformSessionOperation = transitionClientOperation(
operation,
'unknown',
);
return;
}
committedPlatformSession = null;
desiredPlatformSession = null;
restoreCommittedAccessToken();
notifyPlatformSessionGeneration();
platformSessionOperation = transitionClientOperation(
operation,
'success',
);
} catch (error) {
platformSessionOperation = transitionClientOperation(
operation,
'retryable-failure',
);
throw error;
}
if (platformAuthGeneration !== generation) {
await reconcileNativePlatformSessionToCurrentAuthority();
return;
}
committedPlatformSession = null;
desiredPlatformSession = null;
restoreCommittedAccessToken();
notifyPlatformSessionGeneration();
});
}
@@ -409,6 +485,7 @@ export function resetPlatformSessionStateForTests() {
committedPlatformSession = null;
desiredPlatformSession = null;
platformSessionRefreshPromise = null;
platformSessionOperation = null;
platformSessionNativeMutationTail = Promise.resolve();
platformSessionRefreshListeners.clear();
platformSessionGenerationListeners.clear();