From e16bdd95462e1e89f591b4e134125e37b6cdb410 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sun, 10 May 2026 23:10:22 -0400 Subject: [PATCH] fix(web): read snake_case keys in MobileAppDownload (#397) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Server's clientVersionResponse marshals to {version, apk_url, size_bytes} but the component was reading body.apkUrl / body.sizeBytes (camelCase). The !body.apkUrl guard was always true → early return → download button never rendered even when /api/client/version returned 200 with valid data. Verified directly: /api/client/version returns {"version":"v2026.05.10.1","apk_url":"/api/client/apk","size_bytes":65301242} on the deployed v2026.05.10.1 image; the UI just wasn't reading those keys. Map wire (snake_case) → component (camelCase) explicitly via a WireInfo type so the boundary is auditable. Co-Authored-By: Claude Opus 4.7 (1M context) --- web/src/lib/components/MobileAppDownload.svelte | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/web/src/lib/components/MobileAppDownload.svelte b/web/src/lib/components/MobileAppDownload.svelte index cedaddff..6766e96d 100644 --- a/web/src/lib/components/MobileAppDownload.svelte +++ b/web/src/lib/components/MobileAppDownload.svelte @@ -11,6 +11,10 @@ // bandwidth abuse on the APK stream, so this component only shows // for logged-in users. Mount in Settings, never in pre-auth surfaces. + // Server returns snake_case (clientVersionResponse in + // internal/api/client_assets.go). Map to a camelCase struct for + // the rest of the component. + type WireInfo = { version: string; apk_url: string; size_bytes: number }; type Info = { version: string; apkUrl: string; sizeBytes: number }; let info = $state(null); @@ -22,12 +26,12 @@ onMount(async () => { try { - const body = await api.get>('/api/client/version'); - if (!body.version || !body.apkUrl) return; + const body = await api.get>('/api/client/version'); + if (!body.version || !body.apk_url) return; info = { version: body.version, - apkUrl: body.apkUrl, - sizeBytes: body.sizeBytes ?? 0 + apkUrl: body.apk_url, + sizeBytes: body.size_bytes ?? 0 }; } catch { // 404 (no APK), 401 (somehow unauthed), network error — silent.