@vielzeug/herald 26.10.15 → 26.10.16

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/_dev.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"_dev.cjs","names":[],"sources":["../src/_dev.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"],"mappings":"AAGA,SAAgB,KAAK,EAAmB,CAExC"}
1
+ {"version":3,"file":"_dev.cjs","names":[],"sources":["../src/_dev.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"],"mappings":"AAGA,SAAgB,KAAK,EAAmB,CAExC,C"}
package/dist/_dev.js CHANGED
@@ -1,2 +1,6 @@
1
- function warn(e){}export{warn};
1
+ //#region src/_dev.ts
2
+ function warn(e) {}
3
+ //#endregion
4
+ export { warn };
5
+
2
6
  //# sourceMappingURL=_dev.js.map
package/dist/_dev.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"_dev.js","names":[],"sources":["../src/_dev.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"],"mappings":"AAGA,SAAgB,KAAK,EAAmB,CAExC"}
1
+ {"version":3,"file":"_dev.js","names":[],"sources":["../src/_dev.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"],"mappings":";AAGA,SAAgB,KAAK,GAAmB,CAExC"}
package/dist/bus.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bus.cjs","names":[],"sources":["../src/bus.ts"],"sourcesContent":["import { warn as _internalWarn } from './_dev';\nimport { BusDisposedError } from './errors';\nimport type {\n Bus,\n BusOptions,\n EventKey,\n EventMap,\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\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\nexport function createBus<T extends EventMap = Record<string, unknown>>(options?: BusOptions): Bus<T> {\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 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 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 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 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 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 function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): () => void {\n return onWithSignal(event, listener, createSubscriptionScope(opts?.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 return onAnyWithSignal(listener, createSubscriptionScope(opts?.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 function dispatch(event: EventKey<T>, payload: unknown): void {\n let count = 0;\n let firstError: { value: unknown } | undefined;\n const set = listeners.get(event);\n\n if (set?.size) {\n for (const entry of [...set]) {\n try {\n entry.fn(payload);\n } catch (err) {\n firstError ??= { value: err };\n emitTap({ error: err, event, type: 'error' });\n }\n\n count++;\n }\n }\n\n if (wildcards.size) {\n for (const entry of [...wildcards]) {\n try {\n entry.fn(event, payload);\n } catch (err) {\n firstError ??= { value: err };\n emitTap({ error: err, event, type: 'error' });\n }\n\n count++;\n }\n }\n\n emitTap({ event, listeners: count, payload, type: 'emit' });\n\n if (firstError) throw firstError.value;\n }\n\n function emit<K extends EventKey<T>>(event: K, ...args: T[K] extends void ? [] : [payload: T[K]]): void {\n if (disposeController.signal.aborted) return;\n\n const payload = (args as unknown[])[0];\n\n dispatch(event, payload);\n }\n\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>[]>(\n eventList: K,\n opts?: { signal?: AbortSignal },\n ): Promise<WaitAnyResult<T, K>> {\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 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 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.cjs","names":["BusDisposedError","require_errors","listeners","wildcards","tappers","disposeController","busName","options","maxListeners","busTag","tapper","event","signal","called","container","entry","onRemove","wildcard","makeEntry","onLog","set","capturedSet","listener","ref","payload","opts","reject","resolve","count","firstError","err","args","total","handler","activeSignal","raceController","raceSignal","unsubs","settled","unsub","eventList"],"sources":["../src/bus.ts"],"sourcesContent":["import { warn as _internalWarn } from './_dev';\nimport { BusDisposedError } from './errors';\nimport type {\n Bus,\n BusOptions,\n EventKey,\n EventMap,\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\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\nexport function createBus<T extends EventMap = Record<string, unknown>>(options?: BusOptions): Bus<T> {\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 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 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 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 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 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 function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): () => void {\n return onWithSignal(event, listener, createSubscriptionScope(opts?.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 return onAnyWithSignal(listener, createSubscriptionScope(opts?.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 function dispatch(event: EventKey<T>, payload: unknown): void {\n let count = 0;\n let firstError: { value: unknown } | undefined;\n const set = listeners.get(event);\n\n if (set?.size) {\n for (const entry of [...set]) {\n try {\n entry.fn(payload);\n } catch (err) {\n firstError ??= { value: err };\n emitTap({ error: err, event, type: 'error' });\n }\n\n count++;\n }\n }\n\n if (wildcards.size) {\n for (const entry of [...wildcards]) {\n try {\n entry.fn(event, payload);\n } catch (err) {\n firstError ??= { value: err };\n emitTap({ error: err, event, type: 'error' });\n }\n\n count++;\n }\n }\n\n emitTap({ event, listeners: count, payload, type: 'emit' });\n\n if (firstError) throw firstError.value;\n }\n\n function emit<K extends EventKey<T>>(event: K, ...args: T[K] extends void ? [] : [payload: T[K]]): void {\n if (disposeController.signal.aborted) return;\n\n const payload = (args as unknown[])[0];\n\n dispatch(event, payload);\n }\n\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>[]>(\n eventList: K,\n opts?: { signal?: AbortSignal },\n ): Promise<WaitAnyResult<T, K>> {\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 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 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/bus.js CHANGED
@@ -1,2 +1,188 @@
1
- import"./_dev.js";import{BusDisposedError as e}from"./errors.js";var noop=()=>{};function createBus(t){let n=new Map,r=new Set,i=new Set,a=new AbortController,o=t?.name,s=t?.maxListeners,c=o?` (${o})`:``;function emitTap(e){if(i.size!==0)for(let t of i)try{t(e)}catch{}}function createSubscriptionScope(e){return e?AbortSignal.any([a.signal,e]):a.signal}function registerEntry(e,t,n,{event:r,onLog:i,onRemove:a,wildcard:o}){if(n.aborted)return noop;let l=!1;function unsub(){l||(l=!0,e.delete(u),a?.(),n.removeEventListener(`abort`,unsub),r===void 0?o&&emitTap({type:`unsubscribe-any`}):emitTap({event:r,type:`unsubscribe`}))}let u=t(unsub);return e.add(u),n.addEventListener(`abort`,unsub,{once:!0}),r===void 0?o&&emitTap({type:`subscribe-any`}):emitTap({event:r,type:`subscribe`}),s!==void 0&&e.size>s&&`${i}${e.size}${s}${c}`,unsub}function onWithSignal(e,t,r,i){let a=n.get(e);a||(a=new Set,n.set(e,a));let o=a;return registerEntry(o,e=>({fn:t,unsub:e}),r,{event:e,onLog:`on("${e}")`,onRemove:()=>{o.size===0&&n.delete(e),i?.()}})}function onAnyWithSignal(e,t,n){return registerEntry(r,t=>({fn:e,unsub:t}),t,{onLog:`onAny`,onRemove:n,wildcard:!0})}function onceWithSignal(e,t,n,r){let i={unsub:noop};return i.unsub=onWithSignal(e,e=>{i.unsub(),t(e)},n,r),i.unsub}function on(e,t,n){return onWithSignal(e,t,createSubscriptionScope(n?.signal))}function once(e,t,n){return onceWithSignal(e,t,createSubscriptionScope(n?.signal))}function onAny(e,t){return onAnyWithSignal(e,createSubscriptionScope(t?.signal))}function wait(e,t){let n=createSubscriptionScope(t?.signal);return n.aborted?Promise.reject(n.reason):new Promise((t,r)=>{let onAbort=()=>{r(n.reason)};onceWithSignal(e,e=>{n.removeEventListener(`abort`,onAbort),t(e)},n),n.addEventListener(`abort`,onAbort,{once:!0})})}function dispatch(e,t){let i=0,a,o=n.get(e);if(o?.size)for(let n of[...o]){try{n.fn(t)}catch(t){a??={value:t},emitTap({error:t,event:e,type:`error`})}i++}if(r.size)for(let n of[...r]){try{n.fn(e,t)}catch(t){a??={value:t},emitTap({error:t,event:e,type:`error`})}i++}if(emitTap({event:e,listeners:i,payload:t,type:`emit`}),a)throw a.value}function emit(e,...t){if(a.signal.aborted)return;let n=t[0];dispatch(e,n)}function listenerCount(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 wildcardCount(){return r.size}function eventNames(){return[...n.keys()]}function tap(e,t){if(a.signal.aborted)return noop;let n=createSubscriptionScope(t?.signal);if(n.aborted)return noop;i.add(e);let onAbort=()=>i.delete(e);return n.addEventListener(`abort`,onAbort,{once:!0}),()=>{i.delete(e),n.removeEventListener(`abort`,onAbort)}}function waitAny(e,t){let n=createSubscriptionScope(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 cleanup(){n.removeEventListener(`abort`,onAbort),i.abort();for(let e of o)e()}function onAbort(){s||(s=!0,cleanup(),r(n.reason))}n.addEventListener(`abort`,onAbort,{once:!0});for(let n of e)o.push(onceWithSignal(n,e=>{s||(s=!0,cleanup(),t({event:n,payload:e}))},a))})}function dispose(){a.signal.aborted||(emitTap({type:`dispose`}),a.abort(new e(o)),n.clear(),r.clear(),i.clear())}return{get disposalSignal(){return a.signal},dispose,get disposed(){return a.signal.aborted},emit,eventNames,listenerCount,on,onAny,once,[Symbol.dispose]:dispose,tap,wait,waitAny,wildcardCount}}export{createBus,noop};
1
+ import "./_dev.js";
2
+ import { BusDisposedError as e } from "./errors.js";
3
+ //#region src/bus.ts
4
+ var noop = () => {};
5
+ function createBus(t) {
6
+ let n = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Set(), a = new AbortController(), o = t?.name, s = t?.maxListeners, c = o ? ` (${o})` : "";
7
+ function emitTap(e) {
8
+ if (i.size !== 0) for (let t of i) try {
9
+ t(e);
10
+ } catch {}
11
+ }
12
+ function createSubscriptionScope(e) {
13
+ return e ? AbortSignal.any([a.signal, e]) : a.signal;
14
+ }
15
+ function registerEntry(e, t, n, { event: r, onLog: i, onRemove: a, wildcard: o }) {
16
+ if (n.aborted) return noop;
17
+ let l = !1;
18
+ function unsub() {
19
+ l || (l = !0, e.delete(u), a?.(), n.removeEventListener("abort", unsub), r === void 0 ? o && emitTap({ type: "unsubscribe-any" }) : emitTap({
20
+ event: r,
21
+ type: "unsubscribe"
22
+ }));
23
+ }
24
+ let u = t(unsub);
25
+ return e.add(u), n.addEventListener("abort", unsub, { once: !0 }), r === void 0 ? o && emitTap({ type: "subscribe-any" }) : emitTap({
26
+ event: r,
27
+ type: "subscribe"
28
+ }), s !== void 0 && e.size > s && `${i}${e.size}${s}${c}`, unsub;
29
+ }
30
+ function onWithSignal(e, t, r, i) {
31
+ let a = n.get(e);
32
+ a || (a = /* @__PURE__ */ new Set(), n.set(e, a));
33
+ let o = a;
34
+ return registerEntry(o, (e) => ({
35
+ fn: t,
36
+ unsub: e
37
+ }), r, {
38
+ event: e,
39
+ onLog: `on("${e}")`,
40
+ onRemove: () => {
41
+ o.size === 0 && n.delete(e), i?.();
42
+ }
43
+ });
44
+ }
45
+ function onAnyWithSignal(e, t, n) {
46
+ return registerEntry(r, (t) => ({
47
+ fn: e,
48
+ unsub: t
49
+ }), t, {
50
+ onLog: "onAny",
51
+ onRemove: n,
52
+ wildcard: !0
53
+ });
54
+ }
55
+ function onceWithSignal(e, t, n, r) {
56
+ let i = { unsub: noop };
57
+ return i.unsub = onWithSignal(e, (e) => {
58
+ i.unsub(), t(e);
59
+ }, n, r), i.unsub;
60
+ }
61
+ function on(e, t, n) {
62
+ return onWithSignal(e, t, createSubscriptionScope(n?.signal));
63
+ }
64
+ function once(e, t, n) {
65
+ return onceWithSignal(e, t, createSubscriptionScope(n?.signal));
66
+ }
67
+ function onAny(e, t) {
68
+ return onAnyWithSignal(e, createSubscriptionScope(t?.signal));
69
+ }
70
+ function wait(e, t) {
71
+ let n = createSubscriptionScope(t?.signal);
72
+ return n.aborted ? Promise.reject(n.reason) : new Promise((t, r) => {
73
+ let onAbort = () => {
74
+ r(n.reason);
75
+ };
76
+ onceWithSignal(e, (e) => {
77
+ n.removeEventListener("abort", onAbort), t(e);
78
+ }, n), n.addEventListener("abort", onAbort, { once: !0 });
79
+ });
80
+ }
81
+ function dispatch(e, t) {
82
+ let i = 0, a, o = n.get(e);
83
+ if (o?.size) for (let n of [...o]) {
84
+ try {
85
+ n.fn(t);
86
+ } catch (t) {
87
+ a ??= { value: t }, emitTap({
88
+ error: t,
89
+ event: e,
90
+ type: "error"
91
+ });
92
+ }
93
+ i++;
94
+ }
95
+ if (r.size) for (let n of [...r]) {
96
+ try {
97
+ n.fn(e, t);
98
+ } catch (t) {
99
+ a ??= { value: t }, emitTap({
100
+ error: t,
101
+ event: e,
102
+ type: "error"
103
+ });
104
+ }
105
+ i++;
106
+ }
107
+ if (emitTap({
108
+ event: e,
109
+ listeners: i,
110
+ payload: t,
111
+ type: "emit"
112
+ }), a) throw a.value;
113
+ }
114
+ function emit(e, ...t) {
115
+ if (a.signal.aborted) return;
116
+ let n = t[0];
117
+ dispatch(e, n);
118
+ }
119
+ function listenerCount(e) {
120
+ if (e !== void 0) return n.get(e)?.size ?? 0;
121
+ let t = 0;
122
+ for (let e of n.values()) t += e.size;
123
+ return t;
124
+ }
125
+ function wildcardCount() {
126
+ return r.size;
127
+ }
128
+ function eventNames() {
129
+ return [...n.keys()];
130
+ }
131
+ function tap(e, t) {
132
+ if (a.signal.aborted) return noop;
133
+ let n = createSubscriptionScope(t?.signal);
134
+ if (n.aborted) return noop;
135
+ i.add(e);
136
+ let onAbort = () => i.delete(e);
137
+ return n.addEventListener("abort", onAbort, { once: !0 }), () => {
138
+ i.delete(e), n.removeEventListener("abort", onAbort);
139
+ };
140
+ }
141
+ function waitAny(e, t) {
142
+ let n = createSubscriptionScope(t?.signal);
143
+ return n.aborted ? Promise.reject(n.reason) : new Promise((t, r) => {
144
+ let i = new AbortController(), a = AbortSignal.any([n, i.signal]), o = [], s = !1;
145
+ function cleanup() {
146
+ n.removeEventListener("abort", onAbort), i.abort();
147
+ for (let e of o) e();
148
+ }
149
+ function onAbort() {
150
+ s || (s = !0, cleanup(), r(n.reason));
151
+ }
152
+ n.addEventListener("abort", onAbort, { once: !0 });
153
+ for (let n of e) o.push(onceWithSignal(n, (e) => {
154
+ s || (s = !0, cleanup(), t({
155
+ event: n,
156
+ payload: e
157
+ }));
158
+ }, a));
159
+ });
160
+ }
161
+ function dispose() {
162
+ a.signal.aborted || (emitTap({ type: "dispose" }), a.abort(new e(o)), n.clear(), r.clear(), i.clear());
163
+ }
164
+ return {
165
+ get disposalSignal() {
166
+ return a.signal;
167
+ },
168
+ dispose,
169
+ get disposed() {
170
+ return a.signal.aborted;
171
+ },
172
+ emit,
173
+ eventNames,
174
+ listenerCount,
175
+ on,
176
+ onAny,
177
+ once,
178
+ [Symbol.dispose]: dispose,
179
+ tap,
180
+ wait,
181
+ waitAny,
182
+ wildcardCount
183
+ };
184
+ }
185
+ //#endregion
186
+ export { createBus, noop };
187
+
2
188
  //# sourceMappingURL=bus.js.map
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 { BusDisposedError } from './errors';\nimport type {\n Bus,\n BusOptions,\n EventKey,\n EventMap,\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\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\nexport function createBus<T extends EventMap = Record<string, unknown>>(options?: BusOptions): Bus<T> {\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 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 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 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 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 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 function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): () => void {\n return onWithSignal(event, listener, createSubscriptionScope(opts?.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 return onAnyWithSignal(listener, createSubscriptionScope(opts?.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 function dispatch(event: EventKey<T>, payload: unknown): void {\n let count = 0;\n let firstError: { value: unknown } | undefined;\n const set = listeners.get(event);\n\n if (set?.size) {\n for (const entry of [...set]) {\n try {\n entry.fn(payload);\n } catch (err) {\n firstError ??= { value: err };\n emitTap({ error: err, event, type: 'error' });\n }\n\n count++;\n }\n }\n\n if (wildcards.size) {\n for (const entry of [...wildcards]) {\n try {\n entry.fn(event, payload);\n } catch (err) {\n firstError ??= { value: err };\n emitTap({ error: err, event, type: 'error' });\n }\n\n count++;\n }\n }\n\n emitTap({ event, listeners: count, payload, type: 'emit' });\n\n if (firstError) throw firstError.value;\n }\n\n function emit<K extends EventKey<T>>(event: K, ...args: T[K] extends void ? [] : [payload: T[K]]): void {\n if (disposeController.signal.aborted) return;\n\n const payload = (args as unknown[])[0];\n\n dispatch(event, payload);\n }\n\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>[]>(\n eventList: K,\n opts?: { signal?: AbortSignal },\n ): Promise<WaitAnyResult<T, K>> {\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 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 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":["listeners","wildcards","tappers","disposeController","busName","options","maxListeners","busTag","tapper","event","signal","called","container","entry","onRemove","wildcard","makeEntry","onLog","set","capturedSet","listener","ref","payload","opts","resolve","count","firstError","err","args","total","handler","activeSignal","raceController","raceSignal","unsubs","settled","unsub","reject","eventList","BusDisposedError"],"sources":["../src/bus.ts"],"sourcesContent":["import { warn as _internalWarn } from './_dev';\nimport { BusDisposedError } from './errors';\nimport type {\n Bus,\n BusOptions,\n EventKey,\n EventMap,\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\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\nexport function createBus<T extends EventMap = Record<string, unknown>>(options?: BusOptions): Bus<T> {\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 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 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 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 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 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 function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): () => void {\n return onWithSignal(event, listener, createSubscriptionScope(opts?.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 return onAnyWithSignal(listener, createSubscriptionScope(opts?.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 function dispatch(event: EventKey<T>, payload: unknown): void {\n let count = 0;\n let firstError: { value: unknown } | undefined;\n const set = listeners.get(event);\n\n if (set?.size) {\n for (const entry of [...set]) {\n try {\n entry.fn(payload);\n } catch (err) {\n firstError ??= { value: err };\n emitTap({ error: err, event, type: 'error' });\n }\n\n count++;\n }\n }\n\n if (wildcards.size) {\n for (const entry of [...wildcards]) {\n try {\n entry.fn(event, payload);\n } catch (err) {\n firstError ??= { value: err };\n emitTap({ error: err, event, type: 'error' });\n }\n\n count++;\n }\n }\n\n emitTap({ event, listeners: count, payload, type: 'emit' });\n\n if (firstError) throw firstError.value;\n }\n\n function emit<K extends EventKey<T>>(event: K, ...args: T[K] extends void ? [] : [payload: T[K]]): void {\n if (disposeController.signal.aborted) return;\n\n const payload = (args as unknown[])[0];\n\n dispatch(event, payload);\n }\n\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>[]>(\n eventList: K,\n opts?: { signal?: AbortSignal },\n ): Promise<WaitAnyResult<T, K>> {\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 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 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 +1 @@
1
- {"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** 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"],"mappings":"AACA,IAAa,YAAb,cAAiC,KAAM,CACrC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,WAAW,KACvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CACF,EAGa,iBAAb,cAAsC,WAAY,CAChD,YAAY,EAAkB,CAC5B,MAAM,EAAU,QAAQ,EAAQ,eAAiB,iBAAiB,CACpE,CACF"}
1
+ {"version":3,"file":"errors.cjs","names":["message","opts","busName"],"sources":["../src/errors.ts"],"sourcesContent":["/** 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"],"mappings":"AACA,IAAa,YAAb,cAAiC,KAAM,CACrC,YAAY,EAAiB,EAAqB,CAChD,MAAMA,EAASC,CAAI,EACnB,KAAK,KAAO,WAAW,KACvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CACF,EAGa,iBAAb,cAAsC,WAAY,CAChD,YAAY,EAAkB,CAC5B,MAAMC,EAAU,QAAQA,EAAQ,eAAiB,iBAAiB,CACpE,CACF,E"}
package/dist/errors.js CHANGED
@@ -1,2 +1,14 @@
1
- var HeraldError=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},BusDisposedError=class extends HeraldError{constructor(e){super(e?`Bus "${e}" is disposed`:`Bus is disposed`)}};export{BusDisposedError,HeraldError};
1
+ //#region src/errors.ts
2
+ var HeraldError = class extends Error {
3
+ constructor(e, t) {
4
+ super(e, t), this.name = new.target.name, Object.setPrototypeOf(this, new.target.prototype);
5
+ }
6
+ }, BusDisposedError = class extends HeraldError {
7
+ constructor(e) {
8
+ super(e ? `Bus "${e}" is disposed` : "Bus is disposed");
9
+ }
10
+ };
11
+ //#endregion
12
+ export { BusDisposedError, HeraldError };
13
+
2
14
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** 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"],"mappings":"AACA,IAAa,YAAb,cAAiC,KAAM,CACrC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,WAAW,KACvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CACF,EAGa,iBAAb,cAAsC,WAAY,CAChD,YAAY,EAAkB,CAC5B,MAAM,EAAU,QAAQ,EAAQ,eAAiB,iBAAiB,CACpE,CACF"}
1
+ {"version":3,"file":"errors.js","names":["message","opts","busName"],"sources":["../src/errors.ts"],"sourcesContent":["/** 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"],"mappings":";AACA,IAAa,cAAb,cAAiC,MAAM;CACrC,YAAY,GAAiB,GAAqB;EAGhD,AAFA,MAAMA,GAASC,CAAI,GACnB,KAAK,OAAO,WAAW,MACvB,OAAO,eAAe,MAAM,WAAW,SAAS;CAClD;AACF,GAGa,mBAAb,cAAsC,YAAY;CAChD,YAAY,GAAkB;EAC5B,MAAMC,IAAU,QAAQA,EAAQ,iBAAiB,iBAAiB;CACpE;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"herald.cjs","names":[],"sources":["../src/_dev.ts","../src/errors.ts","../src/bus.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","/** 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","import { warn as _internalWarn } from './_dev';\nimport { BusDisposedError } from './errors';\nimport type {\n Bus,\n BusOptions,\n EventKey,\n EventMap,\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\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\nexport function createBus<T extends EventMap = Record<string, unknown>>(options?: BusOptions): Bus<T> {\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 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 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 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 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 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 function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): () => void {\n return onWithSignal(event, listener, createSubscriptionScope(opts?.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 return onAnyWithSignal(listener, createSubscriptionScope(opts?.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 function dispatch(event: EventKey<T>, payload: unknown): void {\n let count = 0;\n let firstError: { value: unknown } | undefined;\n const set = listeners.get(event);\n\n if (set?.size) {\n for (const entry of [...set]) {\n try {\n entry.fn(payload);\n } catch (err) {\n firstError ??= { value: err };\n emitTap({ error: err, event, type: 'error' });\n }\n\n count++;\n }\n }\n\n if (wildcards.size) {\n for (const entry of [...wildcards]) {\n try {\n entry.fn(event, payload);\n } catch (err) {\n firstError ??= { value: err };\n emitTap({ error: err, event, type: 'error' });\n }\n\n count++;\n }\n }\n\n emitTap({ event, listeners: count, payload, type: 'emit' });\n\n if (firstError) throw firstError.value;\n }\n\n function emit<K extends EventKey<T>>(event: K, ...args: T[K] extends void ? [] : [payload: T[K]]): void {\n if (disposeController.signal.aborted) return;\n\n const payload = (args as unknown[])[0];\n\n dispatch(event, payload);\n }\n\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>[]>(\n eventList: K,\n opts?: { signal?: AbortSignal },\n ): Promise<WaitAnyResult<T, K>> {\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 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 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":"herald.cjs","names":["message","opts","busName","listeners","wildcards","tappers","disposeController","options","maxListeners","busTag","tapper","event","signal","called","container","entry","onRemove","wildcard","makeEntry","onLog","set","capturedSet","listener","ref","payload","reject","resolve","count","firstError","err","args","total","handler","activeSignal","raceController","raceSignal","unsubs","settled","unsub","eventList"],"sources":["../src/_dev.ts","../src/errors.ts","../src/bus.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","/** 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","import { warn as _internalWarn } from './_dev';\nimport { BusDisposedError } from './errors';\nimport type {\n Bus,\n BusOptions,\n EventKey,\n EventMap,\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\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\nexport function createBus<T extends EventMap = Record<string, unknown>>(options?: BusOptions): Bus<T> {\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 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 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 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 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 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 function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): () => void {\n return onWithSignal(event, listener, createSubscriptionScope(opts?.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 return onAnyWithSignal(listener, createSubscriptionScope(opts?.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 function dispatch(event: EventKey<T>, payload: unknown): void {\n let count = 0;\n let firstError: { value: unknown } | undefined;\n const set = listeners.get(event);\n\n if (set?.size) {\n for (const entry of [...set]) {\n try {\n entry.fn(payload);\n } catch (err) {\n firstError ??= { value: err };\n emitTap({ error: err, event, type: 'error' });\n }\n\n count++;\n }\n }\n\n if (wildcards.size) {\n for (const entry of [...wildcards]) {\n try {\n entry.fn(event, payload);\n } catch (err) {\n firstError ??= { value: err };\n emitTap({ error: err, event, type: 'error' });\n }\n\n count++;\n }\n }\n\n emitTap({ event, listeners: count, payload, type: 'emit' });\n\n if (firstError) throw firstError.value;\n }\n\n function emit<K extends EventKey<T>>(event: K, ...args: T[K] extends void ? [] : [payload: T[K]]): void {\n if (disposeController.signal.aborted) return;\n\n const payload = (args as unknown[])[0];\n\n dispatch(event, payload);\n }\n\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>[]>(\n eventList: K,\n opts?: { signal?: AbortSignal },\n ): Promise<WaitAnyResult<T, K>> {\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 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 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 +1 @@
1
- {"version":3,"file":"herald.iife.js","names":[],"sources":["../src/_dev.ts","../src/errors.ts","../src/bus.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","/** 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","import { warn as _internalWarn } from './_dev';\nimport { BusDisposedError } from './errors';\nimport type {\n Bus,\n BusOptions,\n EventKey,\n EventMap,\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\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\nexport function createBus<T extends EventMap = Record<string, unknown>>(options?: BusOptions): Bus<T> {\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 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 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 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 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 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 function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): () => void {\n return onWithSignal(event, listener, createSubscriptionScope(opts?.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 return onAnyWithSignal(listener, createSubscriptionScope(opts?.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 function dispatch(event: EventKey<T>, payload: unknown): void {\n let count = 0;\n let firstError: { value: unknown } | undefined;\n const set = listeners.get(event);\n\n if (set?.size) {\n for (const entry of [...set]) {\n try {\n entry.fn(payload);\n } catch (err) {\n firstError ??= { value: err };\n emitTap({ error: err, event, type: 'error' });\n }\n\n count++;\n }\n }\n\n if (wildcards.size) {\n for (const entry of [...wildcards]) {\n try {\n entry.fn(event, payload);\n } catch (err) {\n firstError ??= { value: err };\n emitTap({ error: err, event, type: 'error' });\n }\n\n count++;\n }\n }\n\n emitTap({ event, listeners: count, payload, type: 'emit' });\n\n if (firstError) throw firstError.value;\n }\n\n function emit<K extends EventKey<T>>(event: K, ...args: T[K] extends void ? [] : [payload: T[K]]): void {\n if (disposeController.signal.aborted) return;\n\n const payload = (args as unknown[])[0];\n\n dispatch(event, payload);\n }\n\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>[]>(\n eventList: K,\n opts?: { signal?: AbortSignal },\n ): Promise<WaitAnyResult<T, K>> {\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 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 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":"herald.iife.js","names":["exports","message","opts","busName","listeners","wildcards","tappers","disposeController","options","maxListeners","busTag","tapper","event","signal","called","container","entry","onRemove","wildcard","makeEntry","onLog","set","capturedSet","listener","ref","payload","reject","resolve","count","firstError","err","args","total","handler","activeSignal","raceController","raceSignal","unsubs","settled","unsub","eventList"],"sources":["../src/_dev.ts","../src/errors.ts","../src/bus.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","/** 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","import { warn as _internalWarn } from './_dev';\nimport { BusDisposedError } from './errors';\nimport type {\n Bus,\n BusOptions,\n EventKey,\n EventMap,\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\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\nexport function createBus<T extends EventMap = Record<string, unknown>>(options?: BusOptions): Bus<T> {\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 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 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 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 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 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 function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): () => void {\n return onWithSignal(event, listener, createSubscriptionScope(opts?.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 return onAnyWithSignal(listener, createSubscriptionScope(opts?.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 function dispatch(event: EventKey<T>, payload: unknown): void {\n let count = 0;\n let firstError: { value: unknown } | undefined;\n const set = listeners.get(event);\n\n if (set?.size) {\n for (const entry of [...set]) {\n try {\n entry.fn(payload);\n } catch (err) {\n firstError ??= { value: err };\n emitTap({ error: err, event, type: 'error' });\n }\n\n count++;\n }\n }\n\n if (wildcards.size) {\n for (const entry of [...wildcards]) {\n try {\n entry.fn(event, payload);\n } catch (err) {\n firstError ??= { value: err };\n emitTap({ error: err, event, type: 'error' });\n }\n\n count++;\n }\n }\n\n emitTap({ event, listeners: count, payload, type: 'emit' });\n\n if (firstError) throw firstError.value;\n }\n\n function emit<K extends EventKey<T>>(event: K, ...args: T[K] extends void ? [] : [payload: T[K]]): void {\n if (disposeController.signal.aborted) return;\n\n const payload = (args as unknown[])[0];\n\n dispatch(event, payload);\n }\n\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>[]>(\n eventList: K,\n opts?: { signal?: AbortSignal },\n ): Promise<WaitAnyResult<T, K>> {\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 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 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.js CHANGED
@@ -1,2 +1,195 @@
1
- var HeraldError=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},BusDisposedError=class extends HeraldError{constructor(e){super(e?`Bus "${e}" is disposed`:`Bus is disposed`)}},noop=()=>{};function createBus(e){let t=new Map,n=new Set,r=new Set,i=new AbortController,a=e?.name,o=e?.maxListeners,s=a?` (${a})`:``;function emitTap(e){if(r.size!==0)for(let t of r)try{t(e)}catch{}}function createSubscriptionScope(e){return e?AbortSignal.any([i.signal,e]):i.signal}function registerEntry(e,t,n,{event:r,onLog:i,onRemove:a,wildcard:c}){if(n.aborted)return noop;let l=!1;function unsub(){l||(l=!0,e.delete(u),a?.(),n.removeEventListener(`abort`,unsub),r===void 0?c&&emitTap({type:`unsubscribe-any`}):emitTap({event:r,type:`unsubscribe`}))}let u=t(unsub);return e.add(u),n.addEventListener(`abort`,unsub,{once:!0}),r===void 0?c&&emitTap({type:`subscribe-any`}):emitTap({event:r,type:`subscribe`}),o!==void 0&&e.size>o&&`${i}${e.size}${o}${s}`,unsub}function onWithSignal(e,n,r,i){let a=t.get(e);a||(a=new Set,t.set(e,a));let o=a;return registerEntry(o,e=>({fn:n,unsub:e}),r,{event:e,onLog:`on("${e}")`,onRemove:()=>{o.size===0&&t.delete(e),i?.()}})}function onAnyWithSignal(e,t,r){return registerEntry(n,t=>({fn:e,unsub:t}),t,{onLog:`onAny`,onRemove:r,wildcard:!0})}function onceWithSignal(e,t,n,r){let i={unsub:noop};return i.unsub=onWithSignal(e,e=>{i.unsub(),t(e)},n,r),i.unsub}function on(e,t,n){return onWithSignal(e,t,createSubscriptionScope(n?.signal))}function once(e,t,n){return onceWithSignal(e,t,createSubscriptionScope(n?.signal))}function onAny(e,t){return onAnyWithSignal(e,createSubscriptionScope(t?.signal))}function wait(e,t){let n=createSubscriptionScope(t?.signal);return n.aborted?Promise.reject(n.reason):new Promise((t,r)=>{let onAbort=()=>{r(n.reason)};onceWithSignal(e,e=>{n.removeEventListener(`abort`,onAbort),t(e)},n),n.addEventListener(`abort`,onAbort,{once:!0})})}function dispatch(e,r){let i=0,a,o=t.get(e);if(o?.size)for(let t of[...o]){try{t.fn(r)}catch(t){a??={value:t},emitTap({error:t,event:e,type:`error`})}i++}if(n.size)for(let t of[...n]){try{t.fn(e,r)}catch(t){a??={value:t},emitTap({error:t,event:e,type:`error`})}i++}if(emitTap({event:e,listeners:i,payload:r,type:`emit`}),a)throw a.value}function emit(e,...t){if(i.signal.aborted)return;let n=t[0];dispatch(e,n)}function listenerCount(e){if(e!==void 0)return t.get(e)?.size??0;let n=0;for(let e of t.values())n+=e.size;return n}function wildcardCount(){return n.size}function eventNames(){return[...t.keys()]}function tap(e,t){if(i.signal.aborted)return noop;let n=createSubscriptionScope(t?.signal);if(n.aborted)return noop;r.add(e);let onAbort=()=>r.delete(e);return n.addEventListener(`abort`,onAbort,{once:!0}),()=>{r.delete(e),n.removeEventListener(`abort`,onAbort)}}function waitAny(e,t){let n=createSubscriptionScope(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 cleanup(){n.removeEventListener(`abort`,onAbort),i.abort();for(let e of o)e()}function onAbort(){s||(s=!0,cleanup(),r(n.reason))}n.addEventListener(`abort`,onAbort,{once:!0});for(let n of e)o.push(onceWithSignal(n,e=>{s||(s=!0,cleanup(),t({event:n,payload:e}))},a))})}function dispose(){i.signal.aborted||(emitTap({type:`dispose`}),i.abort(new BusDisposedError(a)),t.clear(),n.clear(),r.clear())}return{get disposalSignal(){return i.signal},dispose,get disposed(){return i.signal.aborted},emit,eventNames,listenerCount,on,onAny,once,[Symbol.dispose]:dispose,tap,wait,waitAny,wildcardCount}}export{BusDisposedError,HeraldError,createBus};
1
+ //#endregion
2
+ //#region src/errors.ts
3
+ var HeraldError = class extends Error {
4
+ constructor(e, t) {
5
+ super(e, t), this.name = new.target.name, Object.setPrototypeOf(this, new.target.prototype);
6
+ }
7
+ }, BusDisposedError = class extends HeraldError {
8
+ constructor(e) {
9
+ super(e ? `Bus "${e}" is disposed` : "Bus is disposed");
10
+ }
11
+ }, noop = () => {};
12
+ function createBus(e) {
13
+ let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set(), i = new AbortController(), a = e?.name, o = e?.maxListeners, s = a ? ` (${a})` : "";
14
+ function emitTap(e) {
15
+ if (r.size !== 0) for (let t of r) try {
16
+ t(e);
17
+ } catch {}
18
+ }
19
+ function createSubscriptionScope(e) {
20
+ return e ? AbortSignal.any([i.signal, e]) : i.signal;
21
+ }
22
+ function registerEntry(e, t, n, { event: r, onLog: i, onRemove: a, wildcard: c }) {
23
+ if (n.aborted) return noop;
24
+ let l = !1;
25
+ function unsub() {
26
+ l || (l = !0, e.delete(u), a?.(), n.removeEventListener("abort", unsub), r === void 0 ? c && emitTap({ type: "unsubscribe-any" }) : emitTap({
27
+ event: r,
28
+ type: "unsubscribe"
29
+ }));
30
+ }
31
+ let u = t(unsub);
32
+ return e.add(u), n.addEventListener("abort", unsub, { once: !0 }), r === void 0 ? c && emitTap({ type: "subscribe-any" }) : emitTap({
33
+ event: r,
34
+ type: "subscribe"
35
+ }), o !== void 0 && e.size > o && `${i}${e.size}${o}${s}`, unsub;
36
+ }
37
+ function onWithSignal(e, n, r, i) {
38
+ let a = t.get(e);
39
+ a || (a = /* @__PURE__ */ new Set(), t.set(e, a));
40
+ let o = a;
41
+ return registerEntry(o, (e) => ({
42
+ fn: n,
43
+ unsub: e
44
+ }), r, {
45
+ event: e,
46
+ onLog: `on("${e}")`,
47
+ onRemove: () => {
48
+ o.size === 0 && t.delete(e), i?.();
49
+ }
50
+ });
51
+ }
52
+ function onAnyWithSignal(e, t, r) {
53
+ return registerEntry(n, (t) => ({
54
+ fn: e,
55
+ unsub: t
56
+ }), t, {
57
+ onLog: "onAny",
58
+ onRemove: r,
59
+ wildcard: !0
60
+ });
61
+ }
62
+ function onceWithSignal(e, t, n, r) {
63
+ let i = { unsub: noop };
64
+ return i.unsub = onWithSignal(e, (e) => {
65
+ i.unsub(), t(e);
66
+ }, n, r), i.unsub;
67
+ }
68
+ function on(e, t, n) {
69
+ return onWithSignal(e, t, createSubscriptionScope(n?.signal));
70
+ }
71
+ function once(e, t, n) {
72
+ return onceWithSignal(e, t, createSubscriptionScope(n?.signal));
73
+ }
74
+ function onAny(e, t) {
75
+ return onAnyWithSignal(e, createSubscriptionScope(t?.signal));
76
+ }
77
+ function wait(e, t) {
78
+ let n = createSubscriptionScope(t?.signal);
79
+ return n.aborted ? Promise.reject(n.reason) : new Promise((t, r) => {
80
+ let onAbort = () => {
81
+ r(n.reason);
82
+ };
83
+ onceWithSignal(e, (e) => {
84
+ n.removeEventListener("abort", onAbort), t(e);
85
+ }, n), n.addEventListener("abort", onAbort, { once: !0 });
86
+ });
87
+ }
88
+ function dispatch(e, r) {
89
+ let i = 0, a, o = t.get(e);
90
+ if (o?.size) for (let t of [...o]) {
91
+ try {
92
+ t.fn(r);
93
+ } catch (t) {
94
+ a ??= { value: t }, emitTap({
95
+ error: t,
96
+ event: e,
97
+ type: "error"
98
+ });
99
+ }
100
+ i++;
101
+ }
102
+ if (n.size) for (let t of [...n]) {
103
+ try {
104
+ t.fn(e, r);
105
+ } catch (t) {
106
+ a ??= { value: t }, emitTap({
107
+ error: t,
108
+ event: e,
109
+ type: "error"
110
+ });
111
+ }
112
+ i++;
113
+ }
114
+ if (emitTap({
115
+ event: e,
116
+ listeners: i,
117
+ payload: r,
118
+ type: "emit"
119
+ }), a) throw a.value;
120
+ }
121
+ function emit(e, ...t) {
122
+ if (i.signal.aborted) return;
123
+ let n = t[0];
124
+ dispatch(e, n);
125
+ }
126
+ function listenerCount(e) {
127
+ if (e !== void 0) return t.get(e)?.size ?? 0;
128
+ let n = 0;
129
+ for (let e of t.values()) n += e.size;
130
+ return n;
131
+ }
132
+ function wildcardCount() {
133
+ return n.size;
134
+ }
135
+ function eventNames() {
136
+ return [...t.keys()];
137
+ }
138
+ function tap(e, t) {
139
+ if (i.signal.aborted) return noop;
140
+ let n = createSubscriptionScope(t?.signal);
141
+ if (n.aborted) return noop;
142
+ r.add(e);
143
+ let onAbort = () => r.delete(e);
144
+ return n.addEventListener("abort", onAbort, { once: !0 }), () => {
145
+ r.delete(e), n.removeEventListener("abort", onAbort);
146
+ };
147
+ }
148
+ function waitAny(e, t) {
149
+ let n = createSubscriptionScope(t?.signal);
150
+ return n.aborted ? Promise.reject(n.reason) : new Promise((t, r) => {
151
+ let i = new AbortController(), a = AbortSignal.any([n, i.signal]), o = [], s = !1;
152
+ function cleanup() {
153
+ n.removeEventListener("abort", onAbort), i.abort();
154
+ for (let e of o) e();
155
+ }
156
+ function onAbort() {
157
+ s || (s = !0, cleanup(), r(n.reason));
158
+ }
159
+ n.addEventListener("abort", onAbort, { once: !0 });
160
+ for (let n of e) o.push(onceWithSignal(n, (e) => {
161
+ s || (s = !0, cleanup(), t({
162
+ event: n,
163
+ payload: e
164
+ }));
165
+ }, a));
166
+ });
167
+ }
168
+ function dispose() {
169
+ i.signal.aborted || (emitTap({ type: "dispose" }), i.abort(new BusDisposedError(a)), t.clear(), n.clear(), r.clear());
170
+ }
171
+ return {
172
+ get disposalSignal() {
173
+ return i.signal;
174
+ },
175
+ dispose,
176
+ get disposed() {
177
+ return i.signal.aborted;
178
+ },
179
+ emit,
180
+ eventNames,
181
+ listenerCount,
182
+ on,
183
+ onAny,
184
+ once,
185
+ [Symbol.dispose]: dispose,
186
+ tap,
187
+ wait,
188
+ waitAny,
189
+ wildcardCount
190
+ };
191
+ }
192
+ //#endregion
193
+ export { BusDisposedError, HeraldError, createBus };
194
+
2
195
  //# sourceMappingURL=herald.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"herald.js","names":[],"sources":["../src/_dev.ts","../src/errors.ts","../src/bus.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","/** 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","import { warn as _internalWarn } from './_dev';\nimport { BusDisposedError } from './errors';\nimport type {\n Bus,\n BusOptions,\n EventKey,\n EventMap,\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\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\nexport function createBus<T extends EventMap = Record<string, unknown>>(options?: BusOptions): Bus<T> {\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 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 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 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 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 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 function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): () => void {\n return onWithSignal(event, listener, createSubscriptionScope(opts?.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 return onAnyWithSignal(listener, createSubscriptionScope(opts?.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 function dispatch(event: EventKey<T>, payload: unknown): void {\n let count = 0;\n let firstError: { value: unknown } | undefined;\n const set = listeners.get(event);\n\n if (set?.size) {\n for (const entry of [...set]) {\n try {\n entry.fn(payload);\n } catch (err) {\n firstError ??= { value: err };\n emitTap({ error: err, event, type: 'error' });\n }\n\n count++;\n }\n }\n\n if (wildcards.size) {\n for (const entry of [...wildcards]) {\n try {\n entry.fn(event, payload);\n } catch (err) {\n firstError ??= { value: err };\n emitTap({ error: err, event, type: 'error' });\n }\n\n count++;\n }\n }\n\n emitTap({ event, listeners: count, payload, type: 'emit' });\n\n if (firstError) throw firstError.value;\n }\n\n function emit<K extends EventKey<T>>(event: K, ...args: T[K] extends void ? [] : [payload: T[K]]): void {\n if (disposeController.signal.aborted) return;\n\n const payload = (args as unknown[])[0];\n\n dispatch(event, payload);\n }\n\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>[]>(\n eventList: K,\n opts?: { signal?: AbortSignal },\n ): Promise<WaitAnyResult<T, K>> {\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 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 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":"herald.js","names":["message","opts","busName","listeners","wildcards","tappers","disposeController","options","maxListeners","busTag","tapper","event","signal","called","container","entry","onRemove","wildcard","makeEntry","onLog","set","capturedSet","listener","ref","payload","resolve","count","firstError","err","args","total","handler","activeSignal","raceController","raceSignal","unsubs","settled","unsub","reject","eventList"],"sources":["../src/_dev.ts","../src/errors.ts","../src/bus.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","/** 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","import { warn as _internalWarn } from './_dev';\nimport { BusDisposedError } from './errors';\nimport type {\n Bus,\n BusOptions,\n EventKey,\n EventMap,\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\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\nexport function createBus<T extends EventMap = Record<string, unknown>>(options?: BusOptions): Bus<T> {\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 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 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 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 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 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 function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): () => void {\n return onWithSignal(event, listener, createSubscriptionScope(opts?.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 return onAnyWithSignal(listener, createSubscriptionScope(opts?.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 function dispatch(event: EventKey<T>, payload: unknown): void {\n let count = 0;\n let firstError: { value: unknown } | undefined;\n const set = listeners.get(event);\n\n if (set?.size) {\n for (const entry of [...set]) {\n try {\n entry.fn(payload);\n } catch (err) {\n firstError ??= { value: err };\n emitTap({ error: err, event, type: 'error' });\n }\n\n count++;\n }\n }\n\n if (wildcards.size) {\n for (const entry of [...wildcards]) {\n try {\n entry.fn(event, payload);\n } catch (err) {\n firstError ??= { value: err };\n emitTap({ error: err, event, type: 'error' });\n }\n\n count++;\n }\n }\n\n emitTap({ event, listeners: count, payload, type: 'emit' });\n\n if (firstError) throw firstError.value;\n }\n\n function emit<K extends EventKey<T>>(event: K, ...args: T[K] extends void ? [] : [payload: T[K]]): void {\n if (disposeController.signal.aborted) return;\n\n const payload = (args as unknown[])[0];\n\n dispatch(event, payload);\n }\n\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>[]>(\n eventList: K,\n opts?: { signal?: AbortSignal },\n ): Promise<WaitAnyResult<T, K>> {\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 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 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/index.js CHANGED
@@ -1 +1,3 @@
1
- import{BusDisposedError as e,HeraldError as t}from"./errors.js";import{createBus as n}from"./bus.js";export{e as BusDisposedError,t as HeraldError,n as createBus};
1
+ import { BusDisposedError as e, HeraldError as t } from "./errors.js";
2
+ import { createBus as n } from "./bus.js";
3
+ export { e as BusDisposedError, t as HeraldError, n as createBus };
@@ -1 +1 @@
1
- {"version":3,"file":"testing.cjs","names":[],"sources":["../../src/testing/testing.ts"],"sourcesContent":["import type { Bus, BusOptions, EventKey, EventMap, HeraldEvent } from '..';\nimport { createBus } from '../bus';\n\n// Property names that must never be used as a bracket-assignment key on a plain object literal :\n// `obj[key] = value` for `key === '__proto__'` invokes `Object.prototype`'s `__proto__` accessor\n// and reassigns `obj`'s own prototype instead of setting an own property. `constructor` and\n// `prototype` are excluded defensively for the same class of risk.\n// Event names come from a caller-supplied `EventMap` type, but nothing prevents a caller from\n// wiring in a dynamically-determined (e.g. user-supplied) event name at runtime.\nconst UNSAFE_OBJECT_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\n\n/** A test bus is a regular bus with typed emission recording on top. */\nexport type TestBus<T extends EventMap> = Bus<T> & {\n /** Returns a snapshot of all payloads dispatched across every recorded event, keyed by event name. */\n allEmitted(): { [K in EventKey<T>]?: T[K][] };\n /** Snapshot of all payloads that were successfully dispatched for the given event key, in order. */\n emitted<K extends EventKey<T>>(event: K): T[K][];\n /** Number of times the given event was successfully dispatched. Shorthand for `emitted(event).length`. */\n emittedCount<K extends EventKey<T>>(event: K): number;\n /** Clear emitted records without disposing the bus. */\n reset(): void;\n};\n\nexport function createTestBus<T extends EventMap = Record<string, unknown>>(options?: BusOptions): TestBus<T> {\n const records = new Map<string, unknown[]>();\n const bus = createBus<T>(options);\n const disposeBus = bus.dispose;\n\n // Pure observer over the public tap channel: the `emit` event is traced after every\n // listener has run, so a dispatch whose listener throws still records its payload.\n bus.tap((event: HeraldEvent<T>) => {\n if (event.type !== 'emit') return;\n\n const list = records.get(event.event);\n\n if (list) list.push(event.payload);\n else records.set(event.event, [event.payload]);\n });\n\n function allEmitted(): { [K in EventKey<T>]?: T[K][] } {\n const result: { [K in EventKey<T>]?: T[K][] } = {};\n\n for (const [key, list] of records) {\n if (UNSAFE_OBJECT_KEYS.has(key)) continue;\n\n (result as Record<string, unknown[]>)[key] = [...list];\n }\n\n return result;\n }\n\n function emitted<K extends EventKey<T>>(event: K): T[K][] {\n return [...(records.get(event) ?? [])] as T[K][];\n }\n\n function emittedCount<K extends EventKey<T>>(event: K): number {\n return records.get(event)?.length ?? 0;\n }\n\n function dispose(): void {\n disposeBus();\n records.clear();\n }\n\n return Object.assign(bus, {\n allEmitted,\n dispose,\n emitted,\n emittedCount,\n reset: () => records.clear(),\n [Symbol.dispose]: dispose,\n }) as TestBus<T>;\n}\n"],"mappings":"8BASA,IAAM,EAAqB,IAAI,IAAI,CAAC,YAAa,cAAe,WAAW,CAAC,EAc5E,SAAgB,cAA4D,EAAkC,CAC5G,IAAM,EAAU,IAAI,IACd,EAAM,EAAA,UAAa,CAAO,EAC1B,EAAa,EAAI,QAIvB,EAAI,IAAK,GAA0B,CACjC,GAAI,EAAM,OAAS,OAAQ,OAE3B,IAAM,EAAO,EAAQ,IAAI,EAAM,KAAK,EAEhC,EAAM,EAAK,KAAK,EAAM,OAAO,EAC5B,EAAQ,IAAI,EAAM,MAAO,CAAC,EAAM,OAAO,CAAC,CAC/C,CAAC,EAED,SAAS,YAA8C,CACrD,IAAM,EAA0C,CAAC,EAEjD,IAAK,GAAM,CAAC,EAAK,KAAS,EACpB,EAAmB,IAAI,CAAG,IAE9B,EAAsC,GAAO,CAAC,GAAG,CAAI,GAGvD,OAAO,CACT,CAEA,SAAS,QAA+B,EAAkB,CACxD,MAAO,CAAC,GAAI,EAAQ,IAAI,CAAK,GAAK,CAAC,CAAE,CACvC,CAEA,SAAS,aAAoC,EAAkB,CAC7D,OAAO,EAAQ,IAAI,CAAK,CAAC,EAAE,QAAU,CACvC,CAEA,SAAS,SAAgB,CACvB,EAAW,EACX,EAAQ,MAAM,CAChB,CAEA,OAAO,OAAO,OAAO,EAAK,CACxB,WACA,QACA,QACA,aACA,UAAa,EAAQ,MAAM,GAC1B,OAAO,SAAU,OACpB,CAAC,CACH"}
1
+ {"version":3,"file":"testing.cjs","names":["createBus","require_bus","UNSAFE_OBJECT_KEYS","records","bus","options","disposeBus","event","list","result","key"],"sources":["../../src/testing/testing.ts"],"sourcesContent":["import type { Bus, BusOptions, EventKey, EventMap, HeraldEvent } from '..';\nimport { createBus } from '../bus';\n\n// Property names that must never be used as a bracket-assignment key on a plain object literal :\n// `obj[key] = value` for `key === '__proto__'` invokes `Object.prototype`'s `__proto__` accessor\n// and reassigns `obj`'s own prototype instead of setting an own property. `constructor` and\n// `prototype` are excluded defensively for the same class of risk.\n// Event names come from a caller-supplied `EventMap` type, but nothing prevents a caller from\n// wiring in a dynamically-determined (e.g. user-supplied) event name at runtime.\nconst UNSAFE_OBJECT_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\n\n/** A test bus is a regular bus with typed emission recording on top. */\nexport type TestBus<T extends EventMap> = Bus<T> & {\n /** Returns a snapshot of all payloads dispatched across every recorded event, keyed by event name. */\n allEmitted(): { [K in EventKey<T>]?: T[K][] };\n /** Snapshot of all payloads that were successfully dispatched for the given event key, in order. */\n emitted<K extends EventKey<T>>(event: K): T[K][];\n /** Number of times the given event was successfully dispatched. Shorthand for `emitted(event).length`. */\n emittedCount<K extends EventKey<T>>(event: K): number;\n /** Clear emitted records without disposing the bus. */\n reset(): void;\n};\n\nexport function createTestBus<T extends EventMap = Record<string, unknown>>(options?: BusOptions): TestBus<T> {\n const records = new Map<string, unknown[]>();\n const bus = createBus<T>(options);\n const disposeBus = bus.dispose;\n\n // Pure observer over the public tap channel: the `emit` event is traced after every\n // listener has run, so a dispatch whose listener throws still records its payload.\n bus.tap((event: HeraldEvent<T>) => {\n if (event.type !== 'emit') return;\n\n const list = records.get(event.event);\n\n if (list) list.push(event.payload);\n else records.set(event.event, [event.payload]);\n });\n\n function allEmitted(): { [K in EventKey<T>]?: T[K][] } {\n const result: { [K in EventKey<T>]?: T[K][] } = {};\n\n for (const [key, list] of records) {\n if (UNSAFE_OBJECT_KEYS.has(key)) continue;\n\n (result as Record<string, unknown[]>)[key] = [...list];\n }\n\n return result;\n }\n\n function emitted<K extends EventKey<T>>(event: K): T[K][] {\n return [...(records.get(event) ?? [])] as T[K][];\n }\n\n function emittedCount<K extends EventKey<T>>(event: K): number {\n return records.get(event)?.length ?? 0;\n }\n\n function dispose(): void {\n disposeBus();\n records.clear();\n }\n\n return Object.assign(bus, {\n allEmitted,\n dispose,\n emitted,\n emittedCount,\n reset: () => records.clear(),\n [Symbol.dispose]: dispose,\n }) as TestBus<T>;\n}\n"],"mappings":"A,8BASA,IAAME,EAAqB,IAAI,IAAI,CAAC,YAAa,cAAe,WAAW,CAAC,EAc5E,SAAgB,cAA4D,EAAkC,CAC5G,IAAMC,EAAU,IAAI,IACdC,EAAMJ,EAAAA,UAAaK,CAAO,EAC1BC,EAAaF,EAAI,QAIvBA,EAAI,IAAK,GAA0B,CACjC,GAAIG,EAAM,OAAS,OAAQ,OAE3B,IAAMC,EAAOL,EAAQ,IAAII,EAAM,KAAK,EAEhCC,EAAMA,EAAK,KAAKD,EAAM,OAAO,EAC5BJ,EAAQ,IAAII,EAAM,MAAO,CAACA,EAAM,OAAO,CAAC,CAC/C,CAAC,EAED,SAAS,YAA8C,CACrD,IAAME,EAA0C,CAAC,EAEjD,IAAK,GAAM,CAACC,EAAKF,KAASL,EACpBD,EAAmB,IAAIQ,CAAG,IAE9B,EAAsCA,GAAO,CAAC,GAAGF,CAAI,GAGvD,OAAOC,CACT,CAEA,SAAS,QAA+B,EAAkB,CACxD,MAAO,CAAC,GAAIN,EAAQ,IAAII,CAAK,GAAK,CAAC,CAAE,CACvC,CAEA,SAAS,aAAoC,EAAkB,CAC7D,OAAOJ,EAAQ,IAAII,CAAK,CAAC,EAAE,QAAU,CACvC,CAEA,SAAS,SAAgB,CACvBD,EAAW,EACXH,EAAQ,MAAM,CAChB,CAEA,OAAO,OAAO,OAAOC,EAAK,CACxB,WACA,QACA,QACA,aACA,UAAaD,EAAQ,MAAM,GAC1B,OAAO,SAAU,OACpB,CAAC,CACH,C"}
@@ -1,2 +1,41 @@
1
- import{createBus as e}from"../bus.js";var t=new Set([`__proto__`,`constructor`,`prototype`]);function createTestBus(n){let r=new Map,i=e(n),a=i.dispose;i.tap(e=>{if(e.type!==`emit`)return;let t=r.get(e.event);t?t.push(e.payload):r.set(e.event,[e.payload])});function allEmitted(){let e={};for(let[n,i]of r)t.has(n)||(e[n]=[...i]);return e}function emitted(e){return[...r.get(e)??[]]}function emittedCount(e){return r.get(e)?.length??0}function dispose(){a(),r.clear()}return Object.assign(i,{allEmitted,dispose,emitted,emittedCount,reset:()=>r.clear(),[Symbol.dispose]:dispose})}export{createTestBus};
1
+ import { createBus as e } from "../bus.js";
2
+ //#region src/testing/testing.ts
3
+ var t = /* @__PURE__ */ new Set([
4
+ "__proto__",
5
+ "constructor",
6
+ "prototype"
7
+ ]);
8
+ function createTestBus(n) {
9
+ let r = /* @__PURE__ */ new Map(), i = e(n), a = i.dispose;
10
+ i.tap((e) => {
11
+ if (e.type !== "emit") return;
12
+ let t = r.get(e.event);
13
+ t ? t.push(e.payload) : r.set(e.event, [e.payload]);
14
+ });
15
+ function allEmitted() {
16
+ let e = {};
17
+ for (let [n, i] of r) t.has(n) || (e[n] = [...i]);
18
+ return e;
19
+ }
20
+ function emitted(e) {
21
+ return [...r.get(e) ?? []];
22
+ }
23
+ function emittedCount(e) {
24
+ return r.get(e)?.length ?? 0;
25
+ }
26
+ function dispose() {
27
+ a(), r.clear();
28
+ }
29
+ return Object.assign(i, {
30
+ allEmitted,
31
+ dispose,
32
+ emitted,
33
+ emittedCount,
34
+ reset: () => r.clear(),
35
+ [Symbol.dispose]: dispose
36
+ });
37
+ }
38
+ //#endregion
39
+ export { createTestBus };
40
+
2
41
  //# sourceMappingURL=testing.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"testing.js","names":[],"sources":["../../src/testing/testing.ts"],"sourcesContent":["import type { Bus, BusOptions, EventKey, EventMap, HeraldEvent } from '..';\nimport { createBus } from '../bus';\n\n// Property names that must never be used as a bracket-assignment key on a plain object literal :\n// `obj[key] = value` for `key === '__proto__'` invokes `Object.prototype`'s `__proto__` accessor\n// and reassigns `obj`'s own prototype instead of setting an own property. `constructor` and\n// `prototype` are excluded defensively for the same class of risk.\n// Event names come from a caller-supplied `EventMap` type, but nothing prevents a caller from\n// wiring in a dynamically-determined (e.g. user-supplied) event name at runtime.\nconst UNSAFE_OBJECT_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\n\n/** A test bus is a regular bus with typed emission recording on top. */\nexport type TestBus<T extends EventMap> = Bus<T> & {\n /** Returns a snapshot of all payloads dispatched across every recorded event, keyed by event name. */\n allEmitted(): { [K in EventKey<T>]?: T[K][] };\n /** Snapshot of all payloads that were successfully dispatched for the given event key, in order. */\n emitted<K extends EventKey<T>>(event: K): T[K][];\n /** Number of times the given event was successfully dispatched. Shorthand for `emitted(event).length`. */\n emittedCount<K extends EventKey<T>>(event: K): number;\n /** Clear emitted records without disposing the bus. */\n reset(): void;\n};\n\nexport function createTestBus<T extends EventMap = Record<string, unknown>>(options?: BusOptions): TestBus<T> {\n const records = new Map<string, unknown[]>();\n const bus = createBus<T>(options);\n const disposeBus = bus.dispose;\n\n // Pure observer over the public tap channel: the `emit` event is traced after every\n // listener has run, so a dispatch whose listener throws still records its payload.\n bus.tap((event: HeraldEvent<T>) => {\n if (event.type !== 'emit') return;\n\n const list = records.get(event.event);\n\n if (list) list.push(event.payload);\n else records.set(event.event, [event.payload]);\n });\n\n function allEmitted(): { [K in EventKey<T>]?: T[K][] } {\n const result: { [K in EventKey<T>]?: T[K][] } = {};\n\n for (const [key, list] of records) {\n if (UNSAFE_OBJECT_KEYS.has(key)) continue;\n\n (result as Record<string, unknown[]>)[key] = [...list];\n }\n\n return result;\n }\n\n function emitted<K extends EventKey<T>>(event: K): T[K][] {\n return [...(records.get(event) ?? [])] as T[K][];\n }\n\n function emittedCount<K extends EventKey<T>>(event: K): number {\n return records.get(event)?.length ?? 0;\n }\n\n function dispose(): void {\n disposeBus();\n records.clear();\n }\n\n return Object.assign(bus, {\n allEmitted,\n dispose,\n emitted,\n emittedCount,\n reset: () => records.clear(),\n [Symbol.dispose]: dispose,\n }) as TestBus<T>;\n}\n"],"mappings":"sCASA,IAAM,EAAqB,IAAI,IAAI,CAAC,YAAa,cAAe,WAAW,CAAC,EAc5E,SAAgB,cAA4D,EAAkC,CAC5G,IAAM,EAAU,IAAI,IACd,EAAM,EAAa,CAAO,EAC1B,EAAa,EAAI,QAIvB,EAAI,IAAK,GAA0B,CACjC,GAAI,EAAM,OAAS,OAAQ,OAE3B,IAAM,EAAO,EAAQ,IAAI,EAAM,KAAK,EAEhC,EAAM,EAAK,KAAK,EAAM,OAAO,EAC5B,EAAQ,IAAI,EAAM,MAAO,CAAC,EAAM,OAAO,CAAC,CAC/C,CAAC,EAED,SAAS,YAA8C,CACrD,IAAM,EAA0C,CAAC,EAEjD,IAAK,GAAM,CAAC,EAAK,KAAS,EACpB,EAAmB,IAAI,CAAG,IAE9B,EAAsC,GAAO,CAAC,GAAG,CAAI,GAGvD,OAAO,CACT,CAEA,SAAS,QAA+B,EAAkB,CACxD,MAAO,CAAC,GAAI,EAAQ,IAAI,CAAK,GAAK,CAAC,CAAE,CACvC,CAEA,SAAS,aAAoC,EAAkB,CAC7D,OAAO,EAAQ,IAAI,CAAK,CAAC,EAAE,QAAU,CACvC,CAEA,SAAS,SAAgB,CACvB,EAAW,EACX,EAAQ,MAAM,CAChB,CAEA,OAAO,OAAO,OAAO,EAAK,CACxB,WACA,QACA,QACA,aACA,UAAa,EAAQ,MAAM,GAC1B,OAAO,SAAU,OACpB,CAAC,CACH"}
1
+ {"version":3,"file":"testing.js","names":["UNSAFE_OBJECT_KEYS","records","bus","createBus","options","disposeBus","event","list","result","key"],"sources":["../../src/testing/testing.ts"],"sourcesContent":["import type { Bus, BusOptions, EventKey, EventMap, HeraldEvent } from '..';\nimport { createBus } from '../bus';\n\n// Property names that must never be used as a bracket-assignment key on a plain object literal :\n// `obj[key] = value` for `key === '__proto__'` invokes `Object.prototype`'s `__proto__` accessor\n// and reassigns `obj`'s own prototype instead of setting an own property. `constructor` and\n// `prototype` are excluded defensively for the same class of risk.\n// Event names come from a caller-supplied `EventMap` type, but nothing prevents a caller from\n// wiring in a dynamically-determined (e.g. user-supplied) event name at runtime.\nconst UNSAFE_OBJECT_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\n\n/** A test bus is a regular bus with typed emission recording on top. */\nexport type TestBus<T extends EventMap> = Bus<T> & {\n /** Returns a snapshot of all payloads dispatched across every recorded event, keyed by event name. */\n allEmitted(): { [K in EventKey<T>]?: T[K][] };\n /** Snapshot of all payloads that were successfully dispatched for the given event key, in order. */\n emitted<K extends EventKey<T>>(event: K): T[K][];\n /** Number of times the given event was successfully dispatched. Shorthand for `emitted(event).length`. */\n emittedCount<K extends EventKey<T>>(event: K): number;\n /** Clear emitted records without disposing the bus. */\n reset(): void;\n};\n\nexport function createTestBus<T extends EventMap = Record<string, unknown>>(options?: BusOptions): TestBus<T> {\n const records = new Map<string, unknown[]>();\n const bus = createBus<T>(options);\n const disposeBus = bus.dispose;\n\n // Pure observer over the public tap channel: the `emit` event is traced after every\n // listener has run, so a dispatch whose listener throws still records its payload.\n bus.tap((event: HeraldEvent<T>) => {\n if (event.type !== 'emit') return;\n\n const list = records.get(event.event);\n\n if (list) list.push(event.payload);\n else records.set(event.event, [event.payload]);\n });\n\n function allEmitted(): { [K in EventKey<T>]?: T[K][] } {\n const result: { [K in EventKey<T>]?: T[K][] } = {};\n\n for (const [key, list] of records) {\n if (UNSAFE_OBJECT_KEYS.has(key)) continue;\n\n (result as Record<string, unknown[]>)[key] = [...list];\n }\n\n return result;\n }\n\n function emitted<K extends EventKey<T>>(event: K): T[K][] {\n return [...(records.get(event) ?? [])] as T[K][];\n }\n\n function emittedCount<K extends EventKey<T>>(event: K): number {\n return records.get(event)?.length ?? 0;\n }\n\n function dispose(): void {\n disposeBus();\n records.clear();\n }\n\n return Object.assign(bus, {\n allEmitted,\n dispose,\n emitted,\n emittedCount,\n reset: () => records.clear(),\n [Symbol.dispose]: dispose,\n }) as TestBus<T>;\n}\n"],"mappings":";;AASA,IAAMA,oBAAqB,IAAI,IAAI;CAAC;CAAa;CAAe;AAAW,CAAC;AAc5E,SAAgB,cAA4D,GAAkC;CAC5G,IAAMC,oBAAU,IAAI,IAAuB,GACrCC,IAAMC,EAAaC,CAAO,GAC1BC,IAAaH,EAAI;CAIvB,EAAI,KAAK,MAA0B;EACjC,IAAII,EAAM,SAAS,QAAQ;EAE3B,IAAMC,IAAON,EAAQ,IAAIK,EAAM,KAAK;EAEpC,AAAIC,IAAMA,EAAK,KAAKD,EAAM,OAAO,IAC5BL,EAAQ,IAAIK,EAAM,OAAO,CAACA,EAAM,OAAO,CAAC;CAC/C,CAAC;CAED,SAAS,aAA8C;EACrD,IAAME,IAA0C,CAAC;EAEjD,KAAK,IAAM,CAACC,GAAKF,MAASN,GACxB,AAAID,EAAmB,IAAIS,CAAG,MAE9B,EAAsCA,KAAO,CAAC,GAAGF,CAAI;EAGvD,OAAOC;CACT;CAEA,SAAS,QAA+B,GAAkB;EACxD,OAAO,CAAC,GAAIP,EAAQ,IAAIK,CAAK,KAAK,CAAC,CAAE;CACvC;CAEA,SAAS,aAAoC,GAAkB;EAC7D,OAAOL,EAAQ,IAAIK,CAAK,CAAC,EAAE,UAAU;CACvC;CAEA,SAAS,UAAgB;EAEvB,AADAD,EAAW,GACXJ,EAAQ,MAAM;CAChB;CAEA,OAAO,OAAO,OAAOC,GAAK;EACxB;EACA;EACA;EACA;EACA,aAAaD,EAAQ,MAAM;GAC1B,OAAO,UAAU;CACpB,CAAC;AACH"}
package/dist/testing.js CHANGED
@@ -1 +1 @@
1
- import{createTestBus as e}from"./testing/testing.js";export{e as createTestBus};
1
+ export { createTestBus } from "./testing/testing.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vielzeug/herald",
3
- "version": "26.10.15",
3
+ "version": "26.10.16",
4
4
  "description": "Typed synchronous event bus with wildcard subscriptions, one-shot waits, and lifecycle tracing",
5
5
  "repository": {
6
6
  "type": "git",
@@ -53,9 +53,9 @@
53
53
  "test": "vitest"
54
54
  },
55
55
  "devDependencies": {
56
- "@types/node": "^26.6.2",
56
+ "@types/node": "^26.6.5",
57
57
  "typescript": "^6.0.3",
58
- "vite": "^8.3.0",
59
- "vitest": "^5.0.1"
58
+ "vite": "^8.3.4",
59
+ "vitest": "^5.0.5"
60
60
  }
61
61
  }