feat: v0.1.0 — Studio Plugin SDK
First release of the SDK that Studio plugins depend on. What v0.1 ships: - WIT contract under wit/ (studio-plugin.wit + deps/platform/world.wit, both verbatim from fai/platform/wit/). - wit-bindgen 0.36 generate! call with pub_export_macro enabled so the emitted __export_studio_plugin_impl! macro is reachable from downstream plugin crates. - export_plugin!(MyType) convenience macro that wraps the bindgen-generated impl macro. - README documenting usage + v0.1 limits (single-world -> all-three-hooks-required, no proc-macro yet, edition 2021 pinned by wit-bindgen output). What v0.1 doesn't yet do: - Plugins still declare all three Guest impls (theme, translate, output-view). v0.2 splits the WIT into one world per hook. - No #[plugin(...)] proc-macro. v0.2 wraps generate! + Guest impl generation into a single attribute. - Host-side: the hub doesn't yet load studio-plugin-world components or expose InvokePlugin RPC — that's the next push. Validated against the in-tree studio-theme-solarized plugin: 22 KiB stripped .wasm artefact, valid Component Model, passes wasm-tools component wit inspection. Signed-off-by: flemming-it <sf@flemming.it>
This commit is contained in:
commit
3753c6bc37
7 changed files with 562 additions and 0 deletions
107
README.md
Normal file
107
README.md
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
# fai-studio-plugin-sdk
|
||||
|
||||
Rust SDK for writing F∆I Studio plugins.
|
||||
|
||||
## Status
|
||||
|
||||
**v0.1 builds.** Studio plugins targeting the `studio-plugin`
|
||||
world declared in `wit/studio-plugin.wit` can be compiled to
|
||||
`wasm32-wasip2` against this crate today. The proof-of-
|
||||
contract plugin is `studio-theme-solarized` in the
|
||||
fai-modules namespace.
|
||||
|
||||
What's NOT yet implemented:
|
||||
|
||||
- **Hub side**: a Component-Model loader path for
|
||||
`studio-plugin`-world components + the `InvokePlugin`
|
||||
gRPC RPC that Studio talks to. Tracked in
|
||||
`fai/platform/docs/advanced/studio-plugin-sdk.md`.
|
||||
- **Studio side**: `plugin_host.dart` that discovers
|
||||
installed `studio.*` capabilities and dispatches.
|
||||
- **Per-hook worlds**: today's v0.1 ships a single world
|
||||
(`studio-plugin`) that exports all three hooks
|
||||
(`theme`, `translate`, `output-view`). A plugin only
|
||||
caring about one hook still has to declare empty /
|
||||
declined impls for the other two. v0.2 splits into one
|
||||
world per hook.
|
||||
- **`#[plugin(...)]` proc-macro**: v0.1 ships a plain
|
||||
`export_plugin!` macro that wraps the wit-bindgen-emitted
|
||||
`__export_studio_plugin_impl!`. The proc-macro that
|
||||
generates the WIT bindings + the `Guest` impls in one
|
||||
pass arrives in v0.2.
|
||||
|
||||
## Usage
|
||||
|
||||
```toml
|
||||
# Cargo.toml of your plugin
|
||||
[package]
|
||||
name = "my_studio_plugin"
|
||||
version = "0.1.0"
|
||||
edition = "2021" # match SDK edition
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
fai-studio-plugin-sdk = { git = "https://git.flemming.ai/fai/studio-plugin-sdk", branch = "main" }
|
||||
```
|
||||
|
||||
```rust
|
||||
// src/lib.rs of your plugin
|
||||
use fai_studio_plugin_sdk::{bindings, export_plugin};
|
||||
|
||||
type ColorScheme = bindings::fai::studio_plugin::plugin_types::ColorScheme;
|
||||
type PluginError = bindings::fai::studio_plugin::plugin_types::PluginError;
|
||||
type RenderedOutput = bindings::fai::studio_plugin::plugin_types::RenderedOutput;
|
||||
|
||||
struct MyPlugin;
|
||||
|
||||
impl bindings::exports::fai::studio_plugin::theme::Guest for MyPlugin {
|
||||
fn theme_for(brightness: String) -> Result<ColorScheme, PluginError> {
|
||||
// Return a ColorScheme or PluginError::Declined.
|
||||
}
|
||||
}
|
||||
|
||||
// v0.1: every plugin must declare all three hooks. Plugins
|
||||
// that don't actually serve a hook return Declined.
|
||||
impl bindings::exports::fai::studio_plugin::translate::Guest for MyPlugin {
|
||||
fn translate(_: String, _: String, _: String) -> Result<String, PluginError> {
|
||||
Err(PluginError::Declined("not a translate plugin".to_string()))
|
||||
}
|
||||
}
|
||||
impl bindings::exports::fai::studio_plugin::output_view::Guest for MyPlugin {
|
||||
fn render(_: String, _: Vec<u8>) -> Result<RenderedOutput, PluginError> {
|
||||
Err(PluginError::Declined("not a view plugin".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
export_plugin!(MyPlugin);
|
||||
```
|
||||
|
||||
Then:
|
||||
|
||||
```bash
|
||||
cargo build --release --target wasm32-wasip2
|
||||
fai pack . -o my-plugin-0.1.0.fai
|
||||
```
|
||||
|
||||
## WIT layout
|
||||
|
||||
```
|
||||
wit/
|
||||
├── studio-plugin.wit # main world, fai:studio-plugin@0.1.0
|
||||
└── deps/
|
||||
└── platform/
|
||||
└── world.wit # fai:platform@1.0.0 (host imports)
|
||||
```
|
||||
|
||||
Both files are verbatim copies of the authoritative versions
|
||||
in `fai/platform/wit/`. When the contract changes upstream,
|
||||
re-copy here in lock-step.
|
||||
|
||||
## Why edition 2021
|
||||
|
||||
wit-bindgen 0.36 emits `#[link_section]` / unsafe-attribute
|
||||
syntax that the edition-2024 compiler rejects. Bump when
|
||||
moving to a wit-bindgen version with edition-2024-compatible
|
||||
codegen.
|
||||
Loading…
Add table
Add a link
Reference in a new issue