From bd8283774d79fd81358c50a2c2688f5d0321567c Mon Sep 17 00:00:00 2001 From: Lucas Berger Date: Fri, 5 Jun 2026 18:02:56 -0400 Subject: [PATCH] feat(03-07): VitePWA manifest + auth-safe SW denylist + iOS head/icons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add VitePWA plugin to vite.config.ts with registerType:autoUpdate - navigateFallbackDenylist excludes /callback, /api/, /health (T-03-20 Gate 2) - runtimeCaching: [] — no API response caching (T-03-21) - Manifest: name/short_name FamilySync, display:standalone, scope:/, theme_color #4A90D9 - Icons: 192x192, 512x512, 512x512 maskable in manifest - Generate icon-192.png (192x192), icon-512.png (512x512), apple-touch-icon.png (180x180) - Add five iOS head entries: apple-touch-icon link, apple-mobile-web-app-capable/status-bar-style/title - Build verified: dist/manifest.webmanifest emitted with correct fields; SW + workbox emitted --- apps/pwa/index.html | 4 +++ apps/pwa/public/apple-touch-icon.png | Bin 0 -> 617 bytes apps/pwa/public/icon-192.png | Bin 0 -> 699 bytes apps/pwa/public/icon-512.png | Bin 0 -> 4086 bytes apps/pwa/vite.config.ts | 37 ++++++++++++++++++++++++++- 5 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 apps/pwa/public/apple-touch-icon.png create mode 100644 apps/pwa/public/icon-192.png create mode 100644 apps/pwa/public/icon-512.png diff --git a/apps/pwa/index.html b/apps/pwa/index.html index e3cb868..5eca05e 100644 --- a/apps/pwa/index.html +++ b/apps/pwa/index.html @@ -4,6 +4,10 @@ + + + + FamilySync diff --git a/apps/pwa/public/apple-touch-icon.png b/apps/pwa/public/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..69ebb44546a0ab9d79d304b6e2f25a11eb43c15f GIT binary patch literal 617 zcmeAS@N?(olHy`uVBq!ia0vp^TR@nD2}o{QKQWbofyuzr#WAE}&f80Yxz3IPERK)4 zcU|C~)#C8$`sVYiLK!X2etrG=H~YV@v-US^KH@0E?kS^EIDra`myCsf>K>g97d?J= z_Ijnymvec$GWy!*e-G3}~-ZO#4S8&w5=S?+)STbQa&2L^+k-hz$M^RwF; z;_m*6F=qMl>e};JiVMQG+g;~j+`H@R&NPk}SJ$35b#_>vSG!Jlxar#Vr(Oy(4Ve0#df3I^w`bt_btIm_p@oq_B9(!`O_HG@kc}Z>$|#pkq4DCQ z_NV`y|BK~}7;G<{RS+I!j)nuFL{Q-KC(qzC!xs>FVdQ&MBb@08>am A9smFU literal 0 HcmV?d00001 diff --git a/apps/pwa/vite.config.ts b/apps/pwa/vite.config.ts index 0035c59..1a53218 100644 --- a/apps/pwa/vite.config.ts +++ b/apps/pwa/vite.config.ts @@ -1,8 +1,43 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' +import { VitePWA } from 'vite-plugin-pwa' export default defineConfig({ - plugins: [react()], + plugins: [ + react(), + VitePWA({ + registerType: 'autoUpdate', + // ⚠️ CRITICAL: exclude /callback from SW navigation handling (Gate 2 — T-03-20) + // The OIDC authorization-code exchange lands on /callback — if the SW + // intercepts this as a navigation, it serves the cached shell instead of + // letting the server process the authorization code exchange (login loop). + workbox: { + navigateFallback: '/index.html', + navigateFallbackDenylist: [ + /^\/callback/, // OIDC redirect endpoint — must reach the server + /^\/api\//, // API calls — never serve from cache + /^\/health/, // Health endpoint + ], + // No /api caching — runtimeCaching: [] means all API calls fall through to network + runtimeCaching: [], + }, + manifest: { + name: 'FamilySync', + short_name: 'FamilySync', + description: 'Family calendar and lists', + theme_color: '#4A90D9', + background_color: '#ffffff', + display: 'standalone', + scope: '/', + start_url: '/', + icons: [ + { src: '/icon-192.png', sizes: '192x192', type: 'image/png' }, + { src: '/icon-512.png', sizes: '512x512', type: 'image/png' }, + { src: '/icon-512.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' }, + ], + }, + }), + ], server: { proxy: { '/health': 'http://localhost:3000',