4.7 KiB
createInMemoryEventsBus
(no submodules)
Purpose
createInMemoryEventsBus is the factory entry point of
@suaveplan/api-events-in-memory. It returns a fresh
{@link InMemoryEventsBus} whose publish calls are recorded in a
per-topic ring of payloads and whose subscriber delivery is delegated
to a private @suaveplan/events EventBus. Tests can both assert
"this event was published with this payload" (via published(topic))
and assert "this subscriber observed the side-effect" (via the
subscriber callback) without any mocks or test doubles — the real
production bus runs underneath.
Features
- Recording layer wraps every
publish/publishAsync/emitcall; the payload is appended to the topic's history BEFORE dispatch so history is still complete even if a subscriber throws. - Strict-throw history-overflow policy via the cap-bounded
{@link History}.
published(topic)'s "every publish sincereset()" guarantee survives long-running test suites. - Subscriber surface (
on/once/off) mirrors@suaveplan/events'EventBus; the more powerfulEventBus.emitAsyncsemantics are exposed throughpublishAsync(sequential await over registered listeners; same delivery order; same error-capture model). emit(topic, payload)alias satisfies the structuralCapabilityEventBusLikecontract from@suaveplan/api-types/capabilitiesso the bus can be handed to API plugins as theireventscapability without an additional adapter.dispose()clears history AND tears down every subscriber so test isolation is straightforward — call once per test, no leaks.createInMemoryEventBus(no "s") is a stable alias matching the prompt's./adaptersubpath; both spellings will continue to exist.
Usage: Basic
import { createInMemoryEventsBus } from "@suaveplan/api-events-in-memory/bus";
const bus = createInMemoryEventsBus();
const seen: unknown[] = [];
bus.on("billing.invoice.created", (payload) => seen.push(payload));
bus.publish("billing.invoice.created", { invoiceId: "inv_1", amount: 100 });
console.log(bus.published("billing.invoice.created"));
// [{ invoiceId: "inv_1", amount: 100 }]
console.log(seen);
// [{ invoiceId: "inv_1", amount: 100 }]
bus.reset();
console.log(bus.published("billing.invoice.created")); // []
Usage: Advanced
Pin the per-topic cap when the test publishes in a tight loop, then
recover by reset() between batches:
import { createInMemoryEventsBus } from "@suaveplan/api-events-in-memory/bus";
import {
EVENTS_IN_MEMORY_CODES,
EventsInMemoryError,
} from "@suaveplan/api-events-in-memory/error-codes";
const bus = createInMemoryEventsBus({ maxHistoryPerTopic: 3 });
async function fanOut(count: number) {
for (let i = 0; i < count; i += 1) {
await bus.publishAsync("metrics.tick", { i });
}
}
try {
await fanOut(5);
} catch (error) {
if (
error instanceof EventsInMemoryError &&
error.code === EVENTS_IN_MEMORY_CODES.HISTORY_OVERFLOW
) {
bus.reset();
await fanOut(2);
} else {
throw error;
}
}
console.log(bus.published("metrics.tick").length); // 2
bus.dispose();
API Reference
createInMemoryEventsBus(options?: InMemoryEventsBusOptions): InMemoryEventsBus— factory.createInMemoryEventBus— alias, same return value.InMemoryEventsBus.publish(topic, payload): void— sync publish; appends history first.InMemoryEventsBus.publishAsync(topic, payload): Promise<void>— async publish.InMemoryEventsBus.emit(topic, payload): Promise<void>—CapabilityEventBusLikealias.InMemoryEventsBus.on(topic, listener): Unsubscribe— register a subscriber.InMemoryEventsBus.once(topic, listener): Unsubscribe— one-shot subscriber.InMemoryEventsBus.off(topic, listener): void— remove a subscriber.InMemoryEventsBus.published(topic): readonly unknown[]— snapshot of history.InMemoryEventsBus.topics(): readonly string[]— sorted topic names.InMemoryEventsBus.reset(): void— clear history; keep subscribers.InMemoryEventsBus.dispose(): void— clear history AND subscribers.
Implementation Notes
The underlying EventBus is parameterised with the open EventMap
shape (Record<string, unknown>) so the in-memory adapter can carry
any topic name without forcing the test to declare a typed map up
front. Recording happens BEFORE dispatch because the contract that
matters for tests is "this publish was attempted" — history that
drops on subscriber failure would silently hide test bugs. emit and
publishAsync share the same body; emit exists only so the bus
satisfies the structural CapabilityEventBusLike interface from
@suaveplan/api-types.