1
0
forked from boos/BoosAPI

address comments

This commit is contained in:
ksmaze
2026-03-14 20:34:02 -07:00
parent ed3de8cca6
commit 0c7e600d41
2 changed files with 50 additions and 24 deletions
@@ -79,8 +79,8 @@ describe('accounts skipModelFetch behavior', () => {
}); });
expect(response.statusCode).toBe(200); expect(response.statusCode).toBe(200);
// getModels is called ONCE asynchronously by refreshModelsForAccount later in the flow // getModels should NOT be called when skipModelFetch is true
expect(getModelsMock).toHaveBeenCalledTimes(1); expect(getModelsMock).toHaveBeenCalledTimes(0);
const accounts = await db.select().from(schema.accounts).all(); const accounts = await db.select().from(schema.accounts).all();
expect(accounts).toHaveLength(1); expect(accounts).toHaveLength(1);
+48 -22
View File
@@ -1,5 +1,5 @@
import { FastifyInstance } from 'fastify'; import { FastifyInstance } from 'fastify';
import { db, schema } from '../../db/index.js'; import { db, schema, runtimeDbDialect } from '../../db/index.js';
import { and, eq, gte, lt, sql } from 'drizzle-orm'; import { and, eq, gte, lt, sql } from 'drizzle-orm';
import { refreshBalance } from '../../services/balanceService.js'; import { refreshBalance } from '../../services/balanceService.js';
import { getAdapter } from '../../services/platforms/index.js'; import { getAdapter } from '../../services/platforms/index.js';
@@ -979,7 +979,7 @@ export async function accountsRoutes(app: FastifyInstance) {
let verifiedModels: string[] = []; let verifiedModels: string[] = [];
if (credentialMode === 'apikey') { if (credentialMode === 'apikey') {
if (body.skipModelFetch) { if (body.skipModelFetch === true) {
tokenType = 'apikey'; tokenType = 'apikey';
accessToken = ''; accessToken = '';
if (!apiToken) apiToken = rawAccessToken; if (!apiToken) apiToken = rawAccessToken;
@@ -1104,10 +1104,14 @@ export async function accountsRoutes(app: FastifyInstance) {
if (tokenType === 'session') { if (tokenType === 'session') {
try { await refreshBalance(result.id); } catch { } try { await refreshBalance(result.id); } catch { }
} }
try {
await refreshModelsForAccount(result.id); // Try to refresh models only if not skipping.
await rebuildTokenRoutesFromAvailability(); if (body.skipModelFetch !== true) {
} catch { } try {
await refreshModelsForAccount(result.id);
await rebuildTokenRoutesFromAvailability();
} catch { }
}
const account = await db.select().from(schema.accounts).where(eq(schema.accounts.id, result.id)).get(); const account = await db.select().from(schema.accounts).where(eq(schema.accounts.id, result.id)).get();
const finalCredentialMode = account ? resolveStoredCredentialMode(account) : resolvedCredentialMode; const finalCredentialMode = account ? resolveStoredCredentialMode(account) : resolvedCredentialMode;
@@ -1418,7 +1422,7 @@ export async function accountsRoutes(app: FastifyInstance) {
return reply.code(400).send({ message: '模型列表不能为空' }); return reply.code(400).send({ message: '模型列表不能为空' });
} }
const normalizedModels = models.map(m => String(m).trim()).filter(m => m.length > 0); const normalizedModels = Array.from(new Set(models.map(m => String(m).trim()).filter(m => m.length > 0)));
if (normalizedModels.length === 0) { if (normalizedModels.length === 0) {
return reply.code(400).send({ message: '模型列表不能为空' }); return reply.code(400).send({ message: '模型列表不能为空' });
} }
@@ -1433,28 +1437,50 @@ export async function accountsRoutes(app: FastifyInstance) {
try { try {
await db.transaction(async (tx) => { await db.transaction(async (tx) => {
const checkedAt = new Date().toISOString();
for (const modelName of normalizedModels) { for (const modelName of normalizedModels) {
const existing = await tx.select() if (runtimeDbDialect === 'mysql') {
.from(schema.modelAvailability) const existing = await tx.select()
.where(and(eq(schema.modelAvailability.accountId, accountId), eq(schema.modelAvailability.modelName, modelName))) .from(schema.modelAvailability)
.get(); .where(and(eq(schema.modelAvailability.accountId, accountId), eq(schema.modelAvailability.modelName, modelName)))
.get();
if (existing) { if (existing) {
if (!existing.available || !existing.isManual) {
await tx.update(schema.modelAvailability) await tx.update(schema.modelAvailability)
.set({ available: true, latencyMs: null, isManual: true, checkedAt: new Date().toISOString() }) .set({ available: true, latencyMs: null, isManual: true, checkedAt })
.where(eq(schema.modelAvailability.id, existing.id)) .where(eq(schema.modelAvailability.id, existing.id))
.run(); .run();
} else {
await tx.insert(schema.modelAvailability).values({
accountId,
modelName,
available: true,
isManual: true,
latencyMs: null,
checkedAt,
}).run();
} }
} else { } else {
await tx.insert(schema.modelAvailability).values({ // SQLite / PostgreSQL path
accountId, await (tx.insert(schema.modelAvailability)
modelName, .values({
available: true, accountId,
isManual: true, modelName,
latencyMs: null, available: true,
checkedAt: new Date().toISOString(), isManual: true,
}).run(); latencyMs: null,
checkedAt,
}) as any)
.onConflictDoUpdate({
target: [schema.modelAvailability.accountId, schema.modelAvailability.modelName],
set: {
available: true,
isManual: true,
latencyMs: null,
checkedAt,
},
})
.run();
} }
} }
}); });