Code-quality review nits: IEventBus.subscribe docstring said "debug tag" but InMemoryEventBus actually ignores the param entirely. Also add a comment to InMemoryEventBus.publish noting that under failFast only the first rejection rethrows; other failures are intentionally dropped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
43 lines
1.5 KiB
TypeScript
43 lines
1.5 KiB
TypeScript
import type { z } from "zod";
|
|
import type { EventDescriptor } from "./event-descriptor";
|
|
import type { EventHandler, IEventBus } from "./event-bus.interface";
|
|
|
|
export type InMemoryEventBusOptions = {
|
|
/** When true, rethrow the first handler error (default: false — errors swallowed). */
|
|
failFast?: boolean;
|
|
};
|
|
|
|
export class InMemoryEventBus implements IEventBus {
|
|
private readonly handlers = new Map<string, EventHandler<unknown>[]>();
|
|
|
|
constructor(private readonly options: InMemoryEventBusOptions = {}) {}
|
|
|
|
async publish<T>(
|
|
descriptor: EventDescriptor<string, z.ZodType<T>>,
|
|
payload: T,
|
|
): Promise<void> {
|
|
descriptor.schema.parse(payload);
|
|
const subscribers = this.handlers.get(descriptor.name) ?? [];
|
|
if (subscribers.length === 0) return;
|
|
const settled = await Promise.allSettled(
|
|
subscribers.map((h) => h(payload)),
|
|
);
|
|
if (this.options.failFast) {
|
|
const failure = settled.find((s) => s.status === "rejected");
|
|
// Only the first rejection is rethrown. Other failures are intentionally
|
|
// dropped — `failFast` is a test-affordance, not a fault-tolerance design.
|
|
if (failure && failure.status === "rejected") throw failure.reason;
|
|
}
|
|
}
|
|
|
|
subscribe<T>(
|
|
descriptor: EventDescriptor<string, z.ZodType<T>>,
|
|
_consumerFeature: string,
|
|
handler: EventHandler<T>,
|
|
): void {
|
|
const arr = this.handlers.get(descriptor.name) ?? [];
|
|
arr.push(handler as EventHandler<unknown>);
|
|
this.handlers.set(descriptor.name, arr);
|
|
}
|
|
}
|