bnto-core 0.1.1

Core WASM engine library for Bnto — shared types, traits, and orchestration
Documentation

bnto-core

Foundation crate for the bnto engine. Types, traits, pipeline executor, and node registry.

Overview

bnto-core defines the contracts that all node crates implement and the executor that runs pipelines. It has no WASM dependencies. It compiles to native Rust for tests and CLI, or links into the bnto-wasm cdylib for browser execution.

Every other engine crate depends on bnto-core.

Directory Structure

src/
├── lib.rs                # Public API: re-exports all modules
├── errors.rs             # BntoError enum (thiserror)
├── events.rs             # PipelineEvent tagged union for progress reporting
├── metadata.rs           # NodeMetadata, ParameterDef, Constraints, NodeCategory
├── processor.rs          # NodeProcessor trait, NodeInput, NodeOutput
├── progress.rs           # ProgressReporter (target-agnostic closures)
├── registry.rs           # NodeRegistry: compound key dispatch
├── pipeline.rs           # PipelineDefinition, PipelineNode, PipelineFile
├── definition_schema.rs  # JSON Schema generator for .bnto.json
└── executor/
    ├── mod.rs            # Public API + node dispatch logic
    ├── primitive.rs      # Leaf node execution
    ├── container.rs      # Container execution (loop, group, parallel)
    └── tests/            # 13 test modules, 45+ tests

Key Concepts

NodeProcessor Trait

Every node implements this trait:

pub trait NodeProcessor: Send + Sync {
    fn metadata(&self) -> NodeMetadata;
    fn process(&self, input: NodeInput) -> Result<NodeOutput, BntoError>;
}
  • metadata() - self-describes the processor: type, operation, accepted formats, parameters with constraints
  • process() - transforms input bytes into output bytes. Stateless; all config comes via the params map in NodeInput

NodeRegistry

Maps compound keys ("nodeType:operation") to Box<dyn NodeProcessor>. The executor looks up processors by key at runtime.

registry.register("image", "compress", Box::new(CompressImages));
let processor = registry.get("image", "compress")?;

Pipeline Executor

execute_pipeline() is the main entry point. It:

  1. Parses the PipelineDefinition (deserialized from .bnto.json)
  2. Walks nodes in dependency order
  3. Chains output from one node as input to the next
  4. Handles container semantics (loop iterates per-file, group sequences children, parallel fans out)
  5. Emits PipelineEvents for progress reporting

PipelineEvent

Structured progress events consumed by the JS layer:

  • PipelineStarted { total_nodes, total_files }
  • NodeStarted { node_id, node_type, operation }
  • FileProgress { node_id, file_index, total_files, file_name }
  • NodeCompleted { node_id, duration_ms }
  • PipelineCompleted { total_duration_ms }
  • PipelineError { node_id, message }

ParameterDef

Self-describing parameter metadata used by the TypeScript codegen to generate UI controls:

  • Name, type, default value, constraints (min/max/step/options)
  • Conditional visibility (visible_when - show param only when another param has a specific value)
  • Surfaceability flag (whether the param appears in the config panel)

Development

# Run unit tests for this crate
cargo test -p bnto-core

# Run all workspace tests
task wasm:test:unit

# Lint
task wasm:lint

Testing

Extensive executor tests in src/executor/tests/ (13 modules, 45+ test functions):

  • basic.rs - simple pipeline execution
  • containers.rs - loop/group/parallel node semantics
  • errors.rs - error propagation and recovery
  • metadata.rs - processor self-description
  • progress.rs - event emission ordering
  • recipes.rs - full recipe integration tests
  • sub_pipelines.rs - nested pipeline execution