@vielzeug/herald 2.3.0 → 3.0.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/dist/types.d.ts CHANGED
@@ -12,30 +12,6 @@ export type SubscribeOptions = {
12
12
  /** Auto-remove the listener when this signal aborts. */
13
13
  signal?: AbortSignal;
14
14
  };
15
- /**
16
- * Context object passed to `BusOptions.onError` when a listener throws.
17
- * Provides structured access to the error, the triggering event, and a timestamp.
18
- */
19
- export type EmissionErrorContext<T extends EventMap = EventMap> = {
20
- /** The thrown error value. */
21
- err: unknown;
22
- /** The event key that triggered the failing listener. */
23
- event: EventKey<T>;
24
- /** The payload that was passed to the failing listener. */
25
- payload: unknown;
26
- /** Timestamp (ms since epoch) captured at the moment `emit()` was called. */
27
- timestamp: number;
28
- };
29
- /**
30
- * A middleware function called in sequence during `emit()`, before any listeners run.
31
- * Call `next()` to continue the chain. Omitting `next()` prevents all listeners from running.
32
- *
33
- * @example
34
- * const rateLimit: Middleware<Events> = (event, payload, next) => {
35
- * if (shouldAllow(event)) next();
36
- * };
37
- */
38
- export type Middleware<T extends EventMap = EventMap> = (event: EventKey<T>, payload: unknown, next: () => void) => void;
39
15
  /**
40
16
  * Runtime events emitted by {@link Bus.tap}.
41
17
  * Subscribe via `bus.tap(handler)` — handler errors are swallowed.
@@ -58,7 +34,7 @@ export type HeraldEvent<T extends EventMap = EventMap> = {
58
34
  } | {
59
35
  readonly error: unknown;
60
36
  readonly event: EventKey<T>;
61
- readonly type: 'listener-error';
37
+ readonly type: 'error';
62
38
  } | {
63
39
  readonly type: 'dispose';
64
40
  };
@@ -68,35 +44,11 @@ export type BusOptions<T extends EventMap = EventMap> = {
68
44
  * Useful for detecting listener leaks during development. Default: no check.
69
45
  */
70
46
  maxListeners?: number;
71
- /**
72
- * Middleware functions run in order on every `emit()`, before listeners run.
73
- * Each receives `(event, payload, next)` — call `next()` to proceed, or omit to block dispatch.
74
- */
75
- middleware?: readonly Middleware<T>[];
76
47
  /**
77
48
  * Optional display name for this bus instance.
78
49
  * Appears in `BusDisposedError` messages.
79
- * Useful when running multiple buses concurrently to identify which bus produced an error.
80
- *
81
- * **Note:** The name is embedded in `BusDisposedError` messages — avoid using
82
- * sensitive or user-derived values that could leak via error trackers.
83
50
  */
84
51
  name?: string;
85
- /**
86
- * If provided, listener errors are forwarded here instead of re-thrown.
87
- * Receives a structured `EmissionErrorContext` with the error, event key, payload, and timestamp.
88
- *
89
- * **Note:** every registered listener (specific and wildcard) for an emission always runs,
90
- * regardless of `onError` — a throwing listener never prevents the rest from being called.
91
- */
92
- onError?: (context: EmissionErrorContext<T>) => void;
93
- /**
94
- * Called on every emit before middleware and listeners. Throw to reject the payload.
95
- * On throw with `onError` configured, the error is forwarded and `emit()` returns 0.
96
- * On throw without `onError`, the error propagates to the `emit()` caller.
97
- * Receives the typed payload — use it to perform runtime validation with full type information.
98
- */
99
- validatePayload?: <K extends EventKey<T>>(event: K, payload: T[K]) => void;
100
52
  };
101
53
  /** Discriminated-union result type for `waitAny`. */
102
54
  export type WaitAnyResult<T extends EventMap, K extends readonly EventKey<T>[]> = {
@@ -105,49 +57,12 @@ export type WaitAnyResult<T extends EventMap, K extends readonly EventKey<T>[]>
105
57
  payload: T[K[I]];
106
58
  } : never;
107
59
  }[number];
