fix: address codex review findings

This commit is contained in:
Cita
2026-03-21 19:45:29 +08:00
parent 1d8889001f
commit d9e550c279
10 changed files with 638 additions and 167 deletions
+5 -2
View File
@@ -481,7 +481,10 @@ function buildSuccessfulRefreshResult(input: {
};
}
export async function refreshModelsForAccount(accountId: number): Promise<ModelRefreshResult> {
export async function refreshModelsForAccount(
accountId: number,
options?: { allowInactive?: boolean },
): Promise<ModelRefreshResult> {
const row = await db.select().from(schema.accounts)
.innerJoin(schema.sites, eq(schema.accounts.siteId, schema.sites.id))
.where(eq(schema.accounts.id, accountId))
@@ -516,7 +519,7 @@ export async function refreshModelsForAccount(accountId: number): Promise<ModelR
return buildSkippedRefreshResult(accountId, 'site_disabled', '站点已禁用');
}
if (account.status !== 'active') {
if (account.status !== 'active' && !options?.allowInactive) {
return buildSkippedRefreshResult(accountId, 'adapter_or_status', '平台不可用或账号未激活');
}
+12 -2
View File
@@ -242,7 +242,7 @@ async function upsertOauthAccount(input: {
accessToken: input.exchange.accessToken,
apiToken: null,
checkinEnabled: false,
status: 'active',
status: 'disabled',
oauthProvider: input.definition.metadata.provider,
oauthAccountKey: oauth.accountKey || oauth.accountId || null,
oauthProjectId: oauth.projectId || null,
@@ -376,7 +376,10 @@ export async function handleOauthCallback(input: {
throw new Error('failed to persist oauth account');
}
const refreshResult = await refreshModelsForAccount(account.id);
const refreshResult = await refreshModelsForAccount(
account.id,
previousAccount ? { allowInactive: true } : undefined,
);
if (refreshResult.status !== 'success') {
if (created) {
await db.delete(schema.accounts).where(eq(schema.accounts.id, account.id)).run();
@@ -401,6 +404,13 @@ export async function handleOauthCallback(input: {
throw new Error(errorMessage);
}
if (previousAccount) {
await db.update(schema.accounts).set({
status: 'active',
updatedAt: new Date().toISOString(),
}).where(eq(schema.accounts.id, account.id)).run();
}
await rebuildTokenRoutesFromAvailability();
markOauthSessionSuccess(input.state, {
accountId: account.id,
@@ -209,4 +209,48 @@ describe('TokenRouter site status guard', () => {
expect(selected).not.toBeNull();
expect(selected?.tokenValue).toBe('oauth-access-token');
});
it('does not fall back to a stale legacy api token when an oauth-managed row has no access token', async () => {
const site = await db.insert(schema.sites).values({
name: 'codex-site',
url: 'https://chatgpt.com/backend-api/codex',
platform: 'codex',
status: 'active',
}).returning().get();
const account = await db.insert(schema.accounts).values({
siteId: site.id,
username: 'codex-user@example.com',
accessToken: '',
apiToken: 'stale-direct-token',
status: 'active',
extraConfig: JSON.stringify({
credentialMode: 'session',
oauth: {
provider: 'codex',
accountId: 'chatgpt-account-123',
email: 'codex-user@example.com',
planType: 'plus',
},
}),
}).returning().get();
const route = await db.insert(schema.tokenRoutes).values({
modelPattern: 'gpt-5.2-codex',
enabled: true,
}).returning().get();
await db.insert(schema.routeChannels).values({
routeId: route.id,
accountId: account.id,
tokenId: null,
priority: 0,
weight: 10,
enabled: true,
manualOverride: false,
}).run();
const selected = await new TokenRouter().selectChannel('gpt-5.2-codex');
expect(selected).toBeNull();
});
});