3.0 KiB
wasm/handle-request
Purpose
Entry point for the wasm-tier surface. Receives a SerializedRequest
(the WASI-stdio envelope payload), routes by method + URL pathname,
and dispatches to a per-route handler that delegates every business
decision to src/domain/invoice-rules.ts. The result is a
SerializedResponse whose body is base64-url-no-pad encoded.
The function is deliberately small — routing is a flat if-chain
rather than a generic radix-tree matcher because the route set is
stable and tiny. The shape-conformance test compares byte-for-byte
against the trusted-tier handler for every overlapping route; the
flat dispatch keeps the parity contract auditable at a glance.
Features
- Synchronous-style routing — no router dependency.
- Domain delegation — every business decision goes through
domain/invoice-rules.ts. - Base64-url-no-pad body encoding (JSON-clean wire shape).
SuaveplanErrorthrows propagate to the ABI shim (NOT caught here).- RBAC via
SerializedRequest.capabilities.
Usage: Basic
import { plugin } from "@suaveplan/api-plugin-example/wasm";
const res = await plugin.handleRequest({
url: "http://t/example/health",
method: "GET",
headers: [],
bodyBase64: "",
principalId: null,
tenantId: null,
capabilities: [],
requestId: "r-1",
timestamp: Date.now(),
});
console.log(res.status); // 200
Usage: Advanced
import { plugin } from "@suaveplan/api-plugin-example/wasm";
function encode(body: object): string {
const bytes = new TextEncoder().encode(JSON.stringify(body));
let binary = "";
for (let i = 0; i < bytes.length; i += 1) binary += String.fromCharCode(bytes[i] ?? 0);
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
}
const res = await plugin.handleRequest({
url: "http://t/example/invoices",
method: "POST",
headers: [["content-type", "application/json"]],
bodyBase64: encode({ customerId: "c", amountCents: 1, currency: "USD" }),
principalId: null,
tenantId: null,
capabilities: ["example:write"],
requestId: "r-2",
timestamp: Date.now(),
});
API Reference
handleRequest(req: SerializedRequest): Promise<SerializedResponse>— entry point.- Dispatches to:
/example/public/ping,/example/health,/example/invoices(GET list, GET by id, POST create),/example/invoices/:id/finalise,/example/rate-limited,/example/subscription-required,/_/test/fail-response. Unknown routes return 404 withcode: ROUTE_NOT_FOUND.
Implementation Notes
The await Promise.resolve() inside finaliseInvoice mirrors the
trusted tier's microtask yield. The trusted tier uses it to keep its
example.stripe.call_duration_ms histogram observation above zero;
the wasm tier has no histogram to record but keeps the yield so
control-flow timing remains identical for the parity test.
Base64-url-no-pad encoding uses btoa / atob — the wasm-tier
runtime (Javy/QuickJS) ships both. The encoder replaces + with
-, / with _, and strips trailing = padding.