Logix

Flow API

Low-level API reference for Flow and the Fluent DSL.

Audience: library authors, Pattern authors, and anyone interested in the underlying implementation of the Fluent DSL ($.onState/$.onAction).
For everyday product code, you typically only need the Fluent API on $ and do not need to call the low-level functions on this page.

In Logix, the Flow API is the set of “low-level Lego bricks” behind the Fluent DSL:

  • $.onState(selector) / $.onAction(predicate) internally uses the Flow API to build Streams and execution strategies.
  • Pattern/library code can operate directly on the Flow API to reuse the same concurrency and timing semantics.

1. fromState / fromAction: get source streams

// Derive a stream from the current Module state
const keyword$ = $.flow.fromState((s) => s.keyword)

// Filter a specific Action from the Action stream
const submit$ = $.flow.fromAction(
  (a): a is { _tag: "submit" } => a._tag === "submit",
)

2. Stream operators: debounce / filter / map …

Flow API exposes a set of operators equivalent or similar to effect/Stream, so you can use them in scenarios decoupled from the Bound API:

yield* keyword$.pipe(
  $.flow.debounce(300),
  $.flow.filter((kw) => kw.length > 2),
  $.flow.map((kw) => kw.trim()),
)

The error/environment semantics of these operators follow Stream; refer to types for exact behavior.

3. Execution strategies: run / runParallel / runLatest / runExhaust

They map one-to-one to .run* on the Fluent DSL:

yield* submit$.pipe(
  $.flow.run(handleSubmit), // sequential
)

yield* keyword$.pipe(
  $.flow.debounce(300),
  $.flow.runLatest(searchEffect), // latest wins
)
  • run: execute handlers sequentially in arrival order.
  • runParallel: fork one Fiber per event; no concurrency limit.
  • runLatest: cancel the in-flight Fiber when a new event arrives; keep only the latest.
  • runExhaust: ignore new events while the handler is running.

4. Relation to the Fluent DSL

In terms of types and semantics, the relationship can be summarized as:

  • $.onState(selector).run(handler)$.flow.fromState(selector).pipe($.flow.run(handler))
  • $.onAction(predicate).debounce(300).runLatest(handler)$.flow.fromAction(predicate).pipe($.flow.debounce(300), $.flow.runLatest(handler))

Implementation-wise, you don’t have to mechanically build the Fluent DSL by composing Flow API calls line-by-line, but you must preserve semantic equivalence so DevTools/Intent parsing can map across the two layers.

See Also

On this page