diff --git a/src/server/routes/api/downstreamApiKeys.ts b/src/server/routes/api/downstreamApiKeys.ts index 423db26..78afe1e 100644 --- a/src/server/routes/api/downstreamApiKeys.ts +++ b/src/server/routes/api/downstreamApiKeys.ts @@ -22,6 +22,10 @@ function validateKeyShape(key: string): boolean { function looksLikeUniqueViolation(error: unknown): boolean { const message = (error as Error | undefined)?.message || ''; + if (runtimeDbDialect === 'postgres') { + return message.includes('duplicate key value violates unique constraint') && + message.includes('downstream_api_keys_key_unique'); + } return message.includes('UNIQUE constraint failed') && message.includes('downstream_api_keys.key'); } diff --git a/src/server/services/downstreamApiKeyService.ts b/src/server/services/downstreamApiKeyService.ts index 105f6d0..88068db 100644 --- a/src/server/services/downstreamApiKeyService.ts +++ b/src/server/services/downstreamApiKeyService.ts @@ -90,13 +90,25 @@ function normalizePositiveIntegerOrNull(value: unknown): number | null { return normalized; } -function parseJson(value: string | null | undefined): unknown { - if (!value) return null; - try { - return JSON.parse(value); - } catch { - return null; +function parseJson(value: unknown): unknown { + if (value === null || value === undefined) return null; + + // PostgreSQL JSONB columns are returned as parsed objects/arrays by the pg driver + if (typeof value === 'object') { + return value; } + + // SQLite TEXT columns store JSON as strings that need parsing + if (typeof value === 'string') { + if (value === '') return null; + try { + return JSON.parse(value); + } catch { + return null; + } + } + + return null; } export function normalizeGroupNameInput(input: unknown): string | null {