@centralping/ergo
Version [0.8.0]
Added
validate()now validates option keys at factory time. (#320) Theoptionsparameter (second argument) is validated against the recognized keys (formats,allErrors,coerceTypes,ajv) using the sharedlib/validate-options.jsutility. Typos like{format: ['email']}now emit anERGO_VALIDATE_UNKNOWN_OPTIONwarning with a “did you mean?” suggestion, matching the behavior of all other middleware factories. TheValidateOptionsTypeScript interface is tightened to list all four accepted fields explicitly (index signature removed).
Changed
-
OTEL span attributes use stable HTTP semantic conventions. (#324) Replaced deprecated pre-v1.20 attribute names with the stable conventions declared in November 2023:
http.method→http.request.method,http.url→url.path+url.query,http.status_code→http.response.status_code. Theurl.queryattribute is set conditionally (only when the request URL contains a?). Named constants are defined in a newlib/otel-attributes.jsmodule to avoid a runtime dependency on@opentelemetry/semantic-conventions. -
Wire-format primitives delegated to
@centralping/ergo-wire. (#369) Link header formatting, pagination parse/serialize, idempotency key parse/format, and quoted-string sanitization now re-export from@centralping/ergo-wirefor symmetric client/server alignment. Server-only code (IdempotencyStore,generateFingerprint,offsetResponse,cursorResponse) remains in ergo. Existing@centralping/ergo/lib/*import paths are unchanged. -
csrf()validatessecretat construction time. (#313) The requiredsecretparameter is now validated at factory time (typeof+ length check). Missing or invalidsecretthrowsTypeErrorimmediately instead of deferring the error to the first request. This is the firsthttp/middleware factory with factory-time required-parameter validation.
Fixed
-
csrf()encodingoption now forwarded toverify(). (#308) Theencodingfactory option was forwarded toissue()but omitted fromverify(), causing unconditional CSRF verification failure when a non-default encoding (e.g.'hex') was configured.verify()now receives the same encoding used at issuance time. -
Body middleware now eagerly parses all content types within its error boundary. (#323) Compressed JSON, form-urlencoded, and multipart bodies previously used a self-replacing lazy getter on
result.parsedthat deferred parse execution outside the body middleware’stry/catchscope. When a compressed JSON body was malformed, the parse error propagated tohandler.js’s catch-all, producing a 500 Internal Server Error for what is semantically a 400 Bad Request. All paths now parse eagerly within the middleware — malformed compressed JSON correctly returns 400. -
Authorization middleware now uses explicit
{value: info}return wrapping. (#288) Previously,http/authorization.jsreturned the opaqueinfoobject directly on authorization success. If the user’s authorizer returned an object containingvalueorresponsekeys,extractReturn()incompose-with.jswould misinterpret the return as a compose protocol-form object — extractinginfo.valueas the domain result or merginginfo.responseinto the response accumulator. The fix wraps the return as{value: info}, consistent with other domain-producing middleware that handle user-controlled data (paginate.js,tracing.js,idempotency.js). No change to composed pipeline behavior —acc.authstill receives the fullinfoobject. -
createDispatcher()prototype poisoning vulnerability. (#254) The scheme-to-handler map inlib/authorization.jsused a plain{}reduce accumulator, inheritingObject.prototype. CraftedAuthorizationheaders with scheme names matching prototype properties (e.g.,Constructor,__proto__) would bypass the strategy-not-found guard and crash withTypeError— a denial-of-service vector. Replaced withObject.create(null)to align with the project-wide null-prototype policy enforced in all other user-input-keyed parsers. -
Response compression now recognizes RFC 6838 structured syntax suffixes (
+json,+xml). (#307)application/problem+json(ergo’s error format),application/vnd.api+json(JSON:API), and other structured suffix types are now correctly identified as compressible. Previously, only exactapplication/jsonandapplication/xmlsubtypes triggered compression. The\bword boundary also prevents false matches on types likeapplication/jsonp. -
Logger double-logging when response stream emits
errorfollowed byclose. (#312) Theerrorevent handler now callscleanup()before logging, deregistering sibling listeners (finish,close) to prevent the subsequentcloseevent from triggering a spurious “aborted” log entry. All three terminal event handlers (finish,abortviaclose,error) now follow the same pattern: deregister first, then log. Ensures exactly one structured log entry per request lifecycle outcome. -
Corrected Vary token typo in CORS preflight responses:
Access-Control-Request-Methods(plural) →Access-Control-Request-Method(singular). The previous value referenced a non-existent HTTP header, preventing correct cache-key variance for preflight method negotiation. (#259)
Removed
- Removed
utils/observablesmodule and./utils/observablesexport. (#333, #334, #336) The push-based generator coroutine module had zero internal or external consumers. The multipart body parser uses the pull-basedutils/iterables/buffer-splitinstead. Resolves three design findings: dead infrastructure (#333), chain/buffer-split protocol incompatibility (#334), and incorrect “Observable” terminology (#336).