navidrome/plugins/pdk/rust/nd-pdk-host
Kendall Garner 54fe6c254e
feat(plugins): implement plugin specific storage (#5839)
* implement storage api/hooks

* fine. if the error messages are different, just match error

* rename storageMount

* add independent plugin test

* round 2

* .-.

* one more copypasta fail

* docs(plugins): document the Storage host service

The README is the plugin author reference and every other host service has a
section there, but Storage had none, so the /storage guest path contract only
existed in code.

Documents the mount point and its backing directory, the manifest permission,
the host function, and the two behaviours an author would otherwise discover
the hard way: there is no size limit, and the directory outlives an uninstall.

* docs(plugins): correct the library filesystem security notes

The README stated in three places that library filesystem access is read-only,
which stopped being true when AllowWriteAccess was added: an administrator can
grant a plugin write access to libraries.

Corrects those and gives the library and storage mounts the same wording for
what the sandbox guarantees, since both now go through the same jail.

* docs(plugins): describe symlink handling in mounts accurately

The security notes claimed paths resolving outside a mount are rejected, which
overstates the jail. Only lexical escapes are: '..' and absolute paths. Creating
symlinks is denied, but symlinks already present are followed and do reach
outside the mount, which is what lets music libraries link folders in from
elsewhere. Both behaviours are pinned by tests in the plugins package.

---------

Co-authored-by: Deluan Quintão <deluan@navidrome.org>
2026-08-03 14:23:42 -04:00
..
src feat(plugins): implement plugin specific storage (#5839) 2026-08-03 14:23:42 -04:00
.gitignore feat(plugins): New Plugin System with multi-language PDK support (#4833) 2026-01-14 19:22:48 -05:00
Cargo.lock chore(deps): bump bytes in /plugins/pdk/rust/nd-pdk-host (#4973) 2026-02-04 10:11:37 -05:00
Cargo.toml feat(plugins): share plugin DTOs via a types package (#5655) 2026-06-29 21:20:33 -04:00
README.md feat(plugins): New Plugin System with multi-language PDK support (#4833) 2026-01-14 19:22:48 -05:00

Navidrome Host Function Wrappers for Rust

This directory contains auto-generated Rust wrappers for Navidrome's host services. These wrappers provide idiomatic Rust APIs for interacting with Navidrome from WASM plugins.

⚠️ Auto-Generated Code

Do not edit these files manually. They are generated by the ndpgen tool.

To regenerate:

make gen

Usage

Add this crate as a dependency in your plugin's Cargo.toml:

[dependencies]
nd-host = { path = "../../pdk/rust/host" }

Then import the services you need:

use nd_host::{cache, scheduler, library};
use nd_host::library::Library; // Import the typed struct

#[plugin_fn]
pub fn my_callback(input: String) -> FnResult<String> {
    // Use the cache service
    cache::set("my_key", b"my_value", 3600)?;

    // Schedule a recurring task  
    scheduler::schedule_recurring("@every 5m", "payload", "task_id")?;

    // Access library data with typed structs
    let libraries: Vec<Library> = library::get_all_libraries()?;
    for lib in &libraries {
        info!("Library: {} with {} songs", lib.name, lib.total_songs);
    }

    Ok("done".to_string())
}

Typed Structs

Services that work with domain objects provide typed Rust structs instead of serde_json::Value. This enables compile-time type checking and IDE autocompletion.

For example, the library module provides a Library struct:

use nd_host::library::Library;

let libs: Vec<Library> = library::get_all_libraries()?;
println!("First library: {} ({} songs)", libs[0].name, libs[0].total_songs);

All structs derive Debug, Clone, Serialize, and Deserialize for convenient use with logging and serialization.

Available Services

Module Description
artwork Access album and artist artwork
cache Temporary key-value storage with TTL
kvstore Persistent key-value storage
library Access the music library (albums, artists, tracks)
scheduler Schedule one-time and recurring tasks
subsonicapi Make Subsonic API calls
websocket Send real-time messages to clients

Building Plugins

Rust plugins must be compiled to WebAssembly:

cargo build --target wasm32-wasip1 --release

See the webhook-rs example for a complete plugin implementation.