Wahoo provides bounded Server-Sent Events (SSE) and WebSocket primitives. Generated realtime routes return `501 Not Implemented` until the application adds policy.

> **Work in progress:** Do not use Wahoo in production yet.

## SSE Topics

Use a topic for tenant- or subject-scoped events. Authorize the request before you select the topic handler.

```go
events := realtime.NewHub(
    realtime.WithMaxClients(100),
    realtime.WithMaxStreamAge(10*time.Minute),
)

topic, err := events.Topic("tenant:ten_123")
if err != nil {
    return err
}
runtime.Handle("GET /events", authenticated(topic))

events.PublishTo("tenant:ten_123", realtime.Event{
    ID:   "evt_123",
    Name: "project.updated",
    Data: []byte(`{"project_id":"prj_123"}`),
})
```

The hub has a default 1000-client limit, 15-minute stream lifetime, 25-second heartbeats, one buffered event per client, and slow-client eviction. Event data is copied before delivery. SSE clears the normal HTTP write deadline for the selected long-lived response.

`Publish` is global. Use it only for intentionally global events. The hub is local to one Go process. Publish through a shared system when you run more than one instance, then deliver to each instance's authorized local clients.

## Required Application Policy

1. Authenticate the session before the SSE handler attaches.
2. Resolve and authorize the tenant before selecting a topic.
3. Apply per-principal and per-IP connection limits.
4. Publish only tenant-scoped data.
5. Bound event payload size before you publish it.

## WebSockets

`realtime.WebSocket` keeps the request-host same-origin behavior from `coder/websocket`, sets a 1 MiB message limit, and applies a 15-minute connection context. It does not authenticate, rate limit, serialize writes, or provide shared fanout.

```go
runtime.Handle("GET /ws", authenticated(realtime.WebSocket(handleSocket, &websocket.AcceptOptions{
    OriginPatterns: []string{"app.example.com"},
})))
```

Do not use `realtime.Echo()` in a public service. Do not expose internal errors through WebSocket close reasons.

## Test

```bash
go test -race ./...
```

Test authorization before connection setup, tenant isolation, client limits, idle timeouts, message-size limits, and write serialization.