Lavash.Action.Runtime (Lavash v0.4.0-rc.5)

Copy Markdown View Source

Shared action execution runtime for both LiveView and Component.

This module contains the common logic for executing actions:

Runtime-specific operations (invoke, navigate, flash) remain in their respective runtime modules.

Summary

Functions

Execute side effect functions.

Apply pre-cascade run operations. Each body takes a socket and returns a socket; the body runs BEFORE the reactive cascade.

Apply post-cascade run operations. Each body takes a socket and returns a socket; the returned socket replaces the current one.

Apply set operations to state.

Build params map from action params spec and event params.

Coerce a value to the declared type of a state field.

Check if all guard conditions pass.

Functions

apply_effects(socket, effects, params)

Execute side effect functions.

Each effect has a function that receives the current full state. Effects are executed for their side effects; the socket is returned unchanged.

apply_pre_runs(socket, action_name, pre_runs, params, module)

Apply pre-cascade run operations. Each body takes a socket and returns a socket; the body runs BEFORE the reactive cascade.

The runtime sweeps socket.assigns.__changed__ after the body returns and threads any not-yet-dirty fields through LSocket.put_state/3 so the cascade sees them. This means pre-cascade bodies can use either Lavash.Socket.put_state/3 (explicit) or Phoenix.Component.assign/3 (raw) and both end up in lavash's dirty set.

Event params are merged into socket.assigns for the body's duration so socket.assigns.body, .id, etc. resolve from phx-value-* payloads — matches the contract apply_runs/5 uses for post-cascade bodies.

apply_runs(socket, action_name, runs, params, module)

Apply post-cascade run operations. Each body takes a socket and returns a socket; the returned socket replaces the current one.

Runs AFTER the reactive cascade has settled. The body sees consistent calc values and can do socket-level LV ops (stream_insert/4, allow_upload/3, consume_uploaded_entries/3, cancel_upload/3) that don't fit the declarative state-mutation shape.

Writes the body makes to socket.assigns (via put_state, assign/3, or LV ops) land for Phoenix's render diff but do NOT trigger a re-cascade. Calcs depending on what run wrote are stale until the next user event. If you need a derived value of a write, use pre_run instead.

apply_sets(socket, sets, params, module)

Apply set operations to state.

Each set has a field and a value. The value can be:

  • A literal value
  • An rx() struct (reactive expression with @field syntax)
  • A function that receives %{params: params, state: state} (legacy)

Values are coerced to the field's declared type.

build_params(action_params, event_params)

Build params map from action params spec and event params.

Extracts named parameters from the event payload.

coerce_value(value, arg2)

Coerce a value to the declared type of a state field.

Handles:

  • nil state field (no coercion)
  • nil values (pass through)
  • Empty strings for non-string types (convert to nil)
  • String values parsed via Type.parse/2

guards_pass?(socket, module, guards)

Check if all guard conditions pass.

Guards are atoms referencing derived boolean fields that must all be true.