Docs / Packages / @zudojs/messaging
v1.2.1

@zudojs/messaging

An in-process message bus: one part of your program sends a named message, other parts handle it and send an answer back, all without the two sides knowing about each other.

MESSAGING PUB/SUB MIDDLEWARE DISPATCH

OVERVIEW

When one part of an app needs another part to do something, the simplest option is a direct function call. That works until the two parts live in different modules, or until three other parts also want to react. Then every caller has to import every listener, and the code becomes a tangle.

A message bus breaks that tangle. Senders hand a message (a small named object with data) to the bus. The bus looks up the handlers that registered for that message's type, runs them, and hands their return values back to the sender. Sender and handlers only share the message type string, such as "order.placed".

@zudojs/messaging is that bus, kept inside a single Node.js process. It has no network, no queue and no persistence. It is the generic layer; @zudojs/events and @zudojs/cqrs use the same vocabulary for more specific jobs (see Messaging vs Events).

Reach for it when
  • Modules in one process need to talk without importing each other.
  • You want a request/response shape: the handler's return value matters.
  • You want to add logging or timing around every message in one place.
  • You are building a higher-level bus of your own and need the plumbing.
Skip it when
  • A plain function call would do. Two modules that already import each other do not need a bus.
  • You are announcing "something happened" to many listeners. Use @zudojs/events.
  • Work must survive a restart or run on another machine. Use @zudojs/queue.

INSTALLATION

Install the package. It pulls in @zudojs/errors and @zudojs/constants on its own; you do not need to add them.

$ npm install @zudojs/messaging
Source of truth: These docs follow the framework source. If an export shown here is missing from the version you installed, update to the latest @zudojs release.

Requires Node.js 24 or newer and an ES-module project ("type": "module" in package.json).

QUICK START

This creates a bus, registers one handler for the type "user.created", sends a message of that type, and prints what came back.

import { createMessageBus } from "@zudojs/messaging"; const bus = createMessageBus(); // 1. Register a handler. It runs whenever a "user.created" message arrives. bus.on("user.created", async (message) => { console.log("New user:", message.payload); return "welcome email queued"; }, { id: "send-welcome-email" }); // 2. Send a message. send() builds the Message object for you. const result = await bus.send({ type: "user.created", payload: { id: "u-1", email: "ada@example.com" }, }); console.log(result.success); // true console.log(result.value); // "welcome email queued" // 3. Release the bus when you are done with it. bus.dispose();

What you should see, in order: New user: { id: 'u-1', email: 'ada@example.com' }, then true, then welcome email queued.

Tip: Pass an id when you call on() if you want to off() the handler later. Without one the bus generates handler:<type>:<n> from a per-bus counter, so generated ids never collide — but they are not stable across runs, so you cannot hard-code one to remove it.

MESSAGES

A message is a frozen object with four required fields: a unique id, a type string, a payload (any data you like) and a timestamp. The type is the address: handlers register for a type, and the bus routes by it. Dotted names like "order.placed" are the convention.

Optional fields describe where the message came from: source (which subsystem made it), correlationId and causationId (explained under Context) and free-form metadata.

This builds a message by hand and prints the fields the factory filled in for you.

import { createMessage, describeMessage, toCorrelationId } from "@zudojs/messaging"; const message = createMessage({ type: "order.placed", payload: { orderId: "ord-001", total: 4999 }, source: "checkout", correlationId: toCorrelationId("req-abc"), }); console.log(message.id); // "msg:6f1c…" — a fresh random id console.log(message.timestamp); // the Date it was created console.log(describeMessage(message)); // "order.placed (msg:6f1c…)" console.log(Object.isFrozen(message)); // true — messages cannot be edited after creation

Branded ids

MessageId, MessageCorrelationId and MessageCausationId are branded strings: at runtime they are ordinary strings, but TypeScript refuses to accept a plain string where one is expected. This stops you from passing a user id where a message id belongs.

createMessageId() mints a new id. When the id already exists as a string (from a database row, a log line, a network frame), wrap it with toMessageId, toCorrelationId or toCausationId. All three throw a TypeError on an empty or blank string, and createMessage throws the same on an empty type.

Watch out: correlationId: "req-abc" as a bare string is a compile error. Write correlationId: toCorrelationId("req-abc").

HANDLERS

A handler is a function that receives a message and a MessageContext, does some work, and returns a value (or a promise of one). Registering a handler is the "subscribe" half of publish/subscribe: you tell the bus "call me for this type".

