Files
2026-05-27 23:29:53 +01:00

52 lines
3.5 KiB
Markdown

# `@suaveplan/api-router-in-memory` — In-memory Router for tests
**Package**: `@suaveplan/api-router-in-memory`
**Status**: PROPOSED
**Type**: new-package
**Stage**: 5 (Testing kit + conformance suites) — see umbrella `openspec/changes/api-plugin-foundation/`
## Why
Per design doc §13.2, the host testing-utility kit (`@suaveplan/api-host/testing`) ships REAL, in-memory implementations of every capability — production-grade adapters that happen to keep state in process memory, not test doubles. `api-router-in-memory` is the router slot of that kit: a `Router` that dispatches via a fetch-shaped function call rather than a real HTTP listener. Tests run with zero network setup, deterministic timing, and the full pipeline (auth → tenant → validation → handler → response validation → telemetry close) exercised in-process.
The package is also a load-bearing reference: every adapter in Stage 4 runs the same `runRouterConformance` suite (§13.4); this adapter is the canonical in-memory pass — if it fails the suite, the suite itself is suspect.
## What changes
Net-new package depending on `@suaveplan/api-router` (contract + `./testing` conformance), `@suaveplan/api-types`, `@suaveplan/error`.
- ADDED: `createInMemoryRouter(opts)` — direct-surface factory returning a `Router` whose `dispatch(request)` runs the full pipeline synchronously-ish (Promise-returning) without binding a socket.
- ADDED: `host.fetch(method, path, init?)` integration — the `Router` exposes a `fetch`-shaped entry point compatible with the `createTestHost` test ergonomics shown in §13.2.
- ADDED: `InMemoryRouterOptions` — Zod schema (`basePath?: string`, `trackRequests?: boolean` (default true — record every request for assertion)).
- ADDED: `ROUTER_IN_MEMORY_*` error codes (`ROUTER_IN_MEMORY_NO_MATCH`, `ROUTER_IN_MEMORY_DUPLICATE_ROUTE`, `ROUTER_IN_MEMORY_INVALID_OPTIONS`).
- ADDED: Test-recording surface — `router.requests` returns an array of every request that landed (for assertions); `router.reset()` clears the history.
- ADDED: Registration in `@suaveplan/api-host/testing`'s adapter table as the default `router` adapter when callers pass `router: "in-memory"`.
## Out of scope
- HTTP listener — by design.
- Worker-proxy surface — Stage 5 adapters are direct-only; the conformance suite that lives in `api-router/testing` is also run against `api-router-hono` (which DOES ship both surfaces) so the proxy invariants are still pinned.
- Streaming over network — the in-memory router supports `ReadableStream` body/response but no socket-level flushing semantics.
## Source mapping
Genesis-original. Source of design intent: `docs/superpowers/specs/2026-05-13-api-plugin-foundation-design.md`.
| Requirement | Design doc section |
|---|---|
| Real in-memory impl, not a double | §13.2 |
| `host.fetch` integration | §13.2 |
| Request recording for assertions | §13.2 (implicit via `host.events.published` pattern) |
| Registered in `api-host/testing` adapter table | §15 Stage 5 |
## Verification approach
- `src/factory/create-in-memory-router.test.ts` — register routes, dispatch, recording, reset.
- `src/factory/create-in-memory-router.spec-conformance.test.ts` — `runRouterConformance("in-memory-direct", ...)`.
- `src/fetch-shape/fetch-shape.test.ts` — `host.fetch("POST", "/x", { body })` returns `Response`-shaped result with status / headers / body.
- `tests/integration/integration.test.ts` — booted by `createTestHost`'s default adapter table; end-to-end pipeline executed.
## Migration impact
None — additive only.