Error boundaries

Handle failed loaders and server results in the UI — inspired by Leptos <ErrorBoundary>, adapted for Resuma's SSR-first model.

Loader boundaries

Loaders run on the server before paint. Use load_boundary to branch on LoadValue::Ok | Err | Pending:

load_boundary(
    use_user_load(),
    |user| view! {
        <h1>"Hello, " {user.name.clone()}</h1>
    },
    |err| view! {
        <div class="error-banner">
            "Could not load profile: " {err.message.clone()}
        </div>
    },
    || view! { <p aria-busy="true">"Loading profile…"</p> },
)

Result fallback

For synchronous Result&lt;View, E&gt; branches inside a component:

let panel = match build_panel() {
    Ok(v) => v,
    Err(e) => view! { <p class="error">{e}</p> },
};

// Or with the helper:
error_boundary(build_panel(), |msg| view! {
    <p class="error">{msg}</p>
})

Server actions & client errors

Use __resuma.safeAction(name, args) in js! for Result-style handling without try/catch — like Leptos error boundaries for RPC:

onClick={js!(async (_, __resuma) => {
    const res = await __resuma.safeAction("current_time", [input]);
    if (res.ok) {
        okEl.textContent = res.value;
    } else {
        errEl.textContent = res.error;
    }
})}

Progressive enhancement

Forms with &lt;Form submit={…}&gt; still work without JS. Field errors render via .resuma-field-error when the runtime intercepts the POST.