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/// Controlled system access for processors that need external tools.
14/// Browser gets `NoopContext`, CLI gets `NativeContext`, desktop gets `SandboxedContext`.
15pub mod context;
16
17/// Error types for the WASM engine.
18/// Every error that can happen during node execution is defined here.
19pub mod errors;
20
21/// Structured pipeline events — rich progress reporting for multi-node execution.
22/// Powers per-node status highlighting in the editor, progress bars, and error display.
23pub mod events;
24
25/// Definition JSON Schema — validates `.bnto.json` files.
26/// Generates a JSON Schema (Draft 2020-12) describing the Definition structure
27/// so any consumer can validate recipe files without reimplementing TS types.
28pub mod definition_schema;
29
30/// Node metadata types — self-describing processor definitions.
31/// Each processor declares its name, category, parameters, accepted MIME types,
32/// and whether it runs in the browser. Powers the `node_catalog()` WASM export.
33pub mod metadata;
34
35/// The pipeline executor — walks nodes, iterates files, chains outputs.
36/// This is the engine's brain. See `.claude/strategy/engine-execution.md`.
37pub mod executor;
38
39/// Pipeline definition types — what the engine receives to execute.
40/// Mirrors the TypeScript `PipelineDefinition` / `PipelineNode` types.
41pub mod pipeline;
42
43/// The NodeProcessor trait — the contract every node type must implement.
44/// If you're building a new node (like image compression), you implement this.
45pub mod processor;
46
47/// Progress reporting — how nodes tell the UI "I'm 50% done".
48/// Uses target-agnostic closures (no WASM dependency).
49pub mod progress;
50
51/// Node registry — maps node type keys (e.g., "image-compress") to processors.
52/// Replaces the JS-side `wasmLoader.ts` registry.
53pub mod registry;
54
55// --- Re-exports ---
56// These `pub use` statements let users import directly from the crate root.
57// Instead of writing `use bnto_core::errors::BntoError`, they can write
58// `use bnto_core::BntoError`. Convenience!
59pub use context::{NoopContext, ProcessContext};
60pub use definition_schema::definition_json_schema;
61pub use errors::BntoError;
62pub use events::{PipelineEvent, PipelineReporter};
63pub use executor::execute_pipeline;
64pub use metadata::{
65 Constraints, InputCardinality, NodeCategory, NodeMetadata, NodeTypeInfo, ParamCondition,
66 ParamConditionEntry, ParameterDef, ParameterType, all_node_types,
67};
68pub use pipeline::{
69 IterationMode, PipelineDefinition, PipelineFile, PipelineFileResult, PipelineNode,
70 PipelineResult, PipelineSettings,
71};
72pub use processor::{BatchFile, BatchInput, NodeProcessor};
73pub use progress::ProgressReporter;
74pub use registry::NodeRegistry;
75
76// =============================================================================
77// Shared Constants
78// =============================================================================
79//
80// Constants used by multiple node crates live here so there's a single source
81// of truth. When compress, resize, and convert all need the same default JPEG
82// quality, defining it once in bnto-core prevents the values from drifting
83// apart over time.
84
85/// The current `.bnto.json` format version.
86///
87/// This must stay in sync with `CURRENT_FORMAT_VERSION` in `@bnto/nodes`.
88/// The WASM engine uses this to verify that a definition it receives is
89/// compatible with the node processors it has compiled in.
90///
91/// Semver rules: definitions with the same major version are compatible.
92/// A definition at "1.3.0" works fine on an engine that supports "1.0.0".
93pub const FORMAT_VERSION: &str = "1.0.0";
94
95/// Default quality when not specified by the user (1-100 scale).
96/// 80 is the industry sweet spot: significant file size savings with barely
97/// noticeable quality loss for most photos. Used by all image operations
98/// (compress, resize, convert).
99pub const DEFAULT_QUALITY: u8 = 80;
100
101// =============================================================================
102// Utility Functions (Pure Rust — no WASM boundary)
103// =============================================================================
104//
105// NOTE: setup(), version(), and greet() used to live here with #[wasm_bindgen]
106// attributes. They've moved to the bnto-wasm entry point crate which is the
107// single cdylib that produces the .wasm file for the browser. This crate is
108// now purely an rlib (Rust library) — no JS exports.
109//
110// These utility functions remain available as regular Rust functions for use
111// by other crates in the workspace and for testing.
112
113/// Returns the version of the bnto-core crate.
114pub fn version() -> String {
115 env!("CARGO_PKG_VERSION").to_string()
116}
117
118// =============================================================================
119// Tests
120// =============================================================================
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn test_format_version_is_valid_semver() {
128 // FORMAT_VERSION should be a valid semver string (major.minor.patch)
129 let parts: Vec<&str> = FORMAT_VERSION.split('.').collect();
130 assert_eq!(
131 parts.len(),
132 3,
133 "FORMAT_VERSION must have 3 parts (major.minor.patch)"
134 );
135 for part in &parts {
136 part.parse::<u32>()
137 .expect("Each semver part must be a valid number");
138 }
139 }
140
141 #[test]
142 fn test_version_returns_cargo_version() {
143 let v = version();
144 assert!(!v.is_empty(), "Version string should not be empty");
145 assert!(
146 v.contains('.'),
147 "Version should contain dots (semver format)"
148 );
149 }
150}