forked from boos/BoosAPI
fix(api): unwrap downstream key unique violations
This commit is contained in:
@@ -314,6 +314,44 @@ describe('downstream api keys routes', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('rejects duplicate key update with conflict status', async () => {
|
||||||
|
const firstRes = await app.inject({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/api/downstream-keys',
|
||||||
|
payload: {
|
||||||
|
name: 'dup-a',
|
||||||
|
key: 'sk-dup-key-001',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(firstRes.statusCode).toBe(200);
|
||||||
|
|
||||||
|
const secondRes = await app.inject({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/api/downstream-keys',
|
||||||
|
payload: {
|
||||||
|
name: 'dup-b',
|
||||||
|
key: 'sk-dup-key-002',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(secondRes.statusCode).toBe(200);
|
||||||
|
|
||||||
|
const secondId = secondRes.json().item.id as number;
|
||||||
|
const duplicateUpdateRes = await app.inject({
|
||||||
|
method: 'PUT',
|
||||||
|
url: `/api/downstream-keys/${secondId}`,
|
||||||
|
payload: {
|
||||||
|
name: 'dup-b-updated',
|
||||||
|
key: 'sk-dup-key-001',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(duplicateUpdateRes.statusCode).toBe(409);
|
||||||
|
expect(duplicateUpdateRes.json()).toMatchObject({
|
||||||
|
success: false,
|
||||||
|
message: 'API key 已存在',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('returns summary, overview and trend aggregated from proxy logs', async () => {
|
it('returns summary, overview and trend aggregated from proxy logs', async () => {
|
||||||
const inserted = await db.insert(schema.downstreamApiKeys).values({
|
const inserted = await db.insert(schema.downstreamApiKeys).values({
|
||||||
name: 'analytics-key',
|
name: 'analytics-key',
|
||||||
|
|||||||
@@ -20,13 +20,42 @@ function validateKeyShape(key: string): boolean {
|
|||||||
return key.startsWith('sk-') && key.length >= 6;
|
return key.startsWith('sk-') && key.length >= 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
function looksLikeUniqueViolation(error: unknown): boolean {
|
type ErrorLike = {
|
||||||
const message = (error as Error | undefined)?.message || '';
|
message?: string;
|
||||||
if (runtimeDbDialect === 'postgres') {
|
code?: string | number;
|
||||||
return message.includes('duplicate key value violates unique constraint') &&
|
cause?: unknown;
|
||||||
message.includes('downstream_api_keys_key_unique');
|
};
|
||||||
|
|
||||||
|
function getErrorChain(error: unknown): ErrorLike[] {
|
||||||
|
const chain: ErrorLike[] = [];
|
||||||
|
const seen = new Set<unknown>();
|
||||||
|
let current: unknown = error;
|
||||||
|
while (current && typeof current === 'object' && !seen.has(current)) {
|
||||||
|
seen.add(current);
|
||||||
|
chain.push(current as ErrorLike);
|
||||||
|
current = (current as ErrorLike).cause;
|
||||||
}
|
}
|
||||||
return message.includes('UNIQUE constraint failed') && message.includes('downstream_api_keys.key');
|
return chain;
|
||||||
|
}
|
||||||
|
|
||||||
|
function looksLikeUniqueViolation(error: unknown): boolean {
|
||||||
|
const chain = getErrorChain(error);
|
||||||
|
if (runtimeDbDialect === 'postgres') {
|
||||||
|
return chain.some((entry) => {
|
||||||
|
const message = entry.message || '';
|
||||||
|
const code = String(entry.code || '');
|
||||||
|
return code === '23505'
|
||||||
|
|| (message.includes('duplicate key value violates unique constraint')
|
||||||
|
&& message.includes('downstream_api_keys_key_unique'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return chain.some((entry) => {
|
||||||
|
const message = entry.message || '';
|
||||||
|
const code = String(entry.code || '');
|
||||||
|
return code === 'SQLITE_CONSTRAINT'
|
||||||
|
|| code === 'SQLITE_CONSTRAINT_UNIQUE'
|
||||||
|
|| (message.includes('UNIQUE constraint failed') && message.includes('downstream_api_keys.key'));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeBatchIds(raw: unknown): number[] {
|
function normalizeBatchIds(raw: unknown): number[] {
|
||||||
|
|||||||
Reference in New Issue
Block a user