Files
suaveplan/openspec/archive/2026-05-26-api-router-in-memory/specs/api-router-in-memory/spec.md
2026-05-27 23:29:53 +01:00

3.2 KiB

Capability Spec Delta: api-router-in-memory (api-router-in-memory)

Package: @suaveplan/api-router-in-memory Status: PROPOSED

ADDED Requirements

Requirement: Dispatch without a socket

The package SHALL implement Router such that dispatch(request) runs the full request pipeline in-process and returns a Response-shaped value. No socket, port, or HTTP listener is bound.

Scenario: dispatch returns Response without network I/O

  • WHEN a route is registered AND router.dispatch(new Request("/x")) is called
  • THEN the result is a Response AND no network socket is opened (sanity-checked by asserting Bun.listen/net modules were not invoked)

Verified by: src/factory/create-in-memory-router.test.ts::"dispatches without opening any network socket"


Requirement: host.fetch entry point matches design doc

The package SHALL expose host.fetch(method, path, init?) returning a Promise<Response>. The signature MUST be compatible with the createTestHost ergonomics example in §13.2.

Scenario: host.fetch dispatches a POST with body

  • WHEN host.fetch("POST", "/billing/invoices", { body: { amountCents: 10000, currency: "USD" } }) is called against a registered handler
  • THEN the result has status === 201 AND the body parses to the expected JSON

Verified by: src/fetch-shape/fetch-shape.test.ts::"host.fetch POST returns 201 with parsed JSON body"


Requirement: Request recording supports assertions

The router SHALL maintain a requests history when trackRequests: true. Each entry records method, path, and request-id. router.reset() MUST clear the history.

Scenario: history captures every dispatched request

  • WHEN three dispatches happen
  • THEN router.requests has length 3 AND each entry records the correct method+path

Scenario: reset clears history

  • WHEN router.reset() is called after dispatches
  • THEN router.requests has length 0

Verified by: src/recording/request-log.test.ts::"captures every dispatched request" AND src/recording/request-log.test.ts::"reset clears history"


Requirement: Conforms to Router contract

The factory SHALL pass runRouterConformance from @suaveplan/api-router/testing end-to-end.

Scenario: every Router invariant passes

  • WHEN runRouterConformance("in-memory-direct", createInMemoryRouter) runs
  • THEN every invariant reports passing

Verified by: src/factory/create-in-memory-router.spec-conformance.test.ts::"in-memory-direct conforms to Router contract"


Requirement: Registered in api-host/testing adapter table

This adapter SHALL be reachable from createTestHost({ adapters: { router: "in-memory" } }). The lookup table in @suaveplan/api-host/testing SHALL recognize the "in-memory" string sentinel and instantiate this factory.

Scenario: createTestHost resolves the in-memory router

  • WHEN a test calls createTestHost({ adapters: { router: "in-memory" } })
  • THEN host.router is an instance of the factory produced by this package

Verified by: tests/integration/integration.test.ts::"createTestHost resolves router:\"in-memory\" to this adapter"