Several handlers may register for the same type. The bus runs them one after another, lowest priority number first (default 100). With one handler, result.value is that handler's return value. With several, it is an array of their return values in run order. That fan-out is the default; create the bus with allowMultipleHandlers: false for a command or query bus, and a second handler claiming a type already taken is refused with a MessageError naming the type and the handler that holds it.

This registers two handlers for one type, sends a message, then removes one handler. The payload type annotation on the parameter is what gives you message.payload.orderId without a cast.

import { createMessageBus, type Message } from "@zudojs/messaging"; type OrderPlaced = { orderId: string; total: number }; const bus = createMessageBus(); bus.on("order.placed", async (message: Message<OrderPlaced>) => { return `reserved stock for ${message.payload.orderId}`; }, { id: "reserve-stock", priority: 10 }); bus.on("order.placed", async (message: Message<OrderPlaced>) => { return `charged ${message.payload.total}`; }, { id: "charge-card", priority: 20 }); const result = await bus.send({ type: "order.placed", payload: { orderId: "ord-001", total: 4999 }, }); console.log(result.value); // ["reserved stock for ord-001", "charged 4999"] console.log(result.handlerResults.map((r) => r.handlerId)); // ["reserve-stock", "charge-card"] console.log(bus.off("charge-card")); // true — it was found and removed console.log(bus.hasHandlers("order.placed")); // true — reserve-stock is still registered console.log(bus.handlerCount); // 1

Named handler objects

on() wraps your function in a NamedMessageHandler behind the scenes. Build one yourself with addHandler() when a single handler should answer several types, or when you want to ship it disabled. This fragment assumes the bus from the example above.

bus.addHandler({ id: "audit-log", name: "Audit log", messageTypes: ["order.placed", "order.cancelled"], priority: 1, enabled: true, handler: async (message) => { console.log("audit:", message.type); }, });
Watch out: Handler ids must be unique across the whole bus. Registering the same id twice throws DuplicateMessageHandlerError immediately, unless you created the bus with allowDuplicateHandlers: true.

Object-form handlers

The handler field of a NamedMessageHandler accepts either form described by MessageHandlerLike: a plain function, or an object with a handle(message, context) method. The object form lets a class hold the handler's dependencies. this is bound for you, so a class method may use its own fields.

