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

3.5 KiB

@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.