| Crates.io | fusabi-plugin-runtime |
| lib.rs | fusabi-plugin-runtime |
| version | 0.1.1 |
| created_at | 2025-12-05 23:06:08.447072+00 |
| updated_at | 2025-12-05 23:06:08.447072+00 |
| description | Plugin loader, hot-reload, and runtime for Fusabi plugins with manifest validation and capability enforcement |
| homepage | |
| repository | https://github.com/fusabi-lang/fusabi-plugin-runtime |
| max_upload_size | |
| id | 1969373 |
| size | 146,820 |
Plugin loader, hot-reload, and runtime for Fusabi plugins (fsx & fzb) with manifest validation and capability enforcement.
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 | Description |
|---|---|
serde (default) |
Enable manifest parsing and serialization |
watch |
Enable filesystem watching for hot reload |
metrics-prometheus |
Prometheus metrics integration |
Plugins are defined by a TOML manifest:
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"]
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")?;
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")?;
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()?;
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());
});
Plugins must declare required capabilities in their manifest. The runtime validates that:
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)?;
Plugins declare a required API version. The runtime checks compatibility:
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
Licensed under either of:
at your option.