Skip to content Version [0.2.0]
Added
- OpenTelemetry tracing integration.
@opentelemetry/api as a regular dependency with
pipeline-level distributed tracing. New tracing() middleware factory starts an
ergo.pipeline span per request, ends it after send(), and propagates W3C trace context.
Logger automatically includes traceId and spanId when the tracing middleware is active.
Per-stage child spans available via perStage: true option. Zero overhead when the tracing
middleware is not included in the pipeline. (#89)
- Pipeline debug tracing. Pass
{debug: true} as the second argument to handler() to
enable pipeline tracing. When enabled, responseAcc._trace is initialized with
{steps: [], breakAt: undefined}. The compose-with serial and concurrent runners record
each middleware label in steps and set breakAt to the label that triggered a pipeline
break. On error responses (>= 400), _trace appears as an RFC 9457 extension member. (#86)
- compose() accumulator type inference.
compose() now infers the domain accumulator
type from [fn, setPath] tuples. For pipelines with 1–12 tuples, TypeScript infers which
keys exist on the accumulator and their types. Accessing a key from middleware not in the
pipeline is a compile-time error. Pipelines with >12 tuples or only plain functions fall
back to Promise<object>. compose.all() has the same overloaded inference. (#87)
- Middleware result type exports. New consumer-facing type interfaces for middleware
accumulator values:
UrlResult, BodyResult, CookieJar, LogEntry, AcceptsResult,
PreferResult, RateLimitResult, ResponseAccumulator, and MiddlewareTuple. Import
from @centralping/ergo/types. (#87)
- Hand-written type override system.
types-override/ directory holds hand-written
.d.ts files that replace auto-generated declarations after tsc runs. Used for
compose-with.d.ts where JSDoc cannot express the required variadic generic types. (#87)
- Pagination helpers. New
paginate namespace export with parseOffsetParams,
parseCursorParams, offsetResponse, and cursorResponse. Parses query parameters with
bounded defaults, generates RFC 8288 Link headers and X-Total-Count, and returns
pipeline-compatible response objects. Available via import {paginate} from '@centralping/ergo'
or import {parseOffsetParams} from '@centralping/ergo/lib/paginate'. (#85)
- CI type-checking gate validates generated
.d.ts files with skipLibCheck: false and
strict: true via npm run check-types. Prevents shipping broken type declarations. (#83)
- TypeScript usage example alongside the JavaScript Quick Start in
README.md. (#74)
Fixed
formatLinkHeader() now rejects href values containing CR, LF, or NUL characters with a
TypeError, preventing ERR_INVALID_CHAR crashes when malformed hrefs reach
res.setHeader(). (#103)
instance field on all error paths. The RFC 9457 instance field
(urn:uuid:{requestId}) is now populated from the x-request-id response header on all
error paths — pipeline breaks (return-value), caught errors, and endWithProblem (412).
Previously, instance was only populated in the catch block, missing the v2 return-value
error model entirely. (#95)
validate() now emits a one-time process.emitWarning diagnostic with code
ERGO_VALIDATE_UNKNOWN_KEY when the schema map contains unrecognized keys (e.g.
validate({schemas: {body: ...}}) instead of validate({body: ...})). Previously,
unrecognized keys were silently ignored and validation became a no-op. (#84)
- BREAKING:
validate() now returns a 500 response when a body schema is configured but
acc.body is absent, indicating body() was not placed before validate() in the pipeline.
A one-time process.emitWarning diagnostic is emitted with code ERGO_VALIDATE_NO_BODY.
Previously, body validation was silently skipped, allowing invalid request data to reach
the execute handler unchecked. Correctly ordered pipelines are unaffected. (#93)
- BREAKING:
idempotency() now distinguishes missing from malformed Idempotency-Key
headers. A malformed header (present but not a valid RFC 8941 sf-string) always returns
400 with format guidance, regardless of the required option. Previously, a malformed
header with required: false silently passed through as if the header were absent. (#90)
- BREAKING (types only): All middleware factory
.d.ts declarations now emit inferred
function signatures instead of Function. compose()/composeWith() return
(...args) => Promise<object> instead of Function. csrf() and logger() emit
full object types instead of object. No runtime behavior changes. (#75)
.d.ts declarations now compile with skipLibCheck: false. Middleware parameter types
for cookie(), cors(), url(), and lib/cors are specific instead of {}. (#83)