Messaging
Messaging is a custom RPC channel between a gadget’s React frontend and its WASM backend. It runs parallel to the search pipeline and lets you call arbitrary backend logic from your views or settings panels: fetching data from a database, validating input, triggering actions, or anything else your UI needs that the search interface doesn’t cover.
Messaging is optional. Gadgets that only use the standard search result list don’t need it.
Frontend side
Section titled “Frontend side”The sendMessage function is available through the useGadgetRuntime hook:
import { useGadgetRuntime } from "@torchsnap/gadget-sdk/hooks";
const { sendMessage } = useGadgetRuntime();The function signature is:
type GadgetSendMessage = <TPayload = unknown, TResult = unknown>( method: string, payload: TPayload,) => Promise<TResult>;method identifies which operation to invoke on the backend. payload is
serialized as JSON and passed to the backend’s handle_message. The returned
promise resolves with the parsed JSON response, or rejects with an error string.
Example
Section titled “Example”const { sendMessage } = useGadgetRuntime();
async function clearHistory() { await sendMessage("clear_history", {});}
async function loadPage(page: number) { const data = await sendMessage<{ page: number }, HistoryPage>( "get_history", { page }, ); setEntries(data.entries);}Backend side
Section titled “Backend side”On the Rust side, sendMessage calls route to the gadget’s
handle_message export. The
method string maps directly to the first argument. Both the payload and
response are JSON-encoded strings:
impl MessagingGuest for MyGadget { fn handle_message(method: String, payload: String) -> Result<String, String> { match method.as_str() { "get_history" => { let req: PageRequest = messaging::parse_payload(&payload)?; let page = load_history_page(req.page)?; messaging::to_response(&page) } "clear_history" => { clear_history_db()?; messaging::to_response(&true) } _ => Err(format!("unknown method: {method}")), } }}The SDK helpers messaging::parse_payload and messaging::to_response handle
JSON serialization. See the
Exports reference for the full
WIT contract and SDK trait details.
JSON encoding
Section titled “JSON encoding”Both directions are JSON-encoded strings at the WIT boundary:
- Frontend → Backend:
payloadis serialized to JSON by the host before reachinghandle_message. - Backend → Frontend: the
Ok(String)return value is parsed as JSON by the host before resolving thesendMessagepromise.
The TypeScript generic parameters on sendMessage<TPayload, TResult> provide
type safety on the frontend side, but the actual wire format is always a JSON
string. Make sure your Rust types and TypeScript types agree on the shape.
WASM streaming limitation
Section titled “WASM streaming limitation”The sendMessage type signature includes an optional onMessage callback
parameter, but this is only functional for native (non-WASM) gadgets. For WASM
gadgets, the callback is never invoked. This limitation exists because the WIT
messaging::handle-message interface is one-shot by design.