WebSocket endpoint specs — single source of truth for both surface
generation *and* live dispatch. Each entry is auto-mounted via
register_ws_endpoint against the assembled Hono app on every
runtime, so consumers don't call register_ws_endpoint themselves.
Accepts either an array (evaluated eagerly) or a factory
(ctx: AppServerContext) => ReadonlyArray<WsEndpointSpec>
(evaluated after the server context is assembled). Use the factory
form when action lists depend on ctx.deps — e.g. when spreading
create_standard_rpc_actions({...ctx.deps, notification_sender}) over WS.
When non-empty, create_upgrade_websocket must be supplied (throws
otherwise). A factory returning [] does NOT trip the check —
feature-flag gated WS surfaces stay safe.
Every mount gets what the HTTP surface gets: the auth middleware (a
path outside AUTH_MIDDLEWARE_PATH throws at assembly, like
rpc_endpoints), the server's allowed_origins unless the spec
narrows them, and the same action_ip_rate_limiter /
action_account_rate_limiter instances the RPC endpoints charge — one
budget per action across both transports. The upgrade routes register
after the route specs and before post_route_middleware and
static_serving, so neither runs ahead of an upgrade.
Duplicate path values across two WsEndpointSpecs, and a path a
GET RouteSpec already claims, throw at assembly before any endpoint
mounts (Hono would silently shadow them otherwise).
Every mounted transport is added to deps.connection_closer, so
the revocation handlers' post-commit closes reach its sockets —
unconditionally, since those closes are what ends a revoked
credential's connections. AppServer.close removes it again.
Each spec's auth_guard? defaults to true — the factory
registers create_ws_auth_guard against the mounted transport via
deps.audit.add_listener, repeating the close on the audit row.
Wiring is deduped by transport reference identity so two specs
sharing one BackendWebsocketTransport instance get a single
listener; wrapped / proxied transports dedupe as separate
entries (set auth_guard: false on duplicates and compose
against the underlying transport once).