Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Build a plugin

The initial SDK targets Rust and WASI 0.2 components. Install the component target:

rustup target add wasm32-wasip2

The reference implementation uses Rust 1.98. Plugin source can use compatible Rust releases, but its generated component must satisfy the supported WIT API. Native subprocess, OS-specific and unrestricted networking crates are not automatically available inside a component.

Start with the SDK

The SDK lives at plugin_system/sdk in the Memona repository. Until a crates.io release is published, use a checked-out, pinned Memona revision and a path dependency:

[package]
name = "my-memona-plugin"
version = "0.1.0"
edition = "2024"

[lib]
crate-type = ["cdylib"]

[dependencies]
memona-plugin-sdk = { path = "../memona/plugin_system/sdk" }

The path is relative to your own Cargo.toml; adjust it to your checkout. Pin the checkout revision so your build does not silently pick up an API change.

The SDK includes the canonical WIT and generated Rust types. Implement its Guest trait and invoke its export! macro for your implementation type. You do not need wasm-bindgen, wasm-pack, or WIT copies in your plugin repository. cargo doc also exposes the generated Rust API.

struct MyProvider;

// Implement every method of memona_plugin_sdk::Guest for MyProvider.
// Unsupported optional operations return ErrorCode::Unsupported.
memona_plugin_sdk::export!(MyProvider);

This short excerpt shows registration, not a complete implementation. The full buildable example is plugin_system/test-component/src/lib.rs. It is a test fixture, not a WebDAV or IPFS client. From a Memona checkout, build it with:

cargo build --manifest-path plugin_system/Cargo.toml \
  -p memona-plugin-test-component --target wasm32-wasip2 --release

Build your own plugin with:

cargo build --release --target wasm32-wasip2

Call the host

Use the SDK’s generated host interface for network requests. For example, this helper retrieves a bounded HTTP response through the connection’s permissions:

use memona_plugin_sdk::memona::filesystem::host;

pub fn get_bytes(url: &str) -> Result<Vec<u8>, host::HostError> {
    let response = host::http(&host::Request {
        method: "GET".into(),
        url: url.into(),
        headers: Vec::new(),
        body: Vec::new(),
    })?;
    if !(200..300).contains(&response.status) {
        return Err(host::HostError::Unavailable);
    }
    Ok(response.body)
}

Map HTTP statuses to appropriate filesystem errors in a real provider. Supply authentication through request headers using connection configuration; do not hard-code tokens. The host resolves and pins addresses on every request and on every redirect it follows.

Nothing crosses whole. A request body is pushed in pieces of at most 1 MiB and a response body is pulled the same way, so a file of any size moves without either side holding it. The same shape governs reader and writer, which is how a provider serves a file larger than one call allows.

A protocol that is not HTTP uses connect for a TCP stream or bind for a datagram socket, each on a package-declared port. The host resolves and pins DNS and can start TLS so certificate checking stays outside the guest.

Prepare a release

Copy the resulting .wasm component to plugin.wasm, write manifest.json, and ZIP the files at the archive root. Name the archive with a .memona-plugin suffix. A directory wrapping the files inside the ZIP is not accepted.

Use the filesystem behavior guide to handle revisions, unsupported operations and mutation failures correctly. Before publishing, exercise your provider against its real service and test lost connections.