Skip to content

feat: add first-class WebSocket support via ctx.upgrade() and app.ws()#3774

Merged
bartlomieju merged 5 commits into
mainfrom
feat/websocket-support
Apr 22, 2026
Merged

feat: add first-class WebSocket support via ctx.upgrade() and app.ws()#3774
bartlomieju merged 5 commits into
mainfrom
feat/websocket-support

Conversation

@bartlomieju

@bartlomieju bartlomieju commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

Summary

  • ctx.upgrade() on the Context class with two overloads:
    • Bare mode: ctx.upgrade() or ctx.upgrade(options) returns { socket, response } for manual event wiring
    • Managed mode: ctx.upgrade(handlers) accepts { open, message, close, error } and returns the upgrade Response directly
  • app.ws(path, handlers, options?) shorthand that registers a GET route with automatic WebSocket upgrade (managed mode only)
  • Both support idleTimeout and protocol options forwarded to Deno.upgradeWebSocket()
  • Throws HttpError(400) on non-WebSocket requests
  • Case-insensitive Upgrade header check per RFC 6455 §4.2.1
  • Exports WebSocketHandlers and WebSocketUpgradeOptions types from fresh
  • Full documentation page with examples for managed mode, bare mode, broadcast chat, and client-side usage

Test plan

  • deno test -A packages/fresh/src/websocket_test.ts — 9/9 pass
    • Non-WebSocket request returns 400 (unit, via FakeServer — both ctx.upgrade() and app.ws())
    • Bare mode with protocol option (integration, real server)
    • Managed echo (integration, real server)
    • Bare echo (integration, real server)
    • app.ws() shorthand echo (integration, real server)
    • app.ws() with protocol option (integration, real server)
    • Error handler callback wiring (integration, real server)
    • Open + close handler callbacks fire (integration, real server)
  • All integration tests pass with Deno's default resource and op sanitizers enabled
  • deno fmt --check — clean
  • deno lint — clean

🤖 Generated with Claude Code

bartlomieju and others added 5 commits April 21, 2026 19:23
Adds ctx.upgrade() to the Context class with two overloads:
- Bare mode returns { socket, response } for manual event wiring
- Managed mode accepts handlers object and returns Response directly

Adds app.ws() shorthand for registering WebSocket endpoints.
Throws HttpError(400) on non-WebSocket requests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add doc comment on isWebSocketHandlers explaining duck-typing dispatch
  and when it would need updating
- Remove sanitizeOps/sanitizeResources: false from integration tests
  (both sanitizers pass cleanly with defaults)
- Add test for bare-mode ctx.upgrade() with protocol option
- Clarify bare-mode options example in docs and note that app.ws() is
  managed-mode only
- Compare upgrade header case-insensitively per RFC 6455 §4.2.1
- Document the empty-object ({}) edge case in isWebSocketHandlers
- Add test for app.ws() with protocol option
- Add test exercising the error handler callback wiring
@bartlomieju bartlomieju merged commit 0ab5a2a into main Apr 22, 2026
9 checks passed
@bartlomieju bartlomieju deleted the feat/websocket-support branch April 22, 2026 17:17
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