# @suaveplan/api-events-in-memory - In-memory EventsBus adapter for the @suaveplan/api testing kit. Wraps @suaveplan/events' EventBus with a per-topic recording layer so tests can assert that side-effect publishes happened. Exposes published(topic) and reset() helpers, options-bounded history with EVENTS_IN_MEMORY.HISTORY_OVERFLOW protection, Zod-validated options at the boundary, and a small waitFor harness for async assertions. No mocks — the real production bus delivers events to subscribers; this adapter only records publish history. In-memory events bus adapter for the `@suaveplan/api` testing kit. Wraps `@suaveplan/events`' production `EventBus` with a per-topic recording layer so tests can assert that side-effect publishes happened, without booting cross-process IPC and without mocks. The real bus delivers events to subscribers; this adapter only adds a queryable publish history. ## Documentation tree - [bus](./src/bus/bus.md) — `createInMemoryEventsBus` is the factory entry point of `@suaveplan/api-events-in-memory`. It returns a fresh {@link In… - [bus](./src/bus/bus.md) — `createInMemoryEventsBus` is the factory entry point of `@suaveplan/api-events-in-memory`. It returns a fresh {@link In… - [error-codes](./src/error-codes/error-codes.md) — The error-code registry pins the two failure modes that the in-memory events bus exposes to test code. Together they le… - [error-codes](./src/error-codes/error-codes.md) — The error-code registry pins the two failure modes that the in-memory events bus exposes to test code. Together they le… - [history](./src/history/history.md) — `History` is the per-topic append-only payload store that backs `bus.published(topic)`. Each `publish` invocation appen… - [history](./src/history/history.md) — `History` is the per-topic append-only payload store that backs `bus.published(topic)`. Each `publish` invocation appen… - [options](./src/options/options.md) — The options module is the single boundary at which user-supplied configuration enters the in-memory events bus. It owns… - [options](./src/options/options.md) — The options module is the single boundary at which user-supplied configuration enters the in-memory events bus. It owns… - [testing](./src/testing/testing.md) — The testing harness packages an {@link InMemoryEventsBus} with a `waitFor` helper for tests that publish asynchronously… - [testing](./src/testing/testing.md) — The testing harness packages an {@link InMemoryEventsBus} with a `waitFor` helper for tests that publish asynchronously… ## Why Per the API Plugin Foundation design (§13.2), the testing kit needs an events bus whose publishes are observable from the test code: ```ts import { createInMemoryEventsBus } from "@suaveplan/api-events-in-memory"; const bus = createInMemoryEventsBus(); // app code under test bus.publish("billing.invoice.created", { invoiceId: "inv_1", amount: 100 }); // test expect(bus.published("billing.invoice.created")).toHaveLength(1); ``` The simplest correct implementation wraps the production bus and adds a recording layer around `publish` / `publishAsync`. Subscribers fire as usual; ordering and FIFO invariants from the real bus are preserved. ## Install ```sh bun add -d @suaveplan/api-events-in-memory ``` ## Surface - `./` — `createInMemoryEventsBus`, `createInMemoryEventBus` (alias), `InMemoryEventsBus`, `History`, error codes, options. - `./bus` (a.k.a. `./adapter`) — factory + types only. - `./testing` — `createInMemoryEventsBusHarness` with a `waitFor` helper for async assertions. - `./error-codes` — `EVENTS_IN_MEMORY_CODES` + `EventsInMemoryError`. - `./options` — Zod schema + `resolveInMemoryEventsBusOptions`. - `./history` — standalone history ring (used by the bus internally). ## Quick reference ```ts import { createInMemoryEventsBus } from "@suaveplan/api-events-in-memory"; import { createInMemoryEventsBusHarness } from "@suaveplan/api-events-in-memory/testing"; const bus = createInMemoryEventsBus({ maxHistoryPerTopic: 100 }); bus.on("user.signup", (payload) => doStuff(payload)); await bus.publishAsync("user.signup", { userId: "u1" }); expect(bus.published("user.signup")).toEqual([{ userId: "u1" }]); const harness = createInMemoryEventsBusHarness(); await harness.waitFor((b) => b.published("welcome.email").length === 1); harness.dispose(); ``` ## Options | Option | Default | Notes | | ---------------------- | ------- | ------------------------------------------------------------------ | | `maxHistoryPerTopic` | `1000` | Strict-throw cap; `publish` raises `HISTORY_OVERFLOW` past the cap | Invalid options raise `EVENTS_IN_MEMORY.INVALID_OPTIONS` with the underlying `z.ZodError` on `cause`. ## Error codes | Code | Raised when | | ----------------------------------------- | --------------------------------------------------- | | `EVENTS_IN_MEMORY.HISTORY_OVERFLOW` | `publish` would exceed `maxHistoryPerTopic` | | `EVENTS_IN_MEMORY.INVALID_OPTIONS` | factory options fail Zod validation | ## Out of scope - Persistence across process restarts — by design, in-memory. - Multi-host fan-out — see future `api-events-redis`. - Bounded-queue backpressure — `@suaveplan/events` already provides this and the in-memory adapter inherits it through delegation. ## License MIT — Suaveplan Team.