From 14ecae61dce0cd136425636484ca81c4c313be9a Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Fri, 3 Apr 2026 15:10:11 +0200 Subject: [PATCH] feat: enhance error handling in Stalwart API responses --- app/api/account/stalwart/auth/route.ts | 19 +++++++++++++++++-- app/api/account/stalwart/crypto/route.ts | 19 +++++++++++++++++-- app/api/account/stalwart/principal/route.ts | 19 +++++++++++++++++-- .../settings/account-security-settings.tsx | 3 ++- locales/de/common.json | 3 ++- locales/en/common.json | 3 ++- locales/es/common.json | 3 ++- locales/fr/common.json | 3 ++- locales/it/common.json | 3 ++- locales/ja/common.json | 3 ++- locales/nl/common.json | 3 ++- locales/pt/common.json | 3 ++- locales/ru/common.json | 3 ++- 13 files changed, 71 insertions(+), 16 deletions(-) diff --git a/app/api/account/stalwart/auth/route.ts b/app/api/account/stalwart/auth/route.ts index d1ee34a3..4fa0f4d0 100644 --- a/app/api/account/stalwart/auth/route.ts +++ b/app/api/account/stalwart/auth/route.ts @@ -2,6 +2,20 @@ import { NextRequest, NextResponse } from 'next/server'; import { logger } from '@/lib/logger'; import { getStalwartCredentials } from '@/lib/stalwart/credentials'; +/** + * Parse Stalwart error response to extract meaningful error message + */ +function parseStalwartError(responseText: string): string { + try { + const error = JSON.parse(responseText); + if (error.detail) return error.detail; + if (error.error) return error.error; + return `HTTP ${error.status || 'Error'}`; + } catch { + return responseText; + } +} + /** * GET /api/account/stalwart/auth * Proxy to Stalwart GET /api/account/auth @@ -20,9 +34,10 @@ export async function GET(request: NextRequest) { if (!response.ok) { const text = await response.text(); - logger.warn('Stalwart auth info failed', { status: response.status }); + const detail = parseStalwartError(text); + logger.warn('Stalwart auth info failed', { status: response.status, detail }); return NextResponse.json( - { error: 'Failed to fetch auth info', details: text }, + { error: detail || 'Failed to fetch auth info' }, { status: response.status } ); } diff --git a/app/api/account/stalwart/crypto/route.ts b/app/api/account/stalwart/crypto/route.ts index 6c5f3502..07681115 100644 --- a/app/api/account/stalwart/crypto/route.ts +++ b/app/api/account/stalwart/crypto/route.ts @@ -2,6 +2,20 @@ import { NextRequest, NextResponse } from 'next/server'; import { logger } from '@/lib/logger'; import { getStalwartCredentials } from '@/lib/stalwart/credentials'; +/** + * Parse Stalwart error response to extract meaningful error message + */ +function parseStalwartError(responseText: string): string { + try { + const error = JSON.parse(responseText); + if (error.detail) return error.detail; + if (error.error) return error.error; + return `HTTP ${error.status || 'Error'}`; + } catch { + return responseText; + } +} + /** * GET /api/account/stalwart/crypto * Proxy to Stalwart GET /api/account/crypto @@ -20,9 +34,10 @@ export async function GET(request: NextRequest) { if (!response.ok) { const text = await response.text(); - logger.warn('Stalwart crypto info failed', { status: response.status }); + const detail = parseStalwartError(text); + logger.warn('Stalwart crypto info failed', { status: response.status, detail }); return NextResponse.json( - { error: 'Failed to fetch crypto info', details: text }, + { error: detail || 'Failed to fetch crypto info' }, { status: response.status } ); } diff --git a/app/api/account/stalwart/principal/route.ts b/app/api/account/stalwart/principal/route.ts index 5b7131cb..8801c2b6 100644 --- a/app/api/account/stalwart/principal/route.ts +++ b/app/api/account/stalwart/principal/route.ts @@ -2,6 +2,20 @@ import { NextRequest, NextResponse } from 'next/server'; import { logger } from '@/lib/logger'; import { getStalwartCredentials } from '@/lib/stalwart/credentials'; +/** + * Parse Stalwart error response to extract meaningful error message + */ +function parseStalwartError(responseText: string): string { + try { + const error = JSON.parse(responseText); + if (error.detail) return error.detail; + if (error.error) return error.error; + return `HTTP ${error.status || 'Error'}`; + } catch { + return responseText; + } +} + /** * GET /api/account/stalwart/principal * Proxy to Stalwart GET /api/principal/{username} @@ -20,9 +34,10 @@ export async function GET(request: NextRequest) { if (!response.ok) { const text = await response.text(); - logger.warn('Stalwart principal fetch failed', { status: response.status }); + const detail = parseStalwartError(text); + logger.warn('Stalwart principal fetch failed', { status: response.status, detail }); return NextResponse.json( - { error: 'Failed to fetch principal', details: text }, + { error: detail || 'Failed to fetch principal' }, { status: response.status } ); } diff --git a/components/settings/account-security-settings.tsx b/components/settings/account-security-settings.tsx index 51b3a972..5f1624d4 100644 --- a/components/settings/account-security-settings.tsx +++ b/components/settings/account-security-settings.tsx @@ -157,6 +157,7 @@ function DisplayNameSection() { setName(e.target.value)} + placeholder={displayName || t('display_name.placeholder')} className="w-48" />