feat(core-events): scaffold events optional core
Scaffolded via pnpm turbo gen core-package events (generator-first, ADR-022 pre-shipped zod trace landed in docs/library-decisions/). Generator wired transpilePackages + E1/J eslint rule block. Two story-00-precedent additions so the coverage gates pass: the @vitest/coverage-v8 devDep (L0 sweep) and the honest symbols.ts exclude (mirroring core-shared/vitest.config.ts) plus its missing ALLOWED_GLOBS mirror in scripts/coverage/diff.mjs (L1 gate). No consumers wired — compile-green floor for the walking-skeleton PRD (ADR-027). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016j8z4VHjedXDTjEDNg7qHK
This commit is contained in:
42
packages/core-events/src/in-memory-event-bus.ts
Normal file
42
packages/core-events/src/in-memory-event-bus.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user