# fusabi-plugin-runtime
Plugin loader, hot-reload, and runtime for Fusabi plugins (fsx & fzb) with manifest validation and capability enforcement.
## Features
- **Plugin Loading** - Load plugins from source (.fsx) or bytecode (.fzb)
- **Manifest Validation** - Validate plugin manifests and enforce requirements
- **Capability Enforcement** - Ensure plugins only use declared capabilities
- **Hot Reload** - Automatically reload plugins when files change
- **Lifecycle Management** - Initialize, run, and cleanup plugins
- **Plugin Registry** - Manage multiple plugins with concurrent access
## Quick Start
```rust
use fusabi_plugin_runtime::{PluginRuntime, RuntimeConfig};
fn main() -> fusabi_plugin_runtime::Result<()> {
// Create runtime
let runtime = PluginRuntime::new(RuntimeConfig::default())?;
// Load a plugin from manifest
let plugin = runtime.load_manifest("plugins/my-plugin/plugin.toml")?;
// Call a function
let result = runtime.call("my-plugin", "process", &[])?;
println!("Result: {}", result);
Ok(())
}
```
## Feature Flags
| `serde` (default) | Enable manifest parsing and serialization |
| `watch` | Enable filesystem watching for hot reload |
| `metrics-prometheus` | Prometheus metrics integration |
## Plugin Manifest
Plugins are defined by a TOML manifest:
```toml
name = "my-plugin"
version = "1.0.0"
description = "Example plugin"
api-version = { major = 0, minor = 18, patch = 0 }
# Required capabilities
capabilities = ["fs:read", "net:request"]
# Dependencies
[[dependencies]]
name = "json"
version = "^1.0"
# Entry point
source = "main.fsx"
# Exported functions
exports = ["init", "process", "cleanup"]
# Tags for categorization
tags = ["processing", "example"]
```
## Loading Plugins
```rust
use fusabi_plugin_runtime::{PluginLoader, LoaderConfig};
let loader = PluginLoader::new(LoaderConfig::default())?;
// From manifest
let plugin = loader.load_from_manifest("plugin.toml")?;
// From source directly
let plugin = loader.load_source("plugin.fsx")?;
// From bytecode
let plugin = loader.load_bytecode_file("plugin.fzb")?;
```
## Plugin Registry
```rust
use fusabi_plugin_runtime::{PluginRegistry, RegistryConfig};
let registry = PluginRegistry::new(RegistryConfig::default());
// Register plugins
registry.register(plugin)?;
// Get by name
let plugin = registry.get("my-plugin")?;
// Get all running plugins
let running = registry.running();
// Reload a plugin
registry.reload("my-plugin")?;
```
## Hot Reload
```rust
use fusabi_plugin_runtime::{PluginWatcher, WatchConfig, WatchEvent};
let mut watcher = PluginWatcher::new(WatchConfig::default())?;
// Add change handler
watcher.on_change(|event| {
match event {
WatchEvent::Modified { path } => {
println!("File modified: {}", path.display());
// Trigger reload
}
_ => {}
}
});
// Watch plugin directories
watcher.watch("plugins/")?;
watcher.start()?;
```
## Lifecycle Hooks
```rust
use fusabi_plugin_runtime::{PluginRuntime, RuntimeConfig};
let runtime = PluginRuntime::new(RuntimeConfig::default())?;
// Add lifecycle event handler
runtime.on_event(|event| {
println!("Plugin {}: {}", event.plugin_name(), event.event_name());
});
```
## Capability Enforcement
Plugins must declare required capabilities in their manifest. The runtime validates that:
1. All declared capabilities are valid
2. The host grants the required capabilities
3. Plugins don't access undeclared capabilities
```rust
use fusabi_plugin_runtime::{LoaderConfig, Capabilities};
let config = LoaderConfig::new()
.with_engine_config(
EngineConfig::default()
.with_capabilities(Capabilities::safe_defaults())
);
// Plugin requesting fs:write without it being granted will fail
let loader = PluginLoader::new(config)?;
```
## API Version Compatibility
Plugins declare a required API version. The runtime checks compatibility:
```rust
use fusabi_plugin_runtime::{LoaderConfig, ApiVersion};
let config = LoaderConfig::new()
.with_host_api_version(ApiVersion::new(0, 18, 0));
// Plugin requiring 0.19.0 will fail to load
```
## License
Licensed under either of:
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.