From 45acc3b5506537a1eb7b7f0a91fefe6873ebddeb Mon Sep 17 00:00:00 2001 From: Admin Date: Wed, 23 Sep 2026 03:50:54 +0000 Subject: [PATCH] fix: harden PWA boot and auth routing --- index.html | 10 +++++++++- server/index.js | 46 ++++++++++++++++++++++++++++++++++++++++++++-- src/main.tsx | 38 ++++++++++++++++++++++++++------------ vite.config.ts | 10 ++++++++++ 4 files changed, 89 insertions(+), 15 deletions(-) diff --git a/index.html b/index.html index 509aba9..b84f910 100644 --- a/index.html +++ b/index.html @@ -8,7 +8,15 @@ Template Studio -
+
+
+
+
T
+ Template Studio +

Loading…

+
+
+
diff --git a/server/index.js b/server/index.js index b3bf223..c30023a 100644 --- a/server/index.js +++ b/server/index.js @@ -401,8 +401,50 @@ app.delete('/api/api-keys/:id', async (req, res) => { res.status(204).end() }) -app.use(express.static('dist')) -app.get(/^(?!\/api|\/auth).*/, (_req, res) => res.sendFile('index.html', { root: 'dist' })) +app.get('/reset-pwa', (_req, res) => { + res.setHeader('Cache-Control', 'no-store') + res.type('html').send(` +Resetting Template Studio + +

Resetting Template Studio…

+

This clears only Template Studio's local PWA caches and service worker.

+ +`) +}) + +app.use(express.static('dist', { + setHeaders(res, filePath) { + if (filePath.endsWith('/index.html') || filePath.endsWith('/sw.js') || filePath.endsWith('/manifest.webmanifest')) { + res.setHeader('Cache-Control', 'no-store, max-age=0') + return + } + if (filePath.includes('/assets/')) { + res.setHeader('Cache-Control', 'public, max-age=31536000, immutable') + } + } +})) + +app.use('/assets', (_req, res) => res.status(404).type('text').send('Asset not found')) + +app.get(/^(?!\/api|\/auth|\/reset-pwa).*/, (_req, res) => { + res.setHeader('Cache-Control', 'no-store, max-age=0') + res.sendFile('index.html', { root: 'dist' }) +}) app.use((error, _req, res, _next) => { console.error(error) res.status(500).json({ error: 'internal_error' }) diff --git a/src/main.tsx b/src/main.tsx index 3d73fc0..8e04965 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -5,10 +5,32 @@ import { App } from './App' import './styles.css' import './refine.css' -async function bootstrap() { - registerSW({ immediate: true }) +function showBootError(error: unknown) { + document.body.innerHTML = ` +
+

Template Studio

+

The app could not start cleanly.

+
${String(error)}
+

Reset local app cache and reload

+
+ ` +} - const session = await fetch('/api/session', { headers: { Accept: 'application/json' } }) +async function bootstrap() { + registerSW({ + immediate: true, + onRegisteredSW(_url, registration) { + if (registration) void registration.update() + }, + onRegisterError(error) { + console.error('Service worker registration failed', error) + } + }) + + const session = await fetch('/api/session', { + headers: { Accept: 'application/json' }, + cache: 'no-store' + }) if (session.status === 401) { window.location.assign('/auth/login') return @@ -23,12 +45,4 @@ async function bootstrap() { ) } -bootstrap().catch(error => { - document.body.innerHTML = ` -
-

Template Studio

-

Unable to start the application.

-
${String(error)}
-
- ` -}) +bootstrap().catch(showBootError) diff --git a/vite.config.ts b/vite.config.ts index 0114fb7..4e72502 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -7,6 +7,16 @@ export default defineConfig({ react(), VitePWA({ registerType: 'autoUpdate', + workbox: { + cleanupOutdatedCaches: true, + clientsClaim: true, + skipWaiting: true, + navigateFallbackDenylist: [ + /^\/api(?:\/|$)/, + /^\/auth(?:\/|$)/, + /^\/reset-pwa(?:\/|$)/ + ] + }, manifest: { name: 'Arrowstack Template Studio', short_name: 'Templates',