actions/heartbeat.ts

Shared heartbeat action — a fuz_app protocol action carrying both a spec and a handler in one tuple. Consumers spread heartbeat_action (or the protocol_actions bundle from actions/protocol.ts) into the server's actions array so disconnect detection works identically across every repo without per-consumer ping plumbing.

The client's activity-aware heartbeat timer (in FrontendWebsocketClient) issues a heartbeat request whenever the connection has been idle for its configured interval; server-side the dispatcher tracks receive time, so incoming heartbeats keep the socket alive without any handler-level state.

Nullary input/output today. {client_ts, server_ts} fields can be added later if clock-skew telemetry ever matters — the Action container is open for additions without churning consumer call sites.

Declarations
#

3 declarations

view source

heartbeat_action
#

actions/heartbeat.ts view source

Action<{ method: string; initiator: "frontend" | "backend" | "both"; side_effects: boolean; input: ZodType<unknown, unknown, $ZodTypeInternals<unknown, unknown>>; output: ZodType<unknown, unknown, $ZodTypeInternals<unknown, unknown>>; ... 6 more ...; rate_limit?: "both" | ... 2 more ... | undefined; } | { ...; } | {...

Protocol-action tuple — spread into the server's actions array for dispatch (or via protocol_actions from actions/protocol.ts) so the dispatcher resolves the heartbeat handler. The frontend-side spread happens via protocol_action_specs — the client doesn't run the echo handler, but the spec must be in ActionRegistry so create_rpc_client types app.api.heartbeat() against the shared spec.

heartbeat_action_spec
#

actions/heartbeat.ts view source

{ method: string; kind: "request_response"; initiator: "frontend"; auth: { account: "required"; actor: "none"; }; side_effects: false; input: ZodDefault<ZodObject<{}, $strict>>; output: ZodObject<...>; async: true; description: string; }

ActionSpec for the shared heartbeat. Account-required, actor-none — upgrade-time auth has already admitted the socket; heartbeats don't need role gating or actor resolution. side_effects: false keeps it orthogonal to state changes.

heartbeat_handler
#

actions/heartbeat.ts view source

(): Record<string, never>

Handler — nullary echo. Stateless, suitable for high-frequency pings.

returns

Record<string, never>

Imported by
#