fix: session HUD syntax error + no-cache the app shell

- The roster card's empty-state string had a broken apostrophe escape
  ("who\\'s") that terminated the string early — a syntax error that killed the
  whole session.html script, so the HUD only rendered from a stale cached shell.
  Reworded to drop the apostrophe.
- Add a middleware that sets Cache-Control: no-cache on HTML/JS so a PWA can't
  keep serving a stale shell after a deploy (iOS heuristically caches when no
  cache header is present — the reason a hard refresh + reopen didn't update).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-04 03:54:18 +00:00
parent 9b844bc356
commit 5da13a7321
2 changed files with 11 additions and 1 deletions
+10
View File
@@ -50,6 +50,16 @@ def _last_user_message(messages: list[dict]) -> str:
def create_app() -> FastAPI: def create_app() -> FastAPI:
app = FastAPI(title="Lyra Web") app = FastAPI(title="Lyra Web")
@app.middleware("http")
async def _no_stale_shell(request: Request, call_next):
"""Always revalidate HTML/JS so a PWA can't serve a stale app shell after a
deploy (iOS applies heuristic caching when no cache header is set)."""
resp = await call_next(request)
ct = resp.headers.get("content-type", "")
if "text/html" in ct or "javascript" in ct:
resp.headers["Cache-Control"] = "no-cache, must-revalidate"
return resp
@app.get("/_health") @app.get("/_health")
async def health() -> dict: async def health() -> dict:
return {"ok": True} return {"ok": True}
+1 -1
View File
@@ -380,7 +380,7 @@
<button class="mini" title="Rename / fix" onclick="renamePlayer(${v.id}, '${esc(v.name||'').replace(/'/g,"\\'")}')">✎</button> <button class="mini" title="Rename / fix" onclick="renamePlayer(${v.id}, '${esc(v.name||'').replace(/'/g,"\\'")}')">✎</button>
${v.last_note ? `<div class="note-meta">“${esc(v.last_note)}”</div>` : ''} ${v.last_note ? `<div class="note-meta">“${esc(v.last_note)}”</div>` : ''}
</li>`).join('')}</ul>` </li>`).join('')}</ul>`
: '<p class="empty">No roster yet — tell Lyra who\\'s at the table.</p>'} : '<p class="empty">No roster yet — tell Lyra who is at the table.</p>'}
</div> </div>
<div class="card"> <div class="card">