Unknown-path WS probes (e.g. /waapi) generate three INFO lines from
uvicorn.access + uvicorn.error on every attempt. Install a logging.Filter
on both loggers at startup to drop:
- access log entries: "WebSocket <path>" 403
- error log entries: "connection rejected ..." / "connection closed"
These are handled gracefully by _SPAStaticFiles; the logs add no value.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The middleware was calling the handler as a raw ASGI callable
(scope, receive, send), but websocket_endpoint expects (WebSocket, token).
This caused an AttributeError on every connection attempt, which made the
frontend hit its 30s exponential backoff cap and spam reconnects.
Fix: construct a WebSocket object from scope/receive/send and extract the
?token= query param before calling the handler, matching what FastAPI's
routing machinery would do.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
_WSInterceptMiddleware intercepts /ws WebSocket scopes at the outermost
ASGI layer before Starlette routing is consulted, so Mount('/') can never
hand a WS connection to _SPAStaticFiles regardless of route ordering.
Also downgrade the _SPAStaticFiles non-HTTP fallback log from WARNING to
DEBUG — the graceful close still fires as a safety net, but no longer
spams the log since the middleware handles the normal case.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
In Starlette 0.52+, Mount('/') returns Match.FULL for every WebSocket
scope. If APIWebSocketRoute('/ws') is somehow not matched first, the
StaticFiles mount catches the connection and crashes with:
assert scope["type"] == "http" # AssertionError
Two-layer fix:
- _SPAStaticFiles.__call__: gracefully close non-HTTP connections with
WebSocketClose() and log a warning with the actual path/type so the
routing issue can be diagnosed.
- app.add_websocket_route('/ws', websocket_endpoint): belt-and-suspenders
registration using Starlette's base WebSocketRoute (simpler than
FastAPI's APIWebSocketRoute) right before the StaticFiles mount. If
include_router's APIWebSocketRoute doesn't match, this fallback will.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rewrote README.md to reflect the actual project state: dual Discord
bot + FastAPI web UI, WorkflowInspector-based dynamic node injection,
no SerialJobQueue, full env var table, frontend build steps, web auth
setup, and updated credits/troubleshooting.
Removed three files that were actively misleading:
- DEVELOPMENT.md and QUICK_START.md referenced deleted modules
(job_queue.py, upload.py) and old WorkflowManager/StateManager APIs
- backfill_image_data.py was a completed one-shot migration script
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>