Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
11 KiB
11 KiB
@suaveplan/events - Typed event-bus substrate: pub/sub with deterministic FIFO, interceptor API, bounded-queue backpressure, idempotent listeners, Zod-validated envelopes, passive observability adapter.
Summary
Typed event-bus substrate for Suaveplan. Pub/sub with deterministic FIFO delivery, interceptor API, bounded-queue backpressure, idempotent listeners, Zod-validated envelopes, and a passive observability adapter.
Documentation tree
- bus — (no submodules)
- event-bus — (no submodules)
- clock — (no submodules)
- default-clock — (no submodules)
- envelope — (no submodules)
- envelope — (no submodules)
- codes —
EVENTS_CODESis the frozen registry of every failure code@suaveplan/eventscan raise. All codes share the `EVENTS.… - events-error —
EventsErroris the single concrete error class thrown or captured by@suaveplan/events. It extendsSuaveplanError… - id — (no submodules)
- id-generator — (no submodules)
- idempotent — (no submodules)
- idempotent — (no submodules)
- interceptor — (no submodules)
- compose — (no submodules)
- observability — (no submodules)
- with-observability — (no submodules)
- queue — (no submodules)
- bounded-queue — (no submodules)
- events-error —
EventsErroris the single concrete error class thrown or captured by@suaveplan/events. It extendsSuaveplanError… - id — (no submodules)- id-generator — (no submodules)- idempotent — (no submodules)- idempotent — (no submodules)- interceptor — (no submodules)- compose — (no submodules)- observability — (no submodules)- with-observability — (no submodules)- queue — (no submodules)- bounded-queue — (no submodules)- event-bus — (no submodules)- clock — (no submodules)- default-clock — (no submodules)- envelope — (no submodules)- envelope — (no submodules)- codes —
EVENTS_CODESis the frozen registry of every failure code@suaveplan/eventscan raise. All codes share the `EVENTS.… - events-error —
EventsErroris the single concrete error class thrown or captured by@suaveplan/events. It extendsSuaveplanError… - id — (no submodules)- id-generator — (no submodules)- idempotent — (no submodules)- idempotent — (no submodules)- interceptor — (no submodules)- compose — (no submodules)- observability — (no submodules)- with-observability — (no submodules)- queue — (no submodules)- bounded-queue — (no submodules)- event-bus — (no submodules)- clock — (no submodules)- default-clock — (no submodules)- envelope — (no submodules)- envelope — (no submodules)- codes —
EVENTS_CODESis the frozen registry of every failure code@suaveplan/eventscan raise. All codes share the `EVENTS.… - events-error —
EventsErroris the single concrete error class thrown or captured by@suaveplan/events. It extendsSuaveplanError… - id — (no submodules)- id-generator — (no submodules)- idempotent — (no submodules)- idempotent — (no submodules)- interceptor — (no submodules)- compose — (no submodules)- observability — (no submodules)- with-observability — (no submodules)- queue — (no submodules)- bounded-queue — (no submodules)- event-bus — (no submodules)- clock — (no submodules) - default-clock — (no submodules)- envelope — (no submodules) - envelope — (no submodules)- codes —
EVENTS_CODESis the frozen registry of every failure code@suaveplan/eventscan raise. All codes share the `EVENTS.… - events-error —
EventsErroris the single concrete error class thrown or captured by@suaveplan/events. It extendsSuaveplanError… - id — (no submodules) - id-generator — (no submodules)- idempotent — (no submodules) - idempotent — (no submodules)- interceptor — (no submodules) - compose — (no submodules)- observability — (no submodules) - with-observability — (no submodules)- queue — (no submodules) - bounded-queue — (no submodules)
Install
bun add @suaveplan/events
Why
Downstream packages (events-metrics, events-otel, events-schema, events-transport) attach through bus.use(interceptor) or withObservability(bus, adapter) — the core never couples to any of them.
Usage
import { EventBus } from "@suaveplan/events";
type Map = {
"user.signup": { id: string; email: string };
"order.paid": { orderId: string; amount: number };
};
const bus = new EventBus<Map>();
bus.on("user.signup", ({ email }) => sendWelcome(email));
bus.emit("user.signup", { id: "u1", email: "alice@example.com" });
Interceptor
bus.use(async (envelope, next) => {
const start = performance.now();
const result = await next();
histogram.record(performance.now() - start, { type: envelope.type });
return result;
});
Backpressure
import { BoundedQueue } from "@suaveplan/events";
const q = new BoundedQueue<Order>({ capacity: 1000, policy: "block" });
await q.enqueue(order, signal);
Idempotency
import { idempotent } from "@suaveplan/events";
bus.on(
"order.paid",
idempotent(handlePayment, { keyOf: (o) => o.orderId })
);
Error codes
EVENTS.LISTENER.THREW
EVENTS.INTERCEPTOR.THREW
EVENTS.QUEUE.OVERFLOW
EVENTS.QUEUE.ABORTED
EVENTS.QUEUE.INVALID_CAPACITY
EVENTS.EMIT.TIMED_OUT
EVENTS.EMIT.ABORTED
All surface as EventsError extends SuaveplanError<EventsCode> from @suaveplan/error.
Foundation rules honoured
- Runtime deps:
@suaveplan/error,tslib,zod(all catalog-pinned) - Zero Node / browser built-ins in
src/(guarded) Date.now/crypto.randomUUIDlive only inclock/default-clock.tsandid/id-generator.ts(guarded)sideEffects: false, per-module subpath exports- 100% statement / branch / function / line coverage
Testing
bunx turbo lint typecheck test --filter=@suaveplan/events
bunx turbo test:coverage --filter=@suaveplan/events