diff --git a/apps/pwa/src/api/client.ts b/apps/pwa/src/api/client.ts index 7d08ce0..d02de1c 100644 --- a/apps/pwa/src/api/client.ts +++ b/apps/pwa/src/api/client.ts @@ -543,12 +543,15 @@ export interface SetupStatusResponse { * Payload for POST /api/setup/config. * Collects non-secret runtime config written to the app_config table (D-02). * No secrets — VAPID private key and encryption key stay in Docker env. + * + * Field names match the API's configSchema exactly (camelCase). + * API contract: { oidcIssuer, oidcClientId, vapidPublicKey, appExternalUrl } */ export interface SetupConfigPayload { - app_url: string; - oidc_issuer: string; - oidc_client_id: string; - vapid_public_key: string; + appExternalUrl: string; + oidcIssuer: string; + oidcClientId: string; + vapidPublicKey: string; } /** @@ -594,8 +597,26 @@ export async function postSetupConfig(payload: SetupConfigPayload): Promise ({}))) as { error?: string }; - throw new Error(body.error ?? `POST /api/setup/config failed: ${res.status}`); + const body = (await res.json().catch(() => ({}))) as { + error?: string | { name?: string; issues?: Array<{ message: string }> }; + }; + // body.error may be a ZodError object ({ name: "ZodError", issues: [...] }) + // rather than a plain string — extract the first issue message to avoid + // "[object Object]" appearing in the UI (BUG 2 fix). + let message: string; + if (typeof body.error === 'string') { + message = body.error; + } else if ( + body.error && + typeof body.error === 'object' && + Array.isArray((body.error as { issues?: unknown[] }).issues) && + (body.error as { issues: Array<{ message: string }> }).issues.length > 0 + ) { + message = (body.error as { issues: Array<{ message: string }> }).issues[0].message; + } else { + message = `POST /api/setup/config failed: ${res.status}`; + } + throw new Error(message); } } diff --git a/apps/pwa/src/routes/SetupPage.tsx b/apps/pwa/src/routes/SetupPage.tsx index c2b2290..2d310d4 100644 --- a/apps/pwa/src/routes/SetupPage.tsx +++ b/apps/pwa/src/routes/SetupPage.tsx @@ -502,10 +502,10 @@ function Step2Config({ onBack, onSuccess, stepHeadingRef }: Step2Props) { } configMutation.mutate({ - app_url: appUrl.trim(), - oidc_issuer: oidcIssuer.trim(), - oidc_client_id: oidcClientId.trim(), - vapid_public_key: vapidPublicKey.trim(), + appExternalUrl: appUrl.trim(), + oidcIssuer: oidcIssuer.trim(), + oidcClientId: oidcClientId.trim(), + vapidPublicKey: vapidPublicKey.trim(), }); }