docs: consolidate design documentation and standardize crate English

This commit is contained in:
2026-10-12 14:58:00 +09:00
parent a633a53274
commit 4efb0ace1f
404 changed files with 4556 additions and 11654 deletions
+9
View File
@@ -0,0 +1,9 @@
# plugin-pdk
Guest-side JSON/WIT helpers for offline Component Model packages. Without depending on host/runtime crates, it converts Tool and Service inputs/outputs and bounds Tool output size. Using the PDK or validating a package does not authorize installation or execution in a Worker.
## Main entry points
- [`run_json_tool`] and [`export_component_tool!`] — typed Tool input/output boundary
- [`ToolOutput`] and [`ToolError`] — bounded output and errors
- [`ServiceOutput`] and [`export_plugin_instance!`] — instance output contracts
+21 -49
View File
@@ -1,36 +1,4 @@
//! Guest-side helpers for Yoi Component Model Tool plugins.
//!
//! This crate is intentionally small and guest-only: it depends on JSON/WIT
//! binding support, but not on Yoi host/runtime crates. It grants no authority;
//! package manifests and host-side Plugin grants decide whether a Tool or host
//! API can run.
//!
//! Component authors still generate the WIT bindings in their guest crate, then
//! delegate the exported `call` function to [`run_json_tool`] or to the
//! [`export_component_tool!`] macro:
//!
//! ```ignore
//! use yoi_plugin_pdk::wit_bindgen;
//!
//! wit_bindgen::generate!({
//! world: "tool",
//! path: "../../../../resources/plugin/wit",
//! generate_all,
//! runtime_path: "yoi_plugin_pdk::wit_bindgen::rt",
//! });
//!
//! fn echo(
//! ctx: yoi_plugin_pdk::ToolContext,
//! input: EchoInput,
//! ) -> Result<yoi_plugin_pdk::ToolOutput, yoi_plugin_pdk::ToolError> {
//! yoi_plugin_pdk::ToolOutput::json(
//! format!("{} ok", ctx.tool_name()),
//! EchoOutput { text: input.text },
//! )
//! }
//!
//! yoi_plugin_pdk::export_component_tool!(Plugin, echo);
//! ```
#![doc = include_str!("../README.md")]
use serde::Serialize;
use serde::de::DeserializeOwned;
@@ -51,9 +19,9 @@ pub const TOOL_WIT: &str = include_str!("../../../resources/plugin/wit/yoi-plugi
pub const HOST_WIT: &str =
include_str!("../../../resources/plugin/wit/deps/yoi-host/yoi-host-v1.wit");
/// Maximum serialized ToolOutput JSON accepted by Yoi's current Plugin runtime.
/// Serialized JSON limit defined by the offline Tool world's output contract.
pub const MAX_TOOL_OUTPUT_BYTES: usize = 64 * 1024;
/// Maximum summary bytes accepted by Yoi's current Plugin runtime.
/// Byte limit for summaries in the offline Tool world.
pub const MAX_SUMMARY_BYTES: usize = 1024;
/// Conservative content cap that leaves room for JSON framing and escaping.
pub const MAX_CONTENT_BYTES: usize = MAX_TOOL_OUTPUT_BYTES - MAX_SUMMARY_BYTES - 4096;
@@ -80,7 +48,11 @@ impl ToolContext {
}
}
/// ToolOutput JSON shape accepted by the current Yoi Plugin runtime.
/// Bounded Tool output formatted on the guest side.
///
/// Shorten text at character boundaries and recheck the serialized JSON limit, including escapes.
/// Typed JSON through [`Self::json`] errors on overflow rather than truncating and breaking
/// its structure. Providing this output format does not provide Plugin execution by Workers.
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
pub struct ToolOutput {
summary: String,
@@ -308,11 +280,11 @@ where
})
}
/// Execute a typed JSON Tool handler and return ToolOutput JSON for the runtime.
/// Guest-side boundary that runs a typed JSON handler and converts the result to ToolOutput JSON.
///
/// Handler errors and parse/serialization failures are not panics or host-side
/// authority decisions. They are rendered into ordinary ToolOutput JSON so the
/// runtime can route them through the normal Tool result path.
/// Convert parse, handler, and serialization failures to the normal output form. These errors
/// are not host authorization decisions, and catching handler panics is not guaranteed.
/// The PDK does not depend on host/runtime crates or grant permissions through input conversion.
pub fn run_json_tool<I, F>(tool_name: &str, input_json: &str, handler: F) -> String
where
I: DeserializeOwned,
@@ -328,16 +300,11 @@ where
}
}
/// Implement the generated Component Model `Guest` trait for a typed JSON
/// handler and export it with the `wit-bindgen` generated `export!` macro.
/// Connect a typed JSON handler to a WIT `Guest` implementation and component export.
///
/// The caller must import the PDK's `wit_bindgen` re-export and invoke
/// `wit_bindgen::generate!` for the `tool` world first, with
/// `runtime_path: "yoi_plugin_pdk::wit_bindgen::rt"`. That defines the
/// `Guest` trait and `export!` macro in the current module. The generated
/// component still imports only WIT-declared
/// host APIs; this macro does not grant filesystem, network, or environment
/// authority.
/// Use guest-generated bindings and centralize handler conversion in [`run_json_tool`].
/// This macro grants no host API permissions and is not a mechanism for registering or
/// executing dynamic Plugins in the current Worker.
#[macro_export]
macro_rules! export_component_tool {
($adapter:ident, $handler:path) => {
@@ -642,6 +609,11 @@ impl ServiceOutputCommand {
}
}
/// Instance processing results and output commands requested from the host.
///
/// The guest does not send anything here; it returns commands as data tied to the original
/// ingress event. Command creation/serialization and host authorization/execution are separate
/// boundaries. This type provides neither network permissions nor the current Worker execution mechanism.
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct ServiceOutput {
#[serde(default)]
@@ -0,0 +1,38 @@
//! Minimal Component Model Tool plugin authoring sketch using `yoi-plugin-pdk`.
//!
//! Build this as a `wasm32-unknown-unknown` cdylib with Component Model tooling
//! and package the adapted component as `plugin.component.wasm`.
use serde::{Deserialize, Serialize};
use yoi_plugin_pdk::wit_bindgen;
use yoi_plugin_pdk::{ToolContext, ToolError, ToolOutput};
wit_bindgen::generate!({
world: "tool",
path: "../../../resources/plugin/wit",
generate_all,
runtime_path: "yoi_plugin_pdk::wit_bindgen::rt",
});
#[derive(Debug, Deserialize)]
struct EchoInput {
text: String,
}
#[derive(Debug, Serialize)]
struct EchoOutput<'a> {
tool: &'a str,
text: String,
}
fn handle_echo(ctx: ToolContext, input: EchoInput) -> Result<ToolOutput, ToolError> {
ToolOutput::json(
format!("{} ok", ctx.tool_name()),
EchoOutput {
tool: ctx.tool_name(),
text: input.text,
},
)
}
yoi_plugin_pdk::export_component_tool!(Plugin, handle_echo);
+3 -8
View File
@@ -10,17 +10,14 @@ const TEMPLATE_LIB: &str =
include_str!("../../../resources/plugin/templates/rust-component-tool/src/lib.rs");
const TEMPLATE_PLUGIN: &str =
include_str!("../../../resources/plugin/templates/rust-component-tool/plugin.toml");
const TEMPLATE_README: &str =
include_str!("../../../resources/plugin/templates/rust-component-tool/README.md");
const SERVICE_TEMPLATE_CARGO: &str =
include_str!("../../../resources/plugin/templates/rust-component-instance/Cargo.toml");
const SERVICE_TEMPLATE_LIB: &str =
include_str!("../../../resources/plugin/templates/rust-component-instance/src/lib.rs");
const SERVICE_TEMPLATE_PLUGIN: &str =
include_str!("../../../resources/plugin/templates/rust-component-instance/plugin.toml");
const SERVICE_TEMPLATE_README: &str =
include_str!("../../../resources/plugin/templates/rust-component-instance/README.md");
const SAMPLE_LIB: &str = include_str!("../../../docs/examples/plugin-component-tool/lib.rs");
// Preserve the removed document's source as a byte-identical fixture to keep the test input unchanged.
const SAMPLE_LIB: &str = include_str!("fixtures/component-tool-source.txt");
const PDK_CARGO: &str = include_str!("../Cargo.toml");
#[test]
@@ -50,7 +47,6 @@ fn rust_component_tool_template_has_expected_files() {
assert!(TEMPLATE_LIB.contains("runtime_path: \"yoi_plugin_pdk::wit_bindgen::rt\""));
assert!(TEMPLATE_LIB.contains("yoi_plugin_pdk::export_component_tool!"));
assert!(TEMPLATE_LIB.contains("ToolOutput::json"));
assert!(TEMPLATE_README.contains("Component Model Tool Plugin"));
}
#[test]
@@ -114,12 +110,11 @@ fn rust_component_service_template_has_event_output_pattern() {
assert!(SERVICE_TEMPLATE_LIB.contains("PluginIngressEvent"));
assert!(SERVICE_TEMPLATE_LIB.contains("ServiceOutput::websocket_send"));
assert!(!SERVICE_TEMPLATE_LIB.contains("recv(timeout"));
assert!(SERVICE_TEMPLATE_README.contains("output command"));
assert!(!SERVICE_TEMPLATE_PLUGIN.contains("kind = \"wasm\""));
}
#[test]
fn documented_sample_uses_pdk_component_path() {
fn component_tool_fixture_uses_pdk_bindings() {
assert!(SAMPLE_LIB.contains("use yoi_plugin_pdk::wit_bindgen"));
assert!(SAMPLE_LIB.contains("wit_bindgen::generate!"));
assert!(SAMPLE_LIB.contains("generate_all"));