@vielzeug/herald 2.2.0 → 2.3.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/bus.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bus.js","names":[],"sources":["../src/bus.ts"],"sourcesContent":["import { warn as _internalWarn } from './_dev';\nimport { callSafely, type SafeCallResult } from './_safe';\nimport { BusDisposedError, HeraldConfigError } from './errors';\nimport type {\n Bus,\n BusOptions,\n EmissionErrorContext,\n EventKey,\n EventMap,\n EventStream,\n HeraldEvent,\n Listener,\n SubscribeOptions,\n Unsubscribe,\n WaitAnyResult,\n} from './types';\n\n// Module-scoped noop — shared across all bus instances to avoid per-bus allocation.\n// @internal — exported only for sibling internal modules; stripped from public declarations via stripInternal.\n/** @internal */\nexport const noop = () => {};\n\n/** @internal */\nexport type SignalScope = { dispose(): void; signal: AbortSignal };\n\n/** @internal */\nexport function createSignalScope(...candidates: Array<AbortSignal | undefined>): SignalScope {\n const signals = candidates.filter((signal): signal is AbortSignal => signal !== undefined);\n\n if (signals.length === 1) return { dispose: noop, signal: signals[0]! };\n\n const aborted = signals.find((signal) => signal.aborted);\n\n if (aborted) return { dispose: noop, signal: aborted };\n\n const controller = new AbortController();\n const listeners = new Map<AbortSignal, () => void>();\n let disposed = false;\n\n function dispose(): void {\n if (disposed) return;\n\n disposed = true;\n for (const [signal, listener] of listeners) signal.removeEventListener('abort', listener);\n listeners.clear();\n }\n\n for (const signal of signals) {\n const listener = () => {\n controller.abort(signal.reason);\n dispose();\n };\n\n listeners.set(signal, listener);\n signal.addEventListener('abort', listener, { once: true });\n }\n\n return { dispose, signal: controller.signal };\n}\n\n/**\n * Returns a signal that aborts as soon as any provided signal aborts.\n * Input listeners remain active until one input aborts; use signal-owning APIs for early cleanup.\n */\nexport function combineSignals(first: AbortSignal, ...rest: AbortSignal[]): AbortSignal {\n return createSignalScope(first, ...rest).signal;\n}\n\n// Each registration gets a unique Entry object, allowing the same listener function\n// to be registered multiple times independently (aligns with Node EventEmitter / mitt).\ntype Entry = { fn: Listener<unknown>; unsub: () => void };\ntype WildcardEntry = { fn: (event: string, payload: unknown) => void; unsub: () => void };\n\ntype RegisterEntryOpts<T extends EventMap> = {\n event?: EventKey<T>;\n onLog: string;\n onRemove?: () => void;\n wildcard?: boolean;\n};\n\n// makeEventStream wraps an AsyncGenerator with AsyncDisposable.\nfunction makeEventStream<V>(gen: AsyncGenerator<V>, onDispose: () => Promise<void>): EventStream<V> {\n return Object.assign(gen, {\n [Symbol.asyncDispose]: onDispose,\n }) as unknown as EventStream<V>;\n}\n\n/** @internal */\nexport type InternalBusOptions<T extends EventMap> = BusOptions<T> & {\n /** @internal Called after middleware passes, before listeners run. Used by TestBus. */\n _onDispatch?: (event: EventKey<T>, payload: unknown) => void;\n};\n\nexport function createBus<T extends EventMap = Record<string, unknown>>(options?: BusOptions<T>): Bus<T> {\n return createBusInternal(options);\n}\n\n/** @internal */\nexport function createBusInternal<T extends EventMap = Record<string, unknown>>(\n options?: InternalBusOptions<T>,\n): Bus<T> {\n // Per-event set of Entry objects. Set identity prevents accidental dedup of entries;\n // the same fn can appear in multiple entries with independent lifetimes.\n const listeners = new Map<string, Set<Entry>>();\n const wildcards = new Set<WildcardEntry>();\n const tappers = new Set<(event: HeraldEvent<T>) => void>();\n const disposeController = new AbortController();\n const busName = options?.name;\n const maxListeners = options?.maxListeners;\n const busTag = busName ? ` (${busName})` : '';\n\n function emitTap(event: HeraldEvent<T>): void {\n if (tappers.size === 0) return;\n for (const tapper of tappers) {\n try {\n tapper(event);\n } catch {\n // Observability must not affect bus behavior.\n }\n }\n }\n\n function doWarn(msg: string): void {\n _internalWarn(msg);\n }\n\n function createSubscriptionScope(signal?: AbortSignal): SignalScope {\n return signal\n ? createSignalScope(disposeController.signal, signal)\n : { dispose: noop, signal: disposeController.signal };\n }\n\n // callSafe is defined once per bus (not per emit) — avoids re-allocating on every emission.\n // Captures options.onError via closure. Used in emit() for both specific and wildcard loops.\n // Does not rethrow directly — see dispatch(), which continues the broadcast to every remaining\n // listener (including wildcards) before rethrowing the first captured error, if any.\n function callSafe(fn: () => void, event: EventKey<T>, payload: unknown, timestamp: number): SafeCallResult {\n const onError = options?.onError\n ? (err: unknown) => options.onError?.({ err, event, payload, timestamp } as EmissionErrorContext<T>)\n : undefined;\n\n return callSafely(fn, onError);\n }\n\n // registerEntry opts object — self-documenting call sites.\n function registerEntry<E extends { unsub: () => void }>(\n container: Set<E>,\n makeEntry: (unsub: () => void) => E,\n signal: AbortSignal,\n { event, onLog, onRemove, wildcard }: RegisterEntryOpts<T>,\n ): () => void {\n if (signal.aborted) return noop;\n\n // Boolean guard makes unsub idempotent — a second call after re-registration would\n // otherwise see an empty container and incorrectly delete the outer map entry.\n let called = false;\n\n function unsub() {\n if (called) return;\n\n called = true;\n container.delete(entry);\n onRemove?.();\n signal.removeEventListener('abort', unsub);\n\n if (event !== undefined) emitTap({ event, type: 'unsubscribe' });\n else if (wildcard) emitTap({ type: 'unsubscribe-any' });\n }\n\n // Function declaration is hoisted so `entry` can reference `unsub` directly.\n const entry = makeEntry(unsub);\n\n container.add(entry);\n signal.addEventListener('abort', unsub, { once: true });\n\n if (event !== undefined) emitTap({ event, type: 'subscribe' });\n else if (wildcard) emitTap({ type: 'subscribe-any' });\n\n if (maxListeners !== undefined && container.size > maxListeners) {\n doWarn(\n `${onLog} has ${container.size} listeners, exceeding maxListeners (${maxListeners}). Possible memory leak.${busTag}`,\n );\n }\n\n return unsub;\n }\n\n function onWithSignal<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n let set = listeners.get(event);\n\n if (!set) {\n set = new Set();\n listeners.set(event, set);\n }\n\n // Capture the set reference so unsub can safely delete from it even after\n // the event key has been removed from the outer map.\n const capturedSet = set;\n\n return registerEntry(capturedSet, (unsub) => ({ fn: listener as Listener<unknown>, unsub }), signal, {\n event,\n onLog: `on(\"${event}\")`,\n onRemove: () => {\n if (capturedSet.size === 0) listeners.delete(event);\n\n onRemove?.();\n },\n });\n }\n\n function onAnyWithSignal(\n listener: (event: EventKey<T>, payload: unknown) => void,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n return registerEntry(\n wildcards,\n (unsub) => ({ fn: listener as (event: string, payload: unknown) => void, unsub }),\n signal,\n { onLog: 'onAny', onRemove, wildcard: true },\n );\n }\n\n // Use a const ref object to hold the unsub handle — avoids the forward-reference that\n // TypeScript cannot prove safe with `const unsub = f(() => unsub)`. The `ref` binding never\n // changes (only its property is mutated), satisfying prefer-const. By the time the inner\n // callback fires (only possible after onWithSignal returns), ref.unsub is the real handle.\n function onceWithSignal<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n const ref = { unsub: noop as Unsubscribe };\n\n ref.unsub = onWithSignal(\n event,\n (payload) => {\n ref.unsub();\n listener(payload);\n },\n signal,\n onRemove,\n );\n\n return ref.unsub;\n }\n\n // onAny with once — fires the wildcard listener exactly once, then auto-removes.\n function onAnyWithOnce(\n listener: (event: EventKey<T>, payload: unknown) => void,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n const ref = { unsub: noop as Unsubscribe };\n\n ref.unsub = onAnyWithSignal(\n (event, payload) => {\n ref.unsub();\n listener(event, payload);\n },\n signal,\n onRemove,\n );\n\n return ref.unsub;\n }\n\n function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): () => void {\n const scope = createSubscriptionScope(opts?.signal);\n\n if (opts?.once) return onceWithSignal(event, listener, scope.signal, scope.dispose);\n\n return onWithSignal(event, listener, scope.signal, scope.dispose);\n }\n\n function once<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n opts?: { signal?: AbortSignal },\n ): () => void {\n const scope = createSubscriptionScope(opts?.signal);\n\n return onceWithSignal(event, listener, scope.signal, scope.dispose);\n }\n\n function onAny(listener: (event: EventKey<T>, payload: unknown) => void, opts?: SubscribeOptions): () => void {\n const scope = createSubscriptionScope(opts?.signal);\n\n if (opts?.once) return onAnyWithOnce(listener, scope.signal, scope.dispose);\n\n return onAnyWithSignal(listener, scope.signal, scope.dispose);\n }\n\n function wait<K extends EventKey<T>>(event: K, opts?: { signal?: AbortSignal }): Promise<T[K]> {\n const scope = createSubscriptionScope(opts?.signal);\n\n if (scope.signal.aborted) return Promise.reject(scope.signal.reason);\n\n return new Promise<T[K]>((resolve, reject) => {\n const onAbort = () => {\n scope.dispose();\n reject(scope.signal.reason);\n };\n\n onceWithSignal(\n event,\n (payload) => {\n scope.signal.removeEventListener('abort', onAbort);\n scope.dispose();\n resolve(payload);\n },\n scope.signal,\n );\n\n scope.signal.addEventListener('abort', onAbort, { once: true });\n });\n }\n\n // events() subscribes eagerly — the listener is registered when events() is called, not when\n // the first .next() runs. This ensures events emitted before iteration begins are buffered.\n // maxBuffer is validated synchronously so callers get a HeraldConfigError at call time.\n function events<K extends EventKey<T>>(\n event: K,\n opts?: { maxBuffer?: number; signal?: AbortSignal },\n ): EventStream<T[K]> {\n const maxBuffer = opts?.maxBuffer ?? Infinity;\n\n if (!(maxBuffer > 0)) throw new HeraldConfigError('maxBuffer must be a positive number');\n\n const scope = createSubscriptionScope(opts?.signal);\n const activeSignal = scope.signal;\n\n if (activeSignal.aborted) {\n const empty = (async function* (): AsyncGenerator<T[K]> {})();\n\n return makeEventStream(empty, async (): Promise<void> => {});\n }\n\n const queue: T[K][] = [];\n let wake: (() => void) | undefined;\n\n const unsub = onWithSignal(\n event,\n (payload) => {\n if (queue.length >= maxBuffer) queue.shift();\n\n queue.push(payload);\n wake?.();\n },\n activeSignal,\n scope.dispose,\n );\n\n async function* generate(): AsyncGenerator<T[K]> {\n try {\n while (!activeSignal.aborted) {\n if (queue.length) {\n yield queue.shift()!;\n continue;\n }\n\n const { promise, resolve } = Promise.withResolvers<void>();\n const abortHandler = (): void => {\n resolve();\n };\n\n wake = resolve;\n activeSignal.addEventListener('abort', abortHandler, { once: true });\n await promise;\n activeSignal.removeEventListener('abort', abortHandler);\n wake = undefined;\n }\n } finally {\n unsub();\n }\n }\n\n const gen = generate();\n\n // Symbol.asyncDispose calls unsub() directly because gen.return() only runs the finally\n // block when the generator has been started (at least one next() call). The unsub guard\n // (called = false in registerEntry) makes this idempotent.\n return makeEventStream(gen, async (): Promise<void> => {\n unsub();\n await gen.return(undefined as unknown as T[K]);\n });\n }\n\n // dispatch is defined at createBus() scope (once per bus, not per emit call) — consistent with\n // callSafe. Receives event/payload/timestamp as arguments so it can be invoked from both the\n // direct path and the middleware chain without capturing per-emit locals in a closure.\n function dispatch(event: EventKey<T>, payload: unknown, timestamp: number): number {\n options?._onDispatch?.(event, payload);\n\n let count = 0;\n let firstError: { err: unknown } | undefined;\n const set = listeners.get(event);\n\n if (set?.size) {\n for (const entry of [...set]) {\n const result = callSafe(() => entry.fn(payload), event, payload, timestamp);\n\n if (result.threw) {\n if (!firstError) firstError = { err: result.err };\n emitTap({ error: result.err, event, type: 'listener-error' });\n }\n\n count++;\n }\n }\n\n if (wildcards.size) {\n for (const entry of [...wildcards]) {\n const result = callSafe(() => entry.fn(event, payload), event, payload, timestamp);\n\n if (result.threw) {\n if (!firstError) firstError = { err: result.err };\n emitTap({ error: result.err, event, type: 'listener-error' });\n }\n\n count++;\n }\n }\n\n emitTap({ event, listeners: count, payload, type: 'emit' });\n\n if (firstError) throw firstError.err;\n\n return count;\n }\n\n // emit() returns the number of listeners invoked (specific + wildcard).\n // Returns 0 if bus is disposed, middleware blocked dispatch, or validatePayload rejected.\n // validatePayload runs first, then middleware, then listeners.\n function emit<K extends EventKey<T>>(event: K, ...args: T[K] extends void ? [] : [payload: T[K]]): number {\n if (disposeController.signal.aborted) return 0;\n\n const payload = (args as unknown[])[0];\n const timestamp = Date.now();\n\n if (options?.validatePayload) {\n try {\n options.validatePayload(event, payload as T[K]);\n } catch (err) {\n if (options?.onError) {\n options.onError({ err, event, payload, timestamp } as EmissionErrorContext<T>);\n\n return 0;\n }\n\n throw err;\n }\n }\n\n const middleware = options?.middleware;\n\n if (!middleware?.length) return dispatch(event, payload, timestamp);\n\n const middlewareList = middleware;\n\n function run(index: number): number {\n const current = middlewareList[index];\n\n if (!current) return dispatch(event, payload, timestamp);\n\n let result = 0;\n let continued = false;\n let synchronous = true;\n\n current(event, payload, () => {\n if (!synchronous || continued) return;\n\n continued = true;\n result = run(index + 1);\n });\n\n synchronous = false;\n\n return result;\n }\n\n return run(0);\n }\n\n // listenerCount counts specific-event listeners only.\n // wildcardCount() is the separate accessor for onAny listeners.\n function listenerCount(event?: EventKey<T>): number {\n if (event !== undefined) return listeners.get(event)?.size ?? 0;\n\n let total = 0;\n\n for (const set of listeners.values()) total += set.size;\n\n return total;\n }\n\n function wildcardCount(): number {\n return wildcards.size;\n }\n\n function eventNames(): EventKey<T>[] {\n return [...listeners.keys()] as EventKey<T>[];\n }\n\n function tap(handler: (event: HeraldEvent<T>) => void, opts?: { signal?: AbortSignal }): () => void {\n if (disposeController.signal.aborted) return noop;\n\n const scope = createSubscriptionScope(opts?.signal);\n\n if (scope.signal.aborted) return noop;\n\n tappers.add(handler);\n\n const onAbort = () => tappers.delete(handler);\n\n scope.signal.addEventListener('abort', onAbort, { once: true });\n\n return () => {\n tappers.delete(handler);\n scope.signal.removeEventListener('abort', onAbort);\n scope.dispose();\n };\n }\n\n function waitAny<K extends readonly [EventKey<T>, EventKey<T>, ...EventKey<T>[]]>(\n eventList: K,\n opts?: { signal?: AbortSignal },\n ): Promise<WaitAnyResult<T, K>> {\n if (eventList.length < 2) throw new HeraldConfigError('waitAny() requires at least 2 event keys');\n\n const activeScope = createSubscriptionScope(opts?.signal);\n\n if (activeScope.signal.aborted) return Promise.reject(activeScope.signal.reason);\n\n return new Promise<WaitAnyResult<T, K>>((resolve, reject) => {\n const raceController = new AbortController();\n const raceScope = createSignalScope(activeScope.signal, raceController.signal);\n const unsubs: Unsubscribe[] = [];\n let settled = false;\n\n function cleanup(): void {\n activeScope.signal.removeEventListener('abort', onAbort);\n raceController.abort();\n raceScope.dispose();\n activeScope.dispose();\n for (const unsub of unsubs) unsub();\n }\n\n function onAbort(): void {\n if (settled) return;\n\n settled = true;\n cleanup();\n reject(activeScope.signal.reason);\n }\n\n activeScope.signal.addEventListener('abort', onAbort, { once: true });\n\n for (const event of eventList) {\n unsubs.push(\n onceWithSignal(\n event as EventKey<T>,\n (payload) => {\n if (settled) return;\n\n settled = true;\n cleanup();\n resolve({ event, payload } as WaitAnyResult<T, K>);\n },\n raceScope.signal,\n ),\n );\n }\n });\n }\n\n function dispose(): void {\n if (disposeController.signal.aborted) return;\n\n // Emit dispose first — tappers are cleared by the abort cascade below,\n // so the event must fire before abort triggers their auto-cleanup.\n emitTap({ type: 'dispose' });\n disposeController.abort(new BusDisposedError(busName));\n listeners.clear();\n wildcards.clear();\n tappers.clear();\n }\n\n return {\n get disposalSignal() {\n return disposeController.signal;\n },\n dispose,\n get disposed() {\n return disposeController.signal.aborted;\n },\n emit,\n eventNames,\n events,\n listenerCount,\n on,\n onAny,\n once,\n [Symbol.dispose]: dispose,\n tap,\n wait,\n waitAny,\n wildcardCount,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"bus.js","names":[],"sources":["../src/bus.ts"],"sourcesContent":["import { warn as _internalWarn } from './_dev';\nimport { callSafely, type SafeCallResult } from './_safe';\nimport { BusDisposedError, HeraldConfigError } from './errors';\nimport type {\n Bus,\n BusOptions,\n EmissionErrorContext,\n EventKey,\n EventMap,\n EventStream,\n HeraldEvent,\n Listener,\n SubscribeOptions,\n Unsubscribe,\n WaitAnyResult,\n} from './types';\n\n// Module-scoped noop — shared across all bus instances to avoid per-bus allocation.\n/** @internal */\nexport const noop = () => {};\n\n// Each registration gets a unique Entry object, allowing the same listener function\n// to be registered multiple times independently (aligns with Node EventEmitter / mitt).\ntype Entry = { fn: Listener<unknown>; unsub: () => void };\ntype WildcardEntry = { fn: (event: string, payload: unknown) => void; unsub: () => void };\n\ntype RegisterEntryOpts<T extends EventMap> = {\n event?: EventKey<T>;\n onLog: string;\n onRemove?: () => void;\n wildcard?: boolean;\n};\n\n// makeEventStream wraps an AsyncGenerator with AsyncDisposable.\nfunction makeEventStream<V>(gen: AsyncGenerator<V>, onDispose: () => Promise<void>): EventStream<V> {\n return Object.assign(gen, {\n [Symbol.asyncDispose]: onDispose,\n }) as unknown as EventStream<V>;\n}\n\nexport function createBus<T extends EventMap = Record<string, unknown>>(options?: BusOptions<T>): Bus<T> {\n // Per-event set of Entry objects. Set identity prevents accidental dedup of entries;\n // the same fn can appear in multiple entries with independent lifetimes.\n const listeners = new Map<string, Set<Entry>>();\n const wildcards = new Set<WildcardEntry>();\n const tappers = new Set<(event: HeraldEvent<T>) => void>();\n const disposeController = new AbortController();\n const busName = options?.name;\n const maxListeners = options?.maxListeners;\n const busTag = busName ? ` (${busName})` : '';\n\n function emitTap(event: HeraldEvent<T>): void {\n if (tappers.size === 0) return;\n for (const tapper of tappers) {\n try {\n tapper(event);\n } catch {\n // Observability must not affect bus behavior.\n }\n }\n }\n\n function doWarn(msg: string): void {\n _internalWarn(msg);\n }\n\n function createSubscriptionScope(signal?: AbortSignal): AbortSignal {\n return signal ? AbortSignal.any([disposeController.signal, signal]) : disposeController.signal;\n }\n\n // callSafe is defined once per bus (not per emit) — avoids re-allocating on every emission.\n // Captures options.onError via closure. Used in emit() for both specific and wildcard loops.\n // Does not rethrow directly — see dispatch(), which continues the broadcast to every remaining\n // listener (including wildcards) before rethrowing the first captured error, if any.\n function callSafe(fn: () => void, event: EventKey<T>, payload: unknown, timestamp: number): SafeCallResult {\n const onError = options?.onError\n ? (err: unknown) => options.onError?.({ err, event, payload, timestamp } as EmissionErrorContext<T>)\n : undefined;\n\n return callSafely(fn, onError);\n }\n\n // registerEntry opts object — self-documenting call sites.\n function registerEntry<E extends { unsub: () => void }>(\n container: Set<E>,\n makeEntry: (unsub: () => void) => E,\n signal: AbortSignal,\n { event, onLog, onRemove, wildcard }: RegisterEntryOpts<T>,\n ): () => void {\n if (signal.aborted) return noop;\n\n // Boolean guard makes unsub idempotent — a second call after re-registration would\n // otherwise see an empty container and incorrectly delete the outer map entry.\n let called = false;\n\n function unsub() {\n if (called) return;\n\n called = true;\n container.delete(entry);\n onRemove?.();\n signal.removeEventListener('abort', unsub);\n\n if (event !== undefined) emitTap({ event, type: 'unsubscribe' });\n else if (wildcard) emitTap({ type: 'unsubscribe-any' });\n }\n\n // Function declaration is hoisted so `entry` can reference `unsub` directly.\n const entry = makeEntry(unsub);\n\n container.add(entry);\n signal.addEventListener('abort', unsub, { once: true });\n\n if (event !== undefined) emitTap({ event, type: 'subscribe' });\n else if (wildcard) emitTap({ type: 'subscribe-any' });\n\n if (maxListeners !== undefined && container.size > maxListeners) {\n doWarn(\n `${onLog} has ${container.size} listeners, exceeding maxListeners (${maxListeners}). Possible memory leak.${busTag}`,\n );\n }\n\n return unsub;\n }\n\n function onWithSignal<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n let set = listeners.get(event);\n\n if (!set) {\n set = new Set();\n listeners.set(event, set);\n }\n\n // Capture the set reference so unsub can safely delete from it even after\n // the event key has been removed from the outer map.\n const capturedSet = set;\n\n return registerEntry(capturedSet, (unsub) => ({ fn: listener as Listener<unknown>, unsub }), signal, {\n event,\n onLog: `on(\"${event}\")`,\n onRemove: () => {\n if (capturedSet.size === 0) listeners.delete(event);\n\n onRemove?.();\n },\n });\n }\n\n function onAnyWithSignal(\n listener: (event: EventKey<T>, payload: unknown) => void,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n return registerEntry(\n wildcards,\n (unsub) => ({ fn: listener as (event: string, payload: unknown) => void, unsub }),\n signal,\n { onLog: 'onAny', onRemove, wildcard: true },\n );\n }\n\n // Use a const ref object to hold the unsub handle — avoids the forward-reference that\n // TypeScript cannot prove safe with `const unsub = f(() => unsub)`. The `ref` binding never\n // changes (only its property is mutated), satisfying prefer-const. By the time the inner\n // callback fires (only possible after onWithSignal returns), ref.unsub is the real handle.\n function onceWithSignal<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n const ref = { unsub: noop as Unsubscribe };\n\n ref.unsub = onWithSignal(\n event,\n (payload) => {\n ref.unsub();\n listener(payload);\n },\n signal,\n onRemove,\n );\n\n return ref.unsub;\n }\n\n // onAny with once — fires the wildcard listener exactly once, then auto-removes.\n function onAnyWithOnce(\n listener: (event: EventKey<T>, payload: unknown) => void,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n const ref = { unsub: noop as Unsubscribe };\n\n ref.unsub = onAnyWithSignal(\n (event, payload) => {\n ref.unsub();\n listener(event, payload);\n },\n signal,\n onRemove,\n );\n\n return ref.unsub;\n }\n\n function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): () => void {\n const signal = createSubscriptionScope(opts?.signal);\n\n if (opts?.once) return onceWithSignal(event, listener, signal);\n\n return onWithSignal(event, listener, signal);\n }\n\n function once<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n opts?: { signal?: AbortSignal },\n ): () => void {\n const signal = createSubscriptionScope(opts?.signal);\n\n return onceWithSignal(event, listener, signal);\n }\n\n function onAny(listener: (event: EventKey<T>, payload: unknown) => void, opts?: SubscribeOptions): () => void {\n const signal = createSubscriptionScope(opts?.signal);\n\n if (opts?.once) return onAnyWithOnce(listener, signal);\n\n return onAnyWithSignal(listener, signal);\n }\n\n function wait<K extends EventKey<T>>(event: K, opts?: { signal?: AbortSignal }): Promise<T[K]> {\n const signal = createSubscriptionScope(opts?.signal);\n\n if (signal.aborted) return Promise.reject(signal.reason);\n\n return new Promise<T[K]>((resolve, reject) => {\n const onAbort = () => {\n reject(signal.reason);\n };\n\n onceWithSignal(\n event,\n (payload) => {\n signal.removeEventListener('abort', onAbort);\n resolve(payload);\n },\n signal,\n );\n\n signal.addEventListener('abort', onAbort, { once: true });\n });\n }\n\n // events() subscribes eagerly — the listener is registered when events() is called, not when\n // the first .next() runs. This ensures events emitted before iteration begins are buffered.\n // maxBuffer is validated synchronously so callers get a HeraldConfigError at call time.\n function events<K extends EventKey<T>>(\n event: K,\n opts?: { maxBuffer?: number; signal?: AbortSignal },\n ): EventStream<T[K]> {\n const maxBuffer = opts?.maxBuffer ?? Infinity;\n\n if (!(maxBuffer > 0)) throw new HeraldConfigError('maxBuffer must be a positive number');\n\n const activeSignal = createSubscriptionScope(opts?.signal);\n\n if (activeSignal.aborted) {\n const empty = (async function* (): AsyncGenerator<T[K]> {})();\n\n return makeEventStream(empty, async (): Promise<void> => {});\n }\n\n const queue: T[K][] = [];\n let wake: (() => void) | undefined;\n\n const unsub = onWithSignal(\n event,\n (payload) => {\n if (queue.length >= maxBuffer) queue.shift();\n\n queue.push(payload);\n wake?.();\n },\n activeSignal,\n undefined,\n );\n\n async function* generate(): AsyncGenerator<T[K]> {\n try {\n while (!activeSignal.aborted) {\n if (queue.length) {\n yield queue.shift()!;\n continue;\n }\n\n const { promise, resolve } = Promise.withResolvers<void>();\n const abortHandler = (): void => {\n resolve();\n };\n\n wake = resolve;\n activeSignal.addEventListener('abort', abortHandler, { once: true });\n await promise;\n activeSignal.removeEventListener('abort', abortHandler);\n wake = undefined;\n }\n } finally {\n unsub();\n }\n }\n\n const gen = generate();\n\n // Symbol.asyncDispose calls unsub() directly because gen.return() only runs the finally\n // block when the generator has been started (at least one next() call). The unsub guard\n // (called = false in registerEntry) makes this idempotent.\n return makeEventStream(gen, async (): Promise<void> => {\n unsub();\n await gen.return(undefined as unknown as T[K]);\n });\n }\n\n // dispatch is defined at createBus() scope (once per bus, not per emit call) — consistent with\n // callSafe. Receives event/payload/timestamp as arguments so it can be invoked from both the\n // direct path and the middleware chain without capturing per-emit locals in a closure.\n function dispatch(event: EventKey<T>, payload: unknown, timestamp: number): number {\n options?._onDispatch?.(event, payload);\n\n let count = 0;\n let firstError: { err: unknown } | undefined;\n const set = listeners.get(event);\n\n if (set?.size) {\n for (const entry of [...set]) {\n const result = callSafe(() => entry.fn(payload), event, payload, timestamp);\n\n if (result.threw) {\n if (!firstError) firstError = { err: result.err };\n emitTap({ error: result.err, event, type: 'listener-error' });\n }\n\n count++;\n }\n }\n\n if (wildcards.size) {\n for (const entry of [...wildcards]) {\n const result = callSafe(() => entry.fn(event, payload), event, payload, timestamp);\n\n if (result.threw) {\n if (!firstError) firstError = { err: result.err };\n emitTap({ error: result.err, event, type: 'listener-error' });\n }\n\n count++;\n }\n }\n\n emitTap({ event, listeners: count, payload, type: 'emit' });\n\n if (firstError) throw firstError.err;\n\n return count;\n }\n\n // emit() returns the number of listeners invoked (specific + wildcard).\n // Returns 0 if bus is disposed, middleware blocked dispatch, or validatePayload rejected.\n // validatePayload runs first, then middleware, then listeners.\n function emit<K extends EventKey<T>>(event: K, ...args: T[K] extends void ? [] : [payload: T[K]]): number {\n if (disposeController.signal.aborted) return 0;\n\n const payload = (args as unknown[])[0];\n const timestamp = Date.now();\n\n if (options?.validatePayload) {\n try {\n options.validatePayload(event, payload as T[K]);\n } catch (err) {\n if (options?.onError) {\n options.onError({ err, event, payload, timestamp } as EmissionErrorContext<T>);\n\n return 0;\n }\n\n throw err;\n }\n }\n\n const middleware = options?.middleware;\n\n if (!middleware?.length) return dispatch(event, payload, timestamp);\n\n const middlewareList = middleware;\n\n function run(index: number): number {\n const current = middlewareList[index];\n\n if (!current) return dispatch(event, payload, timestamp);\n\n let result = 0;\n let continued = false;\n let synchronous = true;\n\n current(event, payload, () => {\n if (!synchronous || continued) return;\n\n continued = true;\n result = run(index + 1);\n });\n\n synchronous = false;\n\n return result;\n }\n\n return run(0);\n }\n\n // listenerCount counts specific-event listeners only.\n // wildcardCount() is the separate accessor for onAny listeners.\n function listenerCount(event?: EventKey<T>): number {\n if (event !== undefined) return listeners.get(event)?.size ?? 0;\n\n let total = 0;\n\n for (const set of listeners.values()) total += set.size;\n\n return total;\n }\n\n function wildcardCount(): number {\n return wildcards.size;\n }\n\n function eventNames(): EventKey<T>[] {\n return [...listeners.keys()] as EventKey<T>[];\n }\n\n function tap(handler: (event: HeraldEvent<T>) => void, opts?: { signal?: AbortSignal }): () => void {\n if (disposeController.signal.aborted) return noop;\n\n const signal = createSubscriptionScope(opts?.signal);\n\n if (signal.aborted) return noop;\n\n tappers.add(handler);\n\n const onAbort = () => tappers.delete(handler);\n\n signal.addEventListener('abort', onAbort, { once: true });\n\n return () => {\n tappers.delete(handler);\n signal.removeEventListener('abort', onAbort);\n };\n }\n\n function waitAny<K extends readonly [EventKey<T>, EventKey<T>, ...EventKey<T>[]]>(\n eventList: K,\n opts?: { signal?: AbortSignal },\n ): Promise<WaitAnyResult<T, K>> {\n if (eventList.length < 2) throw new HeraldConfigError('waitAny() requires at least 2 event keys');\n\n const activeSignal = createSubscriptionScope(opts?.signal);\n\n if (activeSignal.aborted) return Promise.reject(activeSignal.reason);\n\n return new Promise<WaitAnyResult<T, K>>((resolve, reject) => {\n const raceController = new AbortController();\n const raceSignal = AbortSignal.any([activeSignal, raceController.signal]);\n const unsubs: Unsubscribe[] = [];\n let settled = false;\n\n function cleanup(): void {\n activeSignal.removeEventListener('abort', onAbort);\n raceController.abort();\n for (const unsub of unsubs) unsub();\n }\n\n function onAbort(): void {\n if (settled) return;\n\n settled = true;\n cleanup();\n reject(activeSignal.reason);\n }\n\n activeSignal.addEventListener('abort', onAbort, { once: true });\n\n for (const event of eventList) {\n unsubs.push(\n onceWithSignal(\n event as EventKey<T>,\n (payload) => {\n if (settled) return;\n\n settled = true;\n cleanup();\n resolve({ event, payload } as WaitAnyResult<T, K>);\n },\n raceSignal,\n ),\n );\n }\n });\n }\n\n function dispose(): void {\n if (disposeController.signal.aborted) return;\n\n // Emit dispose first — tappers are cleared by the abort cascade below,\n // so the event must fire before abort triggers their auto-cleanup.\n emitTap({ type: 'dispose' });\n disposeController.abort(new BusDisposedError(busName));\n listeners.clear();\n wildcards.clear();\n tappers.clear();\n }\n\n return {\n get disposalSignal() {\n return disposeController.signal;\n },\n dispose,\n get disposed() {\n return disposeController.signal.aborted;\n },\n emit,\n eventNames,\n events,\n listenerCount,\n on,\n onAny,\n once,\n [Symbol.dispose]: dispose,\n tap,\n wait,\n waitAny,\n wildcardCount,\n };\n}\n"],"mappings":"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"}
package/dist/herald.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e,t){try{return e(),{threw:!1}}catch(e){return t?(t(e),{threw:!1}):{err:e,threw:!0}}}var t=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},n=class extends t{constructor(e){super(e?`Bus "${e}" is disposed`:`Bus is disposed`)}},r=class extends t{},i=()=>{};function a(...e){let t=e.filter(e=>e!==void 0);if(t.length===1)return{dispose:i,signal:t[0]};let n=t.find(e=>e.aborted);if(n)return{dispose:i,signal:n};let r=new AbortController,a=new Map,o=!1;function s(){if(!o){o=!0;for(let[e,t]of a)e.removeEventListener(`abort`,t);a.clear()}}for(let e of t){let t=()=>{r.abort(e.reason),s()};a.set(e,t),e.addEventListener(`abort`,t,{once:!0})}return{dispose:s,signal:r.signal}}function o(e,...t){return a(e,...t).signal}function s(e,t){return Object.assign(e,{[Symbol.asyncDispose]:t})}function c(e){return l(e)}function l(t){let o=new Map,c=new Set,l=new Set,u=new AbortController,d=t?.name,f=t?.maxListeners,p=d?` (${d})`:``;function m(e){if(l.size!==0)for(let t of l)try{t(e)}catch{}}function h(e){return e?a(u.signal,e):{dispose:i,signal:u.signal}}function g(n,r,i,a){return e(n,t?.onError?e=>t.onError?.({err:e,event:r,payload:i,timestamp:a}):void 0)}function _(e,t,n,{event:r,onLog:a,onRemove:o,wildcard:s}){if(n.aborted)return i;let c=!1;function l(){c||(c=!0,e.delete(u),o?.(),n.removeEventListener(`abort`,l),r===void 0?s&&m({type:`unsubscribe-any`}):m({event:r,type:`unsubscribe`}))}let u=t(l);return e.add(u),n.addEventListener(`abort`,l,{once:!0}),r===void 0?s&&m({type:`subscribe-any`}):m({event:r,type:`subscribe`}),f!==void 0&&e.size>f&&`${a}${e.size}${f}${p}`,l}function v(e,t,n,r){let i=o.get(e);i||(i=new Set,o.set(e,i));let a=i;return _(a,e=>({fn:t,unsub:e}),n,{event:e,onLog:`on("${e}")`,onRemove:()=>{a.size===0&&o.delete(e),r?.()}})}function y(e,t,n){return _(c,t=>({fn:e,unsub:t}),t,{onLog:`onAny`,onRemove:n,wildcard:!0})}function b(e,t,n,r){let a={unsub:i};return a.unsub=v(e,e=>{a.unsub(),t(e)},n,r),a.unsub}function x(e,t,n){let r={unsub:i};return r.unsub=y((t,n)=>{r.unsub(),e(t,n)},t,n),r.unsub}function S(e,t,n){let r=h(n?.signal);return n?.once?b(e,t,r.signal,r.dispose):v(e,t,r.signal,r.dispose)}function C(e,t,n){let r=h(n?.signal);return b(e,t,r.signal,r.dispose)}function w(e,t){let n=h(t?.signal);return t?.once?x(e,n.signal,n.dispose):y(e,n.signal,n.dispose)}function T(e,t){let n=h(t?.signal);return n.signal.aborted?Promise.reject(n.signal.reason):new Promise((t,r)=>{let i=()=>{n.dispose(),r(n.signal.reason)};b(e,e=>{n.signal.removeEventListener(`abort`,i),n.dispose(),t(e)},n.signal),n.signal.addEventListener(`abort`,i,{once:!0})})}function E(e,t){let n=t?.maxBuffer??1/0;if(!(n>0))throw new r(`maxBuffer must be a positive number`);let i=h(t?.signal),a=i.signal;if(a.aborted)return s((async function*(){})(),async()=>{});let o=[],c,l=v(e,e=>{o.length>=n&&o.shift(),o.push(e),c?.()},a,i.dispose);async function*u(){try{for(;!a.aborted;){if(o.length){yield o.shift();continue}let{promise:e,resolve:t}=Promise.withResolvers(),n=()=>{t()};c=t,a.addEventListener(`abort`,n,{once:!0}),await e,a.removeEventListener(`abort`,n),c=void 0}}finally{l()}}let d=u();return s(d,async()=>{l(),await d.return(void 0)})}function D(e,n,r){t?._onDispatch?.(e,n);let i=0,a,s=o.get(e);if(s?.size)for(let t of[...s]){let o=g(()=>t.fn(n),e,n,r);o.threw&&(a||={err:o.err},m({error:o.err,event:e,type:`listener-error`})),i++}if(c.size)for(let t of[...c]){let o=g(()=>t.fn(e,n),e,n,r);o.threw&&(a||={err:o.err},m({error:o.err,event:e,type:`listener-error`})),i++}if(m({event:e,listeners:i,payload:n,type:`emit`}),a)throw a.err;return i}function O(e,...n){if(u.signal.aborted)return 0;let r=n[0],i=Date.now();if(t?.validatePayload)try{t.validatePayload(e,r)}catch(n){if(t?.onError)return t.onError({err:n,event:e,payload:r,timestamp:i}),0;throw n}let a=t?.middleware;if(!a?.length)return D(e,r,i);let o=a;function s(t){let n=o[t];if(!n)return D(e,r,i);let a=0,c=!1,l=!0;return n(e,r,()=>{!l||c||(c=!0,a=s(t+1))}),l=!1,a}return s(0)}function k(e){if(e!==void 0)return o.get(e)?.size??0;let t=0;for(let e of o.values())t+=e.size;return t}function A(){return c.size}function j(){return[...o.keys()]}function M(e,t){if(u.signal.aborted)return i;let n=h(t?.signal);if(n.signal.aborted)return i;l.add(e);let r=()=>l.delete(e);return n.signal.addEventListener(`abort`,r,{once:!0}),()=>{l.delete(e),n.signal.removeEventListener(`abort`,r),n.dispose()}}function N(e,t){if(e.length<2)throw new r(`waitAny() requires at least 2 event keys`);let n=h(t?.signal);return n.signal.aborted?Promise.reject(n.signal.reason):new Promise((t,r)=>{let i=new AbortController,o=a(n.signal,i.signal),s=[],c=!1;function l(){n.signal.removeEventListener(`abort`,u),i.abort(),o.dispose(),n.dispose();for(let e of s)e()}function u(){c||(c=!0,l(),r(n.signal.reason))}n.signal.addEventListener(`abort`,u,{once:!0});for(let n of e)s.push(b(n,e=>{c||(c=!0,l(),t({event:n,payload:e}))},o.signal))})}function P(){u.signal.aborted||(m({type:`dispose`}),u.abort(new n(d)),o.clear(),c.clear(),l.clear())}return{get disposalSignal(){return u.signal},dispose:P,get disposed(){return u.signal.aborted},emit:O,eventNames:j,events:E,listenerCount:k,on:S,onAny:w,once:C,[Symbol.dispose]:P,tap:M,wait:T,waitAny:N,wildcardCount:A}}function u(e,t,n,i){if(n.length===0)throw new r(`pipeEvents() requires at least one entry`);let o=a(e.disposalSignal,t.disposalSignal,i?.signal),s=t.emit,c=n.map(t=>{if(typeof t==`string`){let n=t;return e.on(n,e=>s(n,e),{signal:o.signal})}let{from:n,to:r}=t;return e.on(n,e=>s(r,e),{signal:o.signal})});return()=>{for(let e of c)e();o.dispose()}}exports.BusDisposedError=n,exports.HeraldConfigError=r,exports.HeraldError=t,exports.combineSignals=o,exports.createBus=c,exports.pipeEvents=u;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e,t){try{return e(),{threw:!1}}catch(e){return t?(t(e),{threw:!1}):{err:e,threw:!0}}}var t=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},n=class extends t{constructor(e){super(e?`Bus "${e}" is disposed`:`Bus is disposed`)}},r=class extends t{},i=()=>{};function a(e,t){return Object.assign(e,{[Symbol.asyncDispose]:t})}function o(t){let o=new Map,s=new Set,c=new Set,l=new AbortController,u=t?.name,d=t?.maxListeners,f=u?` (${u})`:``;function p(e){if(c.size!==0)for(let t of c)try{t(e)}catch{}}function m(e){return e?AbortSignal.any([l.signal,e]):l.signal}function h(n,r,i,a){return e(n,t?.onError?e=>t.onError?.({err:e,event:r,payload:i,timestamp:a}):void 0)}function g(e,t,n,{event:r,onLog:a,onRemove:o,wildcard:s}){if(n.aborted)return i;let c=!1;function l(){c||(c=!0,e.delete(u),o?.(),n.removeEventListener(`abort`,l),r===void 0?s&&p({type:`unsubscribe-any`}):p({event:r,type:`unsubscribe`}))}let u=t(l);return e.add(u),n.addEventListener(`abort`,l,{once:!0}),r===void 0?s&&p({type:`subscribe-any`}):p({event:r,type:`subscribe`}),d!==void 0&&e.size>d&&`${a}${e.size}${d}${f}`,l}function _(e,t,n,r){let i=o.get(e);i||(i=new Set,o.set(e,i));let a=i;return g(a,e=>({fn:t,unsub:e}),n,{event:e,onLog:`on("${e}")`,onRemove:()=>{a.size===0&&o.delete(e),r?.()}})}function v(e,t,n){return g(s,t=>({fn:e,unsub:t}),t,{onLog:`onAny`,onRemove:n,wildcard:!0})}function y(e,t,n,r){let a={unsub:i};return a.unsub=_(e,e=>{a.unsub(),t(e)},n,r),a.unsub}function b(e,t,n){let r={unsub:i};return r.unsub=v((t,n)=>{r.unsub(),e(t,n)},t,n),r.unsub}function x(e,t,n){let r=m(n?.signal);return n?.once?y(e,t,r):_(e,t,r)}function S(e,t,n){return y(e,t,m(n?.signal))}function C(e,t){let n=m(t?.signal);return t?.once?b(e,n):v(e,n)}function w(e,t){let n=m(t?.signal);return n.aborted?Promise.reject(n.reason):new Promise((t,r)=>{let i=()=>{r(n.reason)};y(e,e=>{n.removeEventListener(`abort`,i),t(e)},n),n.addEventListener(`abort`,i,{once:!0})})}function T(e,t){let n=t?.maxBuffer??1/0;if(!(n>0))throw new r(`maxBuffer must be a positive number`);let i=m(t?.signal);if(i.aborted)return a((async function*(){})(),async()=>{});let o=[],s,c=_(e,e=>{o.length>=n&&o.shift(),o.push(e),s?.()},i,void 0);async function*l(){try{for(;!i.aborted;){if(o.length){yield o.shift();continue}let{promise:e,resolve:t}=Promise.withResolvers(),n=()=>{t()};s=t,i.addEventListener(`abort`,n,{once:!0}),await e,i.removeEventListener(`abort`,n),s=void 0}}finally{c()}}let u=l();return a(u,async()=>{c(),await u.return(void 0)})}function E(e,n,r){t?._onDispatch?.(e,n);let i=0,a,c=o.get(e);if(c?.size)for(let t of[...c]){let o=h(()=>t.fn(n),e,n,r);o.threw&&(a||={err:o.err},p({error:o.err,event:e,type:`listener-error`})),i++}if(s.size)for(let t of[...s]){let o=h(()=>t.fn(e,n),e,n,r);o.threw&&(a||={err:o.err},p({error:o.err,event:e,type:`listener-error`})),i++}if(p({event:e,listeners:i,payload:n,type:`emit`}),a)throw a.err;return i}function D(e,...n){if(l.signal.aborted)return 0;let r=n[0],i=Date.now();if(t?.validatePayload)try{t.validatePayload(e,r)}catch(n){if(t?.onError)return t.onError({err:n,event:e,payload:r,timestamp:i}),0;throw n}let a=t?.middleware;if(!a?.length)return E(e,r,i);let o=a;function s(t){let n=o[t];if(!n)return E(e,r,i);let a=0,c=!1,l=!0;return n(e,r,()=>{!l||c||(c=!0,a=s(t+1))}),l=!1,a}return s(0)}function O(e){if(e!==void 0)return o.get(e)?.size??0;let t=0;for(let e of o.values())t+=e.size;return t}function k(){return s.size}function A(){return[...o.keys()]}function j(e,t){if(l.signal.aborted)return i;let n=m(t?.signal);if(n.aborted)return i;c.add(e);let r=()=>c.delete(e);return n.addEventListener(`abort`,r,{once:!0}),()=>{c.delete(e),n.removeEventListener(`abort`,r)}}function M(e,t){if(e.length<2)throw new r(`waitAny() requires at least 2 event keys`);let n=m(t?.signal);return n.aborted?Promise.reject(n.reason):new Promise((t,r)=>{let i=new AbortController,a=AbortSignal.any([n,i.signal]),o=[],s=!1;function c(){n.removeEventListener(`abort`,l),i.abort();for(let e of o)e()}function l(){s||(s=!0,c(),r(n.reason))}n.addEventListener(`abort`,l,{once:!0});for(let n of e)o.push(y(n,e=>{s||(s=!0,c(),t({event:n,payload:e}))},a))})}function N(){l.signal.aborted||(p({type:`dispose`}),l.abort(new n(u)),o.clear(),s.clear(),c.clear())}return{get disposalSignal(){return l.signal},dispose:N,get disposed(){return l.signal.aborted},emit:D,eventNames:A,events:T,listenerCount:O,on:x,onAny:C,once:S,[Symbol.dispose]:N,tap:j,wait:w,waitAny:M,wildcardCount:k}}function s(e,t,n,i){if(n.length===0)throw new r(`pipeEvents() requires at least one entry`);let a=[e.disposalSignal,t.disposalSignal];i?.signal&&a.push(i.signal);let o=AbortSignal.any(a),s=t.emit,c=n.map(t=>{if(typeof t==`string`){let n=t;return e.on(n,e=>s(n,e),{signal:o})}let{from:n,to:r}=t;return e.on(n,e=>s(r,e),{signal:o})});return()=>{for(let e of c)e()}}exports.BusDisposedError=n,exports.HeraldConfigError=r,exports.HeraldError=t,exports.createBus=o,exports.pipeEvents=s;
2
2
  //# sourceMappingURL=herald.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"herald.cjs","names":[],"sources":["../src/_dev.ts","../src/_safe.ts","../src/errors.ts","../src/bus.ts","../src/pipe.ts"],"sourcesContent":["const isDev = !(globalThis as { __HERALD_PROD__?: boolean }).__HERALD_PROD__;\n\n/** @internal @security Messages may include user-supplied data. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/herald] ${msg}`);\n}\n","/**\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","/** Base class for all herald errors. Use `instanceof HeraldError` to catch any herald-originated error. */\nexport class HeraldError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when an operation is attempted on a disposed event bus. */\nexport class BusDisposedError extends HeraldError {\n constructor(busName?: string) {\n super(busName ? `Bus \"${busName}\" is disposed` : 'Bus is disposed');\n }\n}\n\n/** Thrown when a herald API is called with invalid arguments or configuration. */\nexport class HeraldConfigError extends HeraldError {}\n","import { warn as _internalWarn } from './_dev';\nimport { callSafely, type SafeCallResult } from './_safe';\nimport { BusDisposedError, HeraldConfigError } from './errors';\nimport type {\n Bus,\n BusOptions,\n EmissionErrorContext,\n EventKey,\n EventMap,\n EventStream,\n HeraldEvent,\n Listener,\n SubscribeOptions,\n Unsubscribe,\n WaitAnyResult,\n} from './types';\n\n// Module-scoped noop — shared across all bus instances to avoid per-bus allocation.\n// @internal — exported only for sibling internal modules; stripped from public declarations via stripInternal.\n/** @internal */\nexport const noop = () => {};\n\n/** @internal */\nexport type SignalScope = { dispose(): void; signal: AbortSignal };\n\n/** @internal */\nexport function createSignalScope(...candidates: Array<AbortSignal | undefined>): SignalScope {\n const signals = candidates.filter((signal): signal is AbortSignal => signal !== undefined);\n\n if (signals.length === 1) return { dispose: noop, signal: signals[0]! };\n\n const aborted = signals.find((signal) => signal.aborted);\n\n if (aborted) return { dispose: noop, signal: aborted };\n\n const controller = new AbortController();\n const listeners = new Map<AbortSignal, () => void>();\n let disposed = false;\n\n function dispose(): void {\n if (disposed) return;\n\n disposed = true;\n for (const [signal, listener] of listeners) signal.removeEventListener('abort', listener);\n listeners.clear();\n }\n\n for (const signal of signals) {\n const listener = () => {\n controller.abort(signal.reason);\n dispose();\n };\n\n listeners.set(signal, listener);\n signal.addEventListener('abort', listener, { once: true });\n }\n\n return { dispose, signal: controller.signal };\n}\n\n/**\n * Returns a signal that aborts as soon as any provided signal aborts.\n * Input listeners remain active until one input aborts; use signal-owning APIs for early cleanup.\n */\nexport function combineSignals(first: AbortSignal, ...rest: AbortSignal[]): AbortSignal {\n return createSignalScope(first, ...rest).signal;\n}\n\n// Each registration gets a unique Entry object, allowing the same listener function\n// to be registered multiple times independently (aligns with Node EventEmitter / mitt).\ntype Entry = { fn: Listener<unknown>; unsub: () => void };\ntype WildcardEntry = { fn: (event: string, payload: unknown) => void; unsub: () => void };\n\ntype RegisterEntryOpts<T extends EventMap> = {\n event?: EventKey<T>;\n onLog: string;\n onRemove?: () => void;\n wildcard?: boolean;\n};\n\n// makeEventStream wraps an AsyncGenerator with AsyncDisposable.\nfunction makeEventStream<V>(gen: AsyncGenerator<V>, onDispose: () => Promise<void>): EventStream<V> {\n return Object.assign(gen, {\n [Symbol.asyncDispose]: onDispose,\n }) as unknown as EventStream<V>;\n}\n\n/** @internal */\nexport type InternalBusOptions<T extends EventMap> = BusOptions<T> & {\n /** @internal Called after middleware passes, before listeners run. Used by TestBus. */\n _onDispatch?: (event: EventKey<T>, payload: unknown) => void;\n};\n\nexport function createBus<T extends EventMap = Record<string, unknown>>(options?: BusOptions<T>): Bus<T> {\n return createBusInternal(options);\n}\n\n/** @internal */\nexport function createBusInternal<T extends EventMap = Record<string, unknown>>(\n options?: InternalBusOptions<T>,\n): Bus<T> {\n // Per-event set of Entry objects. Set identity prevents accidental dedup of entries;\n // the same fn can appear in multiple entries with independent lifetimes.\n const listeners = new Map<string, Set<Entry>>();\n const wildcards = new Set<WildcardEntry>();\n const tappers = new Set<(event: HeraldEvent<T>) => void>();\n const disposeController = new AbortController();\n const busName = options?.name;\n const maxListeners = options?.maxListeners;\n const busTag = busName ? ` (${busName})` : '';\n\n function emitTap(event: HeraldEvent<T>): void {\n if (tappers.size === 0) return;\n for (const tapper of tappers) {\n try {\n tapper(event);\n } catch {\n // Observability must not affect bus behavior.\n }\n }\n }\n\n function doWarn(msg: string): void {\n _internalWarn(msg);\n }\n\n function createSubscriptionScope(signal?: AbortSignal): SignalScope {\n return signal\n ? createSignalScope(disposeController.signal, signal)\n : { dispose: noop, signal: disposeController.signal };\n }\n\n // callSafe is defined once per bus (not per emit) — avoids re-allocating on every emission.\n // Captures options.onError via closure. Used in emit() for both specific and wildcard loops.\n // Does not rethrow directly — see dispatch(), which continues the broadcast to every remaining\n // listener (including wildcards) before rethrowing the first captured error, if any.\n function callSafe(fn: () => void, event: EventKey<T>, payload: unknown, timestamp: number): SafeCallResult {\n const onError = options?.onError\n ? (err: unknown) => options.onError?.({ err, event, payload, timestamp } as EmissionErrorContext<T>)\n : undefined;\n\n return callSafely(fn, onError);\n }\n\n // registerEntry opts object — self-documenting call sites.\n function registerEntry<E extends { unsub: () => void }>(\n container: Set<E>,\n makeEntry: (unsub: () => void) => E,\n signal: AbortSignal,\n { event, onLog, onRemove, wildcard }: RegisterEntryOpts<T>,\n ): () => void {\n if (signal.aborted) return noop;\n\n // Boolean guard makes unsub idempotent — a second call after re-registration would\n // otherwise see an empty container and incorrectly delete the outer map entry.\n let called = false;\n\n function unsub() {\n if (called) return;\n\n called = true;\n container.delete(entry);\n onRemove?.();\n signal.removeEventListener('abort', unsub);\n\n if (event !== undefined) emitTap({ event, type: 'unsubscribe' });\n else if (wildcard) emitTap({ type: 'unsubscribe-any' });\n }\n\n // Function declaration is hoisted so `entry` can reference `unsub` directly.\n const entry = makeEntry(unsub);\n\n container.add(entry);\n signal.addEventListener('abort', unsub, { once: true });\n\n if (event !== undefined) emitTap({ event, type: 'subscribe' });\n else if (wildcard) emitTap({ type: 'subscribe-any' });\n\n if (maxListeners !== undefined && container.size > maxListeners) {\n doWarn(\n `${onLog} has ${container.size} listeners, exceeding maxListeners (${maxListeners}). Possible memory leak.${busTag}`,\n );\n }\n\n return unsub;\n }\n\n function onWithSignal<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n let set = listeners.get(event);\n\n if (!set) {\n set = new Set();\n listeners.set(event, set);\n }\n\n // Capture the set reference so unsub can safely delete from it even after\n // the event key has been removed from the outer map.\n const capturedSet = set;\n\n return registerEntry(capturedSet, (unsub) => ({ fn: listener as Listener<unknown>, unsub }), signal, {\n event,\n onLog: `on(\"${event}\")`,\n onRemove: () => {\n if (capturedSet.size === 0) listeners.delete(event);\n\n onRemove?.();\n },\n });\n }\n\n function onAnyWithSignal(\n listener: (event: EventKey<T>, payload: unknown) => void,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n return registerEntry(\n wildcards,\n (unsub) => ({ fn: listener as (event: string, payload: unknown) => void, unsub }),\n signal,\n { onLog: 'onAny', onRemove, wildcard: true },\n );\n }\n\n // Use a const ref object to hold the unsub handle — avoids the forward-reference that\n // TypeScript cannot prove safe with `const unsub = f(() => unsub)`. The `ref` binding never\n // changes (only its property is mutated), satisfying prefer-const. By the time the inner\n // callback fires (only possible after onWithSignal returns), ref.unsub is the real handle.\n function onceWithSignal<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n const ref = { unsub: noop as Unsubscribe };\n\n ref.unsub = onWithSignal(\n event,\n (payload) => {\n ref.unsub();\n listener(payload);\n },\n signal,\n onRemove,\n );\n\n return ref.unsub;\n }\n\n // onAny with once — fires the wildcard listener exactly once, then auto-removes.\n function onAnyWithOnce(\n listener: (event: EventKey<T>, payload: unknown) => void,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n const ref = { unsub: noop as Unsubscribe };\n\n ref.unsub = onAnyWithSignal(\n (event, payload) => {\n ref.unsub();\n listener(event, payload);\n },\n signal,\n onRemove,\n );\n\n return ref.unsub;\n }\n\n function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): () => void {\n const scope = createSubscriptionScope(opts?.signal);\n\n if (opts?.once) return onceWithSignal(event, listener, scope.signal, scope.dispose);\n\n return onWithSignal(event, listener, scope.signal, scope.dispose);\n }\n\n function once<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n opts?: { signal?: AbortSignal },\n ): () => void {\n const scope = createSubscriptionScope(opts?.signal);\n\n return onceWithSignal(event, listener, scope.signal, scope.dispose);\n }\n\n function onAny(listener: (event: EventKey<T>, payload: unknown) => void, opts?: SubscribeOptions): () => void {\n const scope = createSubscriptionScope(opts?.signal);\n\n if (opts?.once) return onAnyWithOnce(listener, scope.signal, scope.dispose);\n\n return onAnyWithSignal(listener, scope.signal, scope.dispose);\n }\n\n function wait<K extends EventKey<T>>(event: K, opts?: { signal?: AbortSignal }): Promise<T[K]> {\n const scope = createSubscriptionScope(opts?.signal);\n\n if (scope.signal.aborted) return Promise.reject(scope.signal.reason);\n\n return new Promise<T[K]>((resolve, reject) => {\n const onAbort = () => {\n scope.dispose();\n reject(scope.signal.reason);\n };\n\n onceWithSignal(\n event,\n (payload) => {\n scope.signal.removeEventListener('abort', onAbort);\n scope.dispose();\n resolve(payload);\n },\n scope.signal,\n );\n\n scope.signal.addEventListener('abort', onAbort, { once: true });\n });\n }\n\n // events() subscribes eagerly — the listener is registered when events() is called, not when\n // the first .next() runs. This ensures events emitted before iteration begins are buffered.\n // maxBuffer is validated synchronously so callers get a HeraldConfigError at call time.\n function events<K extends EventKey<T>>(\n event: K,\n opts?: { maxBuffer?: number; signal?: AbortSignal },\n ): EventStream<T[K]> {\n const maxBuffer = opts?.maxBuffer ?? Infinity;\n\n if (!(maxBuffer > 0)) throw new HeraldConfigError('maxBuffer must be a positive number');\n\n const scope = createSubscriptionScope(opts?.signal);\n const activeSignal = scope.signal;\n\n if (activeSignal.aborted) {\n const empty = (async function* (): AsyncGenerator<T[K]> {})();\n\n return makeEventStream(empty, async (): Promise<void> => {});\n }\n\n const queue: T[K][] = [];\n let wake: (() => void) | undefined;\n\n const unsub = onWithSignal(\n event,\n (payload) => {\n if (queue.length >= maxBuffer) queue.shift();\n\n queue.push(payload);\n wake?.();\n },\n activeSignal,\n scope.dispose,\n );\n\n async function* generate(): AsyncGenerator<T[K]> {\n try {\n while (!activeSignal.aborted) {\n if (queue.length) {\n yield queue.shift()!;\n continue;\n }\n\n const { promise, resolve } = Promise.withResolvers<void>();\n const abortHandler = (): void => {\n resolve();\n };\n\n wake = resolve;\n activeSignal.addEventListener('abort', abortHandler, { once: true });\n await promise;\n activeSignal.removeEventListener('abort', abortHandler);\n wake = undefined;\n }\n } finally {\n unsub();\n }\n }\n\n const gen = generate();\n\n // Symbol.asyncDispose calls unsub() directly because gen.return() only runs the finally\n // block when the generator has been started (at least one next() call). The unsub guard\n // (called = false in registerEntry) makes this idempotent.\n return makeEventStream(gen, async (): Promise<void> => {\n unsub();\n await gen.return(undefined as unknown as T[K]);\n });\n }\n\n // dispatch is defined at createBus() scope (once per bus, not per emit call) — consistent with\n // callSafe. Receives event/payload/timestamp as arguments so it can be invoked from both the\n // direct path and the middleware chain without capturing per-emit locals in a closure.\n function dispatch(event: EventKey<T>, payload: unknown, timestamp: number): number {\n options?._onDispatch?.(event, payload);\n\n let count = 0;\n let firstError: { err: unknown } | undefined;\n const set = listeners.get(event);\n\n if (set?.size) {\n for (const entry of [...set]) {\n const result = callSafe(() => entry.fn(payload), event, payload, timestamp);\n\n if (result.threw) {\n if (!firstError) firstError = { err: result.err };\n emitTap({ error: result.err, event, type: 'listener-error' });\n }\n\n count++;\n }\n }\n\n if (wildcards.size) {\n for (const entry of [...wildcards]) {\n const result = callSafe(() => entry.fn(event, payload), event, payload, timestamp);\n\n if (result.threw) {\n if (!firstError) firstError = { err: result.err };\n emitTap({ error: result.err, event, type: 'listener-error' });\n }\n\n count++;\n }\n }\n\n emitTap({ event, listeners: count, payload, type: 'emit' });\n\n if (firstError) throw firstError.err;\n\n return count;\n }\n\n // emit() returns the number of listeners invoked (specific + wildcard).\n // Returns 0 if bus is disposed, middleware blocked dispatch, or validatePayload rejected.\n // validatePayload runs first, then middleware, then listeners.\n function emit<K extends EventKey<T>>(event: K, ...args: T[K] extends void ? [] : [payload: T[K]]): number {\n if (disposeController.signal.aborted) return 0;\n\n const payload = (args as unknown[])[0];\n const timestamp = Date.now();\n\n if (options?.validatePayload) {\n try {\n options.validatePayload(event, payload as T[K]);\n } catch (err) {\n if (options?.onError) {\n options.onError({ err, event, payload, timestamp } as EmissionErrorContext<T>);\n\n return 0;\n }\n\n throw err;\n }\n }\n\n const middleware = options?.middleware;\n\n if (!middleware?.length) return dispatch(event, payload, timestamp);\n\n const middlewareList = middleware;\n\n function run(index: number): number {\n const current = middlewareList[index];\n\n if (!current) return dispatch(event, payload, timestamp);\n\n let result = 0;\n let continued = false;\n let synchronous = true;\n\n current(event, payload, () => {\n if (!synchronous || continued) return;\n\n continued = true;\n result = run(index + 1);\n });\n\n synchronous = false;\n\n return result;\n }\n\n return run(0);\n }\n\n // listenerCount counts specific-event listeners only.\n // wildcardCount() is the separate accessor for onAny listeners.\n function listenerCount(event?: EventKey<T>): number {\n if (event !== undefined) return listeners.get(event)?.size ?? 0;\n\n let total = 0;\n\n for (const set of listeners.values()) total += set.size;\n\n return total;\n }\n\n function wildcardCount(): number {\n return wildcards.size;\n }\n\n function eventNames(): EventKey<T>[] {\n return [...listeners.keys()] as EventKey<T>[];\n }\n\n function tap(handler: (event: HeraldEvent<T>) => void, opts?: { signal?: AbortSignal }): () => void {\n if (disposeController.signal.aborted) return noop;\n\n const scope = createSubscriptionScope(opts?.signal);\n\n if (scope.signal.aborted) return noop;\n\n tappers.add(handler);\n\n const onAbort = () => tappers.delete(handler);\n\n scope.signal.addEventListener('abort', onAbort, { once: true });\n\n return () => {\n tappers.delete(handler);\n scope.signal.removeEventListener('abort', onAbort);\n scope.dispose();\n };\n }\n\n function waitAny<K extends readonly [EventKey<T>, EventKey<T>, ...EventKey<T>[]]>(\n eventList: K,\n opts?: { signal?: AbortSignal },\n ): Promise<WaitAnyResult<T, K>> {\n if (eventList.length < 2) throw new HeraldConfigError('waitAny() requires at least 2 event keys');\n\n const activeScope = createSubscriptionScope(opts?.signal);\n\n if (activeScope.signal.aborted) return Promise.reject(activeScope.signal.reason);\n\n return new Promise<WaitAnyResult<T, K>>((resolve, reject) => {\n const raceController = new AbortController();\n const raceScope = createSignalScope(activeScope.signal, raceController.signal);\n const unsubs: Unsubscribe[] = [];\n let settled = false;\n\n function cleanup(): void {\n activeScope.signal.removeEventListener('abort', onAbort);\n raceController.abort();\n raceScope.dispose();\n activeScope.dispose();\n for (const unsub of unsubs) unsub();\n }\n\n function onAbort(): void {\n if (settled) return;\n\n settled = true;\n cleanup();\n reject(activeScope.signal.reason);\n }\n\n activeScope.signal.addEventListener('abort', onAbort, { once: true });\n\n for (const event of eventList) {\n unsubs.push(\n onceWithSignal(\n event as EventKey<T>,\n (payload) => {\n if (settled) return;\n\n settled = true;\n cleanup();\n resolve({ event, payload } as WaitAnyResult<T, K>);\n },\n raceScope.signal,\n ),\n );\n }\n });\n }\n\n function dispose(): void {\n if (disposeController.signal.aborted) return;\n\n // Emit dispose first — tappers are cleared by the abort cascade below,\n // so the event must fire before abort triggers their auto-cleanup.\n emitTap({ type: 'dispose' });\n disposeController.abort(new BusDisposedError(busName));\n listeners.clear();\n wildcards.clear();\n tappers.clear();\n }\n\n return {\n get disposalSignal() {\n return disposeController.signal;\n },\n dispose,\n get disposed() {\n return disposeController.signal.aborted;\n },\n emit,\n eventNames,\n events,\n listenerCount,\n on,\n onAny,\n once,\n [Symbol.dispose]: dispose,\n tap,\n wait,\n waitAny,\n wildcardCount,\n };\n}\n","import { createSignalScope } from './bus';\nimport { 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 scope = createSignalScope(source.disposalSignal, target.disposalSignal, opts?.signal);\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: scope.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: scope.signal });\n });\n\n return () => {\n for (const unsub of unsubs) unsub();\n scope.dispose();\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"herald.cjs","names":[],"sources":["../src/_dev.ts","../src/_safe.ts","../src/errors.ts","../src/bus.ts","../src/pipe.ts"],"sourcesContent":["const isDev = !(globalThis as { __HERALD_PROD__?: boolean }).__HERALD_PROD__;\n\n/** @internal @security Messages may include user-supplied data. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/herald] ${msg}`);\n}\n","/**\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","/** Base class for all herald errors. Use `instanceof HeraldError` to catch any herald-originated error. */\nexport class HeraldError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when an operation is attempted on a disposed event bus. */\nexport class BusDisposedError extends HeraldError {\n constructor(busName?: string) {\n super(busName ? `Bus \"${busName}\" is disposed` : 'Bus is disposed');\n }\n}\n\n/** Thrown when a herald API is called with invalid arguments or configuration. */\nexport class HeraldConfigError extends HeraldError {}\n","import { warn as _internalWarn } from './_dev';\nimport { callSafely, type SafeCallResult } from './_safe';\nimport { BusDisposedError, HeraldConfigError } from './errors';\nimport type {\n Bus,\n BusOptions,\n EmissionErrorContext,\n EventKey,\n EventMap,\n EventStream,\n HeraldEvent,\n Listener,\n SubscribeOptions,\n Unsubscribe,\n WaitAnyResult,\n} from './types';\n\n// Module-scoped noop — shared across all bus instances to avoid per-bus allocation.\n/** @internal */\nexport const noop = () => {};\n\n// Each registration gets a unique Entry object, allowing the same listener function\n// to be registered multiple times independently (aligns with Node EventEmitter / mitt).\ntype Entry = { fn: Listener<unknown>; unsub: () => void };\ntype WildcardEntry = { fn: (event: string, payload: unknown) => void; unsub: () => void };\n\ntype RegisterEntryOpts<T extends EventMap> = {\n event?: EventKey<T>;\n onLog: string;\n onRemove?: () => void;\n wildcard?: boolean;\n};\n\n// makeEventStream wraps an AsyncGenerator with AsyncDisposable.\nfunction makeEventStream<V>(gen: AsyncGenerator<V>, onDispose: () => Promise<void>): EventStream<V> {\n return Object.assign(gen, {\n [Symbol.asyncDispose]: onDispose,\n }) as unknown as EventStream<V>;\n}\n\nexport function createBus<T extends EventMap = Record<string, unknown>>(options?: BusOptions<T>): Bus<T> {\n // Per-event set of Entry objects. Set identity prevents accidental dedup of entries;\n // the same fn can appear in multiple entries with independent lifetimes.\n const listeners = new Map<string, Set<Entry>>();\n const wildcards = new Set<WildcardEntry>();\n const tappers = new Set<(event: HeraldEvent<T>) => void>();\n const disposeController = new AbortController();\n const busName = options?.name;\n const maxListeners = options?.maxListeners;\n const busTag = busName ? ` (${busName})` : '';\n\n function emitTap(event: HeraldEvent<T>): void {\n if (tappers.size === 0) return;\n for (const tapper of tappers) {\n try {\n tapper(event);\n } catch {\n // Observability must not affect bus behavior.\n }\n }\n }\n\n function doWarn(msg: string): void {\n _internalWarn(msg);\n }\n\n function createSubscriptionScope(signal?: AbortSignal): AbortSignal {\n return signal ? AbortSignal.any([disposeController.signal, signal]) : disposeController.signal;\n }\n\n // callSafe is defined once per bus (not per emit) — avoids re-allocating on every emission.\n // Captures options.onError via closure. Used in emit() for both specific and wildcard loops.\n // Does not rethrow directly — see dispatch(), which continues the broadcast to every remaining\n // listener (including wildcards) before rethrowing the first captured error, if any.\n function callSafe(fn: () => void, event: EventKey<T>, payload: unknown, timestamp: number): SafeCallResult {\n const onError = options?.onError\n ? (err: unknown) => options.onError?.({ err, event, payload, timestamp } as EmissionErrorContext<T>)\n : undefined;\n\n return callSafely(fn, onError);\n }\n\n // registerEntry opts object — self-documenting call sites.\n function registerEntry<E extends { unsub: () => void }>(\n container: Set<E>,\n makeEntry: (unsub: () => void) => E,\n signal: AbortSignal,\n { event, onLog, onRemove, wildcard }: RegisterEntryOpts<T>,\n ): () => void {\n if (signal.aborted) return noop;\n\n // Boolean guard makes unsub idempotent — a second call after re-registration would\n // otherwise see an empty container and incorrectly delete the outer map entry.\n let called = false;\n\n function unsub() {\n if (called) return;\n\n called = true;\n container.delete(entry);\n onRemove?.();\n signal.removeEventListener('abort', unsub);\n\n if (event !== undefined) emitTap({ event, type: 'unsubscribe' });\n else if (wildcard) emitTap({ type: 'unsubscribe-any' });\n }\n\n // Function declaration is hoisted so `entry` can reference `unsub` directly.\n const entry = makeEntry(unsub);\n\n container.add(entry);\n signal.addEventListener('abort', unsub, { once: true });\n\n if (event !== undefined) emitTap({ event, type: 'subscribe' });\n else if (wildcard) emitTap({ type: 'subscribe-any' });\n\n if (maxListeners !== undefined && container.size > maxListeners) {\n doWarn(\n `${onLog} has ${container.size} listeners, exceeding maxListeners (${maxListeners}). Possible memory leak.${busTag}`,\n );\n }\n\n return unsub;\n }\n\n function onWithSignal<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n let set = listeners.get(event);\n\n if (!set) {\n set = new Set();\n listeners.set(event, set);\n }\n\n // Capture the set reference so unsub can safely delete from it even after\n // the event key has been removed from the outer map.\n const capturedSet = set;\n\n return registerEntry(capturedSet, (unsub) => ({ fn: listener as Listener<unknown>, unsub }), signal, {\n event,\n onLog: `on(\"${event}\")`,\n onRemove: () => {\n if (capturedSet.size === 0) listeners.delete(event);\n\n onRemove?.();\n },\n });\n }\n\n function onAnyWithSignal(\n listener: (event: EventKey<T>, payload: unknown) => void,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n return registerEntry(\n wildcards,\n (unsub) => ({ fn: listener as (event: string, payload: unknown) => void, unsub }),\n signal,\n { onLog: 'onAny', onRemove, wildcard: true },\n );\n }\n\n // Use a const ref object to hold the unsub handle — avoids the forward-reference that\n // TypeScript cannot prove safe with `const unsub = f(() => unsub)`. The `ref` binding never\n // changes (only its property is mutated), satisfying prefer-const. By the time the inner\n // callback fires (only possible after onWithSignal returns), ref.unsub is the real handle.\n function onceWithSignal<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n const ref = { unsub: noop as Unsubscribe };\n\n ref.unsub = onWithSignal(\n event,\n (payload) => {\n ref.unsub();\n listener(payload);\n },\n signal,\n onRemove,\n );\n\n return ref.unsub;\n }\n\n // onAny with once — fires the wildcard listener exactly once, then auto-removes.\n function onAnyWithOnce(\n listener: (event: EventKey<T>, payload: unknown) => void,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n const ref = { unsub: noop as Unsubscribe };\n\n ref.unsub = onAnyWithSignal(\n (event, payload) => {\n ref.unsub();\n listener(event, payload);\n },\n signal,\n onRemove,\n );\n\n return ref.unsub;\n }\n\n function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): () => void {\n const signal = createSubscriptionScope(opts?.signal);\n\n if (opts?.once) return onceWithSignal(event, listener, signal);\n\n return onWithSignal(event, listener, signal);\n }\n\n function once<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n opts?: { signal?: AbortSignal },\n ): () => void {\n const signal = createSubscriptionScope(opts?.signal);\n\n return onceWithSignal(event, listener, signal);\n }\n\n function onAny(listener: (event: EventKey<T>, payload: unknown) => void, opts?: SubscribeOptions): () => void {\n const signal = createSubscriptionScope(opts?.signal);\n\n if (opts?.once) return onAnyWithOnce(listener, signal);\n\n return onAnyWithSignal(listener, signal);\n }\n\n function wait<K extends EventKey<T>>(event: K, opts?: { signal?: AbortSignal }): Promise<T[K]> {\n const signal = createSubscriptionScope(opts?.signal);\n\n if (signal.aborted) return Promise.reject(signal.reason);\n\n return new Promise<T[K]>((resolve, reject) => {\n const onAbort = () => {\n reject(signal.reason);\n };\n\n onceWithSignal(\n event,\n (payload) => {\n signal.removeEventListener('abort', onAbort);\n resolve(payload);\n },\n signal,\n );\n\n signal.addEventListener('abort', onAbort, { once: true });\n });\n }\n\n // events() subscribes eagerly — the listener is registered when events() is called, not when\n // the first .next() runs. This ensures events emitted before iteration begins are buffered.\n // maxBuffer is validated synchronously so callers get a HeraldConfigError at call time.\n function events<K extends EventKey<T>>(\n event: K,\n opts?: { maxBuffer?: number; signal?: AbortSignal },\n ): EventStream<T[K]> {\n const maxBuffer = opts?.maxBuffer ?? Infinity;\n\n if (!(maxBuffer > 0)) throw new HeraldConfigError('maxBuffer must be a positive number');\n\n const activeSignal = createSubscriptionScope(opts?.signal);\n\n if (activeSignal.aborted) {\n const empty = (async function* (): AsyncGenerator<T[K]> {})();\n\n return makeEventStream(empty, async (): Promise<void> => {});\n }\n\n const queue: T[K][] = [];\n let wake: (() => void) | undefined;\n\n const unsub = onWithSignal(\n event,\n (payload) => {\n if (queue.length >= maxBuffer) queue.shift();\n\n queue.push(payload);\n wake?.();\n },\n activeSignal,\n undefined,\n );\n\n async function* generate(): AsyncGenerator<T[K]> {\n try {\n while (!activeSignal.aborted) {\n if (queue.length) {\n yield queue.shift()!;\n continue;\n }\n\n const { promise, resolve } = Promise.withResolvers<void>();\n const abortHandler = (): void => {\n resolve();\n };\n\n wake = resolve;\n activeSignal.addEventListener('abort', abortHandler, { once: true });\n await promise;\n activeSignal.removeEventListener('abort', abortHandler);\n wake = undefined;\n }\n } finally {\n unsub();\n }\n }\n\n const gen = generate();\n\n // Symbol.asyncDispose calls unsub() directly because gen.return() only runs the finally\n // block when the generator has been started (at least one next() call). The unsub guard\n // (called = false in registerEntry) makes this idempotent.\n return makeEventStream(gen, async (): Promise<void> => {\n unsub();\n await gen.return(undefined as unknown as T[K]);\n });\n }\n\n // dispatch is defined at createBus() scope (once per bus, not per emit call) — consistent with\n // callSafe. Receives event/payload/timestamp as arguments so it can be invoked from both the\n // direct path and the middleware chain without capturing per-emit locals in a closure.\n function dispatch(event: EventKey<T>, payload: unknown, timestamp: number): number {\n options?._onDispatch?.(event, payload);\n\n let count = 0;\n let firstError: { err: unknown } | undefined;\n const set = listeners.get(event);\n\n if (set?.size) {\n for (const entry of [...set]) {\n const result = callSafe(() => entry.fn(payload), event, payload, timestamp);\n\n if (result.threw) {\n if (!firstError) firstError = { err: result.err };\n emitTap({ error: result.err, event, type: 'listener-error' });\n }\n\n count++;\n }\n }\n\n if (wildcards.size) {\n for (const entry of [...wildcards]) {\n const result = callSafe(() => entry.fn(event, payload), event, payload, timestamp);\n\n if (result.threw) {\n if (!firstError) firstError = { err: result.err };\n emitTap({ error: result.err, event, type: 'listener-error' });\n }\n\n count++;\n }\n }\n\n emitTap({ event, listeners: count, payload, type: 'emit' });\n\n if (firstError) throw firstError.err;\n\n return count;\n }\n\n // emit() returns the number of listeners invoked (specific + wildcard).\n // Returns 0 if bus is disposed, middleware blocked dispatch, or validatePayload rejected.\n // validatePayload runs first, then middleware, then listeners.\n function emit<K extends EventKey<T>>(event: K, ...args: T[K] extends void ? [] : [payload: T[K]]): number {\n if (disposeController.signal.aborted) return 0;\n\n const payload = (args as unknown[])[0];\n const timestamp = Date.now();\n\n if (options?.validatePayload) {\n try {\n options.validatePayload(event, payload as T[K]);\n } catch (err) {\n if (options?.onError) {\n options.onError({ err, event, payload, timestamp } as EmissionErrorContext<T>);\n\n return 0;\n }\n\n throw err;\n }\n }\n\n const middleware = options?.middleware;\n\n if (!middleware?.length) return dispatch(event, payload, timestamp);\n\n const middlewareList = middleware;\n\n function run(index: number): number {\n const current = middlewareList[index];\n\n if (!current) return dispatch(event, payload, timestamp);\n\n let result = 0;\n let continued = false;\n let synchronous = true;\n\n current(event, payload, () => {\n if (!synchronous || continued) return;\n\n continued = true;\n result = run(index + 1);\n });\n\n synchronous = false;\n\n return result;\n }\n\n return run(0);\n }\n\n // listenerCount counts specific-event listeners only.\n // wildcardCount() is the separate accessor for onAny listeners.\n function listenerCount(event?: EventKey<T>): number {\n if (event !== undefined) return listeners.get(event)?.size ?? 0;\n\n let total = 0;\n\n for (const set of listeners.values()) total += set.size;\n\n return total;\n }\n\n function wildcardCount(): number {\n return wildcards.size;\n }\n\n function eventNames(): EventKey<T>[] {\n return [...listeners.keys()] as EventKey<T>[];\n }\n\n function tap(handler: (event: HeraldEvent<T>) => void, opts?: { signal?: AbortSignal }): () => void {\n if (disposeController.signal.aborted) return noop;\n\n const signal = createSubscriptionScope(opts?.signal);\n\n if (signal.aborted) return noop;\n\n tappers.add(handler);\n\n const onAbort = () => tappers.delete(handler);\n\n signal.addEventListener('abort', onAbort, { once: true });\n\n return () => {\n tappers.delete(handler);\n signal.removeEventListener('abort', onAbort);\n };\n }\n\n function waitAny<K extends readonly [EventKey<T>, EventKey<T>, ...EventKey<T>[]]>(\n eventList: K,\n opts?: { signal?: AbortSignal },\n ): Promise<WaitAnyResult<T, K>> {\n if (eventList.length < 2) throw new HeraldConfigError('waitAny() requires at least 2 event keys');\n\n const activeSignal = createSubscriptionScope(opts?.signal);\n\n if (activeSignal.aborted) return Promise.reject(activeSignal.reason);\n\n return new Promise<WaitAnyResult<T, K>>((resolve, reject) => {\n const raceController = new AbortController();\n const raceSignal = AbortSignal.any([activeSignal, raceController.signal]);\n const unsubs: Unsubscribe[] = [];\n let settled = false;\n\n function cleanup(): void {\n activeSignal.removeEventListener('abort', onAbort);\n raceController.abort();\n for (const unsub of unsubs) unsub();\n }\n\n function onAbort(): void {\n if (settled) return;\n\n settled = true;\n cleanup();\n reject(activeSignal.reason);\n }\n\n activeSignal.addEventListener('abort', onAbort, { once: true });\n\n for (const event of eventList) {\n unsubs.push(\n onceWithSignal(\n event as EventKey<T>,\n (payload) => {\n if (settled) return;\n\n settled = true;\n cleanup();\n resolve({ event, payload } as WaitAnyResult<T, K>);\n },\n raceSignal,\n ),\n );\n }\n });\n }\n\n function dispose(): void {\n if (disposeController.signal.aborted) return;\n\n // Emit dispose first — tappers are cleared by the abort cascade below,\n // so the event must fire before abort triggers their auto-cleanup.\n emitTap({ type: 'dispose' });\n disposeController.abort(new BusDisposedError(busName));\n listeners.clear();\n wildcards.clear();\n tappers.clear();\n }\n\n return {\n get disposalSignal() {\n return disposeController.signal;\n },\n dispose,\n get disposed() {\n return disposeController.signal.aborted;\n },\n emit,\n eventNames,\n events,\n listenerCount,\n on,\n onAny,\n once,\n [Symbol.dispose]: dispose,\n tap,\n wait,\n waitAny,\n wildcardCount,\n };\n}\n","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":"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"}
