Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/edda

crates/nornir-saga/src/ui/mod.rs

//! # `nornir-saga::ui` — live UI-movement viewer + deterministic replay
//!
//! View live UI movements from a saga (an Elm `Msg` stream) and **replay them so
//! a web page actually moves**. This is the consumer/viewer/replay side of a
//! saga-enabled Njord (the Njord emitter is a separate, coordinated change — see
//! `.nornir/nornir-saga.md`); everything here is demoable with **synthetic
//! sagas**, no live Njord and no real browser required.
//!
//! ```text
//!   saga-enabled app (facett Elm component OR Njord-alike)
//!        │  ui::tap(&msg)   ← the ONE dev-only tap at the Elm `update` choke point
//!        │                    (feature `saga`; compiled OUT of release)
//!        ▼
//!   ui::capture buffer ── drain_saga() ──▶  Saga (Vec<TimedUiMsg>)   ← the contract
//!                                             │
//!         ┌───────────────────────────────────┼──────────────────────────────┐
//!         ▼ LIVE                               ▼ REPLAY                        ▼ DRIVE REAL PAGE
//!   SagaSource → Viewer (ELM)            Player (seek/scale/          WebReplayDriver
//!   fold → state_json                    deterministic) → frames      (Mock · Noop · WebDriver)
//!         │                                    │                              │
//!         └────────────── web frontend (axum + SSE, feature `web`) ───────────┘
//! ```
//!
//! ## Pieces
//! * [`msg`] — the **contract**: [`UiMsg`] / [`TimedUiMsg`] / [`Saga`].
//! * [`capture`] — the DEV-ONLY **tap** ([`tap`] / [`SagaMsg`] / [`drain_saga`]),
//!   gated behind the off-by-default `saga` feature (release ships nothing).
//! * [`emit`] — the pluggable **emit seam** ([`Emitter`] + [`UiSink`]:
//!   [`VecSink`] / [`ChannelSink`] / [`NullSink`]) a host feeds its `Msg` stream
//!   through (LIVE via [`ChannelSink`] → [`ChannelSource`]).
//! * [`viewer`] — the **ELM viewer** ([`Viewer`] / [`ViewerModel`] / `state_json`).
//! * [`source`] — the **source seam** ([`SagaSource`], [`RecordedSource`],
//!   [`ChannelSource`]).
//! * [`player`] — the **replay engine** ([`Player`]: seek / time-scale /
//!   deterministic [`Frame`]s).
//! * [`driver`] — the **[`WebReplayDriver`]** seam ([`DriveAction`],
//!   [`MockDriver`], [`NoopDriver`], [`drive_saga`]; real WebDriver behind
//!   feature `drive`).
//! * [`synthetic`] — [`demo_saga`] plus the **wire-against fixture**
//!   ([`SyntheticApp`] / [`wire_synthetic`] / [`wired_saga`]): a saga-enabled ELM
//!   app that emits a scripted `Msg` stream through the emit seam, proving
//!   capture → replay end to end with no real Njord.
//! * [`web`] — the axum + SSE frontend (feature `web`).

pub mod capture;
pub mod driver;
pub mod emit;
pub mod msg;
pub mod player;
pub mod source;
pub mod synthetic;
pub mod viewer;

#[cfg(feature = "web")]
pub mod web;

/// **Njord-support replay primitives** (feature `web`): the DOM query/assert
/// surface ([`njord::DomAssertDriver`]), the PII-redacted input-injection seam
/// ([`njord::RedactedInputs`] / [`njord::inject_inputs`]), and the blessed
/// `data-saga` / `data-saga-field` locator convention. Gated HARD behind `web`
/// so the lean core (and Njord's own build) link none of it.
#[cfg(feature = "web")]
pub mod njord;

pub use capture::{capture, drain_saga, tap, SagaMsg};
pub use driver::{drive_plan, drive_saga, DriveAction, MockDriver, NoopDriver, WebReplayDriver};
pub use emit::{ChannelSink, Emitter, NullSink, UiSink, VecSink};
pub use msg::{saga_to_ui, Saga, TimedUiMsg, UiMsg};
pub use player::{Frame, Player, ReplayVerdict};
pub use source::{ChannelSource, RecordedSource, SagaSource};
pub use synthetic::{
    demo_saga, synthetic_movement_count, synthetic_movements, synthetic_script, wire_synthetic,
    wired_saga, AppMsg, SyntheticApp,
};
pub use viewer::{Counts, Point, Viewer, ViewerEffect, ViewerModel, ViewerMsg};