Postboy Help

Middleware Reference

Reference page for the middleware pipeline of @artstesh/postboy (applies to v3.5.x): the middleware base class, the pipeline types, decisions, and cancellation. For the conceptual model see Middleware; for cancellation in depth see Middleware cancellation; for the upgrade from the 3.4 single-hook interface see Migrating middleware from 3.4.

Every fire/fireCallback/exec passes through the pipeline. There is no handle() hook anymore — middleware is the abstract class below.

PostboyMiddleware

import { PostboyMiddleware } from '@artstesh/postboy'; abstract class PostboyMiddleware { readonly name: string; // defaults to the class name canHandle(context: PipelineContext): boolean; // filter; default true before(context: PipelineContext): MiddlewareDecision; // return Interrupt to cancel after(context: PipelineContext, result?: unknown): void; dispose(): void; }

Member

Description

name

Readonly identifier used in cancellation diagnostics; defaults to the class name — set an explicit stable name for searchable logs

canHandle(context)

Filter consulted for both before and after; false skips the middleware entirely for the operation. Keep it fast and side-effect free

before(context)

Pre-hook; an Interrupt decision cancels the operation (see below)

after(context, result?)

Post-hook; result carries the Execute-stage handler's return value, and the hook runs on every Callback-stage result emission

dispose()

Cleanup on removal and on bus disposal; keep it safe and idempotent

Registration is message-driven: exec(new AddMiddleware(mw)) appends to the chain, exec(new RemoveMiddleware(mw)) removes by instance identity and calls mw.dispose(). Adding the same instance twice runs its hooks twice. See the Infrastructure Messages Reference.

MiddlewareStage

enum MiddlewareStage { Publish = 1, Callback, Execute }

Stage

Meaning

Typical result in after

Publish

fire broadcasting

undefined

Callback

fireCallback request/response

emitted result values, once per emission

Execute

synchronous exec

the handler's return value

Use stage-first filtering in canHandle (context.stage) to avoid running middleware unnecessarily — the pipeline also processes infrastructure messages.

MiddlewareDecision / MiddlewareDecisionType

enum MiddlewareDecisionType { Continue = 1, Interrupt } interface MiddlewareDecision { type: MiddlewareDecisionType }

Decision

Effect

{ type: Continue }

The operation proceeds to the next middleware, then runs

{ type: Interrupt }

The operation is cancelled immediately (see cancellation semantics)

Cancellation is a control-flow stop at the bus boundary. It is not: a handler throwing during execution, a callback stream erroring later, or a subscriber unsubscribing — those are failures and runtime conditions, not middleware cancellation.

PipelineContext

interface PipelineContext<T extends PostboyMessage = PostboyMessage> { stage: MiddlewareStage; // which lane is executing message: T; // the message instance being processed }

Treat the context as read-only. The message instance is the same object that will be delivered or executed if the operation proceeds.

PipelineResult

PipelineResult is the outcome of one pass over the chain, produced and consumed internally by the middleware service. It is exported from the package root for typing purposes only — treat it as opaque and do not construct it.

CancelDetails / CancelError

import { CancelError } from '@artstesh/postboy'; class CancelError extends Error { readonly details: CancelDetails; name = 'PostboyCancelError'; }

Field of details

Type

Description

stage

MiddlewareStage

The lane that was interrupted

middleware

string

The name of the middleware that returned Interrupt

messageId

string

The static ID of the cancelled message

namespace?

string

Namespace of the registrator, when relevant

reason?

string

Optional human-readable reason

Detect it with error instanceof CancelError or error.name === 'PostboyCancelError' — an isCancelError helper exists in the sources but is not exported. Log stage, messageId, and middleware to debug unexpected cancellations; keep secrets and PII out of reason.

Execution semantics

  • Order. Middleware runs in registration order: the before hooks first, then the stage operation, then the after hooks in registration order for every middleware whose canHandle is true.

  • Short-circuit. The first middleware returning Interrupt from before wins and becomes the cancellation identity: later middleware is not evaluated, the stage operation does not run (Publish: not broadcast; Callback: request not delivered; Execute: handler not invoked), and after is not called for any middleware for that operation.

  • Surfacing. fire, exec, and fireCallback throw CancelError synchronously at the call site — catch it where cancellation is expected.

Behavioral matrix

Hook

Called when

Can cancel?

Runs on cancellation?

canHandle

Every operation, before anything else

No

Yes — it is the filter

before

canHandle returned true

Yes (Interrupt)

Yes — it is where Interrupt occurs

after

canHandle returned true and the operation reached the post phase

No

No

dispose

Middleware removal or bus disposal

No

Not operation-level — lifecycle-level

Practical corollary: a logging middleware placed after a guard will not see cancelled attempts; place logging middleware before guards when cancelled attempts must be recorded. For ready-made middleware patterns see Middleware recipes.

07 September 2026