@@ -1,2 +1,2 @@
1
- var Herald=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function t(e,t){try{return e(),{threw:!1}}catch(e){return t?(t(e),{threw:!1}):{err:e,threw:!0}}}var n=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},r=class extends n{constructor(e){super(e?`Bus "${e}" is disposed`:`Bus is disposed`)}},i=class extends n{},a=()=>{};function o(...e){let t=e.filter(e=>e!==void 0);if(t.length===1)return{dispose:a,signal:t[0]};let n=t.find(e=>e.aborted);if(n)return{dispose:a,signal:n};let r=new AbortController,i=new Map,o=!1;function s(){if(!o){o=!0;for(let[e,t]of i)e.removeEventListener(`abort`,t);i.clear()}}for(let e of t){let t=()=>{r.abort(e.reason),s()};i.set(e,t),e.addEventListener(`abort`,t,{once:!0})}return{dispose:s,signal:r.signal}}function s(e,...t){return o(e,...t).signal}function c(e,t){return Object.assign(e,{[Symbol.asyncDispose]:t})}function l(e){return u(e)}function u(e){let n=new Map,s=new Set,l=new Set,u=new AbortController,d=e?.name,f=e?.maxListeners,p=d?` (${d})`:``;function m(e){if(l.size!==0)for(let t of l)try{t(e)}catch{}}function h(e){return e?o(u.signal,e):{dispose:a,signal:u.signal}}function g(n,r,i,a){return t(n,e?.onError?t=>e.onError?.({err:t,event:r,payload:i,timestamp:a}):void 0)}function _(e,t,n,{event:r,onLog:i,onRemove:o,wildcard:s}){if(n.aborted)return a;let c=!1;function l(){c||(c=!0,e.delete(u),o?.(),n.removeEventListener(`abort`,l),r===void 0?s&&m({type:`unsubscribe-any`}):m({event:r,type:`unsubscribe`}))}let u=t(l);return e.add(u),n.addEventListener(`abort`,l,{once:!0}),r===void 0?s&&m({type:`subscribe-any`}):m({event:r,type:`subscribe`}),f!==void 0&&e.size>f&&`${i}${e.size}${f}${p}`,l}function v(e,t,r,i){let a=n.get(e);a||(a=new Set,n.set(e,a));let o=a;return _(o,e=>({fn:t,unsub:e}),r,{event:e,onLog:`on("${e}")`,onRemove:()=>{o.size===0&&n.delete(e),i?.()}})}function y(e,t,n){return _(s,t=>({fn:e,unsub:t}),t,{onLog:`onAny`,onRemove:n,wildcard:!0})}function b(e,t,n,r){let i={unsub:a};return i.unsub=v(e,e=>{i.unsub(),t(e)},n,r),i.unsub}function x(e,t,n){let r={unsub:a};return r.unsub=y((t,n)=>{r.unsub(),e(t,n)},t,n),r.unsub}function S(e,t,n){let r=h(n?.signal);return n?.once?b(e,t,r.signal,r.dispose):v(e,t,r.signal,r.dispose)}function C(e,t,n){let r=h(n?.signal);return b(e,t,r.signal,r.dispose)}function w(e,t){let n=h(t?.signal);return t?.once?x(e,n.signal,n.dispose):y(e,n.signal,n.dispose)}function T(e,t){let n=h(t?.signal);return n.signal.aborted?Promise.reject(n.signal.reason):new Promise((t,r)=>{let i=()=>{n.dispose(),r(n.signal.reason)};b(e,e=>{n.signal.removeEventListener(`abort`,i),n.dispose(),t(e)},n.signal),n.signal.addEventListener(`abort`,i,{once:!0})})}function E(e,t){let n=t?.maxBuffer??1/0;if(!(n>0))throw new i(`maxBuffer must be a positive number`);let r=h(t?.signal),a=r.signal;if(a.aborted)return c((async function*(){})(),async()=>{});let o=[],s,l=v(e,e=>{o.length>=n&&o.shift(),o.push(e),s?.()},a,r.dispose);async function*u(){try{for(;!a.aborted;){if(o.length){yield o.shift();continue}let{promise:e,resolve:t}=Promise.withResolvers(),n=()=>{t()};s=t,a.addEventListener(`abort`,n,{once:!0}),await e,a.removeEventListener(`abort`,n),s=void 0}}finally{l()}}let d=u();return c(d,async()=>{l(),await d.return(void 0)})}function D(t,r,i){e?._onDispatch?.(t,r);let a=0,o,c=n.get(t);if(c?.size)for(let e of[...c]){let n=g(()=>e.fn(r),t,r,i);n.threw&&(o||={err:n.err},m({error:n.err,event:t,type:`listener-error`})),a++}if(s.size)for(let e of[...s]){let n=g(()=>e.fn(t,r),t,r,i);n.threw&&(o||={err:n.err},m({error:n.err,event:t,type:`listener-error`})),a++}if(m({event:t,listeners:a,payload:r,type:`emit`}),o)throw o.err;return a}function O(t,...n){if(u.signal.aborted)return 0;let r=n[0],i=Date.now();if(e?.validatePayload)try{e.validatePayload(t,r)}catch(n){if(e?.onError)return e.onError({err:n,event:t,payload:r,timestamp:i}),0;throw n}let a=e?.middleware;if(!a?.length)return D(t,r,i);let o=a;function s(e){let n=o[e];if(!n)return D(t,r,i);let a=0,c=!1,l=!0;return n(t,r,()=>{!l||c||(c=!0,a=s(e+1))}),l=!1,a}return s(0)}function k(e){if(e!==void 0)return n.get(e)?.size??0;let t=0;for(let e of n.values())t+=e.size;return t}function A(){return s.size}function j(){return[...n.keys()]}function M(e,t){if(u.signal.aborted)return a;let n=h(t?.signal);if(n.signal.aborted)return a;l.add(e);let r=()=>l.delete(e);return n.signal.addEventListener(`abort`,r,{once:!0}),()=>{l.delete(e),n.signal.removeEventListener(`abort`,r),n.dispose()}}function N(e,t){if(e.length<2)throw new i(`waitAny() requires at least 2 event keys`);let n=h(t?.signal);return n.signal.aborted?Promise.reject(n.signal.reason):new Promise((t,r)=>{let i=new AbortController,a=o(n.signal,i.signal),s=[],c=!1;function l(){n.signal.removeEventListener(`abort`,u),i.abort(),a.dispose(),n.dispose();for(let e of s)e()}function u(){c||(c=!0,l(),r(n.signal.reason))}n.signal.addEventListener(`abort`,u,{once:!0});for(let n of e)s.push(b(n,e=>{c||(c=!0,l(),t({event:n,payload:e}))},a.signal))})}function P(){u.signal.aborted||(m({type:`dispose`}),u.abort(new r(d)),n.clear(),s.clear(),l.clear())}return{get disposalSignal(){return u.signal},dispose:P,get disposed(){return u.signal.aborted},emit:O,eventNames:j,events:E,listenerCount:k,on:S,onAny:w,once:C,[Symbol.dispose]:P,tap:M,wait:T,waitAny:N,wildcardCount:A}}function d(e,t,n,r){if(n.length===0)throw new i(`pipeEvents() requires at least one entry`);let a=o(e.disposalSignal,t.disposalSignal,r?.signal),s=t.emit,c=n.map(t=>{if(typeof t==`string`){let n=t;return e.on(n,e=>s(n,e),{signal:a.signal})}let{from:n,to:r}=t;return e.on(n,e=>s(r,e),{signal:a.signal})});return()=>{for(let e of c)e();a.dispose()}}return e.BusDisposedError=r,e.HeraldConfigError=i,e.HeraldError=n,e.combineSignals=s,e.createBus=l,e.pipeEvents=d,e})({});
1
+ var Herald=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function t(e,t){try{return e(),{threw:!1}}catch(e){return t?(t(e),{threw:!1}):{err:e,threw:!0}}}var n=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},r=class extends n{constructor(e){super(e?`Bus "${e}" is disposed`:`Bus is disposed`)}},i=class extends n{},a=()=>{};function o(e,t){return Object.assign(e,{[Symbol.asyncDispose]:t})}function s(e){let n=new Map,s=new Set,c=new Set,l=new AbortController,u=e?.name,d=e?.maxListeners,f=u?` (${u})`:``;function p(e){if(c.size!==0)for(let t of c)try{t(e)}catch{}}function m(e){return e?AbortSignal.any([l.signal,e]):l.signal}function h(n,r,i,a){return t(n,e?.onError?t=>e.onError?.({err:t,event:r,payload:i,timestamp:a}):void 0)}function g(e,t,n,{event:r,onLog:i,onRemove:o,wildcard:s}){if(n.aborted)return a;let c=!1;function l(){c||(c=!0,e.delete(u),o?.(),n.removeEventListener(`abort`,l),r===void 0?s&&p({type:`unsubscribe-any`}):p({event:r,type:`unsubscribe`}))}let u=t(l);return e.add(u),n.addEventListener(`abort`,l,{once:!0}),r===void 0?s&&p({type:`subscribe-any`}):p({event:r,type:`subscribe`}),d!==void 0&&e.size>d&&`${i}${e.size}${d}${f}`,l}function _(e,t,r,i){let a=n.get(e);a||(a=new Set,n.set(e,a));let o=a;return g(o,e=>({fn:t,unsub:e}),r,{event:e,onLog:`on("${e}")`,onRemove:()=>{o.size===0&&n.delete(e),i?.()}})}function v(e,t,n){return g(s,t=>({fn:e,unsub:t}),t,{onLog:`onAny`,onRemove:n,wildcard:!0})}function y(e,t,n,r){let i={unsub:a};return i.unsub=_(e,e=>{i.unsub(),t(e)},n,r),i.unsub}function b(e,t,n){let r={unsub:a};return r.unsub=v((t,n)=>{r.unsub(),e(t,n)},t,n),r.unsub}function x(e,t,n){let r=m(n?.signal);return n?.once?y(e,t,r):_(e,t,r)}function S(e,t,n){return y(e,t,m(n?.signal))}function C(e,t){let n=m(t?.signal);return t?.once?b(e,n):v(e,n)}function w(e,t){let n=m(t?.signal);return n.aborted?Promise.reject(n.reason):new Promise((t,r)=>{let i=()=>{r(n.reason)};y(e,e=>{n.removeEventListener(`abort`,i),t(e)},n),n.addEventListener(`abort`,i,{once:!0})})}function T(e,t){let n=t?.maxBuffer??1/0;if(!(n>0))throw new i(`maxBuffer must be a positive number`);let r=m(t?.signal);if(r.aborted)return o((async function*(){})(),async()=>{});let a=[],s,c=_(e,e=>{a.length>=n&&a.shift(),a.push(e),s?.()},r,void 0);async function*l(){try{for(;!r.aborted;){if(a.length){yield a.shift();continue}let{promise:e,resolve:t}=Promise.withResolvers(),n=()=>{t()};s=t,r.addEventListener(`abort`,n,{once:!0}),await e,r.removeEventListener(`abort`,n),s=void 0}}finally{c()}}let u=l();return o(u,async()=>{c(),await u.return(void 0)})}function E(t,r,i){e?._onDispatch?.(t,r);let a=0,o,c=n.get(t);if(c?.size)for(let e of[...c]){let n=h(()=>e.fn(r),t,r,i);n.threw&&(o||={err:n.err},p({error:n.err,event:t,type:`listener-error`})),a++}if(s.size)for(let e of[...s]){let n=h(()=>e.fn(t,r),t,r,i);n.threw&&(o||={err:n.err},p({error:n.err,event:t,type:`listener-error`})),a++}if(p({event:t,listeners:a,payload:r,type:`emit`}),o)throw o.err;return a}function D(t,...n){if(l.signal.aborted)return 0;let r=n[0],i=Date.now();if(e?.validatePayload)try{e.validatePayload(t,r)}catch(n){if(e?.onError)return e.onError({err:n,event:t,payload:r,timestamp:i}),0;throw n}let a=e?.middleware;if(!a?.length)return E(t,r,i);let o=a;function s(e){let n=o[e];if(!n)return E(t,r,i);let a=0,c=!1,l=!0;return n(t,r,()=>{!l||c||(c=!0,a=s(e+1))}),l=!1,a}return s(0)}function O(e){if(e!==void 0)return n.get(e)?.size??0;let t=0;for(let e of n.values())t+=e.size;return t}function k(){return s.size}function A(){return[...n.keys()]}function j(e,t){if(l.signal.aborted)return a;let n=m(t?.signal);if(n.aborted)return a;c.add(e);let r=()=>c.delete(e);return n.addEventListener(`abort`,r,{once:!0}),()=>{c.delete(e),n.removeEventListener(`abort`,r)}}function M(e,t){if(e.length<2)throw new i(`waitAny() requires at least 2 event keys`);let n=m(t?.signal);return n.aborted?Promise.reject(n.reason):new Promise((t,r)=>{let i=new AbortController,a=AbortSignal.any([n,i.signal]),o=[],s=!1;function c(){n.removeEventListener(`abort`,l),i.abort();for(let e of o)e()}function l(){s||(s=!0,c(),r(n.reason))}n.addEventListener(`abort`,l,{once:!0});for(let n of e)o.push(y(n,e=>{s||(s=!0,c(),t({event:n,payload:e}))},a))})}function N(){l.signal.aborted||(p({type:`dispose`}),l.abort(new r(u)),n.clear(),s.clear(),c.clear())}return{get disposalSignal(){return l.signal},dispose:N,get disposed(){return l.signal.aborted},emit:D,eventNames:A,events:T,listenerCount:O,on:x,onAny:C,once:S,[Symbol.dispose]:N,tap:j,wait:w,waitAny:M,wildcardCount:k}}function c(e,t,n,r){if(n.length===0)throw new i(`pipeEvents() requires at least one entry`);let a=[e.disposalSignal,t.disposalSignal];r?.signal&&a.push(r.signal);let o=AbortSignal.any(a),s=t.emit,c=n.map(t=>{if(typeof t==`string`){let n=t;return e.on(n,e=>s(n,e),{signal:o})}let{from:n,to:r}=t;return e.on(n,e=>s(r,e),{signal:o})});return()=>{for(let e of c)e()}}return e.BusDisposedError=r,e.HeraldConfigError=i,e.HeraldError=n,e.createBus=s,e.pipeEvents=c,e})({});
2
2
  //# sourceMappingURL=herald.iife.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"herald.iife.js","names":[],"sources":["../src/_dev.ts","../src/_safe.ts","../src/errors.ts","../src/bus.ts","../src/pipe.ts"],"sourcesContent":["const isDev = !(globalThis as { __HERALD_PROD__?: boolean }).__HERALD_PROD__;\n\n/** @internal @security Messages may include user-supplied data. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/herald] ${msg}`);\n}\n","/**\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","/** Base class for all herald errors. Use `instanceof HeraldError` to catch any herald-originated error. */\nexport class HeraldError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when an operation is attempted on a disposed event bus. */\nexport class BusDisposedError extends HeraldError {\n constructor(busName?: string) {\n super(busName ? `Bus \"${busName}\" is disposed` : 'Bus is disposed');\n }\n}\n\n/** Thrown when a herald API is called with invalid arguments or configuration. */\nexport class HeraldConfigError extends HeraldError {}\n","import { warn as _internalWarn } from './_dev';\nimport { callSafely, type SafeCallResult } from './_safe';\nimport { BusDisposedError, HeraldConfigError } from './errors';\nimport type {\n Bus,\n BusOptions,\n EmissionErrorContext,\n EventKey,\n EventMap,\n EventStream,\n HeraldEvent,\n Listener,\n SubscribeOptions,\n Unsubscribe,\n WaitAnyResult,\n} from './types';\n\n// Module-scoped noop — shared across all bus instances to avoid per-bus allocation.\n// @internal — exported only for sibling internal modules; stripped from public declarations via stripInternal.\n/** @internal */\nexport const noop = () => {};\n\n/** @internal */\nexport type SignalScope = { dispose(): void; signal: AbortSignal };\n\n/** @internal */\nexport function createSignalScope(...candidates: Array<AbortSignal | undefined>): SignalScope {\n const signals = candidates.filter((signal): signal is AbortSignal => signal !== undefined);\n\n if (signals.length === 1) return { dispose: noop, signal: signals[0]! };\n\n const aborted = signals.find((signal) => signal.aborted);\n\n if (aborted) return { dispose: noop, signal: aborted };\n\n const controller = new AbortController();\n const listeners = new Map<AbortSignal, () => void>();\n let disposed = false;\n\n function dispose(): void {\n if (disposed) return;\n\n disposed = true;\n for (const [signal, listener] of listeners) signal.removeEventListener('abort', listener);\n listeners.clear();\n }\n\n for (const signal of signals) {\n const listener = () => {\n controller.abort(signal.reason);\n dispose();\n };\n\n listeners.set(signal, listener);\n signal.addEventListener('abort', listener, { once: true });\n }\n\n return { dispose, signal: controller.signal };\n}\n\n/**\n * Returns a signal that aborts as soon as any provided signal aborts.\n * Input listeners remain active until one input aborts; use signal-owning APIs for early cleanup.\n */\nexport function combineSignals(first: AbortSignal, ...rest: AbortSignal[]): AbortSignal {\n return createSignalScope(first, ...rest).signal;\n}\n\n// Each registration gets a unique Entry object, allowing the same listener function\n// to be registered multiple times independently (aligns with Node EventEmitter / mitt).\ntype Entry = { fn: Listener<unknown>; unsub: () => void };\ntype WildcardEntry = { fn: (event: string, payload: unknown) => void; unsub: () => void };\n\ntype RegisterEntryOpts<T extends EventMap> = {\n event?: EventKey<T>;\n onLog: string;\n onRemove?: () => void;\n wildcard?: boolean;\n};\n\n// makeEventStream wraps an AsyncGenerator with AsyncDisposable.\nfunction makeEventStream<V>(gen: AsyncGenerator<V>, onDispose: () => Promise<void>): EventStream<V> {\n return Object.assign(gen, {\n [Symbol.asyncDispose]: onDispose,\n }) as unknown as EventStream<V>;\n}\n\n/** @internal */\nexport type InternalBusOptions<T extends EventMap> = BusOptions<T> & {\n /** @internal Called after middleware passes, before listeners run. Used by TestBus. */\n _onDispatch?: (event: EventKey<T>, payload: unknown) => void;\n};\n\nexport function createBus<T extends EventMap = Record<string, unknown>>(options?: BusOptions<T>): Bus<T> {\n return createBusInternal(options);\n}\n\n/** @internal */\nexport function createBusInternal<T extends EventMap = Record<string, unknown>>(\n options?: InternalBusOptions<T>,\n): Bus<T> {\n // Per-event set of Entry objects. Set identity prevents accidental dedup of entries;\n // the same fn can appear in multiple entries with independent lifetimes.\n const listeners = new Map<string, Set<Entry>>();\n const wildcards = new Set<WildcardEntry>();\n const tappers = new Set<(event: HeraldEvent<T>) => void>();\n const disposeController = new AbortController();\n const busName = options?.name;\n const maxListeners = options?.maxListeners;\n const busTag = busName ? ` (${busName})` : '';\n\n function emitTap(event: HeraldEvent<T>): void {\n if (tappers.size === 0) return;\n for (const tapper of tappers) {\n try {\n tapper(event);\n } catch {\n // Observability must not affect bus behavior.\n }\n }\n }\n\n function doWarn(msg: string): void {\n _internalWarn(msg);\n }\n\n function createSubscriptionScope(signal?: AbortSignal): SignalScope {\n return signal\n ? createSignalScope(disposeController.signal, signal)\n : { dispose: noop, signal: disposeController.signal };\n }\n\n // callSafe is defined once per bus (not per emit) — avoids re-allocating on every emission.\n // Captures options.onError via closure. Used in emit() for both specific and wildcard loops.\n // Does not rethrow directly — see dispatch(), which continues the broadcast to every remaining\n // listener (including wildcards) before rethrowing the first captured error, if any.\n function callSafe(fn: () => void, event: EventKey<T>, payload: unknown, timestamp: number): SafeCallResult {\n const onError = options?.onError\n ? (err: unknown) => options.onError?.({ err, event, payload, timestamp } as EmissionErrorContext<T>)\n : undefined;\n\n return callSafely(fn, onError);\n }\n\n // registerEntry opts object — self-documenting call sites.\n function registerEntry<E extends { unsub: () => void }>(\n container: Set<E>,\n makeEntry: (unsub: () => void) => E,\n signal: AbortSignal,\n { event, onLog, onRemove, wildcard }: RegisterEntryOpts<T>,\n ): () => void {\n if (signal.aborted) return noop;\n\n // Boolean guard makes unsub idempotent — a second call after re-registration would\n // otherwise see an empty container and incorrectly delete the outer map entry.\n let called = false;\n\n function unsub() {\n if (called) return;\n\n called = true;\n container.delete(entry);\n onRemove?.();\n signal.removeEventListener('abort', unsub);\n\n if (event !== undefined) emitTap({ event, type: 'unsubscribe' });\n else if (wildcard) emitTap({ type: 'unsubscribe-any' });\n }\n\n // Function declaration is hoisted so `entry` can reference `unsub` directly.\n const entry = makeEntry(unsub);\n\n container.add(entry);\n signal.addEventListener('abort', unsub, { once: true });\n\n if (event !== undefined) emitTap({ event, type: 'subscribe' });\n else if (wildcard) emitTap({ type: 'subscribe-any' });\n\n if (maxListeners !== undefined && container.size > maxListeners) {\n doWarn(\n `${onLog} has ${container.size} listeners, exceeding maxListeners (${maxListeners}). Possible memory leak.${busTag}`,\n );\n }\n\n return unsub;\n }\n\n function onWithSignal<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n let set = listeners.get(event);\n\n if (!set) {\n set = new Set();\n listeners.set(event, set);\n }\n\n // Capture the set reference so unsub can safely delete from it even after\n // the event key has been removed from the outer map.\n const capturedSet = set;\n\n return registerEntry(capturedSet, (unsub) => ({ fn: listener as Listener<unknown>, unsub }), signal, {\n event,\n onLog: `on(\"${event}\")`,\n onRemove: () => {\n if (capturedSet.size === 0) listeners.delete(event);\n\n onRemove?.();\n },\n });\n }\n\n function onAnyWithSignal(\n listener: (event: EventKey<T>, payload: unknown) => void,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n return registerEntry(\n wildcards,\n (unsub) => ({ fn: listener as (event: string, payload: unknown) => void, unsub }),\n signal,\n { onLog: 'onAny', onRemove, wildcard: true },\n );\n }\n\n // Use a const ref object to hold the unsub handle — avoids the forward-reference that\n // TypeScript cannot prove safe with `const unsub = f(() => unsub)`. The `ref` binding never\n // changes (only its property is mutated), satisfying prefer-const. By the time the inner\n // callback fires (only possible after onWithSignal returns), ref.unsub is the real handle.\n function onceWithSignal<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n const ref = { unsub: noop as Unsubscribe };\n\n ref.unsub = onWithSignal(\n event,\n (payload) => {\n ref.unsub();\n listener(payload);\n },\n signal,\n onRemove,\n );\n\n return ref.unsub;\n }\n\n // onAny with once — fires the wildcard listener exactly once, then auto-removes.\n function onAnyWithOnce(\n listener: (event: EventKey<T>, payload: unknown) => void,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n const ref = { unsub: noop as Unsubscribe };\n\n ref.unsub = onAnyWithSignal(\n (event, payload) => {\n ref.unsub();\n listener(event, payload);\n },\n signal,\n onRemove,\n );\n\n return ref.unsub;\n }\n\n function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): () => void {\n const scope = createSubscriptionScope(opts?.signal);\n\n if (opts?.once) return onceWithSignal(event, listener, scope.signal, scope.dispose);\n\n return onWithSignal(event, listener, scope.signal, scope.dispose);\n }\n\n function once<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n opts?: { signal?: AbortSignal },\n ): () => void {\n const scope = createSubscriptionScope(opts?.signal);\n\n return onceWithSignal(event, listener, scope.signal, scope.dispose);\n }\n\n function onAny(listener: (event: EventKey<T>, payload: unknown) => void, opts?: SubscribeOptions): () => void {\n const scope = createSubscriptionScope(opts?.signal);\n\n if (opts?.once) return onAnyWithOnce(listener, scope.signal, scope.dispose);\n\n return onAnyWithSignal(listener, scope.signal, scope.dispose);\n }\n\n function wait<K extends EventKey<T>>(event: K, opts?: { signal?: AbortSignal }): Promise<T[K]> {\n const scope = createSubscriptionScope(opts?.signal);\n\n if (scope.signal.aborted) return Promise.reject(scope.signal.reason);\n\n return new Promise<T[K]>((resolve, reject) => {\n const onAbort = () => {\n scope.dispose();\n reject(scope.signal.reason);\n };\n\n onceWithSignal(\n event,\n (payload) => {\n scope.signal.removeEventListener('abort', onAbort);\n scope.dispose();\n resolve(payload);\n },\n scope.signal,\n );\n\n scope.signal.addEventListener('abort', onAbort, { once: true });\n });\n }\n\n // events() subscribes eagerly — the listener is registered when events() is called, not when\n // the first .next() runs. This ensures events emitted before iteration begins are buffered.\n // maxBuffer is validated synchronously so callers get a HeraldConfigError at call time.\n function events<K extends EventKey<T>>(\n event: K,\n opts?: { maxBuffer?: number; signal?: AbortSignal },\n ): EventStream<T[K]> {\n const maxBuffer = opts?.maxBuffer ?? Infinity;\n\n if (!(maxBuffer > 0)) throw new HeraldConfigError('maxBuffer must be a positive number');\n\n const scope = createSubscriptionScope(opts?.signal);\n const activeSignal = scope.signal;\n\n if (activeSignal.aborted) {\n const empty = (async function* (): AsyncGenerator<T[K]> {})();\n\n return makeEventStream(empty, async (): Promise<void> => {});\n }\n\n const queue: T[K][] = [];\n let wake: (() => void) | undefined;\n\n const unsub = onWithSignal(\n event,\n (payload) => {\n if (queue.length >= maxBuffer) queue.shift();\n\n queue.push(payload);\n wake?.();\n },\n activeSignal,\n scope.dispose,\n );\n\n async function* generate(): AsyncGenerator<T[K]> {\n try {\n while (!activeSignal.aborted) {\n if (queue.length) {\n yield queue.shift()!;\n continue;\n }\n\n const { promise, resolve } = Promise.withResolvers<void>();\n const abortHandler = (): void => {\n resolve();\n };\n\n wake = resolve;\n activeSignal.addEventListener('abort', abortHandler, { once: true });\n await promise;\n activeSignal.removeEventListener('abort', abortHandler);\n wake = undefined;\n }\n } finally {\n unsub();\n }\n }\n\n const gen = generate();\n\n // Symbol.asyncDispose calls unsub() directly because gen.return() only runs the finally\n // block when the generator has been started (at least one next() call). The unsub guard\n // (called = false in registerEntry) makes this idempotent.\n return makeEventStream(gen, async (): Promise<void> => {\n unsub();\n await gen.return(undefined as unknown as T[K]);\n });\n }\n\n // dispatch is defined at createBus() scope (once per bus, not per emit call) — consistent with\n // callSafe. Receives event/payload/timestamp as arguments so it can be invoked from both the\n // direct path and the middleware chain without capturing per-emit locals in a closure.\n function dispatch(event: EventKey<T>, payload: unknown, timestamp: number): number {\n options?._onDispatch?.(event, payload);\n\n let count = 0;\n let firstError: { err: unknown } | undefined;\n const set = listeners.get(event);\n\n if (set?.size) {\n for (const entry of [...set]) {\n const result = callSafe(() => entry.fn(payload), event, payload, timestamp);\n\n if (result.threw) {\n if (!firstError) firstError = { err: result.err };\n emitTap({ error: result.err, event, type: 'listener-error' });\n }\n\n count++;\n }\n }\n\n if (wildcards.size) {\n for (const entry of [...wildcards]) {\n const result = callSafe(() => entry.fn(event, payload), event, payload, timestamp);\n\n if (result.threw) {\n if (!firstError) firstError = { err: result.err };\n emitTap({ error: result.err, event, type: 'listener-error' });\n }\n\n count++;\n }\n }\n\n emitTap({ event, listeners: count, payload, type: 'emit' });\n\n if (firstError) throw firstError.err;\n\n return count;\n }\n\n // emit() returns the number of listeners invoked (specific + wildcard).\n // Returns 0 if bus is disposed, middleware blocked dispatch, or validatePayload rejected.\n // validatePayload runs first, then middleware, then listeners.\n function emit<K extends EventKey<T>>(event: K, ...args: T[K] extends void ? [] : [payload: T[K]]): number {\n if (disposeController.signal.aborted) return 0;\n\n const payload = (args as unknown[])[0];\n const timestamp = Date.now();\n\n if (options?.validatePayload) {\n try {\n options.validatePayload(event, payload as T[K]);\n } catch (err) {\n if (options?.onError) {\n options.onError({ err, event, payload, timestamp } as EmissionErrorContext<T>);\n\n return 0;\n }\n\n throw err;\n }\n }\n\n const middleware = options?.middleware;\n\n if (!middleware?.length) return dispatch(event, payload, timestamp);\n\n const middlewareList = middleware;\n\n function run(index: number): number {\n const current = middlewareList[index];\n\n if (!current) return dispatch(event, payload, timestamp);\n\n let result = 0;\n let continued = false;\n let synchronous = true;\n\n current(event, payload, () => {\n if (!synchronous || continued) return;\n\n continued = true;\n result = run(index + 1);\n });\n\n synchronous = false;\n\n return result;\n }\n\n return run(0);\n }\n\n // listenerCount counts specific-event listeners only.\n // wildcardCount() is the separate accessor for onAny listeners.\n function listenerCount(event?: EventKey<T>): number {\n if (event !== undefined) return listeners.get(event)?.size ?? 0;\n\n let total = 0;\n\n for (const set of listeners.values()) total += set.size;\n\n return total;\n }\n\n function wildcardCount(): number {\n return wildcards.size;\n }\n\n function eventNames(): EventKey<T>[] {\n return [...listeners.keys()] as EventKey<T>[];\n }\n\n function tap(handler: (event: HeraldEvent<T>) => void, opts?: { signal?: AbortSignal }): () => void {\n if (disposeController.signal.aborted) return noop;\n\n const scope = createSubscriptionScope(opts?.signal);\n\n if (scope.signal.aborted) return noop;\n\n tappers.add(handler);\n\n const onAbort = () => tappers.delete(handler);\n\n scope.signal.addEventListener('abort', onAbort, { once: true });\n\n return () => {\n tappers.delete(handler);\n scope.signal.removeEventListener('abort', onAbort);\n scope.dispose();\n };\n }\n\n function waitAny<K extends readonly [EventKey<T>, EventKey<T>, ...EventKey<T>[]]>(\n eventList: K,\n opts?: { signal?: AbortSignal },\n ): Promise<WaitAnyResult<T, K>> {\n if (eventList.length < 2) throw new HeraldConfigError('waitAny() requires at least 2 event keys');\n\n const activeScope = createSubscriptionScope(opts?.signal);\n\n if (activeScope.signal.aborted) return Promise.reject(activeScope.signal.reason);\n\n return new Promise<WaitAnyResult<T, K>>((resolve, reject) => {\n const raceController = new AbortController();\n const raceScope = createSignalScope(activeScope.signal, raceController.signal);\n const unsubs: Unsubscribe[] = [];\n let settled = false;\n\n function cleanup(): void {\n activeScope.signal.removeEventListener('abort', onAbort);\n raceController.abort();\n raceScope.dispose();\n activeScope.dispose();\n for (const unsub of unsubs) unsub();\n }\n\n function onAbort(): void {\n if (settled) return;\n\n settled = true;\n cleanup();\n reject(activeScope.signal.reason);\n }\n\n activeScope.signal.addEventListener('abort', onAbort, { once: true });\n\n for (const event of eventList) {\n unsubs.push(\n onceWithSignal(\n event as EventKey<T>,\n (payload) => {\n if (settled) return;\n\n settled = true;\n cleanup();\n resolve({ event, payload } as WaitAnyResult<T, K>);\n },\n raceScope.signal,\n ),\n );\n }\n });\n }\n\n function dispose(): void {\n if (disposeController.signal.aborted) return;\n\n // Emit dispose first — tappers are cleared by the abort cascade below,\n // so the event must fire before abort triggers their auto-cleanup.\n emitTap({ type: 'dispose' });\n disposeController.abort(new BusDisposedError(busName));\n listeners.clear();\n wildcards.clear();\n tappers.clear();\n }\n\n return {\n get disposalSignal() {\n return disposeController.signal;\n },\n dispose,\n get disposed() {\n return disposeController.signal.aborted;\n },\n emit,\n eventNames,\n events,\n listenerCount,\n on,\n onAny,\n once,\n [Symbol.dispose]: dispose,\n tap,\n wait,\n waitAny,\n wildcardCount,\n };\n}\n","import { createSignalScope } from './bus';\nimport { 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 scope = createSignalScope(source.disposalSignal, target.disposalSignal, opts?.signal);\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: scope.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: scope.signal });\n });\n\n return () => {\n for (const unsub of unsubs) unsub();\n scope.dispose();\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"herald.iife.js","names":[],"sources":["../src/_dev.ts","../src/_safe.ts","../src/errors.ts","../src/bus.ts","../src/pipe.ts"],"sourcesContent":["const isDev = !(globalThis as { __HERALD_PROD__?: boolean }).__HERALD_PROD__;\n\n/** @internal @security Messages may include user-supplied data. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/herald] ${msg}`);\n}\n","/**\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","/** Base class for all herald errors. Use `instanceof HeraldError` to catch any herald-originated error. */\nexport class HeraldError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when an operation is attempted on a disposed event bus. */\nexport class BusDisposedError extends HeraldError {\n constructor(busName?: string) {\n super(busName ? `Bus \"${busName}\" is disposed` : 'Bus is disposed');\n }\n}\n\n/** Thrown when a herald API is called with invalid arguments or configuration. */\nexport class HeraldConfigError extends HeraldError {}\n","import { warn as _internalWarn } from './_dev';\nimport { callSafely, type SafeCallResult } from './_safe';\nimport { BusDisposedError, HeraldConfigError } from './errors';\nimport type {\n Bus,\n BusOptions,\n EmissionErrorContext,\n EventKey,\n EventMap,\n EventStream,\n HeraldEvent,\n Listener,\n SubscribeOptions,\n Unsubscribe,\n WaitAnyResult,\n} from './types';\n\n// Module-scoped noop — shared across all bus instances to avoid per-bus allocation.\n/** @internal */\nexport const noop = () => {};\n\n// Each registration gets a unique Entry object, allowing the same listener function\n// to be registered multiple times independently (aligns with Node EventEmitter / mitt).\ntype Entry = { fn: Listener<unknown>; unsub: () => void };\ntype WildcardEntry = { fn: (event: string, payload: unknown) => void; unsub: () => void };\n\ntype RegisterEntryOpts<T extends EventMap> = {\n event?: EventKey<T>;\n onLog: string;\n onRemove?: () => void;\n wildcard?: boolean;\n};\n\n// makeEventStream wraps an AsyncGenerator with AsyncDisposable.\nfunction makeEventStream<V>(gen: AsyncGenerator<V>, onDispose: () => Promise<void>): EventStream<V> {\n return Object.assign(gen, {\n [Symbol.asyncDispose]: onDispose,\n }) as unknown as EventStream<V>;\n}\n\nexport function createBus<T extends EventMap = Record<string, unknown>>(options?: BusOptions<T>): Bus<T> {\n // Per-event set of Entry objects. Set identity prevents accidental dedup of entries;\n // the same fn can appear in multiple entries with independent lifetimes.\n const listeners = new Map<string, Set<Entry>>();\n const wildcards = new Set<WildcardEntry>();\n const tappers = new Set<(event: HeraldEvent<T>) => void>();\n const disposeController = new AbortController();\n const busName = options?.name;\n const maxListeners = options?.maxListeners;\n const busTag = busName ? ` (${busName})` : '';\n\n function emitTap(event: HeraldEvent<T>): void {\n if (tappers.size === 0) return;\n for (const tapper of tappers) {\n try {\n tapper(event);\n } catch {\n // Observability must not affect bus behavior.\n }\n }\n }\n\n function doWarn(msg: string): void {\n _internalWarn(msg);\n }\n\n function createSubscriptionScope(signal?: AbortSignal): AbortSignal {\n return signal ? AbortSignal.any([disposeController.signal, signal]) : disposeController.signal;\n }\n\n // callSafe is defined once per bus (not per emit) — avoids re-allocating on every emission.\n // Captures options.onError via closure. Used in emit() for both specific and wildcard loops.\n // Does not rethrow directly — see dispatch(), which continues the broadcast to every remaining\n // listener (including wildcards) before rethrowing the first captured error, if any.\n function callSafe(fn: () => void, event: EventKey<T>, payload: unknown, timestamp: number): SafeCallResult {\n const onError = options?.onError\n ? (err: unknown) => options.onError?.({ err, event, payload, timestamp } as EmissionErrorContext<T>)\n : undefined;\n\n return callSafely(fn, onError);\n }\n\n // registerEntry opts object — self-documenting call sites.\n function registerEntry<E extends { unsub: () => void }>(\n container: Set<E>,\n makeEntry: (unsub: () => void) => E,\n signal: AbortSignal,\n { event, onLog, onRemove, wildcard }: RegisterEntryOpts<T>,\n ): () => void {\n if (signal.aborted) return noop;\n\n // Boolean guard makes unsub idempotent — a second call after re-registration would\n // otherwise see an empty container and incorrectly delete the outer map entry.\n let called = false;\n\n function unsub() {\n if (called) return;\n\n called = true;\n container.delete(entry);\n onRemove?.();\n signal.removeEventListener('abort', unsub);\n\n if (event !== undefined) emitTap({ event, type: 'unsubscribe' });\n else if (wildcard) emitTap({ type: 'unsubscribe-any' });\n }\n\n // Function declaration is hoisted so `entry` can reference `unsub` directly.\n const entry = makeEntry(unsub);\n\n container.add(entry);\n signal.addEventListener('abort', unsub, { once: true });\n\n if (event !== undefined) emitTap({ event, type: 'subscribe' });\n else if (wildcard) emitTap({ type: 'subscribe-any' });\n\n if (maxListeners !== undefined && container.size > maxListeners) {\n doWarn(\n `${onLog} has ${container.size} listeners, exceeding maxListeners (${maxListeners}). Possible memory leak.${busTag}`,\n );\n }\n\n return unsub;\n }\n\n function onWithSignal<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n let set = listeners.get(event);\n\n if (!set) {\n set = new Set();\n listeners.set(event, set);\n }\n\n // Capture the set reference so unsub can safely delete from it even after\n // the event key has been removed from the outer map.\n const capturedSet = set;\n\n return registerEntry(capturedSet, (unsub) => ({ fn: listener as Listener<unknown>, unsub }), signal, {\n event,\n onLog: `on(\"${event}\")`,\n onRemove: () => {\n if (capturedSet.size === 0) listeners.delete(event);\n\n onRemove?.();\n },\n });\n }\n\n function onAnyWithSignal(\n listener: (event: EventKey<T>, payload: unknown) => void,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n return registerEntry(\n wildcards,\n (unsub) => ({ fn: listener as (event: string, payload: unknown) => void, unsub }),\n signal,\n { onLog: 'onAny', onRemove, wildcard: true },\n );\n }\n\n // Use a const ref object to hold the unsub handle — avoids the forward-reference that\n // TypeScript cannot prove safe with `const unsub = f(() => unsub)`. The `ref` binding never\n // changes (only its property is mutated), satisfying prefer-const. By the time the inner\n // callback fires (only possible after onWithSignal returns), ref.unsub is the real handle.\n function onceWithSignal<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n const ref = { unsub: noop as Unsubscribe };\n\n ref.unsub = onWithSignal(\n event,\n (payload) => {\n ref.unsub();\n listener(payload);\n },\n signal,\n onRemove,\n );\n\n return ref.unsub;\n }\n\n // onAny with once — fires the wildcard listener exactly once, then auto-removes.\n function onAnyWithOnce(\n listener: (event: EventKey<T>, payload: unknown) => void,\n signal: AbortSignal,\n onRemove?: () => void,\n ): () => void {\n const ref = { unsub: noop as Unsubscribe };\n\n ref.unsub = onAnyWithSignal(\n (event, payload) => {\n ref.unsub();\n listener(event, payload);\n },\n signal,\n onRemove,\n );\n\n return ref.unsub;\n }\n\n function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): () => void {\n const signal = createSubscriptionScope(opts?.signal);\n\n if (opts?.once) return onceWithSignal(event, listener, signal);\n\n return onWithSignal(event, listener, signal);\n }\n\n function once<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n opts?: { signal?: AbortSignal },\n ): () => void {\n const signal = createSubscriptionScope(opts?.signal);\n\n return onceWithSignal(event, listener, signal);\n }\n\n function onAny(listener: (event: EventKey<T>, payload: unknown) => void, opts?: SubscribeOptions): () => void {\n const signal = createSubscriptionScope(opts?.signal);\n\n if (opts?.once) return onAnyWithOnce(listener, signal);\n\n return onAnyWithSignal(listener, signal);\n }\n\n function wait<K extends EventKey<T>>(event: K, opts?: { signal?: AbortSignal }): Promise<T[K]> {\n const signal = createSubscriptionScope(opts?.signal);\n\n if (signal.aborted) return Promise.reject(signal.reason);\n\n return new Promise<T[K]>((resolve, reject) => {\n const onAbort = () => {\n reject(signal.reason);\n };\n\n onceWithSignal(\n event,\n (payload) => {\n signal.removeEventListener('abort', onAbort);\n resolve(payload);\n },\n signal,\n );\n\n signal.addEventListener('abort', onAbort, { once: true });\n });\n }\n\n // events() subscribes eagerly — the listener is registered when events() is called, not when\n // the first .next() runs. This ensures events emitted before iteration begins are buffered.\n // maxBuffer is validated synchronously so callers get a HeraldConfigError at call time.\n function events<K extends EventKey<T>>(\n event: K,\n opts?: { maxBuffer?: number; signal?: AbortSignal },\n ): EventStream<T[K]> {\n const maxBuffer = opts?.maxBuffer ?? Infinity;\n\n if (!(maxBuffer > 0)) throw new HeraldConfigError('maxBuffer must be a positive number');\n\n const activeSignal = createSubscriptionScope(opts?.signal);\n\n if (activeSignal.aborted) {\n const empty = (async function* (): AsyncGenerator<T[K]> {})();\n\n return makeEventStream(empty, async (): Promise<void> => {});\n }\n\n const queue: T[K][] = [];\n let wake: (() => void) | undefined;\n\n const unsub = onWithSignal(\n event,\n (payload) => {\n if (queue.length >= maxBuffer) queue.shift();\n\n queue.push(payload);\n wake?.();\n },\n activeSignal,\n undefined,\n );\n\n async function* generate(): AsyncGenerator<T[K]> {\n try {\n while (!activeSignal.aborted) {\n if (queue.length) {\n yield queue.shift()!;\n continue;\n }\n\n const { promise, resolve } = Promise.withResolvers<void>();\n const abortHandler = (): void => {\n resolve();\n };\n\n wake = resolve;\n activeSignal.addEventListener('abort', abortHandler, { once: true });\n await promise;\n activeSignal.removeEventListener('abort', abortHandler);\n wake = undefined;\n }\n } finally {\n unsub();\n }\n }\n\n const gen = generate();\n\n // Symbol.asyncDispose calls unsub() directly because gen.return() only runs the finally\n // block when the generator has been started (at least one next() call). The unsub guard\n // (called = false in registerEntry) makes this idempotent.\n return makeEventStream(gen, async (): Promise<void> => {\n unsub();\n await gen.return(undefined as unknown as T[K]);\n });\n }\n\n // dispatch is defined at createBus() scope (once per bus, not per emit call) — consistent with\n // callSafe. Receives event/payload/timestamp as arguments so it can be invoked from both the\n // direct path and the middleware chain without capturing per-emit locals in a closure.\n function dispatch(event: EventKey<T>, payload: unknown, timestamp: number): number {\n options?._onDispatch?.(event, payload);\n\n let count = 0;\n let firstError: { err: unknown } | undefined;\n const set = listeners.get(event);\n\n if (set?.size) {\n for (const entry of [...set]) {\n const result = callSafe(() => entry.fn(payload), event, payload, timestamp);\n\n if (result.threw) {\n if (!firstError) firstError = { err: result.err };\n emitTap({ error: result.err, event, type: 'listener-error' });\n }\n\n count++;\n }\n }\n\n if (wildcards.size) {\n for (const entry of [...wildcards]) {\n const result = callSafe(() => entry.fn(event, payload), event, payload, timestamp);\n\n if (result.threw) {\n if (!firstError) firstError = { err: result.err };\n emitTap({ error: result.err, event, type: 'listener-error' });\n }\n\n count++;\n }\n }\n\n emitTap({ event, listeners: count, payload, type: 'emit' });\n\n if (firstError) throw firstError.err;\n\n return count;\n }\n\n // emit() returns the number of listeners invoked (specific + wildcard).\n // Returns 0 if bus is disposed, middleware blocked dispatch, or validatePayload rejected.\n // validatePayload runs first, then middleware, then listeners.\n function emit<K extends EventKey<T>>(event: K, ...args: T[K] extends void ? [] : [payload: T[K]]): number {\n if (disposeController.signal.aborted) return 0;\n\n const payload = (args as unknown[])[0];\n const timestamp = Date.now();\n\n if (options?.validatePayload) {\n try {\n options.validatePayload(event, payload as T[K]);\n } catch (err) {\n if (options?.onError) {\n options.onError({ err, event, payload, timestamp } as EmissionErrorContext<T>);\n\n return 0;\n }\n\n throw err;\n }\n }\n\n const middleware = options?.middleware;\n\n if (!middleware?.length) return dispatch(event, payload, timestamp);\n\n const middlewareList = middleware;\n\n function run(index: number): number {\n const current = middlewareList[index];\n\n if (!current) return dispatch(event, payload, timestamp);\n\n let result = 0;\n let continued = false;\n let synchronous = true;\n\n current(event, payload, () => {\n if (!synchronous || continued) return;\n\n continued = true;\n result = run(index + 1);\n });\n\n synchronous = false;\n\n return result;\n }\n\n return run(0);\n }\n\n // listenerCount counts specific-event listeners only.\n // wildcardCount() is the separate accessor for onAny listeners.\n function listenerCount(event?: EventKey<T>): number {\n if (event !== undefined) return listeners.get(event)?.size ?? 0;\n\n let total = 0;\n\n for (const set of listeners.values()) total += set.size;\n\n return total;\n }\n\n function wildcardCount(): number {\n return wildcards.size;\n }\n\n function eventNames(): EventKey<T>[] {\n return [...listeners.keys()] as EventKey<T>[];\n }\n\n function tap(handler: (event: HeraldEvent<T>) => void, opts?: { signal?: AbortSignal }): () => void {\n if (disposeController.signal.aborted) return noop;\n\n const signal = createSubscriptionScope(opts?.signal);\n\n if (signal.aborted) return noop;\n\n tappers.add(handler);\n\n const onAbort = () => tappers.delete(handler);\n\n signal.addEventListener('abort', onAbort, { once: true });\n\n return () => {\n tappers.delete(handler);\n signal.removeEventListener('abort', onAbort);\n };\n }\n\n function waitAny<K extends readonly [EventKey<T>, EventKey<T>, ...EventKey<T>[]]>(\n eventList: K,\n opts?: { signal?: AbortSignal },\n ): Promise<WaitAnyResult<T, K>> {\n if (eventList.length < 2) throw new HeraldConfigError('waitAny() requires at least 2 event keys');\n\n const activeSignal = createSubscriptionScope(opts?.signal);\n\n if (activeSignal.aborted) return Promise.reject(activeSignal.reason);\n\n return new Promise<WaitAnyResult<T, K>>((resolve, reject) => {\n const raceController = new AbortController();\n const raceSignal = AbortSignal.any([activeSignal, raceController.signal]);\n const unsubs: Unsubscribe[] = [];\n let settled = false;\n\n function cleanup(): void {\n activeSignal.removeEventListener('abort', onAbort);\n raceController.abort();\n for (const unsub of unsubs) unsub();\n }\n\n function onAbort(): void {\n if (settled) return;\n\n settled = true;\n cleanup();\n reject(activeSignal.reason);\n }\n\n activeSignal.addEventListener('abort', onAbort, { once: true });\n\n for (const event of eventList) {\n unsubs.push(\n onceWithSignal(\n event as EventKey<T>,\n (payload) => {\n if (settled) return;\n\n settled = true;\n cleanup();\n resolve({ event, payload } as WaitAnyResult<T, K>);\n },\n raceSignal,\n ),\n );\n }\n });\n }\n\n function dispose(): void {\n if (disposeController.signal.aborted) return;\n\n // Emit dispose first — tappers are cleared by the abort cascade below,\n // so the event must fire before abort triggers their auto-cleanup.\n emitTap({ type: 'dispose' });\n disposeController.abort(new BusDisposedError(busName));\n listeners.clear();\n wildcards.clear();\n tappers.clear();\n }\n\n return {\n get disposalSignal() {\n return disposeController.signal;\n },\n dispose,\n get disposed() {\n return disposeController.signal.aborted;\n },\n emit,\n eventNames,\n events,\n listenerCount,\n on,\n onAny,\n once,\n [Symbol.dispose]: dispose,\n tap,\n wait,\n waitAny,\n wildcardCount,\n };\n}\n","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":"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"}
