@zudojs/messaging 1.2.0 → 1.2.2

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
@@ -117,6 +117,33 @@ that ignores its signal. `handlerResults` still lists every handler that
117
117
  finished. Before 1.2.0 an abort during the last handler was reported as
118
118
  `success: true`.
119
119
 
120
+ The error's `cause` is the signal's `reason`, so the reason you aborted with
121
+ survives the dispatch:
122
+
123
+ ```typescript
124
+ const controller = new AbortController();
125
+ bus.on("report", () => {
126
+ controller.abort(new Error("user navigated away"));
127
+ });
128
+
129
+ const result = await bus.send(
130
+ { type: "report", payload: {} },
131
+ { signal: controller.signal },
132
+ );
133
+ result.error; // MessageDispatchAbortedError
134
+ result.error?.cause; // Error: user navigated away
135
+ ```
136
+
137
+ A signal that is already aborted when the dispatch starts rejects the call
138
+ with the same error and the same `cause`. `controller.abort()` without an
139
+ argument gives the platform's default `AbortError` `DOMException` as the
140
+ cause. Before 1.2.2 `cause` was always `undefined`.
141
+
142
+ Cancellation uses only `AbortSignal` and `setTimeout`, so it works in
143
+ browsers and other non-Node runtimes. 1.2.0 scheduled the abort with Node's
144
+ `setImmediate`, and aborting a dispatch in a browser threw
145
+ `ReferenceError: setImmediate is not defined`; later releases do not.
146
+
120
147
  ## Timeouts
121
148
 
122
149
  `timeout` is honoured by the dispatcher itself, so it applies whether you hold
@@ -20,7 +20,8 @@ export interface AbortRejection {
20
20
  * The error a dispatch fails with once `signal` has aborted.
21
21
  *
22
22
  * A timeout aborts with its own {@link MessageTimeoutError}, which is kept;
23
- * any other abort is reported as {@link MessageDispatchAbortedError}.
23
+ * any other abort is reported as {@link MessageDispatchAbortedError}, whose
24
+ * `cause` is the signal's `reason`.
24
25
  */
25
26
  export declare function abortErrorFor(signal: AbortSignal, message: Message): Error;
26
27
  /** Throws the dispatch's abort error when `signal` has aborted. */
@@ -33,6 +34,11 @@ export declare function assertDispatchNotAborted(signal: AbortSignal, message: M
33
34
  * The rejection waits one macrotask. A handler that aborts and then returns
34
35
  * synchronously has its result recorded first, so `handlerResults` still
35
36
  * lists every handler that finished.
37
+ *
38
+ * The macrotask is a `setTimeout(…, 0)`, not `setImmediate`: the package is
39
+ * not Node-only, and browsers have no `setImmediate`, so an abort there
40
+ * threw a `ReferenceError`. A microtask would not do — the dispatch records
41
+ * a handler's result several promise hops after the handler returns.
36
42
  */
37
43
  export declare function abortRejection(signal: AbortSignal, message: Message): AbortRejection;
38
44
  //# sourceMappingURL=dispatcher.abort.d.ts.map
@@ -13,7 +13,8 @@ import { MessageDispatchAbortedError, MessageTimeoutError, } from "@zudojs/error
13
13
  * The error a dispatch fails with once `signal` has aborted.
14
14
  *
15
15
  * A timeout aborts with its own {@link MessageTimeoutError}, which is kept;
16
- * any other abort is reported as {@link MessageDispatchAbortedError}.
16
+ * any other abort is reported as {@link MessageDispatchAbortedError}, whose
17
+ * `cause` is the signal's `reason`.
17
18
  */
18
19
  export function abortErrorFor(signal, message) {
19
20
  if (signal.reason instanceof MessageTimeoutError)
@@ -21,6 +22,7 @@ export function abortErrorFor(signal, message) {
21
22
  return new MessageDispatchAbortedError(undefined, {
22
23
  messageType: message.type,
23
24
  messageId: message.id,
25
+ cause: signal.reason,
24
26
  });
25
27
  }
26
28
  /** Throws the dispatch's abort error when `signal` has aborted. */
@@ -36,13 +38,18 @@ export function assertDispatchNotAborted(signal, message) {
36
38
  * The rejection waits one macrotask. A handler that aborts and then returns
37
39
  * synchronously has its result recorded first, so `handlerResults` still
38
40
  * lists every handler that finished.
41
+ *
42
+ * The macrotask is a `setTimeout(…, 0)`, not `setImmediate`: the package is
43
+ * not Node-only, and browsers have no `setImmediate`, so an abort there
44
+ * threw a `ReferenceError`. A microtask would not do — the dispatch records
45
+ * a handler's result several promise hops after the handler returns.
39
46
  */
40
47
  export function abortRejection(signal, message) {
41
48
  let pending;
42
49
  let onAbort;
43
50
  const promise = new Promise((_resolve, reject) => {
44
51
  onAbort = () => {
45
- pending = setImmediate(() => reject(abortErrorFor(signal, message)));
52
+ pending = setTimeout(() => reject(abortErrorFor(signal, message)), 0);
46
53
  };
47
54
  signal.addEventListener("abort", onAbort, { once: true });
48
55
  });
@@ -55,7 +62,7 @@ export function abortRejection(signal, message) {
55
62
  if (onAbort)
56
63
  signal.removeEventListener("abort", onAbort);
57
64
  if (pending !== undefined)
58
- clearImmediate(pending);
65
+ clearTimeout(pending);
59
66
  },
60
67
  };
61
68
  }
@@ -155,8 +155,11 @@ export class DefaultDispatcher {
155
155
  * timeout can abort the work without the caller losing its own cancellation.
156
156
  */
157
157
  resolveSignal(signal, controller) {
158
- if (signal?.aborted)
159
- throw new MessageDispatchAbortedError();
158
+ if (signal?.aborted) {
159
+ throw new MessageDispatchAbortedError(undefined, {
160
+ cause: signal.reason,
161
+ });
162
+ }
160
163
  if (!signal) {
161
164
  return { signal: controller.signal, release: () => { } };
162
165
  }
@@ -176,6 +179,7 @@ export class DefaultDispatcher {
176
179
  throw new MessageDispatchAbortedError(undefined, {
177
180
  messageType: message.type,
178
181
  messageId: message.id,
182
+ cause: context.signal.reason,
179
183
  });
180
184
  }
181
185
  const start = performance.now();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zudojs/messaging",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
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,9 +19,9 @@
19
19
  "!dist/.tsbuildinfo"
20
20
  ],
21
21
  "dependencies": {
22
- "@zudojs/constants": "1.1.2",
23
- "@zudojs/errors": "1.3.0",
24
- "@zudojs/middleware": "1.1.0"
22
+ "@zudojs/constants": "1.1.3",
23
+ "@zudojs/errors": "1.3.1",
24
+ "@zudojs/middleware": "1.1.1"
25
25
  },
26
26
  "engines": {
27
27
  "node": ">=24.0.0"