@zudojs/messaging 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  In-process message bus infrastructure with handlers, middleware, and publish/subscribe patterns.
4
4
 
5
+ <!-- zudo-docs:start -->
6
+
7
+ **Documentation:** [zudojs.oyinlola.site/docs/packages-messaging](https://zudojs.oyinlola.site/docs/packages-messaging) · **For AI agents:** [Markdown version](https://zudojs.oyinlola.site/docs/packages-messaging.md), [llms.txt](https://zudojs.oyinlola.site/llms.txt)
8
+
9
+ <!-- zudo-docs:end -->
10
+
5
11
  ## Installation
6
12
 
7
13
  ```bash
@@ -4,6 +4,7 @@
4
4
  * @module dispatcher/dispatcherCore
5
5
  */
6
6
  import { createMessageContext } from "../messageContext/messageContextType.type.js";
7
+ import { resolveMessageHandler } from "../messageHandler/messageHandlerType.type.js";
7
8
  import { HandlerRegistryStore } from "../handlerRegistry/handlerRegistryStore.js";
8
9
  import { runMessagePipeline } from "../messageMiddleware/messageMiddlewarePipeline.js";
9
10
  import { MessageDispatchAbortedError, MessageHandlerError, MessageMiddlewareError, MessageTimeoutError, MessageBusDisposedError, } from "@zudojs/errors";
@@ -80,7 +81,11 @@ export class DefaultDispatcher {
80
81
  value: pipelineResult.result,
81
82
  message,
82
83
  context,
83
- handlerResults,
84
+ // A copy, not the live array: on a timeout the dispatch settles
85
+ // while a handler is still running, and that handler later pushed
86
+ // a `success: true` record into the result the caller was already
87
+ // holding for a dispatch that had failed.
88
+ handlerResults: [...handlerResults],
84
89
  middlewareResult: pipelineResult,
85
90
  duration: performance.now() - dispatchStart,
86
91
  };
@@ -91,7 +96,7 @@ export class DefaultDispatcher {
91
96
  error: error instanceof Error ? error : new Error(String(error)),
92
97
  message,
93
98
  context,
94
- handlerResults,
99
+ handlerResults: [...handlerResults],
95
100
  duration: performance.now() - dispatchStart,
96
101
  };
97
102
  }
@@ -190,7 +195,11 @@ export class DefaultDispatcher {
190
195
  }
191
196
  async executeHandler(handler, message, context) {
192
197
  try {
193
- return await handler.handler(message, context);
198
+ // Handlers may be a plain function or an object with a `handle`
199
+ // method. Calling `handler.handler(...)` directly made the object
200
+ // form crash on every dispatch, so it goes through the same
201
+ // normaliser the public type advertises.
202
+ return await resolveMessageHandler(handler.handler)(message, context);
194
203
  }
195
204
  catch (error) {
196
205
  throw new MessageHandlerError(`Handler "${handler.id}" failed: ${error instanceof Error ? error.message : String(error)}`, {
@@ -9,6 +9,7 @@
9
9
  import type { Message } from "../message/messageType.type.js";
10
10
  import type { MessageContext, MessageContextOptions } from "../messageContext/messageContextType.type.js";
11
11
  import type { MessageMiddlewareLike, MessageMiddlewareOptions, MessageMiddlewarePipelineResult } from "../messageMiddleware/messageMiddlewareType.type.js";
12
+ import type { HandlerRegistryStore } from "../handlerRegistry/handlerRegistryStore.js";
12
13
  /**
13
14
  * Result of dispatching a message.
14
15
  */
@@ -90,5 +91,18 @@ export interface Dispatcher {
90
91
  * @returns Whether a registration was removed.
91
92
  */
92
93
  removeMiddleware(middlewareId: string): boolean;
94
+ /**
95
+ * The ids of every registered global middleware, in the order they run.
96
+ */
97
+ listMiddleware(): readonly string[];
98
+ /**
99
+ * The handler registry this dispatcher resolves handlers from.
100
+ */
101
+ getRegistry(): HandlerRegistryStore;
102
+ /**
103
+ * Releases the dispatcher: drops all middleware and rejects any further
104
+ * dispatch with `MessageBusDisposedError`.
105
+ */
106
+ dispose(): void;
93
107
  }
94
108
  //# sourceMappingURL=dispatcherType.type.d.ts.map
@@ -35,8 +35,13 @@ export interface NamedMessageHandler<TMessage extends Message = Message, TResult
35
35
  readonly id: string;
36
36
  /** Human-readable name for debugging. */
37
37
  readonly name: string;
38
- /** The handler function. */
39
- readonly handler: MessageHandler<TMessage, TResult>;
38
+ /**
39
+ * The handler itself: a function, or an object with a `handle` method.
40
+ *
41
+ * The dispatcher normalises both forms through
42
+ * {@link resolveMessageHandler} before invoking them.
43
+ */
44
+ readonly handler: MessageHandlerLike<TMessage, TResult>;
40
45
  /** Message types this handler processes. */
41
46
  readonly messageTypes: readonly string[];
42
47
  /** Execution priority (lower = earlier). Default: 100. */
@@ -13,6 +13,6 @@ export function resolveMessageHandler(handler) {
13
13
  if (typeof handler === "function") {
14
14
  return handler;
15
15
  }
16
- return handler.handle;
16
+ return handler.handle.bind(handler);
17
17
  }
18
18
  //# sourceMappingURL=messageHandlerType.type.js.map
@@ -3,32 +3,7 @@
3
3
  *
4
4
  * @module messageMiddleware/messageMiddlewarePipeline
5
5
  */
6
- /**
7
- * Compose an array of middleware into a single function.
8
- *
9
- * The returned function executes middleware in order.
10
- * If no middleware is provided, the handler is called directly.
11
- */
12
- function compose(middlewareList, handler) {
13
- if (middlewareList.length === 0) {
14
- return handler;
15
- }
16
- return async (context) => {
17
- let index = -1;
18
- async function dispatch(i) {
19
- if (i <= index) {
20
- throw new Error("next() called multiple times");
21
- }
22
- index = i;
23
- if (i < middlewareList.length) {
24
- const mw = middlewareList[i];
25
- return mw(context, () => dispatch(i + 1));
26
- }
27
- return handler(context);
28
- }
29
- return dispatch(0);
30
- };
31
- }
6
+ import { compose } from "@zudojs/middleware";
32
7
  /**
33
8
  * Resolves a MessageMiddlewareLike to a plain MessageMiddleware function.
34
9
  */
@@ -36,7 +11,7 @@ function resolveMiddlewareLike(mw) {
36
11
  if (typeof mw === "function") {
37
12
  return mw;
38
13
  }
39
- return mw.handle;
14
+ return mw.handle.bind(mw);
40
15
  }
41
16
  /**
42
17
  * Runs a handler through a middleware pipeline and returns the
@@ -78,7 +53,8 @@ export async function runMessagePipeline(middlewareList, handler, message, optio
78
53
  };
79
54
  });
80
55
  const pipelineStart = performance.now();
81
- const composed = compose(resolvedMiddleware, async (ctx) => handler(message, ctx));
56
+ // Unbounded depth: the list length is fixed by the registered middleware.
57
+ const composed = compose(resolvedMiddleware, async (ctx) => handler(message, ctx), { maxDepth: Number.POSITIVE_INFINITY });
82
58
  const context = {
83
59
  message,
84
60
  context: options.context ?? {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zudojs/messaging",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "In-process message bus infrastructure with handlers, middleware, and publish/subscribe patterns.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -19,8 +19,9 @@
19
19
  "!dist/.tsbuildinfo"
20
20
  ],
21
21
  "dependencies": {
22
- "@zudojs/errors": "1.0.1",
23
- "@zudojs/constants": "1.0.1"
22
+ "@zudojs/constants": "1.1.1",
23
+ "@zudojs/errors": "1.2.0",
24
+ "@zudojs/middleware": "1.0.3"
24
25
  },
25
26
  "engines": {
26
27
  "node": ">=24.0.0"