Files
skills/docs/api-stack/api/api-host/src/pipeline-events-bus/noop-bus.md
2026-05-29 08:20:56 +01:00

3.0 KiB

noop-bus — zero-cost default PipelineEventsBus

Purpose

NoopPipelineEventsBus is the default value the host installs on HostAdapters.pipelineEvents when no operator-supplied bus is configured. Production deployments that don't care about per-stage observability incur zero overhead — emit is a no-op that allocates nothing, and subscribe returns a cached unsubscribe so callers do not allocate per registration.

The pipeline emits 22 events per successful request (entered + completed for each of the 11 §6 stages); on a noop bus that is 22 method calls that immediately return. With listeners present it becomes 22 synchronous listener invocations. The split avoids forcing every host to pay observability cost when nobody is listening.

Features

  • Implements PipelineEventsBus from @suaveplan/api-types/pipeline-events.
  • Zero per-call allocation — emit neither reads the event nor allocates.
  • Module-scoped NOOP_UNSUBSCRIBE shared across every subscribe call.
  • Stateless — the exported noopPipelineEventsBus singleton is safe to share across hosts.

Usage: Basic

import { NoopPipelineEventsBus } from "@suaveplan/api-host";

const bus = new NoopPipelineEventsBus();
bus.emit({ requestId: "x", stage: "auth", outcome: "entered", at: Date.now() });
// — no-op, no listeners, nothing observable.

Usage: Advanced

Use the shared singleton when constructing host configs to avoid per-host allocation. This is what createHost does internally when adapters.pipelineEvents is omitted:

import { noopPipelineEventsBus } from "@suaveplan/api-host";

const host = await createHost({
    adapters: {
        // ...
        pipelineEvents: noopPipelineEventsBus,
    },
    plugins: [],
});

Production builds that wire an OTel exporter (@suaveplan/api-host-otel-pipeline, follow-up change) replace this with a bridging bus; the host code path is identical.

API Reference

export class NoopPipelineEventsBus implements PipelineEventsBus {
    emit(event: PipelineStageEvent): void; // no-op
    subscribe(listener: PipelineEventListener): PipelineEventUnsubscribe; // cached no-op unsubscribe
}

export const noopPipelineEventsBus: NoopPipelineEventsBus;

Implementation Notes

The unused parameter is bound with a void reference so static analyzers do not flag it as dead code AND so the structural type compatibility check passes verbatim against PipelineEventsBus.emit. The class form (rather than a frozen object literal) is required so consumers can instanceof NoopPipelineEventsBus when they need to bail out of observability bridging — the foundation closure smoke does this to confirm the default is in place when no explicit bus is wired.

NOOP_UNSUBSCRIBE is module-scoped (not a method-local closure) because returning the same function from every subscribe call lets V8 keep a single shared hidden class and avoids per-call closure allocation. The benchmark in noop-bus.test.ts measures both paths and asserts the zero-allocation invariant.