fix: harden PWA boot and auth routing
This commit is contained in:
parent
99c0d5887e
commit
45acc3b550
10
index.html
10
index.html
@ -8,7 +8,15 @@
|
||||
<title>Template Studio</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<div id="root">
|
||||
<main id="boot-shell" style="font-family:system-ui,-apple-system,sans-serif;min-height:100dvh;display:grid;place-items:center;background:#f7f9fb;color:#172033">
|
||||
<div style="text-align:center;padding:24px">
|
||||
<div style="width:42px;height:42px;margin:0 auto 14px;border-radius:12px;background:#111827;color:white;display:grid;place-items:center;font-weight:800">T</div>
|
||||
<strong>Template Studio</strong>
|
||||
<p style="margin:6px 0 0;color:#718096;font-size:13px">Loading…</p>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -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(`<!doctype html>
|
||||
<html><head><meta name="viewport" content="width=device-width,initial-scale=1"><title>Resetting Template Studio</title></head>
|
||||
<body style="font-family:system-ui,-apple-system,sans-serif;padding:32px;color:#172033">
|
||||
<h1>Resetting Template Studio…</h1>
|
||||
<p>This clears only Template Studio's local PWA caches and service worker.</p>
|
||||
<script>
|
||||
(async () => {
|
||||
try {
|
||||
if ('serviceWorker' in navigator) {
|
||||
const registrations = await navigator.serviceWorker.getRegistrations()
|
||||
await Promise.all(registrations.map(registration => registration.unregister()))
|
||||
}
|
||||
if ('caches' in window) {
|
||||
const names = await caches.keys()
|
||||
await Promise.all(names.map(name => caches.delete(name)))
|
||||
}
|
||||
} finally {
|
||||
location.replace('/?fresh=' + Date.now())
|
||||
}
|
||||
})()
|
||||
</script>
|
||||
</body></html>`)
|
||||
})
|
||||
|
||||
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' })
|
||||
|
||||
38
src/main.tsx
38
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 = `
|
||||
<main style="font-family:system-ui,-apple-system,sans-serif;padding:24px;max-width:720px;margin:48px auto;color:#172033">
|
||||
<h1 style="margin-bottom:8px">Template Studio</h1>
|
||||
<p style="color:#64748b">The app could not start cleanly.</p>
|
||||
<pre style="white-space:pre-wrap;background:#f1f5f9;padding:12px;border-radius:10px">${String(error)}</pre>
|
||||
<p><a href="/reset-pwa" style="color:#1d4ed8;font-weight:700">Reset local app cache and reload</a></p>
|
||||
</main>
|
||||
`
|
||||
}
|
||||
|
||||
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 = `
|
||||
<main style="font-family:system-ui;padding:24px;max-width:720px;margin:auto">
|
||||
<h1>Template Studio</h1>
|
||||
<p>Unable to start the application.</p>
|
||||
<pre style="white-space:pre-wrap">${String(error)}</pre>
|
||||
</main>
|
||||
`
|
||||
})
|
||||
bootstrap().catch(showBootError)
|
||||
|
||||
@ -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',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user