noether-core 0.4.1

Noether core: type system, effects, content-addressed stage schema, Ed25519 signing, stdlib
Documentation
use crate::effects::{Effect, EffectSet};
use crate::stage::{Stage, StageBuilder};
use crate::types::NType;
use ed25519_dalek::SigningKey;
use serde_json::json;

pub fn stages(key: &SigningKey) -> Vec<Stage> {
    vec![
        StageBuilder::new("branch")
            .input(NType::record([
                ("condition", NType::Bool),
                ("if_true", NType::Any),
                ("if_false", NType::Any),
            ]))
            .output(NType::Any)
            .pure()
            .description("Select between two values based on a boolean condition")
            .example(
                json!({"condition": true, "if_true": "yes", "if_false": "no"}),
                json!("yes"),
            )
            .example(
                json!({"condition": false, "if_true": "yes", "if_false": "no"}),
                json!("no"),
            )
            .example(
                json!({"condition": true, "if_true": 1, "if_false": 2}),
                json!(1),
            )
            .example(
                json!({"condition": false, "if_true": null, "if_false": "default"}),
                json!("default"),
            )
            .example(
                json!({"condition": true, "if_true": [1, 2], "if_false": []}),
                json!([1, 2]),
            )
            .tag("control")
            .tag("conditional")
            .tag("pure")
            .alias("if_else")
            .alias("ternary")
            .alias("cond")
            .alias("conditional")
            .build_stdlib(key)
            .unwrap(),
        StageBuilder::new("retry")
            .input(NType::record([
                ("stage_id", NType::Text),
                ("input", NType::Any),
                ("max_attempts", NType::Number),
                ("delay_ms", NType::optional(NType::Number)),
            ]))
            .output(NType::Any)
            .effects(EffectSet::new([Effect::Fallible, Effect::Process]))
            .description(
                "Retry a fallible stage up to N times with optional delay between attempts",
            )
            .example(
                json!({"stage_id": "abc", "input": "data", "max_attempts": 3, "delay_ms": 100}),
                json!("result"),
            )
            .example(
                json!({"stage_id": "abc", "input": 42, "max_attempts": 1, "delay_ms": null}),
                json!(42),
            )
            .example(
                json!({"stage_id": "def", "input": null, "max_attempts": 5, "delay_ms": 500}),
                json!("ok"),
            )
            .example(
                json!({"stage_id": "ghi", "input": "test", "max_attempts": 2, "delay_ms": 0}),
                json!("test"),
            )
            .example(
                json!({"stage_id": "jkl", "input": [1], "max_attempts": 3, "delay_ms": null}),
                json!([1]),
            )
            .tag("control")
            .tag("resilience")
            .tag("error-handling")
            .alias("retry_on_failure")
            .alias("with_retries")
            .alias("backoff")
            .build_stdlib(key)
            .unwrap(),
        StageBuilder::new("fallback")
            .input(NType::record([
                ("stages", NType::List(Box::new(NType::Text))),
                ("input", NType::Any),
            ]))
            .output(NType::Any)
            .effects(EffectSet::new([Effect::Fallible, Effect::Process]))
            .description("Try stages in order until one succeeds; fails if all fail")
            .example(
                json!({"stages": ["primary", "secondary"], "input": "data"}),
                json!("result"),
            )
            .example(json!({"stages": ["a", "b", "c"], "input": 42}), json!(42))
            .example(json!({"stages": ["fast"], "input": "x"}), json!("x"))
            .example(
                json!({"stages": ["s1", "s2"], "input": null}),
                json!("from_s2"),
            )
            .example(
                json!({"stages": ["main", "backup"], "input": [1, 2]}),
                json!([1, 2]),
            )
            .tag("control")
            .tag("resilience")
            .tag("error-handling")
            .alias("try_catch")
            .alias("with_fallback")
            .alias("or_else")
            .build_stdlib(key)
            .unwrap(),
        StageBuilder::new("timeout")
            .input(NType::record([
                ("stage_id", NType::Text),
                ("input", NType::Any),
                ("timeout_ms", NType::Number),
            ]))
            .output(NType::Any)
            .effects(EffectSet::new([Effect::Fallible, Effect::Process]))
            .description("Run a stage with a deadline; fails if the stage exceeds the timeout")
            .example(
                json!({"stage_id": "fast", "input": "data", "timeout_ms": 5000}),
                json!("result"),
            )
            .example(
                json!({"stage_id": "slow", "input": 42, "timeout_ms": 100}),
                json!(42),
            )
            .example(
                json!({"stage_id": "s1", "input": null, "timeout_ms": 1000}),
                json!(null),
            )
            .example(
                json!({"stage_id": "s2", "input": "test", "timeout_ms": 10000}),
                json!("done"),
            )
            .example(
                json!({"stage_id": "s3", "input": [1], "timeout_ms": 500}),
                json!([1]),
            )
            .tag("control")
            .tag("resilience")
            .tag("deadline")
            .alias("with_timeout")
            .alias("deadline")
            .alias("max_duration")
            .build_stdlib(key)
            .unwrap(),
        StageBuilder::new("race")
            .input(NType::record([
                ("stages", NType::List(Box::new(NType::Text))),
                ("input", NType::Any),
            ]))
            .output(NType::Any)
            .effects(EffectSet::new([Effect::Fallible, Effect::Process]))
            .description("Run multiple stages concurrently; return the first to complete")
            .example(
                json!({"stages": ["fast", "slow"], "input": "data"}),
                json!("fast_result"),
            )
            .example(json!({"stages": ["a", "b", "c"], "input": 42}), json!(42))
            .example(json!({"stages": ["s1"], "input": "x"}), json!("x"))
            .example(
                json!({"stages": ["p1", "p2"], "input": null}),
                json!("winner"),
            )
            .example(json!({"stages": ["r1", "r2"], "input": [1]}), json!([1]))
            .tag("control")
            .tag("concurrent")
            .tag("parallel")
            .alias("first_success")
            .alias("any_of")
            .alias("fastest")
            .build_stdlib(key)
            .unwrap(),
        StageBuilder::new("parallel")
            .input(NType::record([
                ("stages", NType::List(Box::new(NType::Text))),
                ("inputs", NType::List(Box::new(NType::Any))),
            ]))
            .output(NType::List(Box::new(NType::Any)))
            .effects(EffectSet::new([Effect::Fallible, Effect::Process]))
            .description("Run N stages concurrently on N inputs; collect all results")
            .example(
                json!({"stages": ["s1", "s2"], "inputs": ["a", "b"]}),
                json!(["r1", "r2"]),
            )
            .example(json!({"stages": ["s1"], "inputs": [42]}), json!([42]))
            .example(json!({"stages": [], "inputs": []}), json!([]))
            .example(
                json!({"stages": ["a", "b", "c"], "inputs": [1, 2, 3]}),
                json!([1, 2, 3]),
            )
            .example(
                json!({"stages": ["x", "y"], "inputs": [null, null]}),
                json!([null, null]),
            )
            .tag("control")
            .tag("concurrent")
            .tag("parallel")
            .alias("concurrent_map")
            .alias("run_all")
            .alias("fan_out")
            .build_stdlib(key)
            .unwrap(),
    ]
}