Initial Commit
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
# 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
|
||||
|
||||
```ts
|
||||
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
|
||||
|
||||
```ts
|
||||
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.
|
||||
Reference in New Issue
Block a user