Connection validation functions for LiveFlow.
Provides composable validator functions that check whether a connection
between two nodes/handles should be allowed. Each validator takes a flow
state and connection params, returning :ok or {:error, reason}.
Usage
Validators can be composed in a list and run with validate/3:
validators = [
&LiveFlow.Validation.no_duplicate_edges/2,
&LiveFlow.Validation.nodes_exist/2,
&LiveFlow.Validation.no_cycles/2
]
case LiveFlow.Validation.validate(flow, params, validators) do
:ok -> # create the edge
{:error, reason} -> # reject with reason
endOr use presets for common combinations:
validators = LiveFlow.Validation.preset(:strict)Presets
:default— no duplicate edges + nodes exist:strict— default + handles valid + connectable check
Summary
Functions
Validates that the source and target handles exist on their respective
nodes and that both handles have connectable: true.
Limits the maximum number of connections per handle.
Prevents cycles in the flow graph.
Rejects duplicate edges between the same source/target/handles.
Validates that both source and target nodes exist in the flow.
Returns a preset list of validators.
Validates that both handles share the same connect_type.
Runs a list of validators against the given flow and connection params.
Types
@type validator() :: (LiveFlow.State.t(), conn_params() -> :ok | {:error, String.t()})
Functions
@spec handles_valid(LiveFlow.State.t(), conn_params()) :: :ok | {:error, String.t()}
Validates that the source and target handles exist on their respective
nodes and that both handles have connectable: true.
@spec max_connections(LiveFlow.State.t(), conn_params(), keyword()) :: :ok | {:error, String.t()}
Limits the maximum number of connections per handle.
Checks both the source and target handles. If either already has
max or more connections, the new connection is rejected.
Options
:max- Maximum connections per handle (required)
@spec no_cycles(LiveFlow.State.t(), conn_params()) :: :ok | {:error, String.t()}
Prevents cycles in the flow graph.
Rejects a connection if there is already a path from the target node back to the source node (which would create a cycle).
@spec no_duplicate_edges(LiveFlow.State.t(), conn_params()) :: :ok | {:error, String.t()}
Rejects duplicate edges between the same source/target/handles.
Uses State.edge_exists?/5 which was previously unused.
@spec nodes_exist(LiveFlow.State.t(), conn_params()) :: :ok | {:error, String.t()}
Validates that both source and target nodes exist in the flow.
@spec preset(:default | :strict) :: [validator()]
Returns a preset list of validators.
:default—[no_duplicate_edges, nodes_exist]:strict— default +[handles_valid]
@spec types_compatible(LiveFlow.State.t(), conn_params()) :: :ok | {:error, String.t()}
Validates that both handles share the same connect_type.
If either handle has no connect_type set (nil), the check passes.
Only rejects when both handles have explicit types that don't match.
@spec validate(LiveFlow.State.t(), conn_params(), [validator()]) :: :ok | {:error, String.t()}
Runs a list of validators against the given flow and connection params.
Returns :ok if all validators pass, or {:error, reason} on the
first failure (short-circuits).