feat: deliver committed Ticket events to plugin services

This commit is contained in:
2026-10-31 04:58:19 +09:00
parent 4f7dcfda61
commit b508fef698
94 changed files with 11852 additions and 247 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
# plugin-pdk
Guest-side Rust helpers for the versioned Component Model Tool contract. [`ToolContext`] decodes only non-secret invocation data; [`ToolOutput`] rejects oversized data and separates structured output from presentation text. [`export_component_tool!`] adapts generated WIT bindings and preserves the result's error arm.
Guest-side Rust helpers for the versioned Component Model Tool and Service contracts. [`ToolContext`] decodes only non-secret invocation data; [`ToolOutput`] rejects oversized data and separates structured output from presentation text. [`export_component_tool!`] adapts generated WIT bindings and preserves the result's error arm.
Host authorization, schema validation, effect receipts and execution belong to the Host, not this crate. The PDK does not import WASI, implement a Host, or provide Service/event/Workdir/WebSocket stubs. Old v1 packages require an explicit v2 rebuild rather than a compatibility adapter.
Host authorization, schema validation, effect receipts and execution belong to the Host, not this crate. [`export_component_service!`] adapts authored lifecycle/event handlers to the separate exact Service world without a guest task loop. The PDK does not import WASI, implement a Host, or provide Workdir/WebSocket stubs. Old v1 packages require an explicit v2 rebuild rather than a compatibility adapter.
+40
View File
@@ -18,6 +18,9 @@ pub const TICKET_TOOL_WIT: &str =
include_str!("../../../resources/plugin/wit-ticket/yoi-plugin-v2.1.wit");
pub const TICKET_HOST_WIT: &str =
include_str!("../../../resources/plugin/wit-ticket/deps/yoi-host-v2.1/yoi-host-v2.1.wit");
pub const SERVICE_WORLD: &str = "yoi:plugin/ticket-service-plugin@2.2.0";
pub const SERVICE_WIT: &str =
include_str!("../../../resources/plugin/wit-service/yoi-plugin-v2.2.wit");
pub const MAX_EXTENSION_DATA_BYTES: usize = 64 * 1024;
/// Encode a cell without implicit mutation retries or schema conversion.
@@ -361,3 +364,40 @@ mod tests {
assert!(error.message().ends_with('語'));
}
}
/// Bind authored Service handlers to the generated ABI without a guest task loop.
/// Each handler runs in fresh memory; recovery state belongs to Host data/receipts.
#[macro_export]
macro_rules! export_component_service {
($adapter:ident, $start:path, $event:path, $stop:path) => {
struct $adapter;
impl exports::yoi::plugin::service::Guest for $adapter {
fn on_start(
config: String,
) -> ::std::result::Result<(), exports::yoi::plugin::service::ServiceError> {
$start(config).map_err(|e: $crate::ToolError| {
exports::yoi::plugin::service::ServiceError {
code: e.code_str().into(),
message: e.message().into(),
}
})
}
fn on_event(
input: exports::yoi::plugin::service::Envelope,
) -> exports::yoi::plugin::service::EventResult {
$event(input)
}
fn on_stop(
reason: String,
) -> ::std::result::Result<(), exports::yoi::plugin::service::ServiceError> {
$stop(reason).map_err(|e: $crate::ToolError| {
exports::yoi::plugin::service::ServiceError {
code: e.code_str().into(),
message: e.message().into(),
}
})
}
}
export!($adapter);
};
}
@@ -0,0 +1,50 @@
use yoi_plugin_pdk::{ToolError, wit_bindgen};
wit_bindgen::generate!({
world: "ticket-service-plugin",
path: "../../resources/plugin/wit-service",
generate_all,
runtime_path: "yoi_plugin_pdk::wit_bindgen::rt",
});
fn start(config: String) -> Result<(), ToolError> {
if config == "invalid" {
Err(ToolError::invalid_input("bad config"))
} else {
Ok(())
}
}
fn event(_: exports::yoi::plugin::service::Envelope) -> exports::yoi::plugin::service::EventResult {
exports::yoi::plugin::service::EventResult::RetryAfter(20)
}
fn stop(_: String) -> Result<(), ToolError> {
Ok(())
}
yoi_plugin_pdk::export_component_service!(ServiceProbe, start, event, stop);
#[test]
fn service_macro_preserves_lifecycle_error_arm() {
use exports::yoi::plugin::service::Guest;
assert_eq!(
ServiceProbe::on_start("invalid".into()).unwrap_err().code,
"invalid_input"
);
ServiceProbe::on_stop("shutdown".into()).unwrap();
}
#[test]
fn service_dependencies_preserve_exact_older_pins() {
assert_eq!(
yoi_plugin_pdk::HOST_WIT,
include_str!("../../../resources/plugin/wit-service/deps/yoi-host-v2/yoi-host-v2.wit")
);
assert_eq!(
yoi_plugin_pdk::TICKET_HOST_WIT,
include_str!("../../../resources/plugin/wit-service/deps/yoi-host-v2.1/yoi-host-v2.1.wit")
);
assert_eq!(
yoi_plugin_pdk::SERVICE_WORLD,
"yoi:plugin/ticket-service-plugin@2.2.0"
);
assert_eq!(
yoi_plugin_pdk::SERVICE_WIT,
include_str!("../../../resources/plugin/wit-service/yoi-plugin-v2.2.wit")
);
}