# 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:
```rust
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.
```rust
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 `PipelineEvent`s 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
```bash
# 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