108
- /**
109
- * Keys present in both `S` and `T` where `S[K]` is assignable to `T[K]`.
110
- * These keys can be forwarded from a source bus to a target bus without a type cast.
111
- */
112
- export type PipeableKey<S extends EventMap, T extends EventMap> = {
113
- [K in EventKey<S> & EventKey<T>]: S[K] extends T[K] ? K : never;
114
- }[EventKey<S> & EventKey<T>];
115
- /**
116
- * A single pipe entry passed to `pipeEvents`:
117
- * - A `PipeableKey` string — forward the event under the same name.
118
- * - A `{ from, to }` object — forward the event under a different name on the target bus.
119
- */
120
- export type RenamedPipeEntry<S extends EventMap, T extends EventMap> = {
121
- [From in EventKey<S>]: {
122
- [To in EventKey<T>]: S[From] extends T[To] ? {
123
- from: From;
124
- to: To;
125
- } : never;
126
- }[EventKey<T>];
127
- }[EventKey<S>];
128
- export type PipeEntry<S extends EventMap, T extends EventMap> = PipeableKey<S, T> | RenamedPipeEntry<S, T>;
129
- /**
130
- * An `AsyncGenerator` extended with `AsyncDisposable`. Returned by `bus.events()`.
131
- *
132
- * Use `await using` for guaranteed cleanup, or call `[Symbol.asyncDispose]()` explicitly.
133
- * Compose with standard async-generator utilities (e.g. `for await` + `break`) or
134
- * user-space operators as needed.
135
- *
136
- * @example
137
- * await using stream = bus.events('count');
138
- * for await (const n of stream) { ... } // subscription cleaned up automatically
139
- */
140
- export type EventStream<T> = AsyncGenerator<T> & AsyncDisposable;
141
60
  export type Bus<T extends EventMap> = {
142
61
  /** Alias for dispose() — enables the `using` keyword for automatic cleanup. */
143
62
  [Symbol.dispose](): void;
144
63
  /**
145
64
  * Signal that fires when the bus is disposed.
146
65
  * Use to tie other lifecycles (subscriptions, pipes, timers) to this bus's lifetime.
147
- *
148
- * @example
149
- * // Stop piping when the target bus is disposed
150
- * source.on('event', handler, { signal: target.disposalSignal });
151
66
  */
152
67
  readonly disposalSignal: AbortSignal;
153
68
  /** Permanently dispose the bus — clears all listeners; pending waits are rejected. Idempotent. */
@@ -156,37 +71,12 @@ export type Bus<T extends EventMap> = {
156
71
  readonly disposed: boolean;
157
72
  /**
158
73
  * Emit an event, calling all registered listeners synchronously.
159
- * Returns the total number of listeners that were invoked (specific + wildcard).
160
- * Returns `0` if the bus is disposed, if a middleware blocked dispatch, or if `validatePayload` rejected.
161
- *
162
- * @remarks **Listener throws:** every listener still runs even if an earlier one throws. Without
163
- * `onError` configured, the first thrown error is rethrown once every listener has been called —
164
- * it never short-circuits the rest of the broadcast. With `onError` configured, errors are
165
- * forwarded per-listener and `emit()` never throws for a listener failure.
74
+ * Returns `void`. Every listener runs even if an earlier one throws; listener errors are reported
75
+ * through `tap` as `error` events, then the first error is rethrown after dispatch.
166
76
  */
167
- emit<K extends EventKey<T>>(event: K, ...args: T[K] extends void ? [] : [payload: T[K]]): number;
77
+ emit<K extends EventKey<T>>(event: K, ...args: T[K] extends void ? [] : [payload: T[K]]): void;
168
78
  /** Returns the list of event names that currently have at least one active listener. */
169
79
  eventNames(): EventKey<T>[];
170
- /**
171
- * Async-iterate over all future emits of an event. Terminates when the bus is disposed or signal aborts.
172
- *
173
- * @remarks **Eager subscription:** The subscription starts when `events()` is called, not when the
174
- * first iteration begins. Events emitted before the first `await` are buffered and will be yielded.
175
- *
176
- * @remarks **Buffer:** Internal buffer is unbounded by default. Pass `maxBuffer` to cap it — oldest
177
- * values are dropped when the buffer is full. Validation is synchronous: `maxBuffer ≤ 0` throws
178
- * `HeraldConfigError` at call time, before any iteration.
179
- *
180
- * @remarks **Cleanup:** Returns an `EventStream` — use `await using` for guaranteed cleanup:
181
- * ```ts
182
- * await using stream = bus.events('event');
183
- * for await (const val of stream) { ... }
184
- * ```
185
- */
186
- events<K extends EventKey<T>>(event: K, options?: {
187
- maxBuffer?: number;
188
- signal?: AbortSignal;
189
- }): EventStream<T[K]>;
190
80
  /**
191
81
  * Number of active specific-event listeners for a given event key.
192
82
  * Does not include wildcard (`onAny`) listeners — use `wildcardCount()` for those.
@@ -198,27 +88,15 @@ export type Bus<T extends EventMap> = {
198
88
  *
199
89
  * - `opts.signal` — auto-unsubscribe when the signal aborts.
200
90
  * - `opts.once` — auto-unsubscribe after the first invocation (equivalent to `bus.once()`).
201
- *
202
- * The same listener function can be registered multiple times — each registration is independent
203
- * and receives its own unsubscribe handle.
204
91
  */
205
92
  on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): Unsubscribe;
206
93
  /**
207
94
  * Subscribe to **all** events. The listener is called after event-specific listeners on every emit,
208
95
  * receiving the event name and payload. Returns an unsubscribe function.
209
- *
210
- * - `opts.signal` — auto-unsubscribe when the signal aborts.
211
- * - `opts.once` — auto-unsubscribe after the first invocation.
212
- *
213
- * Useful for cross-cutting concerns like logging, analytics, and tracing.
214
- *
215
- * @example
216
- * bus.onAny((event, payload) => logger.debug('dispatched', { event, payload }));
217
96
  */
218
97
  onAny(listener: (event: EventKey<T>, payload: unknown) => void, opts?: SubscribeOptions): Unsubscribe;
219
98
  /**
220
99
  * Subscribe once — auto-unsubscribes after the first emit. Stops early when the signal aborts.
221
- * Convenience wrapper around `bus.on(event, listener, { once: true, signal: opts?.signal })`.
222
100
  */
223
101
  once<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: {
224
102
  signal?: AbortSignal;
@@ -233,7 +111,7 @@ export type Bus<T extends EventMap> = {
233
111
  }): Promise<T[K]>;
234
112
  /**
235
113
  * Resolve when any of the listed events (minimum 2) fires first.
236
- * Returns a typed `{ event, payload }` discriminated union — the winning event name is narrowed to a literal.
114
+ * Returns a typed `{ event, payload }` discriminated union.
237
115
  * Rejects with `BusDisposedError` if the bus is disposed, or with the signal's reason if the signal aborts.
238
116
  */
239
117
  waitAny<const K extends readonly [EventKey<T>, EventKey<T>, ...EventKey<T>[]]>(events: K, opts?: {
@@ -241,15 +119,11 @@ export type Bus<T extends EventMap> = {
241
119
  }): Promise<WaitAnyResult<T, K>>;
242
120
  /**
243
121
  * Number of active wildcard (`onAny`) listeners.
244
- * These fire on every emission regardless of event key.
245
122
  */
246
123
  wildcardCount(): number;
247
124
  /**
248
- * Observe runtime events (emit, subscribe, unsubscribe, listener-error, dispose) without
125
+ * Observe runtime events (emit, subscribe, unsubscribe, error, dispose) without
249
126
  * affecting bus behavior. Handler errors are swallowed. Returns an unsubscribe function.
250
- *
251
- * @example
252
- * bus.tap((event) => console.debug(`herald:${event.type}`, event));
253
127
  */
254
128
  tap(handler: (event: HeraldEvent<T>) => void, options?: {
255
129
  signal?: AbortSignal;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vielzeug/herald",
3
- "version": "2.3.0",
3
+ "version": "3.0.0",
4
4
  "description": "Typed event bus — pub/sub with namespaces, wildcards, and once-listeners",
5
5
  "repository": {
6
6
  "type": "git",
@@ -43,19 +43,19 @@
43
43
  },
44
44
  "scripts": {
45
45
  "bench": "vitest bench",
46
- "build": "vite build && pnpm run build:bundle && pnpm run build:types",
46
+ "build": "vite build && pnpm --silent run build:bundle && pnpm --silent run build:types",
47
47
  "build:bundle": "vite build --config vite.bundle.config.ts",
48
48
  "build:types": "tsc -p tsconfig.declarations.json",
49
49
  "fix": "biome check --write src",
50
50
  "lint": "biome ci src",
51
- "prepublishOnly": "pnpm run build",
51
+ "prepublishOnly": "pnpm --silent run build",
52
52
  "preview": "vite preview",
53
53
  "test": "vitest"
54
54
  },
55
55
  "devDependencies": {
56
- "@types/node": "^26.2.0",
56
+ "@types/node": "^26.4.1",
57
57
  "typescript": "^6.0.3",
58
- "vite": "^8.2.1",
59
- "vitest": "^4.1.10"
58
+ "vite": "^8.2.2",
59
+ "vitest": "^5.0.0"
60
60
  }
61
61
  }
package/dist/_safe.cjs DELETED
@@ -1,2 +0,0 @@
1
- function e(e,t){try{return e(),{threw:!1}}catch(e){return t?(t(e),{threw:!1}):{err:e,threw:!0}}}exports.callSafely=e;
2
- //# sourceMappingURL=_safe.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"_safe.cjs","names":[],"sources":["../src/_safe.ts"],"sourcesContent":["/**\n * Result of a {@link callSafely} invocation. Discriminated on `threw` so a caller can tell\n * \"didn't throw\" apart from \"threw `undefined`\" — inspecting `err` alone can't make that call.\n *\n * @internal\n */\nexport type SafeCallResult = { err: unknown; threw: true } | { threw: false };\n\n/**\n * Calls `fn()`, guarding against a throw.\n *\n * - If `fn()` throws and `onError` is provided, forwards the error to `onError` and reports\n * `{ threw: false }` — the caller treats this call as handled.\n * - If `fn()` throws and no `onError` is provided, the error is **not** rethrown here — it is\n * returned as `{ threw: true, err }` so the caller can decide when (or whether) to rethrow,\n * e.g. after finishing a batch of independent calls.\n *\n * @internal\n */\nexport function callSafely(fn: () => void, onError?: (err: unknown) => void): SafeCallResult {\n try {\n fn();\n\n return { threw: false };\n } catch (err) {\n if (onError) {\n onError(err);\n\n return { threw: false };\n }\n\n return { err, threw: true };\n }\n}\n"],"mappings":"AAmBA,SAAgB,EAAW,EAAgB,EAAkD,CAC3F,GAAI,CAGF,OAFA,EAAG,EAEI,CAAE,MAAO,EAAM,CACxB,OAAS,EAAK,CAOZ,OANI,GACF,EAAQ,CAAG,EAEJ,CAAE,MAAO,EAAM,GAGjB,CAAE,MAAK,MAAO,EAAK,CAC5B,CACF"}
package/dist/_safe.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=_safe.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"_safe.d.ts","sourceRoot":"","sources":["../src/_safe.ts"],"names":[],"mappings":""}
package/dist/_safe.js DELETED
@@ -1,15 +0,0 @@
1
- //#region src/_safe.ts
2
- function e(e, t) {
3
- try {
4
- return e(), { threw: !1 };
5
- } catch (e) {
6
- return t ? (t(e), { threw: !1 }) : {
7
- err: e,
8
- threw: !0
9
- };
10
- }
11
- }
12
- //#endregion
13
- export { e as callSafely };
14
-
15
- //# sourceMappingURL=_safe.js.map
package/dist/_safe.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"_safe.js","names":[],"sources":["../src/_safe.ts"],"sourcesContent":["/**\n * Result of a {@link callSafely} invocation. Discriminated on `threw` so a caller can tell\n * \"didn't throw\" apart from \"threw `undefined`\" — inspecting `err` alone can't make that call.\n *\n * @internal\n */\nexport type SafeCallResult = { err: unknown; threw: true } | { threw: false };\n\n/**\n * Calls `fn()`, guarding against a throw.\n *\n * - If `fn()` throws and `onError` is provided, forwards the error to `onError` and reports\n * `{ threw: false }` — the caller treats this call as handled.\n * - If `fn()` throws and no `onError` is provided, the error is **not** rethrown here — it is\n * returned as `{ threw: true, err }` so the caller can decide when (or whether) to rethrow,\n * e.g. after finishing a batch of independent calls.\n *\n * @internal\n */\nexport function callSafely(fn: () => void, onError?: (err: unknown) => void): SafeCallResult {\n try {\n fn();\n\n return { threw: false };\n } catch (err) {\n if (onError) {\n onError(err);\n\n return { threw: false };\n }\n\n return { err, threw: true };\n }\n}\n"],"mappings":";AAmBA,SAAgB,EAAW,GAAgB,GAAkD;CAC3F,IAAI;EAGF,OAFA,EAAG,GAEI,EAAE,OAAO,GAAM;CACxB,SAAS,GAAK;EAOZ,OANI,KACF,EAAQ,CAAG,GAEJ,EAAE,OAAO,GAAM,KAGjB;GAAE;GAAK,OAAO;EAAK;CAC5B;AACF"}
package/dist/pipe.cjs DELETED
@@ -1,2 +0,0 @@
1
- const e=require("./errors.cjs");function t(t,n,r,i){if(r.length===0)throw new e.HeraldConfigError(`pipeEvents() requires at least one entry`);let a=[t.disposalSignal,n.disposalSignal];i?.signal&&a.push(i.signal);let o=AbortSignal.any(a),s=n.emit,c=r.map(e=>{if(typeof e==`string`){let n=e;return t.on(n,e=>s(n,e),{signal:o})}let{from:n,to:r}=e;return t.on(n,e=>s(r,e),{signal:o})});return()=>{for(let e of c)e()}}exports.pipeEvents=t;
2
- //# sourceMappingURL=pipe.cjs.map
package/dist/pipe.cjs.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"pipe.cjs","names":[],"sources":["../src/pipe.ts"],"sourcesContent":["import { HeraldConfigError } from './errors';\nimport type { Bus, EventKey, EventMap, PipeableKey, PipeEntry, Unsubscribe } from './types';\n\n/**\n * Forward selected events from `source` to `target`.\n *\n * Each entry in the `entries` array is either:\n * - A **string key** — forward the event under the same name. Source and target need not share the\n * same event map type; only the listed keys must exist in both with compatible payload types.\n * - A **`{ from, to }` object** — forward the event under a different name on the target bus,\n * enabling cross-domain event translation.\n *\n * The pipe tears down automatically when either bus is disposed, or when the provided `signal`\n * aborts. Call the returned function to stop piping manually at any time.\n *\n * @example\n * const unpipe = pipeEvents(featureBus, auditBus, ['user:login', 'user:logout']);\n * unpipe(); // stop piping\n *\n * @example\n * pipeEvents(authBus, appBus, [{ from: 'auth:login', to: 'user:authenticated' }]);\n */\nexport function pipeEvents<S extends EventMap, T extends EventMap>(\n source: Bus<S>,\n target: Bus<T>,\n entries: readonly [NoInfer<PipeEntry<S, T>>, ...NoInfer<PipeEntry<S, T>>[]],\n opts?: { signal?: AbortSignal },\n): Unsubscribe {\n if (entries.length === 0) throw new HeraldConfigError('pipeEvents() requires at least one entry');\n\n const signals: AbortSignal[] = [source.disposalSignal, target.disposalSignal];\n\n if (opts?.signal) signals.push(opts.signal);\n\n const signal = AbortSignal.any(signals);\n\n // Cast needed: emit's conditional rest args (void vs payload) cannot be resolved in a generic\n // context. At runtime, passing undefined for void events is safe — the bus ignores it.\n const emitTarget = target.emit as unknown as (event: EventKey<T>, payload?: unknown) => void;\n\n const unsubs = entries.map((entry) => {\n if (typeof entry === 'string') {\n const key = entry as PipeableKey<S, T>;\n\n return source.on(key as EventKey<S>, (payload) => emitTarget(key as unknown as EventKey<T>, payload), {\n signal,\n });\n }\n\n const { from, to } = entry as { from: EventKey<S>; to: EventKey<T> };\n\n return source.on(from, (payload) => emitTarget(to, payload), { signal });\n });\n\n return () => {\n for (const unsub of unsubs) unsub();\n };\n}\n"],"mappings":"gCAsBA,SAAgB,EACd,EACA,EACA,EACA,EACa,CACb,GAAI,EAAQ,SAAW,EAAG,MAAM,IAAI,EAAA,kBAAkB,0CAA0C,EAEhG,IAAM,EAAyB,CAAC,EAAO,eAAgB,EAAO,cAAc,EAExE,GAAM,QAAQ,EAAQ,KAAK,EAAK,MAAM,EAE1C,IAAM,EAAS,YAAY,IAAI,CAAO,EAIhC,EAAa,EAAO,KAEpB,EAAS,EAAQ,IAAK,GAAU,CACpC,GAAI,OAAO,GAAU,SAAU,CAC7B,IAAM,EAAM,EAEZ,OAAO,EAAO,GAAG,EAAqB,GAAY,EAAW,EAA+B,CAAO,EAAG,CACpG,QACF,CAAC,CACH,CAEA,GAAM,CAAE,OAAM,MAAO,EAErB,OAAO,EAAO,GAAG,EAAO,GAAY,EAAW,EAAI,CAAO,EAAG,CAAE,QAAO,CAAC,CACzE,CAAC,EAED,UAAa,CACX,IAAK,IAAM,KAAS,EAAQ,EAAM,CACpC,CACF"}
package/dist/pipe.d.ts DELETED
@@ -1,24 +0,0 @@
1
- import type { Bus, EventMap, PipeEntry, Unsubscribe } from './types';
2
- /**
3
- * Forward selected events from `source` to `target`.
4
- *
5
- * Each entry in the `entries` array is either:
6
- * - A **string key** — forward the event under the same name. Source and target need not share the
7
- * same event map type; only the listed keys must exist in both with compatible payload types.
8
- * - A **`{ from, to }` object** — forward the event under a different name on the target bus,
9
- * enabling cross-domain event translation.
10
- *
11
- * The pipe tears down automatically when either bus is disposed, or when the provided `signal`
12
- * aborts. Call the returned function to stop piping manually at any time.
13
- *
14
- * @example
15
- * const unpipe = pipeEvents(featureBus, auditBus, ['user:login', 'user:logout']);
16
- * unpipe(); // stop piping
17
- *
18
- * @example
19
- * pipeEvents(authBus, appBus, [{ from: 'auth:login', to: 'user:authenticated' }]);
20
- */
21
- export declare function pipeEvents<S extends EventMap, T extends EventMap>(source: Bus<S>, target: Bus<T>, entries: readonly [NoInfer<PipeEntry<S, T>>, ...NoInfer<PipeEntry<S, T>>[]], opts?: {
22
- signal?: AbortSignal;
23
- }): Unsubscribe;
24
- //# sourceMappingURL=pipe.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pipe.d.ts","sourceRoot":"","sources":["../src/pipe.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAY,QAAQ,EAAe,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE5F;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EAC/D,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,EACd,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,EACd,OAAO,EAAE,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAC3E,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,GAC9B,WAAW,CA8Bb"}
package/dist/pipe.js DELETED
@@ -1,22 +0,0 @@
1
- import { HeraldConfigError as e } from "./errors.js";
2
- //#region src/pipe.ts
3
- function t(t, n, r, i) {
4
- if (r.length === 0) throw new e("pipeEvents() requires at least one entry");
5
- let a = [t.disposalSignal, n.disposalSignal];
6
- i?.signal && a.push(i.signal);
7
- let o = AbortSignal.any(a), s = n.emit, c = r.map((e) => {
8
- if (typeof e == "string") {
9
- let n = e;
10
- return t.on(n, (e) => s(n, e), { signal: o });
11
- }
12
- let { from: n, to: r } = e;
13
- return t.on(n, (e) => s(r, e), { signal: o });
14
- });
15
- return () => {
16
- for (let e of c) e();
17
- };
18
- }
19
- //#endregion
20
- export { t as pipeEvents };
21
-
22
- //# sourceMappingURL=pipe.js.map
package/dist/pipe.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"pipe.js","names":[],"sources":["../src/pipe.ts"],"sourcesContent":["import { HeraldConfigError } from './errors';\nimport type { Bus, EventKey, EventMap, PipeableKey, PipeEntry, Unsubscribe } from './types';\n\n/**\n * Forward selected events from `source` to `target`.\n *\n * Each entry in the `entries` array is either:\n * - A **string key** — forward the event under the same name. Source and target need not share the\n * same event map type; only the listed keys must exist in both with compatible payload types.\n * - A **`{ from, to }` object** — forward the event under a different name on the target bus,\n * enabling cross-domain event translation.\n *\n * The pipe tears down automatically when either bus is disposed, or when the provided `signal`\n * aborts. Call the returned function to stop piping manually at any time.\n *\n * @example\n * const unpipe = pipeEvents(featureBus, auditBus, ['user:login', 'user:logout']);\n * unpipe(); // stop piping\n *\n * @example\n * pipeEvents(authBus, appBus, [{ from: 'auth:login', to: 'user:authenticated' }]);\n */\nexport function pipeEvents<S extends EventMap, T extends EventMap>(\n source: Bus<S>,\n target: Bus<T>,\n entries: readonly [NoInfer<PipeEntry<S, T>>, ...NoInfer<PipeEntry<S, T>>[]],\n opts?: { signal?: AbortSignal },\n): Unsubscribe {\n if (entries.length === 0) throw new HeraldConfigError('pipeEvents() requires at least one entry');\n\n const signals: AbortSignal[] = [source.disposalSignal, target.disposalSignal];\n\n if (opts?.signal) signals.push(opts.signal);\n\n const signal = AbortSignal.any(signals);\n\n // Cast needed: emit's conditional rest args (void vs payload) cannot be resolved in a generic\n // context. At runtime, passing undefined for void events is safe — the bus ignores it.\n const emitTarget = target.emit as unknown as (event: EventKey<T>, payload?: unknown) => void;\n\n const unsubs = entries.map((entry) => {\n if (typeof entry === 'string') {\n const key = entry as PipeableKey<S, T>;\n\n return source.on(key as EventKey<S>, (payload) => emitTarget(key as unknown as EventKey<T>, payload), {\n signal,\n });\n }\n\n const { from, to } = entry as { from: EventKey<S>; to: EventKey<T> };\n\n return source.on(from, (payload) => emitTarget(to, payload), { signal });\n });\n\n return () => {\n for (const unsub of unsubs) unsub();\n };\n}\n"],"mappings":";;AAsBA,SAAgB,EACd,GACA,GACA,GACA,GACa;CACb,IAAI,EAAQ,WAAW,GAAG,MAAM,IAAI,EAAkB,0CAA0C;CAEhG,IAAM,IAAyB,CAAC,EAAO,gBAAgB,EAAO,cAAc;CAE5E,AAAI,GAAM,UAAQ,EAAQ,KAAK,EAAK,MAAM;CAE1C,IAAM,IAAS,YAAY,IAAI,CAAO,GAIhC,IAAa,EAAO,MAEpB,IAAS,EAAQ,KAAK,MAAU;EACpC,IAAI,OAAO,KAAU,UAAU;GAC7B,IAAM,IAAM;GAEZ,OAAO,EAAO,GAAG,IAAqB,MAAY,EAAW,GAA+B,CAAO,GAAG,EACpG,UACF,CAAC;EACH;EAEA,IAAM,EAAE,SAAM,UAAO;EAErB,OAAO,EAAO,GAAG,IAAO,MAAY,EAAW,GAAI,CAAO,GAAG,EAAE,UAAO,CAAC;CACzE,CAAC;CAED,aAAa;EACX,KAAK,IAAM,KAAS,GAAQ,EAAM;CACpC;AACF"}