Musubi.Event (musubi v0.13.0)

Copy Markdown View Source

Transient server-to-client push events.

push_event/3 queues a fire-and-forget {name, payload} on the socket, the same accumulate-on-socket pattern as Musubi.Stream. Events are per-store: during :after_serialize aggregation the page server drains every store socket via flush_pending/1, stamps each event with the socket's store_id, and folds them into Musubi.Page.PatchEnvelope.events, so one "patch" push carries diff + events. The client dispatches per (store_id, name).

Events own no version, ack, or retry: they ride the envelope, are dispatched once on the client, and are not replayed on reconnect. An event-only cycle still emits an envelope and bumps version.

Summary

Types

Wire-shape push event folded into the patch envelope.

Functions

Drains the queued events for this cycle in FIFO order, wire-serializing each payload, and clears the accumulator.

Queues a transient event on the socket. Returns the socket for pipe-chaining.

Validates each drained event's wire payload against module's declared event schema (dev-correctness, mirroring Musubi.Hooks.ValidateReplySchema). Events are per-store, so module is the store socket that queued them. Musubi.Hooks.ValidateEvents calls this per socket at the :after_serialize stage (a default hook attached to every store socket via config :musubi, :default_hooks).

Types

event()

@type event() :: %{name: String.t(), payload: term()}

Wire-shape push event folded into the patch envelope.

Functions

flush_pending(socket)

@spec flush_pending(Musubi.Socket.t()) :: {[event()], Musubi.Socket.t()}

Drains the queued events for this cycle in FIFO order, wire-serializing each payload, and clears the accumulator.

Called by the page runtime once per render cycle.

Examples

{events, socket} = Musubi.Event.flush_pending(socket)

push_event(socket, name, payload)

@spec push_event(Musubi.Socket.t(), atom() | String.t(), term()) :: Musubi.Socket.t()

Queues a transient event on the socket. Returns the socket for pipe-chaining.

name is an atom or string (stringified); payload is any wire-encodable term, serialized at flush via Musubi.Wire.to_wire/1.

Examples

socket = Musubi.Event.push_event(socket, :toast, %{msg: "saved"})

validate_events!(events, module)

@spec validate_events!([event()], module()) :: [event()]

Validates each drained event's wire payload against module's declared event schema (dev-correctness, mirroring Musubi.Hooks.ValidateReplySchema). Events are per-store, so module is the store socket that queued them. Musubi.Hooks.ValidateEvents calls this per socket at the :after_serialize stage (a default hook attached to every store socket via config :musubi, :default_hooks).

Undeclared event names are skipped (a push with no matching event declaration is not validated). A declared event whose payload is missing a field or has a type mismatch raises ArgumentError (let-it-crash) — there is no security validation here (events are server-pushed, trusted); this only catches developer mistakes. Returns events unchanged.