package/dist/herald.js CHANGED
@@ -1,2 +1,2 @@
1
- function e(e,t){try{return e(),{threw:!1}}catch(e){return t?(t(e),{threw:!1}):{err:e,threw:!0}}}var t=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},n=class extends t{constructor(e){super(e?`Bus "${e}" is disposed`:`Bus is disposed`)}},r=class extends t{},i=()=>{};function a(...e){let t=e.filter(e=>e!==void 0);if(t.length===1)return{dispose:i,signal:t[0]};let n=t.find(e=>e.aborted);if(n)return{dispose:i,signal:n};let r=new AbortController,a=new Map,o=!1;function s(){if(!o){o=!0;for(let[e,t]of a)e.removeEventListener(`abort`,t);a.clear()}}for(let e of t){let t=()=>{r.abort(e.reason),s()};a.set(e,t),e.addEventListener(`abort`,t,{once:!0})}return{dispose:s,signal:r.signal}}function o(e,...t){return a(e,...t).signal}function s(e,t){return Object.assign(e,{[Symbol.asyncDispose]:t})}function c(e){return l(e)}function l(t){let o=new Map,c=new Set,l=new Set,u=new AbortController,d=t?.name,f=t?.maxListeners,p=d?` (${d})`:``;function m(e){if(l.size!==0)for(let t of l)try{t(e)}catch{}}function h(e){return e?a(u.signal,e):{dispose:i,signal:u.signal}}function g(n,r,i,a){return e(n,t?.onError?e=>t.onError?.({err:e,event:r,payload:i,timestamp:a}):void 0)}function _(e,t,n,{event:r,onLog:a,onRemove:o,wildcard:s}){if(n.aborted)return i;let c=!1;function l(){c||(c=!0,e.delete(u),o?.(),n.removeEventListener(`abort`,l),r===void 0?s&&m({type:`unsubscribe-any`}):m({event:r,type:`unsubscribe`}))}let u=t(l);return e.add(u),n.addEventListener(`abort`,l,{once:!0}),r===void 0?s&&m({type:`subscribe-any`}):m({event:r,type:`subscribe`}),f!==void 0&&e.size>f&&`${a}${e.size}${f}${p}`,l}function v(e,t,n,r){let i=o.get(e);i||(i=new Set,o.set(e,i));let a=i;return _(a,e=>({fn:t,unsub:e}),n,{event:e,onLog:`on("${e}")`,onRemove:()=>{a.size===0&&o.delete(e),r?.()}})}function y(e,t,n){return _(c,t=>({fn:e,unsub:t}),t,{onLog:`onAny`,onRemove:n,wildcard:!0})}function b(e,t,n,r){let a={unsub:i};return a.unsub=v(e,e=>{a.unsub(),t(e)},n,r),a.unsub}function x(e,t,n){let r={unsub:i};return r.unsub=y((t,n)=>{r.unsub(),e(t,n)},t,n),r.unsub}function S(e,t,n){let r=h(n?.signal);return n?.once?b(e,t,r.signal,r.dispose):v(e,t,r.signal,r.dispose)}function C(e,t,n){let r=h(n?.signal);return b(e,t,r.signal,r.dispose)}function w(e,t){let n=h(t?.signal);return t?.once?x(e,n.signal,n.dispose):y(e,n.signal,n.dispose)}function T(e,t){let n=h(t?.signal);return n.signal.aborted?Promise.reject(n.signal.reason):new Promise((t,r)=>{let i=()=>{n.dispose(),r(n.signal.reason)};b(e,e=>{n.signal.removeEventListener(`abort`,i),n.dispose(),t(e)},n.signal),n.signal.addEventListener(`abort`,i,{once:!0})})}function E(e,t){let n=t?.maxBuffer??1/0;if(!(n>0))throw new r(`maxBuffer must be a positive number`);let i=h(t?.signal),a=i.signal;if(a.aborted)return s((async function*(){})(),async()=>{});let o=[],c,l=v(e,e=>{o.length>=n&&o.shift(),o.push(e),c?.()},a,i.dispose);async function*u(){try{for(;!a.aborted;){if(o.length){yield o.shift();continue}let{promise:e,resolve:t}=Promise.withResolvers(),n=()=>{t()};c=t,a.addEventListener(`abort`,n,{once:!0}),await e,a.removeEventListener(`abort`,n),c=void 0}}finally{l()}}let d=u();return s(d,async()=>{l(),await d.return(void 0)})}function D(e,n,r){t?._onDispatch?.(e,n);let i=0,a,s=o.get(e);if(s?.size)for(let t of[...s]){let o=g(()=>t.fn(n),e,n,r);o.threw&&(a||={err:o.err},m({error:o.err,event:e,type:`listener-error`})),i++}if(c.size)for(let t of[...c]){let o=g(()=>t.fn(e,n),e,n,r);o.threw&&(a||={err:o.err},m({error:o.err,event:e,type:`listener-error`})),i++}if(m({event:e,listeners:i,payload:n,type:`emit`}),a)throw a.err;return i}function O(e,...n){if(u.signal.aborted)return 0;let r=n[0],i=Date.now();if(t?.validatePayload)try{t.validatePayload(e,r)}catch(n){if(t?.onError)return t.onError({err:n,event:e,payload:r,timestamp:i}),0;throw n}let a=t?.middleware;if(!a?.length)return D(e,r,i);let o=a;function s(t){let n=o[t];if(!n)return D(e,r,i);let a=0,c=!1,l=!0;return n(e,r,()=>{!l||c||(c=!0,a=s(t+1))}),l=!1,a}return s(0)}function k(e){if(e!==void 0)return o.get(e)?.size??0;let t=0;for(let e of o.values())t+=e.size;return t}function A(){return c.size}function j(){return[...o.keys()]}function M(e,t){if(u.signal.aborted)return i;let n=h(t?.signal);if(n.signal.aborted)return i;l.add(e);let r=()=>l.delete(e);return n.signal.addEventListener(`abort`,r,{once:!0}),()=>{l.delete(e),n.signal.removeEventListener(`abort`,r),n.dispose()}}function N(e,t){if(e.length<2)throw new r(`waitAny() requires at least 2 event keys`);let n=h(t?.signal);return n.signal.aborted?Promise.reject(n.signal.reason):new Promise((t,r)=>{let i=new AbortController,o=a(n.signal,i.signal),s=[],c=!1;function l(){n.signal.removeEventListener(`abort`,u),i.abort(),o.dispose(),n.dispose();for(let e of s)e()}function u(){c||(c=!0,l(),r(n.signal.reason))}n.signal.addEventListener(`abort`,u,{once:!0});for(let n of e)s.push(b(n,e=>{c||(c=!0,l(),t({event:n,payload:e}))},o.signal))})}function P(){u.signal.aborted||(m({type:`dispose`}),u.abort(new n(d)),o.clear(),c.clear(),l.clear())}return{get disposalSignal(){return u.signal},dispose:P,get disposed(){return u.signal.aborted},emit:O,eventNames:j,events:E,listenerCount:k,on:S,onAny:w,once:C,[Symbol.dispose]:P,tap:M,wait:T,waitAny:N,wildcardCount:A}}function u(e,t,n,i){if(n.length===0)throw new r(`pipeEvents() requires at least one entry`);let o=a(e.disposalSignal,t.disposalSignal,i?.signal),s=t.emit,c=n.map(t=>{if(typeof t==`string`){let n=t;return e.on(n,e=>s(n,e),{signal:o.signal})}let{from:n,to:r}=t;return e.on(n,e=>s(r,e),{signal:o.signal})});return()=>{for(let e of c)e();o.dispose()}}export{n as BusDisposedError,r as HeraldConfigError,t as HeraldError,o as combineSignals,c as createBus,u as pipeEvents};
1
+ function e(e,t){try{return e(),{threw:!1}}catch(e){return t?(t(e),{threw:!1}):{err:e,threw:!0}}}var t=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},n=class extends t{constructor(e){super(e?`Bus "${e}" is disposed`:`Bus is disposed`)}},r=class extends t{},i=()=>{};function a(e,t){return Object.assign(e,{[Symbol.asyncDispose]:t})}function o(t){let o=new Map,s=new Set,c=new Set,l=new AbortController,u=t?.name,d=t?.maxListeners,f=u?` (${u})`:``;function p(e){if(c.size!==0)for(let t of c)try{t(e)}catch{}}function m(e){return e?AbortSignal.any([l.signal,e]):l.signal}function h(n,r,i,a){return e(n,t?.onError?e=>t.onError?.({err:e,event:r,payload:i,timestamp:a}):void 0)}function g(e,t,n,{event:r,onLog:a,onRemove:o,wildcard:s}){if(n.aborted)return i;let c=!1;function l(){c||(c=!0,e.delete(u),o?.(),n.removeEventListener(`abort`,l),r===void 0?s&&p({type:`unsubscribe-any`}):p({event:r,type:`unsubscribe`}))}let u=t(l);return e.add(u),n.addEventListener(`abort`,l,{once:!0}),r===void 0?s&&p({type:`subscribe-any`}):p({event:r,type:`subscribe`}),d!==void 0&&e.size>d&&`${a}${e.size}${d}${f}`,l}function _(e,t,n,r){let i=o.get(e);i||(i=new Set,o.set(e,i));let a=i;return g(a,e=>({fn:t,unsub:e}),n,{event:e,onLog:`on("${e}")`,onRemove:()=>{a.size===0&&o.delete(e),r?.()}})}function v(e,t,n){return g(s,t=>({fn:e,unsub:t}),t,{onLog:`onAny`,onRemove:n,wildcard:!0})}function y(e,t,n,r){let a={unsub:i};return a.unsub=_(e,e=>{a.unsub(),t(e)},n,r),a.unsub}function b(e,t,n){let r={unsub:i};return r.unsub=v((t,n)=>{r.unsub(),e(t,n)},t,n),r.unsub}function x(e,t,n){let r=m(n?.signal);return n?.once?y(e,t,r):_(e,t,r)}function S(e,t,n){return y(e,t,m(n?.signal))}function C(e,t){let n=m(t?.signal);return t?.once?b(e,n):v(e,n)}function w(e,t){let n=m(t?.signal);return n.aborted?Promise.reject(n.reason):new Promise((t,r)=>{let i=()=>{r(n.reason)};y(e,e=>{n.removeEventListener(`abort`,i),t(e)},n),n.addEventListener(`abort`,i,{once:!0})})}function T(e,t){let n=t?.maxBuffer??1/0;if(!(n>0))throw new r(`maxBuffer must be a positive number`);let i=m(t?.signal);if(i.aborted)return a((async function*(){})(),async()=>{});let o=[],s,c=_(e,e=>{o.length>=n&&o.shift(),o.push(e),s?.()},i,void 0);async function*l(){try{for(;!i.aborted;){if(o.length){yield o.shift();continue}let{promise:e,resolve:t}=Promise.withResolvers(),n=()=>{t()};s=t,i.addEventListener(`abort`,n,{once:!0}),await e,i.removeEventListener(`abort`,n),s=void 0}}finally{c()}}let u=l();return a(u,async()=>{c(),await u.return(void 0)})}function E(e,n,r){t?._onDispatch?.(e,n);let i=0,a,c=o.get(e);if(c?.size)for(let t of[...c]){let o=h(()=>t.fn(n),e,n,r);o.threw&&(a||={err:o.err},p({error:o.err,event:e,type:`listener-error`})),i++}if(s.size)for(let t of[...s]){let o=h(()=>t.fn(e,n),e,n,r);o.threw&&(a||={err:o.err},p({error:o.err,event:e,type:`listener-error`})),i++}if(p({event:e,listeners:i,payload:n,type:`emit`}),a)throw a.err;return i}function D(e,...n){if(l.signal.aborted)return 0;let r=n[0],i=Date.now();if(t?.validatePayload)try{t.validatePayload(e,r)}catch(n){if(t?.onError)return t.onError({err:n,event:e,payload:r,timestamp:i}),0;throw n}let a=t?.middleware;if(!a?.length)return E(e,r,i);let o=a;function s(t){let n=o[t];if(!n)return E(e,r,i);let a=0,c=!1,l=!0;return n(e,r,()=>{!l||c||(c=!0,a=s(t+1))}),l=!1,a}return s(0)}function O(e){if(e!==void 0)return o.get(e)?.size??0;let t=0;for(let e of o.values())t+=e.size;return t}function k(){return s.size}function A(){return[...o.keys()]}function j(e,t){if(l.signal.aborted)return i;let n=m(t?.signal);if(n.aborted)return i;c.add(e);let r=()=>c.delete(e);return n.addEventListener(`abort`,r,{once:!0}),()=>{c.delete(e),n.removeEventListener(`abort`,r)}}function M(e,t){if(e.length<2)throw new r(`waitAny() requires at least 2 event keys`);let n=m(t?.signal);return n.aborted?Promise.reject(n.reason):new Promise((t,r)=>{let i=new AbortController,a=AbortSignal.any([n,i.signal]),o=[],s=!1;function c(){n.removeEventListener(`abort`,l),i.abort();for(let e of o)e()}function l(){s||(s=!0,c(),r(n.reason))}n.addEventListener(`abort`,l,{once:!0});for(let n of e)o.push(y(n,e=>{s||(s=!0,c(),t({event:n,payload:e}))},a))})}function N(){l.signal.aborted||(p({type:`dispose`}),l.abort(new n(u)),o.clear(),s.clear(),c.clear())}return{get disposalSignal(){return l.signal},dispose:N,get disposed(){return l.signal.aborted},emit:D,eventNames:A,events:T,listenerCount:O,on:x,onAny:C,once:S,[Symbol.dispose]:N,tap:j,wait:w,waitAny:M,wildcardCount:k}}function s(e,t,n,i){if(n.length===0)throw new r(`pipeEvents() requires at least one entry`);let a=[e.disposalSignal,t.disposalSignal];i?.signal&&a.push(i.signal);let o=AbortSignal.any(a),s=t.emit,c=n.map(t=>{if(typeof t==`string`){let n=t;return e.on(n,e=>s(n,e),{signal:o})}let{from:n,to:r}=t;return e.on(n,e=>s(r,e),{signal:o})});return()=>{for(let e of c)e()}}export{n as BusDisposedError,r as HeraldConfigError,t as HeraldError,o as createBus,s as pipeEvents};
2
2
  //# sourceMappingURL=herald.js.map