Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
# `request-pipeline-outcomes` — driver config + success/failure result builders
## Purpose
This module ties the bare emitters and validators together for the orchestrator. It exposes `DriverConfig` (the frozen per-pipeline settings bundle), `OutcomeArgs` (the common argument shape carried through every gate-fail branch), `runRequestValidation` (a thin adapter that parses the URL query, short-circuits on streaming / opt-out routes, and emits the dedicated `api.validation.failures_total{where=request}` counter), and the `successResult` / `failResult` builders that translate an outcome into a fully-shaped `PipelineResult`.
These helpers were extracted from `request-pipeline.ts` during the file-size refactor. Behaviour is byte-for-byte identical to the pre-split implementation; the only change is that the shared argument bundle is now reified as a type so each branch can use `...spread` instead of re-listing eight parameters.
## Features
- `DriverConfig` freezes the constructor inputs once and is threaded through every helper, so step-level functions see the same `boundary`, `now`, `instruments`, `defaultTenant`, and `responseValidation` mode.
- `runRequestValidation` is the only piece that knows about the request URL's query — the orchestrator does not parse it directly anymore.
- `successResult` always increments `api.requests_total{outcome=success}` and the duration histogram before returning.
- `failResult` increments the same counter/histogram with `outcome=failure`; the audit envelope is only emitted when a route matched (the 404 path skips audit per spec).
- `OutcomeArgs` is exported so the orchestrator can declare a single `carry` variable and reuse it across every fail branch.
## Usage: Basic
```ts
import {
type DriverConfig,
failResult,
runRequestValidation,
successResult,
} from "@suaveplan/api-host/request-pipeline-outcomes";
const validation = await runRequestValidation(config, { request, route, rootSpan });
if (validation.kind === "fail") {
return failResult(config, { ...carry, failure: validation.failure });
}
return successResult(config, { ...carry, response: handlerResponse });
```
## Usage: Advanced
`DriverConfig` decouples the orchestrator from the `RequestPipeline` class — tests can construct a config object directly and call `runPipeline` to verify behaviour without instantiating the full class:
```ts
const config: DriverConfig = {
options,
instruments,
boundary: new ErrorBoundary({ instruments, logger }),
now: () => 1000,
idempotencyTtlMs: 60_000,
responseValidation: "enforce",
defaultTenant: null,
};
```
`OutcomeArgs.route` is nullable so the 404 path can reuse the same `failResult` shape. Tests that assert "no audit envelope on 404" rely on this branch — supplying a non-null route would silently emit an audit entry.
## API Reference
```ts
interface DriverConfig {
options: RequestPipelineOptions;
instruments: HostInstruments;
boundary: ErrorBoundary;
now: () => number;
idempotencyTtlMs: number;
responseValidation: "enforce" | "warn";
defaultTenant: TenantContext | null;
}
interface OutcomeArgs {
request: Request;
requestId: string;
rootSpan: OtelSpanLike & BoundarySpan;
startedAt: number;
route: PipelineRoute | null;
principal: Principal | null;
tenantCtx: TenantContext | null;
}
function runRequestValidation(
config: DriverConfig,
args: { request: Request; route: PipelineRoute; rootSpan: OtelSpanLike & BoundarySpan }
): Promise<RequestValidationOk | RequestValidationFail>;
function successResult(config: DriverConfig, args: OutcomeArgs & { response: Response }): Promise<PipelineResult>;
function failResult(config: DriverConfig, args: OutcomeArgs & { failure: BoundaryFailure }): Promise<PipelineResult>;
```
## Implementation Notes
`runRequestValidation` is the ONLY function that derives `parsedQuery` from the request URL. Centralising it ensures all three early-validation outcomes (streaming-skip, opt-out, schema-pass) return the same query record shape — without that, the handler ctx could see `{}` on one path and the parsed record on another.
`successResult` calls `withRequestHeaders` exactly once, deliberately. The original implementation also called it once and the post-extracted form preserves that — re-cloning the response would burn an unnecessary `Headers` allocation per request.
`failResult` always emits the `api.requests_total{outcome=failure}` counter, including on the 404 path. That contract is depended on by the `api.errors_by_step` dashboard the host's STATUS docs reference; removing it (e.g. as an optimisation for the no-route case) would silently break the metric.