Skip to main content

reinhardt_dentdelion/
lib.rs

1//! Dentdelion - Plugin System for Reinhardt Framework
2//!
3//! Dentdelion (dent de lion = lion's tooth = dandelion) is a plugin system
4//! that makes it easy to create, distribute, and install plugins for the
5//! Reinhardt web framework.
6//!
7//! # Features
8//!
9//! - **Static Plugins**: Rust crates compiled with your application
10//! - **WASM Plugins**: Dynamic plugins loaded at runtime (with `wasm` feature)
11//! - **TypeScript Plugins**: TypeScript/JavaScript plugins via boa_engine (pure-Rust ECMAScript engine) (with `ts` feature)
12//! - **Capability System**: Fine-grained control over what plugins can do
13//! - **CLI Management**: Install and manage plugins via `reinhardt plugin` commands
14//! - **Multi-Runtime**: Unified interface for Static, WASM, and TypeScript runtimes
15//!
16//! # Naming Convention
17//!
18//! Plugin names should follow the `xxx-delion` pattern:
19//! - `auth-delion` - Authentication plugin
20//! - `rate-limit-delion` - Rate limiting plugin
21//! - `analytics-delion` - Analytics plugin
22//!
23//! # Quick Start
24//!
25//! ## Creating a Plugin
26//!
27//! ```rust
28//! use reinhardt_dentdelion::prelude::*;
29//! use std::sync::Arc;
30//!
31//! struct MyPlugin {
32//!     metadata: PluginMetadata,
33//! }
34//!
35//! impl MyPlugin {
36//!     pub fn new() -> Self {
37//!         Self {
38//!             metadata: PluginMetadata::builder("my-delion", "1.0.0")
39//!                 .description("My awesome plugin")
40//!                 .provides(PluginCapability::Middleware)
41//!                 .build()
42//!                 .unwrap(),
43//!         }
44//!     }
45//! }
46//!
47//! impl Plugin for MyPlugin {
48//!     fn metadata(&self) -> &PluginMetadata {
49//!         &self.metadata
50//!     }
51//!
52//!     fn capabilities(&self) -> &[Capability] {
53//!         &[Capability::Core(PluginCapability::Middleware)]
54//!     }
55//! }
56//!
57//! // Register the plugin for automatic discovery
58//! register_plugin!(|| Arc::new(MyPlugin::new()));
59//! ```
60//!
61//! ## Using the Registry
62//!
63//! ```rust
64//! use reinhardt_dentdelion::prelude::*;
65//! use std::sync::Arc;
66//!
67//! # struct MyPlugin { metadata: PluginMetadata }
68//! # impl MyPlugin {
69//! #     fn new() -> Self {
70//! #         Self {
71//! #             metadata: PluginMetadata::builder("my-delion", "1.0.0")
72//! #                 .build().unwrap(),
73//! #         }
74//! #     }
75//! # }
76//! # impl Plugin for MyPlugin {
77//! #     fn metadata(&self) -> &PluginMetadata { &self.metadata }
78//! #     fn capabilities(&self) -> &[Capability] { &[] }
79//! # }
80//! let registry = PluginRegistry::new();
81//!
82//! // Register plugins
83//! registry.register(Arc::new(MyPlugin::new())).unwrap();
84//!
85//! // Validate dependencies
86//! registry.validate_dependencies().unwrap();
87//!
88//! // Get enable order
89//! let order = registry.get_enable_order().unwrap();
90//! ```
91//!
92//! ## Project Manifest (dentdelion.toml)
93//!
94//! ```toml
95//! [dentdelion]
96//! format_version = "1.0"
97//! wasm_dir = ".dentdelion/plugins"
98//!
99//! [[plugins]]
100//! name = "auth-delion"
101//! type = "static"
102//! version = "1.0.0"
103//! enabled = true
104//!
105//! [plugin_config.auth-delion]
106//! algorithm = "HS256"
107//! ```
108//!
109//! # Feature Flags
110//!
111//! - `default` - Core plugin system only
112//! - `wasm` - WASM plugin support with Component Model (requires wasmtime 36.x)
113//! - `ts` - TypeScript/JavaScript SSR support via boa_engine (pure-Rust ECMAScript engine)
114//! - `cli` - CLI support for crates.io integration
115//! - `full` - All features enabled (wasm + cli); note: `ts` is NOT included in `full`
116//!
117//! # WASM Plugin Support
118//!
119//! When the `wasm` feature is enabled, plugins can be loaded dynamically at runtime
120//! from WebAssembly Component Model files (.wasm).
121//!
122//! ## Key Features
123//!
124//! - **Component Model**: Uses WebAssembly Interface Types (WIT) for type-safe interfaces
125//! - **Sandboxed Execution**: Memory limits, timeouts, and fuel-based CPU metering
126//! - **Host API**: Config, logging, services, HTTP client, and database access
127//! - **Capability-Based Security**: Fine-grained permission checks for sensitive operations
128//!
129//! ## Requirements
130//!
131//! - Plugins must implement the `dentdelion-plugin` WIT world (see `wit/dentdelion.wit`)
132//! - Use `wit-bindgen` or `cargo-component` for code generation
133//! - Data serialized with MessagePack for WASM boundary crossing
134//!
135//! ## Runtime Configuration
136//!
137//! ```ignore
138//! use reinhardt_dentdelion::wasm::{WasmRuntime, WasmRuntimeConfigBuilder};
139//! use std::time::Duration;
140//!
141//! let config = WasmRuntimeConfigBuilder::new()
142//!     .memory_limit_mb(128)
143//!     .timeout(Duration::from_secs(30))
144//!     .fuel_metering(true)
145//!     .initial_fuel(100_000_000)
146//!     .build();
147//!
148//! let runtime = WasmRuntime::new(config)?;
149//! ```
150//!
151//! ## Capabilities
152//!
153//! Two special capabilities are available for WASM plugins:
154//! - `NetworkAccess` - Required for `http_get`/`http_post` host functions
155//! - `DatabaseAccess` - Required for `db_query`/`db_execute` host functions
156//!
157//! # Architecture
158//!
159//! ```text
160//! ┌──────────────────────────────────┐
161//! │        PluginRegistry            │
162//! │    - Plugin registration         │
163//! │    - Dependency resolution       │
164//! │    - Lifecycle management        │
165//! └────────────────┬─────────────────┘
166//!                  │
167//!     ┌────────────┼────────────┐
168//!     │            │            │
169//! ┌───▼──┐     ┌───▼──┐     ┌───▼────┐
170//! │Static│     │ WASM │     │Manifest│
171//! │Plugin│     │Plugin│     │ Parser │
172//! └──────┘     └──────┘     └────────┘
173//! ```
174
175#![warn(missing_docs)]
176#![warn(rustdoc::missing_crate_level_docs)]
177
178pub mod capability;
179pub mod context;
180pub mod error;
181pub mod installer;
182pub mod manifest;
183pub mod metadata;
184pub mod plugin;
185pub mod registry;
186pub mod runtime;
187
188#[cfg(feature = "cli")]
189pub mod crates_io;
190
191#[cfg(feature = "wasm")]
192pub mod wasm;
193
194/// Re-export commonly used types.
195pub mod prelude {
196	pub use crate::capability::{Capability, PluginCapability, PluginTier, TrustLevel};
197	pub use crate::context::{PluginContext, PluginContextBuilder};
198	pub use crate::error::{PluginError, PluginResult, PluginState};
199	pub use crate::installer::PluginInstaller;
200	pub use crate::manifest::{
201		InstalledPlugin, MANIFEST_FILENAME, PluginType, ProjectManifest, WasmPluginConfig,
202	};
203	pub use crate::metadata::{PluginDependency, PluginMetadata, PluginMetadataBuilder};
204	pub use crate::plugin::{
205		ArcPlugin, ArcPluginLifecycle, BoxedPlugin, Plugin, PluginFactory, PluginLifecycle,
206		PluginRegistration,
207	};
208	pub use crate::register_plugin;
209	pub use crate::registry::PluginRegistry;
210	pub use crate::runtime::{
211		ArcRuntime, BoxedRuntime, PluginRuntime, RuntimeError, RuntimeLimits, RuntimeLimitsBuilder,
212		RuntimeType,
213	};
214
215	#[cfg(feature = "cli")]
216	pub use crate::crates_io::CratesIoClient;
217
218	#[cfg(feature = "wasm")]
219	pub use crate::wasm::{
220		ColumnDef, ColumnType, Event, EventBus, IndexDef, ModelRegistry, ModelSchema,
221		SharedEventBus, SharedModelRegistry, SqlMigration,
222	};
223
224	pub use async_trait::async_trait;
225}
226
227// Re-export inventory for plugin registration
228pub use inventory;
229
230#[cfg(test)]
231mod tests {
232	use super::prelude::*;
233	use std::sync::Arc;
234
235	struct TestPlugin {
236		metadata: PluginMetadata,
237		capabilities: Vec<Capability>,
238	}
239
240	impl TestPlugin {
241		fn new() -> Self {
242			Self {
243				metadata: PluginMetadata::builder("test-delion", "1.0.0")
244					.description("Test plugin for integration tests")
245					.author("Test Author")
246					.license("MIT")
247					.provides(PluginCapability::Middleware)
248					.build()
249					.unwrap(),
250				capabilities: vec![Capability::Core(PluginCapability::Middleware)],
251			}
252		}
253	}
254
255	impl Plugin for TestPlugin {
256		fn metadata(&self) -> &PluginMetadata {
257			&self.metadata
258		}
259
260		fn capabilities(&self) -> &[Capability] {
261			&self.capabilities
262		}
263	}
264
265	#[async_trait]
266	impl PluginLifecycle for TestPlugin {
267		async fn on_load(&self, _ctx: &PluginContext) -> Result<(), PluginError> {
268			tracing::info!("TestPlugin loaded");
269			Ok(())
270		}
271
272		async fn on_enable(&self, _ctx: &PluginContext) -> Result<(), PluginError> {
273			tracing::info!("TestPlugin enabled");
274			Ok(())
275		}
276	}
277
278	#[test]
279	fn test_integration() {
280		let registry = PluginRegistry::new();
281		let plugin = Arc::new(TestPlugin::new());
282
283		registry.register(plugin.clone()).unwrap();
284
285		assert!(registry.is_registered("test-delion"));
286		assert_eq!(registry.len(), 1);
287
288		let retrieved = registry.get("test-delion").unwrap();
289		assert_eq!(retrieved.name(), "test-delion");
290		assert_eq!(retrieved.version().to_string(), "1.0.0");
291	}
292
293	#[test]
294	fn test_capability_query() {
295		let registry = PluginRegistry::new();
296		let plugin = Arc::new(TestPlugin::new());
297
298		registry.register(plugin).unwrap();
299		registry
300			.set_state("test-delion", PluginState::Enabled)
301			.unwrap();
302
303		let providers =
304			registry.get_capability_providers(&Capability::Core(PluginCapability::Middleware));
305		assert_eq!(providers.len(), 1);
306	}
307}