Skip to content

fix: session expiry JSON errors, SSE drops, and subpath routing#5

Open
TheGr3atJosh wants to merge 1 commit into
ValienteTechnologies:mainfrom
TheGr3atJosh:bug-fixes
Open

fix: session expiry JSON errors, SSE drops, and subpath routing#5
TheGr3atJosh wants to merge 1 commit into
ValienteTechnologies:mainfrom
TheGr3atJosh:bug-fixes

Conversation

@TheGr3atJosh
Copy link
Copy Markdown
Contributor

Summary

  • Session expiry (Bug 1): require_token now returns a JSON 401 for /api/* routes instead of an HTML redirect, so fetch() callers don't choke on resp.json(). The JS render flow checks resp.status === 401 before parsing and reloads on expiry.
  • SSE connection drops (Bug 2): Gunicorn's --timeout raised from 180 s to 600 s — cold Chromium + WeasyPrint renders after 2–3 min idle were hitting the per-connection deadline. The render thread now catches BaseException so crashes always emit a done event. SSE heartbeat interval reduced 90 s → 15 s for proxy compatibility. A _pollForPdf fallback was added: if the SSE drops mid-render the client polls /api/render/{id}/pdf every 3 s rather than surfacing a false connection-lost error.
  • Subpath routing (Bug 3): window.APP_ROOT is injected from request.script_root so JS fetch calls work correctly under APPLICATION_ROOT=/ghostbadger.

Test plan

  • Log in, render a report — PDF appears without errors
  • Leave the tab idle 3–5 minutes, render again — should complete without "SSE connection closed unexpectedly"
  • Invalidate/expire the session cookie, trigger a render — should redirect to login without a JS console error
  • Deploy with APPLICATION_ROOT=/ghostbadger — all API calls should resolve correctly under the subpath

🤖 Generated with Claude Code

Bug 1 — session expiry caused JSON.parse errors on API fetch calls:
- decorators.py: return 401 JSON for /api/* routes instead of an HTML redirect
- dashboard.js: check resp.status === 401 before calling resp.json(); reload on expiry

Bug 2 — SSE connection closed unexpectedly after idle periods:
- Dockerfile: raise gunicorn --timeout from 180s to 600s; cold Chromium/WeasyPrint
  renders after 2-3 min idle were breaching the per-connection deadline
- routes.py: catch BaseException (not just Exception) in render thread so crashes
  always emit a done event; reduce SSE heartbeat interval 90s → 15s for proxies
- dashboard.js: add _renderDone guard to prevent onerror/done races; when SSE drops
  mid-render (CONNECTING state) fall back to polling /api/render/{id}/pdf every 3s
  instead of immediately surfacing a connection-lost error

Bug 3 — all API calls 404 under APPLICATION_ROOT subpath:
- base.html: inject window.APP_ROOT from Flask's request.script_root
- dashboard.js: define _apiBase = (APP_ROOT || "") + "/dashboard" and replace all
  eight hardcoded /dashboard/api/... fetch URLs with the prefixed base

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@TheGr3atJosh
Copy link
Copy Markdown
Contributor Author

I think the SSE drops are still present but less frequent. I don't fully understand why they are happening. Maybe we convert this to a draft or remove that part of the PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant