# 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`. 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"`