Accumulator Reference
The two-accumulator pipeline model passes two
objects through every middleware in the chain: the domain accumulator
(acc) for inter-middleware data, and the response accumulator for
HTTP response properties. This page is the consolidated reference for
both.
Domain Accumulator
Section titled “Domain Accumulator”Each middleware registers its result at a fixed path on the domain
accumulator via {fn, setPath} config objects. The table below maps every
pipeline-builder key to its accumulator path and typed interface.
| Config Key | setPath (acc.*) | Type Interface | Pipeline Stage |
|---|---|---|---|
tracing | trace | TracingResult | Negotiation |
logger | log | LogEntry | Negotiation |
rateLimit | rateLimit | — | Negotiation |
accepts | accepts | AcceptsResult | Negotiation |
preconditionRequired | precondition | — | Negotiation |
cookie | cookies | CookieJar | Negotiation |
url | url | UrlResult | Negotiation |
paginate | paginate | PaginateResult | Negotiation |
jsonApiQuery | jsonApiQuery | — | Negotiation |
prefer | prefer | PreferResult | Negotiation |
securityHeaders | security | — | Negotiation |
cacheControl | cache | — | Negotiation |
csrf | csrf | — | Authorization |
authorization | auth | AuthorizationResult | Authorization |
body | body | BodyResult | Validation |
idempotency | idempotency | IdempotencyResult | Validation |
validate | validation | — | Validation |
acc.url
Section titled “acc.url”Stored at acc.url by the url() middleware. Parsed URL components using a fast
indexOf + slice parser.
interface UrlResult { query: Record<string, string | string[]>; pathname: string | undefined; search: string | undefined;}| Property | Type | Description |
|---|---|---|
pathname | string | undefined | URL path before the query string |
search | string | undefined | Raw query string including leading ?; undefined when absent |
query | Record<string, string | string[]> | Parsed query parameters (null-prototype object); multi-value keys become arrays |
acc.paginate
Section titled “acc.paginate”Stored at acc.paginate by the paginate() middleware. Parsed pagination parameters — a
discriminated union based on the active strategy.
type PaginateResult = | { strategy: 'offset'; page: number; perPage: number; offset: number; limit: number } | { strategy: 'cursor'; cursor: string | undefined; limit: number };Offset strategy:
| Property | Type | Description |
|---|---|---|
strategy | 'offset' | Active strategy identifier |
page | number | Current page number (clamped to ≥ 1) |
perPage | number | Items per page (clamped to ≤ maxPerPage) |
offset | number | Computed: (page - 1) * perPage |
limit | number | Same as perPage |
Cursor strategy:
| Property | Type | Description |
|---|---|---|
strategy | 'cursor' | Active strategy identifier |
cursor | string | undefined | Opaque cursor token from query; undefined on first page |
limit | number | Items to fetch (clamped to ≤ maxLimit) |
acc.body
Section titled “acc.body”Stored at acc.body by the body() middleware. Parsed request body with metadata.
interface BodyResult { type: string; charset: string; encoding: string; length: number | undefined; received: number; boundary: string | undefined; raw: string; parsed?: unknown;}| Property | Type | Description |
|---|---|---|
type | string | Content-Type MIME type |
charset | string | Character encoding (e.g. 'utf-8') |
encoding | string | Content-Encoding (e.g. 'identity', 'gzip') |
length | number | undefined | Content-Length header value; undefined for chunked |
received | number | Actual bytes received |
boundary | string | undefined | Multipart boundary; undefined for non-multipart |
raw | string | Raw body string before parsing |
parsed | unknown | Parsed body (JSON object, form data, etc.) |
acc.cookies
Section titled “acc.cookies”Stored at acc.cookies by the cookie() middleware. Cookie jar with incoming cookies as
own properties and methods for managing outgoing cookies.
interface CookieJar { set(name: string, value: string, options?: Record<string, unknown>): void; get(name: string): unknown; clear(name: string): void; toHeader(): string[]; readonly size: number; readonly isJar: true; [name: string]: unknown;}Incoming cookies from the Cookie request header are available as own
properties on the jar (e.g. acc.cookies.sessionId). Outgoing cookies
are managed via set(), get(), clear(), and serialized to
Set-Cookie headers by toHeader().
acc.log
Section titled “acc.log”Stored at acc.log by the logger() middleware. Structured request metadata captured at
pipeline entry.
interface LogEntry { requestId: string; timestamp: number; ip: string; method: string; url: string; httpVersion: string; host: Readonly<{ hostname: string; arch: string; platform: string; pid: number; }>; request: { headers: Record<string, string | string[] | undefined>; encrypted: boolean; remoteAddress: string; remotePort: number; }; traceId?: string; spanId?: string;}acc.accepts
Section titled “acc.accepts”Stored at acc.accepts by the accepts() middleware. Content negotiation results.
interface AcceptsResult { type: string | false; language: string | false; charset: string | false; encoding: string | false;}| Property | Type | Description |
|---|---|---|
type | string | false | Best matching content type, or false if unacceptable |
language | string | false | Best matching language |
charset | string | false | Best matching charset |
encoding | string | false | Best matching encoding |
acc.prefer
Section titled “acc.prefer”Stored at acc.prefer by the prefer() middleware. Parsed RFC 7240 Prefer header as a
flat map.
interface PreferResult { [preference: string]: string | true;}Preference names map to their value string, or true for bare tokens.
Example: { return: 'minimal', 'respond-async': true }.
acc.auth
Section titled “acc.auth”Stored at acc.auth by the authorization() middleware. The authenticated identity
returned by the matching strategy’s authorizer function.
type AuthorizationResult = Record<string, unknown>;The shape is opaque — it is entirely determined by the
user-provided authorizer function’s info return value. The type
system represents this as Record<string, unknown>; consumers narrow
via application-level type assertions or generics.
Common patterns:
// Bearer — authorizer returns user objectacc.auth // → { user: { id: "42", role: "admin" } }
// Basic — authorizer returns credentials metadataacc.auth // → { username: "jane", permissions: ["read", "write"] }
// API Key — authorizer returns service identityacc.auth // → { service: "billing", scopes: ["invoices:read"] }acc.trace
Section titled “acc.trace”Stored at acc.trace by the tracing() middleware. OpenTelemetry span and context for
the current request.
interface TracingResult { span: import('@opentelemetry/api').Span; tracer?: import('@opentelemetry/api').Tracer; activeContext?: import('@opentelemetry/api').Context; parentContext: import('@opentelemetry/api').Context; traceId: string; spanId: string;}| Property | Type | Description |
|---|---|---|
span | Span | Active span for the request pipeline |
tracer | Tracer | undefined | Only populated when perStage: true |
activeContext | Context | undefined | Only populated when perStage: true |
parentContext | Context | Parent context for child span creation |
traceId | string | W3C trace ID (hex string) |
spanId | string | Span ID (hex string) |
acc.idempotency
Section titled “acc.idempotency”Stored at acc.idempotency by the idempotency() middleware. Idempotency-Key processing
result — a discriminated union with three variants.
type IdempotencyResult = | Record<string, never> | { key: string; fingerprint: string; complete: (response: unknown) => void; discard: () => void } | { replayed: true };| Variant | When | Shape |
|---|---|---|
Empty object {} | No Idempotency-Key header present (and not required) | Record<string, never> |
| Active key | First request with this key — store the response when done | { key, fingerprint, complete(), discard() } |
| Replayed | Subsequent request with a completed key — response was replayed | { replayed: true } |
ergo-router Seeds
Section titled “ergo-router Seeds”When using @centralping/ergo-router, the domain accumulator is seeded
with route match data before the pipeline runs. These values are
available to all middleware and the execute handler.
acc.route.params
Section titled “acc.route.params”Route parameters extracted by the router’s path matching (powered by
find-my-way). Available immediately — not produced by a middleware
config object.
// Route: "/users/:id/posts/:postId"// Request: GET /users/42/posts/7
acc.route.params // → { id: "42", postId: "7" }Parameter values are always strings. Numeric conversion is the consumer’s responsibility.
Response Accumulator
Section titled “Response Accumulator”The response accumulator collects HTTP response properties set by
middleware. When any middleware sets statusCode, the pipeline breaks
immediately. After pipeline completion (or break), send() reads the
response accumulator to format the HTTP response.
interface ResponseAccumulator { statusCode?: number; headers?: [string, string][]; body?: unknown; detail?: string; retryAfter?: number; instance?: string; location?: string; lastModified?: Date; type?: string; [key: string]: unknown;}| Property | Type | Description |
|---|---|---|
statusCode | number | HTTP status code — setting this breaks the pipeline |
headers | [string, string][] | Response headers as [name, value] tuples (appended, not overwritten) |
body | unknown | Response body (serialized by send()) |
detail | string | RFC 9457 Problem Details detail field |
retryAfter | number | Retry-After header value in seconds |
instance | string | RFC 9457 instance URI |
location | string | Location header value (redirects, 201 Created) |
lastModified | Date | Last-Modified header value |
type | string | RFC 9457 type URI |
Further Reading
Section titled “Further Reading”- Architecture — the two-accumulator pipeline model
- Fast Fail Pipeline — stage-by-stage ordering
- send middleware — how the response accumulator is consumed