bnto_core/lib.rs
1// =============================================================================
2// bnto-core — The Foundation WASM Library
3// =============================================================================
4//
5// Shared foundation for all Bnto WASM node crates: error types,
6// the NodeProcessor trait, progress reporting, pipeline execution,
7// and the node registry. This is an rlib -- it doesn't produce a
8// .wasm file itself. That's the job of the bnto-wasm entry point.
9
10// --- Public Modules ---
11// These are the building blocks that node crates and the web app will use.
12
13/// Centralized string case/formatting — lower, upper, title, slug, deslug, etc.
14/// The Rust equivalent of JS's `change-case` library.
15pub mod case;
16
17/// In-process PATH lookup mirroring `std::process::Command` spawn rules.
18/// Backs `ProcessContext::find_binary` for native contexts.
19pub mod binary_probe;
20
21/// Controlled system access for processors that need external tools.
22/// Browser gets `NoopContext`, CLI gets `NativeContext`, desktop gets `SandboxedContext`.
23pub mod context;
24
25/// Error types for the WASM engine.
26/// Every error that can happen during node execution is defined here.
27pub mod errors;
28
29/// Structured pipeline events — rich progress reporting for multi-node execution.
30/// Powers per-node status highlighting in the editor, progress bars, and error display.
31pub mod events;
32
33/// Definition JSON Schema — validates `.bnto.json` files.
34/// Generates a JSON Schema (Draft 2020-12) describing the Definition structure
35/// so any consumer can validate recipe files without reimplementing TS types.
36pub mod definition_schema;
37
38/// Document-shape types for `.bnto.json` files — the authoring view.
39/// Mirrors the TypeScript `Definition` types and round-trips every real
40/// recipe fixture. Distinct from `pipeline` (the execution-pruned view).
41pub mod definition;
42
43/// Node metadata types — self-describing processor definitions.
44/// Each processor declares its name, category, parameters, accepted MIME types,
45/// and whether it runs in the browser. Powers the `node_catalog()` WASM export.
46pub mod metadata;
47
48/// The pipeline executor — walks nodes, iterates files, chains outputs.
49/// This is the engine's brain. See `.claude/strategy/engine-execution.md`.
50pub mod executor;
51
52/// Pipeline definition types — what the engine receives to execute.
53/// Mirrors the TypeScript `PipelineDefinition` / `PipelineNode` types.
54pub mod pipeline;
55
56/// `InputMode` and its wire-string form (the input node's `mode` param).
57pub mod input_mode;
58
59/// The NodeProcessor trait — the contract every node type must implement.
60/// If you're building a new node (like image compression), you implement this.
61pub mod processor;
62
63/// Progress reporting — how nodes tell the UI "I'm 50% done".
64/// Uses target-agnostic closures (no WASM dependency).
65pub mod progress;
66
67/// Node registry — maps node type keys (e.g., "image-compress") to processors.
68/// Replaces the JS-side `wasmLoader.ts` registry.
69pub mod registry;
70
71/// Node-level field declarations — typed user-facing controls for nodes.
72/// Field values are substituted into `{{fields.*}}` templates at execution time.
73pub mod field_def;
74
75/// Editor state model — pure-data recipe editing state.
76/// Shared by all editor surfaces (TUI List, Wizard, Code, Graph).
77/// No TUI dependency. Sprint 15 extracts to standalone `bnto-editor` crate.
78pub mod editor;
79
80/// Engine-level logging — trait + types for structured diagnostics.
81/// Browser gets `NoopLogger`, CLI gets `FileLogger`.
82pub mod logging;
83
84/// File content abstraction — in-memory bytes or on-disk path reference.
85/// Large files (shell-command outputs) stay on disk as path references to
86/// avoid reading multi-GB files into memory.
87pub mod file_data;
88
89/// Simple dotenv parser — loads KEY=VALUE pairs from `.env` files.
90/// No crate dependency, handles comments, quotes, and `export` prefix.
91pub mod dotenv;
92
93/// Secret declarations for recipes — pre-flight validation of required env vars.
94/// Recipes declare what secrets they need; the engine validates before execution.
95pub mod secrets;
96
97/// Relative paths as output-file names, `/`-separated on every OS.
98pub mod slash_path;
99
100/// Version constraint checking for external dependencies.
101/// Parses `--version` output, extracts version numbers, validates against
102/// constraint strings like `">=6.0"`.
103pub mod version;
104
105// --- Re-exports ---
106// These `pub use` statements let users import directly from the crate root.
107// Instead of writing `use bnto_core::errors::BntoError`, they can write
108// `use bnto_core::BntoError`. Convenience!
109pub use binary_probe::find_on_path;
110pub use context::{NoopContext, ProcessContext};
111pub use definition::{Definition, Edge, Metadata, Port, Position};
112pub use definition_schema::definition_json_schema;
113pub use editor::{EditorError, EditorModel, EditorNode, EditorSnapshot, EditorSource};
114pub use errors::BntoError;
115pub use events::{PipelineEvent, PipelineReporter};
116pub use executor::execute_pipeline;
117pub use executor::template::{
118 build_input_metadata, build_node_outputs_for_input, resolve_ctx_templates,
119 resolve_node_templates,
120};
121pub use field_def::{FieldDef, FieldDefs, FieldOption};
122pub use file_data::FileData;
123pub use logging::{LogEntry, LogLevel, Logger, NoopLogger};
124pub use metadata::{
125 Constraints, Dependency, HostPlatform, InputCardinality, InstallHints, NodeCategory,
126 NodeMetadata, NodeTypeInfo, ParamCondition, ParamConditionEntry, ParameterDef, ParameterType,
127 all_node_types, io_container::io_container_param_defs, node_type_params,
128};
129pub use pipeline::{
130 InputMode, IterationMode, PipelineDefinition, PipelineFile, PipelineFileResult, PipelineNode,
131 PipelineResult, PipelineSettings, first_processing_node_id, resolve_input_mode,
132 resolve_output_directory, resolve_output_mode,
133};
134pub use processor::{BatchFile, BatchInput, NodeProcessor};
135pub use progress::ProgressReporter;
136pub use registry::NodeRegistry;
137pub use secrets::SecretDef;
138pub use slash_path::slash_path;
139pub use version::{VersionCheckResult, VersionConstraint, check_version};
140
141// =============================================================================
142// Shared Constants
143// =============================================================================
144//
145// Constants used by multiple node crates live here so there's a single source
146// of truth. When compress, resize, and convert all need the same default JPEG
147// quality, defining it once in bnto-core prevents the values from drifting
148// apart over time.
149
150/// The current `.bnto.json` format version.
151///
152/// This must stay in sync with `CURRENT_FORMAT_VERSION` in `@bnto/nodes`.
153/// The WASM engine uses this to verify that a definition it receives is
154/// compatible with the node processors it has compiled in.
155///
156/// Semver rules: definitions with the same major version are compatible.
157/// A definition at "1.3.0" works fine on an engine that supports "1.0.0".
158pub const FORMAT_VERSION: &str = "1.0.0";
159
160/// Default quality when not specified by the user (1-100 scale).
161/// 80 is the industry sweet spot: significant file size savings with barely
162/// noticeable quality loss for most photos. Used by all image operations
163/// (compress, resize, convert).
164pub const DEFAULT_QUALITY: u8 = 80;
165
166// =============================================================================
167// Utility Functions (Pure Rust — no WASM boundary)
168// =============================================================================
169//
170// NOTE: setup(), version(), and greet() used to live here with #[wasm_bindgen]
171// attributes. They've moved to the bnto-wasm entry point crate which is the
172// single cdylib that produces the .wasm file for the browser. This crate is
173// now purely an rlib (Rust library) — no JS exports.
174//
175// These utility functions remain available as regular Rust functions for use
176// by other crates in the workspace and for testing.
177
178/// Returns the version of the bnto-core crate.
179pub fn version() -> String {
180 env!("CARGO_PKG_VERSION").to_string()
181}
182
183// =============================================================================
184// Tests
185// =============================================================================
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190
191 #[test]
192 fn test_format_version_is_valid_semver() {
193 // FORMAT_VERSION should be a valid semver string (major.minor.patch)
194 let parts: Vec<&str> = FORMAT_VERSION.split('.').collect();
195 assert_eq!(
196 parts.len(),
197 3,
198 "FORMAT_VERSION must have 3 parts (major.minor.patch)"
199 );
200 for part in &parts {
201 part.parse::<u32>()
202 .expect("Each semver part must be a valid number");
203 }
204 }
205
206 #[test]
207 fn test_version_returns_cargo_version() {
208 let v = version();
209 assert!(!v.is_empty(), "Version string should not be empty");
210 assert!(
211 v.contains('.'),
212 "Version should contain dots (semver format)"
213 );
214 }
215}