feat(wasm): execute client handlers without requests

req: client_local/001\nreq: client_local/004\nreq: client_local/005\nreq: client_local/009\nreq: client_local/010\nreq: client_local/014\nreq: v1_release/001
This commit is contained in:
slhx agent
2026-07-13 12:33:54 +02:00
parent 0d49007c61
commit 40643e360d
16 changed files with 515 additions and 25 deletions
+1
View File
@@ -54,6 +54,7 @@ export interface HemxRuntime {
decodeBatch(buffer: ArrayBuffer): EffectBatch;
atomValue(root: Element | ParentNode | null | undefined, id: number): Uint8Array | undefined;
decodeAtomState(encoded: string): AtomSnapshot[];
registerClientHandler(name: string, handler: () => Uint8Array | Promise<Uint8Array>): void;
}
declare global {
+29 -2
View File
@@ -18,6 +18,7 @@
const sseSources = new WeakMap();
const atomStores = new WeakMap();
const dragKeys = new WeakMap();
const clientHandlers = new Map();
function roots() {
const found = [];
@@ -237,6 +238,15 @@
});
}
async function runClient(el) {
const name = el.getAttribute("data-hemx-client");
const handler = clientHandlers.get(name);
if (!handler) throw new Error(`unknown client-local hemx handler: ${name}`);
const wire = await handler();
if (!(wire instanceof Uint8Array)) throw new Error(`client-local hemx handler ${name} returned an invalid effect batch`);
applyBatch(wire, rootOf(el));
}
async function send(el, eventName, source = el) {
if (el.getAttribute("data-hemx-confirm") && !confirm(el.getAttribute("data-hemx-confirm"))) return;
const { form, data, multipart } = formDataFor(el, eventName, source);
@@ -671,7 +681,11 @@
const direct = closestInRoot(event.target, root, (el) => el.hasAttribute(HID));
if (direct && defaultEvent(direct) === "click") {
event.preventDefault();
schedule(direct, name);
if (direct.hasAttribute("data-hemx-client")) {
runClient(direct).catch((error) => emit(root, "hemx:client-error", String(error)));
} else {
schedule(direct, name);
}
return;
}
}
@@ -935,7 +949,20 @@
if (root) navigateUrl(location.href, root, "none").catch((error) => emit(root, "hemx:error", String(error)));
});
window.hemx = Object.freeze({ runtimeAbiVersion, roots, rootOf, applyHtml, applyBatch, decodeBatch, atomValue, decodeAtomState });
window.hemx = Object.freeze({
runtimeAbiVersion,
roots,
rootOf,
applyHtml,
applyBatch,
decodeBatch,
atomValue,
decodeAtomState,
registerClientHandler(name, handler) {
if (!name || typeof handler !== "function") throw new Error("client handler registration requires a name and function");
clientHandlers.set(name, handler);
},
});
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", start);
else start();