# Route discovery _(no submodules)_ ## Purpose `discoverRoutes(exports, pluginName)` calls the guest's `__suaveplan_routes` export exactly once at bridge-init time, unpacks the `(pointer, length)` pair the guest returns as a packed `bigint`, reads the JSON-encoded `SerializedRoute[]` from linear memory, frees the guest-allocated buffer, and returns the typed array. The bridge uses this list to build the `PipelineRoute` array installed on the host. ## Features - Single bridge-init call — the result is cached by `createSandboxedWasmPluginModule`; the guest is never asked for its routes again. - Trap-protected: a fault inside `__suaveplan_routes` surfaces as `SAND_WASM_BRIDGE.HANDLER_TRAPPED` with `context.phase: "routes"` and a classified `trapKind`. - Malformed-payload aware: bytes that fail Zod validation surface as `SAND_WASM_BRIDGE.UNMARSHAL_FAILED` (re-thrown from `unmarshalRoutes`). - Empty-list tolerant: a guest returning `(0, 0)` is treated as "no routes" rather than as an error, so plugins with lifecycle-only hooks remain valid. - Frees the guest's buffer before returning — the bridge never leaves linear-memory pages owned by the guest's allocator dangling after init. ## Usage: Basic ```ts import { discoverRoutes } from "@suaveplan/api-sandbox-wasm-host-bridge/route-discovery"; const routes = discoverRoutes(exports, "example"); ``` ## Usage: Advanced ```ts import { discoverRoutes } from "@suaveplan/api-sandbox-wasm-host-bridge/route-discovery"; import type { SerializedRoute } from "@suaveplan/api-types/sandbox-bridge"; function buildRouteIndex( exports: import("@suaveplan/api-sandbox-wasm-host-bridge/wasm-abi").WasmAbiExports, plugin: string, ): ReadonlyMap { const routes = discoverRoutes(exports, plugin); const index = new Map(); for (const route of routes) { index.set(`${route.method} ${route.path}`, route); } return index; } ``` ## API Reference - `discoverRoutes(exports: WasmAbiExports, pluginName: string): readonly SerializedRoute[]`. ## Implementation Notes The empty-list case (`pointer === 0 || length === 0`) is reached when the guest's `__suaveplan_routes` returns the literal `bigint` `0n`. We still attempt to free the buffer when `pointer !== 0` to be defensive — a guest that returns `(ptr, 0)` may have legitimately allocated a zero-length buffer that the host still owns the responsibility to release. The freeBuffer helper is a no-op when `pointer === 0`, so the double-guard is safe.