Ingress behaviours wrapped around every subscription handler — the
messaging arm of the transport-neutral behaviour chain shared with the
websocket, queue, and scheduler plugins (IIngressBehavior in
@setu-ts/common).
Each behaviour observes an IngressContext carrying kind: 'messaging',
the topic as name, the delivered message as payload, and the
transport headers from MessageMetadata (absent when the transport
carried no channel — there is deliberately NO attempt: brokers
redeliver and none tracks a delivery count), and runs in declared order
ahead of the handler. A behaviour that returns without calling next()
short-circuits: the handler never sees the message. A behaviour that
throws follows the messaging handler's existing rejection path. The chain
wraps SUBSCRIBE handlers only — respond (RPC) is deliberately not
chained and not armed in this milestone.
With no behaviours configured, the broker chain is byte-identical to the
pre-arm behaviour: no PipelinedBroker decorator is applied at all.
Instance entries are read by the chain at register(); factory entries
are resolved in the onInit phase and a throwing factory rejects
start() naming MessagingPlugin({ behaviors }) and the entry's index
in THIS declared array.
When an entry is a FACTORY, DELIVERY is held until onInit has resolved
the whole chain, so no message reaches a handler through a partial one.
A broker holding a backlog delivers the moment a consumer attaches, and
the gate covers every subscription — this plugin's declared entries and
any a later plugin makes imperatively through the resolved broker — which
is why no registration's timing has to change. It is released once and
costs nothing thereafter.