# `conformance` ## Purpose Builds a paired client/server harness over an in-process `MessageChannel` for conformance tests. The harness is intended for use by every Stage-3 worker-proxy package (`api-db-worker-proxy`, `api-events-worker-proxy`, `api-secrets-worker-proxy`, `api-jobs-worker-proxy`, `api-logger-worker-proxy`, and any successor) so each proxy can verify its capability semantics over a real `MessagePort` round-trip without re-implementing setup boilerplate. The harness exposes the live `client`, `server`, and `ports` handles plus a `dispose()` that tears them all down in the correct order (client first, then server, then port). Tests typically wrap it in a `finally`-style block or per-test setup/teardown. ## Features - Single-call paired construction: pass a handlers factory, get a fully wired client/server/ports triple back. - Idempotent `dispose()` — safe to call inside a test cleanup hook even if the test already closed parts of the harness. - Exposes the underlying `RawWorkerRpcClient` so streaming tests can attach a `StreamDispatcher` via the client's `onStreamFrame` option. ## Usage: Basic ```ts import { runWorkerRpcConformance } from "@suaveplan/api-worker-rpc/testing"; const h = runWorkerRpcConformance(() => ({ ping: () => "pong", })); await expect(h.client.call("ping", [])).resolves.toBe("pong"); h.dispose(); ``` ## Usage: Advanced ```ts import { StreamDispatcher, streamRequest } from "@suaveplan/api-worker-rpc/streaming"; import { runWorkerRpcConformance } from "@suaveplan/api-worker-rpc/testing"; const h = runWorkerRpcConformance(() => ({ rows: async function* () { for (let i = 0; i < 5; i++) yield i; }, })); const dispatcher = new StreamDispatcher(); // Re-wire onStreamFrame on the underlying client — note: in practice you'd // construct the client with this option from the start. The harness ships // without it so test authors can choose whether streaming is exercised. h.dispose(); ``` ## API Reference - `interface ConformanceHarness { client, server, ports, dispose }`. - `runWorkerRpcConformance(factory: () => WorkerRpcHandlers): ConformanceHarness`. ## Implementation Notes - The default harness does NOT install a `StreamDispatcher` — streaming tests construct their own client with the dispatcher's `dispatch` method wired into `onStreamFrame`, then use the harness's ports directly. This keeps the non-streaming path one-line. - The `client` field is a `RawWorkerRpcClient`, not the typed proxy — conformance tests address methods by string and inspect raw frames rather than relying on TypeScript inference. - `dispose()` tolerates partial-prior-closure so per-test `afterEach` can call it unconditionally.