Files
suaveplan/packages/api-stack/api/api-host/src/pipeline-events-bus/pipeline-events-constants.md
2026-05-27 23:29:53 +01:00

2.7 KiB

pipeline-events-constants — runtime constants for PipelineEventsBus

Purpose

@suaveplan/api-types is types-only — adding a runtime export there breaks the byte-size invariant CI enforces. The PipelineEventsBus contract still needs runtime constants for the canonical stage order tuple (so consumers can iterate / assert without re-listing the names) and for the per-stage event-name strings (so OTel bridges can name events without re-deriving them). Those constants live here, in @suaveplan/api-host, where runtime exports are expected.

Features

  • PIPELINE_STAGE_ORDER frozen tuple — canonical §6 execution order matching the PipelineStage union.
  • PIPELINE_EVENT_NAME literal — log-grep friendly namespace prefix (api-host.pipeline.stage).
  • PIPELINE_STAGE_EVENT_NAMES per-stage map — concatenated ${PIPELINE_EVENT_NAME}.<stage> strings for OTel span-event naming.

Usage: Basic

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

for (const stage of PIPELINE_STAGE_ORDER) {
    console.log(stage); // request-id, route-match, tenant, auth, ...
}

Usage: Advanced

Build a per-stage histogram dashboard by indexing the per-stage event-name map:

import { PIPELINE_STAGE_EVENT_NAMES } from "@suaveplan/api-host";
import type { PipelineStage } from "@suaveplan/api-types/pipeline-events";

const histograms = new Map<PipelineStage, number[]>();
for (const stage of Object.keys(PIPELINE_STAGE_EVENT_NAMES) as PipelineStage[]) {
    histograms.set(stage, []);
}

bus.subscribe((event) => {
    if (event.outcome === "completed" || event.outcome === "rejected") {
        histograms.get(event.stage)?.push(event.durationMs ?? 0);
    }
});

API Reference

export const PIPELINE_STAGE_ORDER: readonly PipelineStage[];
export const PIPELINE_EVENT_NAME: "api-host.pipeline.stage";
export const PIPELINE_STAGE_EVENT_NAMES: Readonly<Record<PipelineStage, string>>;

Implementation Notes

The constants are typed as readonly PipelineStage[] (tuple) and Readonly<Record<PipelineStage, string>> (map). The map's value type is string rather than the specific literal because TypeScript widens nested string literals through Readonly<Record<...>>. Consumers that need the literal narrowing import the PIPELINE_STAGE_EVENT_NAMES constant directly — TypeScript preserves the literal types on the const expression.

The tuple MUST stay in lock-step with the PipelineStage union in @suaveplan/api-types/pipeline-events. A satisfies check at the type-test level catches any drift between the two; the conformance harness's order invariant also catches drift at runtime by comparing the actual emit order against this tuple.