actions/register_action_ws.ts view source
60000 Default inactivity window before the server closes a silent socket.
WebSocket JSON-RPC dispatch — the low-level WS transport binding.
Most consumers should mount WS endpoints via register_ws_endpoint (actions/register_ws_endpoint.ts), which wraps this function with the standard upgrade stack (origin check + auth + optional role). This module stays exported as the lower-level entry point for tests that drive the dispatcher directly via create_ws_test_harness.
Symmetric to create_rpc_endpoint (from actions/action_rpc.ts): consumer supplies action specs + a handler map, the dispatcher parses the envelope, checks per-action auth, validates input, invokes the handler with a per-request context, and writes the response.
Extracted from zzz's register_websocket_actions to converge pattern drift
across consumers (zzz, tx, undying). Broadcast-style notifications remain
domain-shaped today — this module only covers per-request dispatch + the
socket-scoped ctx.notify + per-socket ctx.signal. See
BackendWebsocketTransport.send for broadcast.
The consumer is responsible for rejecting unauthenticated upgrades *before*
routing to this handler (fuz_app's require_auth middleware, or
register_ws_endpoint which wires it for you). Inside the dispatcher,
get_request_context(c) is treated as guaranteed non-null and per-action
auth is enforced on each message.
7 declarations
actions/register_action_ws.ts view source
60000 Default inactivity window before the server closes a silent socket.
actions/register_action_ws.ts view source
<TCtx extends BaseHandlerContext>(options: RegisterActionWsOptions<TCtx>): RegisterActionWsResult Mount a JSON-RPC WebSocket endpoint that dispatches to the supplied handler
map. Per-request context is built from the base + consumer-provided
RegisterActionWsOptions.extend_context.
Wire behavior:
- Batch JSON-RPC is rejected (single-message only).
- Notifications (method + no id) are silently dropped per JSON-RPC spec.
- Per-action auth: public / authenticated pass through (upgrade auth
already verified identity); keeper requires daemon_token credential
type *and* the keeper role; role-based {role} requires the named role
via has_role, matching the HTTP path in actions/action_rpc.ts.
- DEV mode validates handler output against the spec's output schema and
warns on mismatches.
optionsRegisterActionWsOptions<TCtx>RegisterActionWsResult the transport (supplied or freshly created) — retain it to wire create_ws_auth_guard or broadcast on audit events.
actions/register_action_ws.ts view source
RegisterActionWsOptions<TCtx> Options for register_action_ws.
TCtxpathMount path (e.g., /api/ws).
stringappThe Hono app to mount on.
HonoupgradeWebSocketHono's upgradeWebSocket helper from the runtime adapter.
UpgradeWebSocketactionsThe actions registered on this endpoint — each carries a spec (drives method lookup, per-action auth, input/output validation) and an optional handler (omit for client-only specs like inbound notifications). Spread protocol_actions from actions/protocol.ts here to complete the disconnect-detection + per-request cancel pairing with the frontend client.
ReadonlyArray<Action<TCtx>>extend_contextBuild the per-request context from the base and the upgrade-time Hono
context. Called once per incoming message. Consumers use this to attach
domain singletons (backend) or per-socket auth (auth,
credential_type) without re-reading them from c inside every handler.
(base: BaseHandlerContext, c: Context) => TCtxtransportExisting transport to register connections with. When omitted, a fresh
one is created and returned in the result. Pass your own to keep a
handle for create_ws_auth_guard and send_to/broadcast.
heartbeatServer-side heartbeat policy. Default-on (receive-silence detection,
60s timeout). false disables the timer entirely — only do this if
the upstream stack (TCP keepalive, Cloudflare idle timeout, etc.)
already owns disconnect detection. Pass an object to tune the timeout.
boolean | ServerHeartbeatOptionsartificial_delayOptional per-message delay for testing loading states. Ignored when 0.
numberlogOptional logger; defaults to [ws] namespace.
LoggerTypeon_socket_openCalled once per socket, after the transport registers the connection.
Awaited before any message is dispatched. Throwing logs an error and
closes the socket with an internal_error frame — a failing bootstrap
should not leave a partially-initialized socket alive.
(ctx: SocketOpenContext) => void | Promise<void>on_socket_closeCalled once per socket on close, *before* the transport removes the
connection. Receives connection_id and identity captured at open
time, so it is safe to read even when the audit guard has already torn
down the transport's internal state. Errors are logged and swallowed.
(ctx: SocketCloseContext) => void | Promise<void>action_ip_rate_limiterPer-IP rate limiter consulted for actions whose spec declares
rate_limit: 'ip' or 'both'. null (or omitted) disables the
IP check. Same limiter is shared with the HTTP RPC dispatcher so
one budget covers both transports per action. Resolved at upgrade
time and reused for every message on the socket.
RateLimiter | nullaction_account_rate_limiterPer-actor rate limiter consulted for actions whose spec declares
rate_limit: 'account' or 'both'. Keyed on
request_context.actor.id. null (or omitted) disables the
account check. Same limiter is shared with the HTTP RPC dispatcher.
RateLimiter | nullactions/register_action_ws.ts view source
RegisterActionWsResult Result of register_action_ws.
transportThe transport bound to the endpoint — supplied or freshly created.
actions/register_action_ws.ts view source
ServerHeartbeatOptions timeoutReceive-silence (ms) past which the server closes the socket with
WS_CLOSE_SERVER_HEARTBEAT_TIMEOUT. Any incoming message resets
the counter — chatty clients never trip it. First timeout
window after socket open is exempt (cold-start grace).
numberactions/register_action_ws.ts view source
SocketCloseContext Context passed to the on_socket_close hook.
Fires before transport.remove_connection runs, so consumer cleanup can
still read identity before it's torn down. Fires for both client-initiated
closes (Hono onClose) and server-initiated closes via audit revocation
(the audit guard calls ws.close(), which triggers Hono's onClose).
wsThe raw WebSocket context at close time.
WSContextconnection_idConnection id captured at open time.
UuididentityAuth identity captured at open time — still valid even if the transport already cleaned up.
actions/register_action_ws.ts view source
SocketOpenContext Context passed to the on_socket_open hook.
Fires after the transport has registered the new connection (so
connection_id is valid) but before any client message can dispatch.
Consumers use this to bootstrap per-socket domain state — e.g. undying
spawns the per-account spirit unit and pushes an initial state snapshot.
wsThe raw WebSocket context — exposed for edge cases; prefer notify for sends.
WSContextconnection_idConnection id assigned by BackendWebsocketTransport.add_connection.
UuididentityAuth identity registered for this connection.
notifySend a JSON-RPC notification to just this socket. Mirrors ctx.notify
on per-message handler contexts — same socket-scoped semantics.
(method: string, params: unknown) => voidsignalFires when this socket closes — threaded through to every handler's ctx.signal.
AbortSignal