Instruction file imported from tyrchen/simple-proxy (
.cursor/rules/extism.mdc). Copyright stays with the author.
Extism 1.10.0 Integration Guide
This guide provides instructions for working with the Extism WebAssembly framework version 1.10.0.
Key Concepts
- Plugin: A WebAssembly module loaded through Extism.
- Manifest: Configuration for the WebAssembly module (memory limits, allowed hosts, etc).
- PluginBuilder: Used to construct plugins with detailed configuration.
- Host Functions: Functions implemented in the host application but callable from WebAssembly.
Loading Plugins
Creating a Manifest
use extism::{Manifest, Wasm};
// From file
let wasm = Wasm::file("path/to/plugin.wasm");
let manifest = Manifest::new([wasm]);
// From URL
let wasm = Wasm::url("https://example.com/plugin.wasm");
let manifest = Manifest::new([wasm]);
// From bytes
let wasm_bytes: Vec<u8> = /* ... */;
let wasm = Wasm::data(wasm_bytes);
let manifest = Manifest::new([wasm]);
// With configuration
let manifest = manifest.with_config_key("key", "value");
Initializing a Plugin
use extism::{Plugin, Function, ValType, UserData};
// Basic initialization
let plugin = Plugin::new(&manifest, [], true)?;
// With PluginBuilder for advanced configuration
let plugin = extism::PluginBuilder::new(manifest)
.with_wasi(true)
// Add plugin constraints
.build()?;
Calling Plugin Functions
// Simple call with string input/output
let result = plugin.call::<&str, &str>("function_name", "input data")?;
// With JSON conversion
use extism::convert::Json;
#[derive(serde::Serialize)]
struct Input { /* ... */ }
#[derive(serde::Deserialize)]
struct Output { /* ... */ }
let input = Input { /* ... */ };
let Json(output): Json<Output> = plugin.call("function_name", Json(input))?;
Registering Host Functions
use extism::{Function, UserData, ValType, CurrentPlugin, Val, PTR};
// Host function implementation
fn my_host_function(
plugin: &mut CurrentPlugin,
inputs: &[Val],
outputs: &mut [Val],
user_data: UserData<()>
) -> Result<(), extism::Error> {
// Handle memory, get inputs, set outputs
Ok(())
}
// Register the function with PluginBuilder
let plugin = extism::PluginBuilder::new(manifest)
.with_wasi(true)
.with_function(
"my_function", // Function name
[PTR], // Parameter types (PTR for pointer parameters)
[PTR], // Return types
UserData::default(), // User data
my_host_function // Function implementation
)
.build()?;
Memory Management in Host Functions
fn host_function(
plugin: &mut CurrentPlugin,
inputs: &[Val],
outputs: &mut [Val],
user_data: UserData<()>
) -> Result<(), extism::Error> {
// Get memory handle from pointer parameter
let handle = plugin.memory_from_val(&inputs[0])
.ok_or_else(|| anyhow::Error::msg("Invalid memory handle"))?;
// Read data from WebAssembly memory
let input_data: String = plugin.memory_get(handle)?;
// Process data
let output_data = process_input(input_data);
// Allocate memory and store result
let result_handle = plugin.memory_new(output_data)?;
// Set output parameter
outputs[0] = plugin.memory_to_val(result_handle);
Ok(())
}
Working with Plugin Interfaces
The PluginInterface trait defines methods that plugins must implement. When implementing custom interfaces:
trait PluginInterface {
fn process_request(&self, request: &Request) -> Result<Response>;
// ...
}
impl PluginInterface for Plugin {
fn process_request(&self, request: &Request) -> Result<Response> {
// Transform request to a format the plugin can understand
let input = serde_json::to_vec(request)?;
// Call the plugin with type Vec<u8>
let output = self.instance.call("process_request", input)?;
// Parse the response
let response: Response = serde_json::from_slice(&output)?;
Ok(response)
}
}
Common Errors and Solutions
Error: No method named with_config_value found for struct Manifest
The 1.10.0 API doesn't have this method. Use:
// Instead of:
manifest.with_config_value(key, value);
// Use:
manifest.with_config_key(key, value.to_string());
Error: No method named has_function found for struct Arc<Plugin>
When working with Arc-wrapped plugins:
// Instead of:
if !self.instance.has_function(function_name) { ... }
// Use:
if !self.instance.function_exists(function_name) { ... }
Error: The trait bound [u8]: FromBytes<'_> is not satisfied
When calling functions that return byte arrays:
// Instead of:
let output = self.instance.call(function_name, input)?;
// Use specific type annotations:
let output: Vec<u8> = self.instance.call(function_name, input)?;
Best Practices
- Error Handling: Always check for and handle errors from plugin operations.
- Memory Management: Free allocated memory when no longer needed to prevent leaks.
- Plugin Reuse: Reuse plugin instances when possible, as instantiation is expensive.
- Type Safety: Use strongly-typed interfaces with proper serialization/deserialization.
- Security: Be careful with the permissions granted to plugins (file access, network).
Upgrading from Older Versions
When upgrading from pre-1.10.0 versions:
- Replace
wasm.timeout_mswithmanifest.with_timeout(Duration::from_millis(timeout_ms)). - Replace
wasm.memory_options.max_pageswith memory configuration in the Manifest. - Update function call syntax to use proper type parameters.
Environment Variables
Debug and optimization can be controlled via environment variables:
EXTISM_ENABLE_WASI_OUTPUT=1: Show WASI stdout/stderrEXTISM_MEMDUMP=path.mem: Dump Extism memory to a fileEXTISM_COREDUMP=path.core: Write coredump on WebAssembly trapEXTISM_DEBUG=1: Generate debug informationEXTISM_PROFILE=perf|jitdump|vtune: Enable profilingEXTISM_CACHE_CONFIG=path/to/config.toml: Enable cache configuration