class AuditHandler { constructor(private readonly sink: AuditSink) {} async handle(message: Message, context: MessageContext) { await this.sink.write(message.type, context.correlationId); return "audited"; } } bus.addHandler({ id: "audit-log", name: "Audit log", messageTypes: ["order.placed"], handler: new AuditHandler(sink), // object form — resolved through resolveMessageHandler }); const result = await bus.send({ type: "order.placed", payload: { id: "o_1" } }); console.log(result.success, result.value); // true "audited"
Changed in v1.1.0: an object-form handler now actually runs. MessageHandlerLike had always advertised the { handle } form, but the dispatcher invoked the registered handler as a function, so every dispatch to an object handler came back as a failed dispatch with handler.handler is not a function in result.error. If you worked around this by wrapping the object yourself — handler: (m, c) => obj.handle(m, c) — that still works and needs no change.

bus.on(type, fn) takes a function only. Register an object-form handler with addHandler(), or normalise it yourself with resolveMessageHandler(handlerLike), which returns a plain bound function.

SENDING AND RESULTS

Dispatching is the "publish" half: the bus takes a message, runs middleware, runs the matching handlers, and returns a DispatchResult. Two methods do it. send(input) builds the message from plain input first. dispatch(message) takes a message you already created, for example one from createDerivedMessage.

A failing handler does not make dispatch throw. Instead the result comes back with success: false and the problem in result.error, wrapped in a MessageHandlerError that names the handler. Dispatching to a type with no handlers also succeeds; value is an empty array.

This shows both outcomes side by side.

import { createMessageBus, createMessage, MessageHandlerError } from "@zudojs/messaging"; const bus = createMessageBus(); bus.on("payment.charge", async () => { throw new Error("card declined"); }, { id: "charge" }); const failed = await bus.dispatch(createMessage({ type: "payment.charge", payload: {} })); console.log(failed.success); // false console.log(failed.error instanceof MessageHandlerError); // true console.log(failed.error?.message); // 'Handler "charge" failed: card declined' const nobody = await bus.send({ type: "nobody.listens", payload: {} }); console.log(nobody.success, nobody.value); // true [] console.log(nobody.duration >= 0); // true — every result carries its duration in ms

What does throw

Only two things reject the promise instead of returning a result: using a bus after dispose() throws MessageBusDisposedError, and passing a signal that is already aborted throws MessageDispatchAbortedError. (send() with an empty type also rejects, with the TypeError from createMessage.) Wrap those calls in try/catch if they can happen in your code.

Timeouts and cancellation

Pass { timeout: 5000 } to one dispatch, or defaultTimeout to createMessageBus, and the bus starts a timer that aborts an AbortSignal. You can also pass your own signal. Handlers that have not started yet are skipped and the result fails with a bare MessageDispatchAbortedError as result.error (not wrapped in a MessageHandlerError).

Watch out: A handler that is already running is not interrupted. Long handlers should check context.signal.aborted between steps and stop themselves. A timed-out dispatch comes back with result.error instanceof MessageTimeoutError.
Changed in v1.2.0: an abort always fails the dispatch. If your own signal aborts while the last (or only) handler is running, the dispatch now settles promptly with success: false and a MessageDispatchAbortedError in result.error, even if that handler ignores the signal and later returns normally. As with a timeout, the dispatch does not wait for such a handler, and result.handlerResults lists only the handlers that finished. This applies to the bus and to a dispatcher used directly. Before v1.2.0 that case came back as success: true. Handlers should still honour the signal (for example context.signal.throwIfAborted() after each await) so the work itself stops:
bus.on("report.build", async (message, context) => { const rows = await loadRows(context.signal); context.signal.throwIfAborted(); return render(rows); }, { id: "build-report" });
Changed in v1.2.1: aborting a dispatch no longer needs Node's setImmediate. In a browser bundle, v1.2.0 threw ReferenceError: setImmediate is not defined the moment a dispatch was aborted. The abort rejection is now scheduled with setTimeout(…, 0), which keeps the same ordering: a handler that aborts the signal and then returns still has its result recorded first. Tested with setImmediate deleted from the global scope: a handler that called controller.abort() and returned gave success: false, MessageDispatchAbortedError, and one successful entry in handlerResults. Nothing changes in Node.
Changed in v1.1.0: result.handlerResults is a snapshot taken when the dispatch settles, so it stops changing once you have awaited the dispatch. Previously it was the live array the dispatcher was still writing into: a handler that kept running past a timeout could push a success: true record into the result of a dispatch that had already failed with MessageTimeoutError. Audit records and metrics derived from handlerResults are now stable.

MIDDLEWARE

Middleware is a function that runs around every dispatch. It receives a context and a next function; calling next() continues to the following middleware and finally to the handlers. Whatever next() resolves to becomes result.value, so you can log, time, or even replace the answer in one place.

Register bus-wide middleware with bus.use() or the middleware option of createMessageBus. Middleware for one dispatch only goes in DispatchOptions.middleware and runs after the bus-wide ones. Order is registration order.

This logs when each message starts and how long it took.

import { createMessageBus } from "@zudojs/messaging"; const bus = createMessageBus(); bus.use(async (ctx, next) => { const started = performance.now(); console.log(`→ ${ctx.message.type} [${ctx.context.correlationId}]`); try { return await next(); } finally { console.log(`← ${ctx.message.type} in ${(performance.now() - started).toFixed(1)}ms`); } }); bus.on("ping", async () => "pong", { id: "ping" }); const result = await bus.send({ type: "ping", payload: null }); console.log(result.value); // "pong"

What you should see: → ping [msg:…], then ← ping in 0.2ms, then pong. The correlation id defaults to the message id because none was set.

The middleware context (MessageMiddlewareContext) exposes message, the dispatch context, the abort signal, an executionId, and a shared state Map you can use to pass values between middleware. A middleware can also be an object with a handle method.

Watch out: If middleware throws, the dispatch result is success: false and result.error is exactly what you threw (not wrapped). Calling next() twice throws MiddlewareNextCalledMultipleTimesError (from @zudojs/errors, a MiddlewareError); the pipeline is compose from @zudojs/middleware. Middleware runs in ascending priority order (default 100), with registration order breaking ties.

CONTEXT, CORRELATION AND CAUSATION

Every handler receives a MessageContext as its second argument. It holds the message, a correlationId, a causationId, an abort signal, a state Map and startedAt.

A correlation id is a label shared by every message that belongs to one bigger operation, such as one HTTP request. A causation id is the id of the single message that directly caused this one. Together they let you trace "why did this happen?" through a chain of messages. If you set neither, both default to the message's own id.

createDerivedMessage builds a follow-up message that inherits the parent's correlation id and records the parent as its cause.

import { createMessage, createDerivedMessage, toCorrelationId, toCausationId } from "@zudojs/messaging"; const placed = createMessage({ type: "order.placed", payload: { orderId: "ord-001" }, correlationId: toCorrelationId("req-abc"), }); const paid = createDerivedMessage(placed, { type: "order.paid", payload: { orderId: "ord-001" }, }); console.log(paid.correlationId); // "req-abc" — inherited console.log(paid.causationId === toCausationId(placed.id)); // true — placed caused paid

Inside a handler, read the ids from the context. This handler dispatches a follow-up on the same bus, keeping the chain intact.

import { createMessageBus, createDerivedMessage } from "@zudojs/messaging"; const bus = createMessageBus(); bus.on("order.placed", async (message, context) => { console.log("correlation:", context.correlationId); await bus.dispatch(createDerivedMessage(message, { type: "order.paid", payload: message.payload })); }, { id: "take-payment" }); bus.on("order.paid", async (message, context) => { console.log("caused by:", context.causationId); }, { id: "ship-order" }); await bus.send({ type: "order.placed", payload: { orderId: "ord-001" } }); // correlation: msg:… (the order.placed id, since none was set) // caused by: msg:… (the same id — order.placed caused order.paid)
In plain words: Handlers receive the same context as middleware: DispatchOptions.context headers, state and id overrides, plus anything middleware put into context.state.
Changed in v1.2.0: bus.send(input, { context: { correlationId, causationId } }) now writes those identifiers onto the message it builds, unless the input carries its own. message.correlationId in the handler is therefore the request id, and createDerivedMessage(message, …) continues the chain instead of starting a new one. Before v1.2.0 the context ids applied to that one dispatch only and never reached the message.
import { createMessageBus, createDerivedMessage, toCorrelationId } from "@zudojs/messaging"; const bus = createMessageBus(); bus.on("order.placed", async (message) => { const paid = createDerivedMessage(message, { type: "order.paid", payload: null }); console.log(message.correlationId, paid.correlationId); }, { id: "take-payment" }); await bus.send( { type: "order.placed", payload: null }, { context: { correlationId: toCorrelationId("req-abc") } }, ); // req-abc req-abc bus.dispose();

MESSAGING VS EVENTS

Both packages route named objects to registered functions inside one process, and neither depends on the other. The difference is intent. A message here is a request that expects an answer: the sender awaits result.value. An event in @zudojs/events is a fact that already happened; the publisher does not want a return value, only that listeners are told.

Question@zudojs/messaging@zudojs/events
UnitMessage with a typeEvent with a type
Sendingbus.send() / bus.dispatch()bus.publish() / bus.emit()
Return valueHandler results come back in result.valueHandlers return nothing useful; you get an emit result
Listeningon(), addHandler()on(), once(), onAny()
When one listener failsDispatch stops; success: falseConfigurable: stop, or continue and report
Lifecycledispose() onlystart() / stop(), event registration

Rule of thumb: "please do X and tell me the outcome" is a message; "X happened" is an event. @zudojs/cqrs goes one step further and splits messages into commands (change something) and queries (read something).

LOWER-LEVEL PIECES

createMessageBus is enough for almost everything. The parts it is built from are exported too, for people writing their own bus on top of this package:

  • HandlerRegistryStore keeps the handlers. register(), unregister(), resolve(type) (sorted by priority, disabled handlers left out), get(), has(), getHandlerIds(), getRegisteredTypes(), size, clear().
  • createDispatcher(registry?) returns a Dispatcher (class DefaultDispatcher) that runs middleware and handlers for one message. The bus adds timeouts, on()/off() and the disposed flag on top. The interface is dispatch(), use(), removeMiddleware(), listMiddleware(), getRegistry() and dispose().
  • runMessagePipeline(middleware, handler, message, options?) runs a middleware chain around any async function and returns { result, executions, duration }.
  • createMessageContext(message, options?) and resolveMessageHandler(handlerLike) are the small helpers the dispatcher uses internally.

This wires a registry and dispatcher by hand, which is exactly what createMessageBus does for you.

import { HandlerRegistryStore, createDispatcher, createMessage } from "@zudojs/messaging"; const registry = new HandlerRegistryStore(); registry.register({ id: "greet", name: "Greeter", messageTypes: ["greet"], handler: async (message) => `hello ${message.payload}`, }); const dispatcher = createDispatcher(registry); const result = await dispatcher.dispatch(createMessage({ type: "greet", payload: "Ada" })); console.log(result.value); // "hello Ada" console.log(registry.getRegisteredTypes()); // ["greet"]

Inspecting and releasing a dispatcher

Three of the dispatcher's methods are about what it holds rather than what it runs.

MethodWhat it returnsNotes
listMiddleware()The ids of every registered global middleware, in the order they run.Ascending priority (default 100), registration order breaking ties. These are the ids use() returned.
getRegistry()The HandlerRegistryStore this dispatcher resolves handlers from.The registry you passed to createDispatcher, or the one it made for you.
dispose()Nothing.Drops all middleware and makes every later dispatch() reject with MessageBusDisposedError. Handlers stay in the registry.
const dispatcher = createDispatcher(registry); const timingId = dispatcher.use(timing, { id: "timing", priority: 10 }); dispatcher.use(logging, { id: "logging" }); console.log(dispatcher.listMiddleware()); // ["timing", "logging"] console.log(dispatcher.removeMiddleware(timingId)); // true console.log(dispatcher.getRegistry() === registry); // true dispatcher.dispose(); // later dispatches reject with MessageBusDisposedError
Changed in v1.1.0: dispose(), getRegistry() and listMiddleware() are now declared on the Dispatcher interface. DefaultDispatcher already implemented all three, but because the interface omitted them, createDispatcher().dispose() did not compile without a cast to DefaultDispatcher. Any such cast can now be dropped.

API REFERENCE

Everything below is exported from @zudojs/messaging.

Functions

NameWhat it doesNotes
createMessageBus(options?)Creates an in-memory MessageBus.Options: allowDuplicateHandlers, allowMultipleHandlers, middleware, defaultTimeout.
createMessage(input)Builds a frozen Message; fills id and timestamp.Throws TypeError on empty type.
createDerivedMessage(parent, input)Builds a follow-up message that inherits correlation and records causation.Explicit ids in input win.
createMessageId()Mints a new random MessageId.Format msg:<uuid>.
toMessageId(s), toCorrelationId(s), toCausationId(s)Brand an existing string as an id.Throw TypeError on blank input.
isMessage(value)Type guard: does this look like a Message?Checks id, type, timestamp, payload.
getMessageType(m), getMessagePayload(m), describeMessage(m)Small accessors.describeMessage returns "type (id)".
createMessageContext(message, options?)Builds a MessageContext.Ids fall back to the message id.
createDispatcher(registry?)Creates a Dispatcher.Makes its own registry if none given.
runMessagePipeline(middleware, handler, message, options?)Runs a middleware chain around a function.Returns { result, executions, duration }.
resolveMessageHandler(h)Turns a function or { handle } object into a function.
isMessageError(e), toMessageError(e), createMessageError(), createMessageHandlerError()Error helpers re-exported from @zudojs/errors.See that package's page.

Classes

NameWhat it doesNotes
InMemoryMessageBusThe bus createMessageBus returns.Methods: send, dispatch, on, addHandler, off, use, hasHandlers, dispose; getters handlerCount, disposed.
HandlerRegistryStoreIn-memory store of named handlers.See Lower-level pieces.
DefaultDispatcherRuns middleware and handlers for one message.Implements the whole Dispatcher interface: dispatch(), use(), removeMiddleware(), listMiddleware(), getRegistry(), dispose().

Types

NameWhat it doesNotes
Message<TPayload>, MessageInput<TPayload>A message, and the input createMessage accepts.Input may omit id and timestamp.
MessageId, MessageCorrelationId, MessageCausationIdBranded id strings.Build with the to… helpers.
MessageHandler, NamedMessageHandler, MessageHandlerLikeHandler function; handler with id, name, types, priority; either form.HandlerResult and MessageHandlerFactory are also exported.
MessageContext, MessageContextOptionsWhat handlers receive as their second argument.
MessageMiddleware, MessageMiddlewareLike, MessageMiddlewareContext, MessageMiddlewareNextMiddleware function shape and its context.Pipeline result types: MessageMiddlewarePipelineResult, MessageMiddlewareExecution.
MessageBus, MessageBusOptionsThe bus interface and its options.
Dispatcher, DispatchOptions, DispatchResult, HandlerExecutionResultDispatch interface, per-call options, and the result shape.Dispatcher: dispatch, use, removeMiddleware, listMiddleware, getRegistry, dispose. DispatchOptions: context, middleware, timeout, signal.
HandlerRegistryOptions, RegisteredHandler, HandlerQueryOptionsRegistry configuration and lookup types.

Errors

All error classes live in @zudojs/errors and are re-exported here. Only the first five in the table are raised by this package, plus the base MessageError when a bus created with allowMultipleHandlers: false refuses a second handler. The rest are exported so your own code and other packages can share one hierarchy.

NameWhat it doesNotes
MessageHandlerErrorA handler threw.Appears in result.error; has handlerId, cause.
DuplicateMessageHandlerErrorHandler id already registered.Thrown by on() / addHandler().
MessageBusDisposedErrorBus used after dispose().Rejects the dispatch promise.
MessageDispatchAbortedErrorSignal aborted before or between handlers.Rejects if aborted up front; otherwise returned as result.error, including an abort while the last handler runs (since v1.2.0).
MessageTimeoutErrorA dispatch ran past its timeout or defaultTimeout.Returned as result.error, even when the last handler finishes later.
MessageError, MessageDispatchError, InvalidMessageError, MessageTypeNotFoundError, MessageHandlerNotFoundError, MessageMiddlewareError, MessageValidationErrorShared hierarchy for messaging errors.Not thrown by this package itself, apart from MessageError as described above.

COMMON MISTAKES

  • Registering handlers without an id and then trying to remove them → generated ids come from a per-bus counter (handler:<type>:<n>), so they never collide, but they depend on registration order and are not something you can hard-code. → Pass an id in the options of on() for any handler you intend to off().
  • Checking for a thrown error instead of result.success → a failing handler never throws from send(), so your catch block stays silent and the failure is missed. → Read result.success and result.error after every dispatch.
  • Passing a plain string as correlationId → TypeScript rejects it because the type is branded. → Wrap it: toCorrelationId("req-abc").
  • Expecting a timeout to stop a running handler → the timer only aborts a signal; the handler keeps going; the dispatch result carries a MessageTimeoutError. → Check context.signal.aborted inside long handlers, or call context.signal.throwIfAborted() after each await.
  • Expecting result.value to always be a single value → with two or more handlers it is an array in priority order, and with none it is []. → Check result.handlerResults.length when the handler count can vary.
  • Using a bus after dispose() → every send/dispatch rejects with MessageBusDisposedError and all handlers are gone. → Dispose once, at shutdown, and check bus.disposed if unsure.

COMPLETE EXPORT INDEX

Every name @zudojs/messaging exports from its package root at v1.1.0 — 69 in total, generated from the package’s own entry point rather than written by hand. The sections above explain the ones you reach for most; this is the exhaustive list, so nothing shipped is undocumented. Names not covered above are typically internal helpers and supporting types.

Show all 69 exports
Classes (15)
DefaultDispatcher DuplicateMessageHandlerError HandlerRegistryStore InMemoryMessageBus InvalidMessageError MessageBusDisposedError MessageDispatchAbortedError MessageDispatchError MessageError MessageHandlerError MessageHandlerNotFoundError MessageMiddlewareError MessageTimeoutError MessageTypeNotFoundError MessageValidationError
Functions (19)
createDerivedMessage createDispatcher createMessage createMessageBus createMessageContext createMessageError createMessageHandlerError createMessageId describeMessage getMessagePayload getMessageType isMessage isMessageError resolveMessageHandler runMessagePipeline toCausationId toCorrelationId toMessageError toMessageId
Interfaces (22)
Dispatcher DispatchOptions DispatchResult HandlerExecutionResult HandlerQueryOptions HandlerRegistryOptions HandlerResult Message MessageBus MessageBusOptions MessageContext MessageContextOptions MessageInput MessageMiddlewareContext MessageMiddlewareExecution MessageMiddlewareObject MessageMiddlewareOptions MessageMiddlewarePipelineOptions MessageMiddlewarePipelineResult NamedMessageHandler RegisteredHandler RegisteredMessageMiddleware
Type aliases (13)
MessageCausationId MessageCorrelationId MessageHandler MessageHandlerFactory MessageHandlerLike MessageId MessageMiddleware MessageMiddlewareLike MessageMiddlewareNext MessagePayload MessageSource MessageTimestamp MessageType