feat(wasm): validate client event and state ABI

req: client_local/005\nreq: client_local/006\nreq: client_local/007\nreq: client_local/008\nreq: client_local/009\nreq: client_local/010\nreq: client_local/014
This commit is contained in:
slhx agent
2026-07-13 12:42:31 +02:00
parent 40643e360d
commit 38eae79a2f
9 changed files with 246 additions and 24 deletions
+31 -6
View File
@@ -89,14 +89,15 @@ pub fn handler(attr: TokenStream, item: TokenStream) -> TokenStream {
if !is_client {
return quote!(#function).into();
}
if !function.sig.inputs.is_empty()
let input_count = function.sig.inputs.len();
if !matches!(input_count, 0 | 2)
|| function.sig.asyncness.is_some()
|| function.sig.unsafety.is_some()
|| function.sig.constness.is_some()
|| !function.sig.generics.params.is_empty()
{
let message = format!(
"client-local hemx handler `{name}` must be a safe, synchronous, non-generic function with no parameters"
"client-local hemx handler `{name}` must be safe, synchronous, non-generic, and accept either no parameters or `(hemx::wasm::ClientEvent, hemx::wasm::ClientState)`"
);
return quote!(
#function
@@ -108,6 +109,11 @@ pub fn handler(attr: TokenStream, item: TokenStream) -> TokenStream {
let function_name = &function.sig.ident;
let export_name = format_ident!("__hemx_client_{function_name}");
let export_module = format_ident!("__hemx_client_export_{function_name}");
let invoke_handler = if input_count == 0 {
quote!(super::#function_name())
} else {
quote!(super::#function_name(event, state))
};
quote!(
#function
@@ -116,11 +122,30 @@ pub fn handler(attr: TokenStream, item: TokenStream) -> TokenStream {
use ::hemx::wasm as wasm_bindgen;
#[::hemx::wasm::wasm_bindgen(js_name = #export_name)]
pub fn invoke() -> ::std::vec::Vec<u8> {
::hemx::wasm::encode_handler_effect(
super::#function_name(),
crate::ui::BUILD_FINGERPRINT,
#[allow(clippy::too_many_arguments)]
pub fn invoke(
event_version: u32,
event_kind: ::std::string::String,
event_value: ::std::option::Option<::std::string::String>,
event_checked: ::std::option::Option<bool>,
event_key: ::std::option::Option<::std::string::String>,
state_version: u32,
encoded_state: ::std::string::String,
) -> ::std::result::Result<::std::vec::Vec<u8>, ::hemx::wasm::JsValue> {
let (event, state) = ::hemx::wasm::decode_client_inputs(
event_version,
event_kind,
event_value,
event_checked,
event_key,
state_version,
encoded_state,
)
.map_err(|error| ::hemx::wasm::JsValue::from_str(&error))?;
Ok(::hemx::wasm::encode_handler_effect(
#invoke_handler,
crate::ui::BUILD_FINGERPRINT,
))
}
}
)