Files
suaveplan/packages/api-stack/api/api-plugin-example/src/wasm/handle-request.md
2026-05-27 23:29:53 +01:00

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).
  • SuaveplanError throws 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 with code: 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.