@vielzeug/herald 1.0.4 → 1.0.6
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 +1 -1
- package/dist/_dev.cjs.map +1 -1
- package/dist/_dev.js +2 -5
- package/dist/_dev.js.map +1 -1
- package/dist/behavior-bus.cjs +1 -1
- package/dist/behavior-bus.cjs.map +1 -1
- package/dist/behavior-bus.js +3 -3
- package/dist/behavior-bus.js.map +1 -1
- package/dist/bus.cjs +1 -1
- package/dist/bus.cjs.map +1 -1
- package/dist/bus.js +121 -118
- package/dist/bus.js.map +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/herald.cjs +1 -1
- package/dist/herald.cjs.map +1 -1
- package/dist/herald.iife.js +1 -1
- package/dist/herald.iife.js.map +1 -1
- package/dist/herald.js +1 -1
- package/dist/herald.js.map +1 -1
- package/dist/pipe.cjs.map +1 -1
- package/dist/pipe.d.ts +2 -2
- package/dist/pipe.d.ts.map +1 -1
- package/dist/pipe.js.map +1 -1
- package/package.json +14 -7
package/dist/_dev.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
function e(e){}exports.warn=e;
|
|
2
2
|
//# sourceMappingURL=_dev.cjs.map
|
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":"
|
|
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,EAAK,EAAmB,CAExC"}
|
package/dist/_dev.js
CHANGED
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":";
|
|
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,EAAK,GAAmB,CAExC"}
|
package/dist/behavior-bus.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./_delegate.cjs"),t=require("./_prototype.cjs"),n=require("./_safe.cjs"),r=require("./bus.cjs");function i(i,a){let o=new Map(Object.entries(i??{}).filter(([,e])=>e!==void 0)),s=r.createBus({...a,_onDispatch:(e,t)=>{o.set(e,t)}});function c(e,t,r){let i=
|
|
1
|
+
const e=require("./_delegate.cjs"),t=require("./_prototype.cjs"),n=require("./_safe.cjs"),r=require("./bus.cjs");function i(i,a){let o=new Map(Object.entries(i??{}).filter(([,e])=>e!==void 0)),s=r.createBus({...a,_onDispatch:(e,t)=>{o.set(e,t)}});function c(e,t,r){let i=a?.onError?e=>a.onError({err:e,event:t,payload:r,timestamp:Date.now()}):void 0,o=n.callSafely(()=>e(r),i);if(o.threw)throw o.err}function l(e,t,n){if(s.disposed||n?.signal?.aborted)return r.noop;if(o.has(e)){let i=o.get(e);if(n?.once)return c(t,e,i),r.noop;c(t,e,i)}return s.on(e,t,n)}function u(e,t,n){return l(e,t,{once:!0,signal:n?.signal})}function d(e){return o.has(e)?o.get(e):void 0}function f(e){e===void 0?o.clear():o.delete(e)}function p(){let e={};for(let[n,r]of o)t.isUnsafeObjectKey(n)||(e[n]=r);return e}function m(){s.dispose(),o.clear()}let h=e.makeBusDelegate(s);return h.current=d,h.dispose=m,h.on=l,h.once=u,h.reset=f,h.snapshot=p,h[Symbol.dispose]=m,h}exports.createBehaviorBus=i;
|
|
2
2
|
//# sourceMappingURL=behavior-bus.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"behavior-bus.cjs","names":[],"sources":["../src/behavior-bus.ts"],"sourcesContent":["import type { InternalBusOptions } from './bus';\nimport type {\n BehaviorBus,\n BehaviorBusOptions,\n BehaviorInitial,\n EmissionErrorContext,\n EventKey,\n EventMap,\n Listener,\n SubscribeOptions,\n Unsubscribe,\n} from './types';\n\nimport { makeBusDelegate } from './_delegate';\nimport { isUnsafeObjectKey } from './_prototype';\nimport { callSafely } from './_safe';\nimport { createBus, noop } from './bus';\n\n/**\n * Creates a bus that replays the last known value for each event to new subscribers.\n *\n * When a listener subscribes via `on()` or `once()`, it immediately receives the current\n * buffered value for that event (if any have been emitted or were provided as initial values).\n * `events()`, `wait()`, and `waitAny()` behave like a regular bus — no replay.\n *\n * @param initial - Optional map of event names to their starting values.\n * @param options - Standard bus options.\n *\n * @example\n * const bus = createBehaviorBus<{ count: number }>({ count: 0 });\n * bus.on('count', (n) => console.log(n)); // logs 0 immediately\n * bus.emit('count', 1);\n * bus.on('count', (n) => console.log(n)); // logs 1 immediately (latest value)\n */\nexport function createBehaviorBus<T extends EventMap>(\n initial?: BehaviorInitial<T>,\n options?: BehaviorBusOptions<T>,\n): BehaviorBus<T> {\n // Flat buffer: one value per event key.\n // Seeded from initial values; updated via _onDispatch when dispatch actually runs.\n const buffers = new Map<string, unknown>(Object.entries(initial ?? {}).filter(([, v]) => v !== undefined));\n\n // _onDispatch fires after middleware passes (dispatch guaranteed to run).\n // This replaces the sentinel-middleware + mutable-flag pattern.\n const bus = createBus<T>({\n ...options,\n _onDispatch: (event: EventKey<T>, payload: unknown) => {\n buffers.set(event as string, payload);\n },\n } as InternalBusOptions<T>);\n\n // Wrap the listener call during synchronous replay so a throw routes through onError when set.\n // Only one listener is replayed per call here (unlike bus.ts's dispatch() broadcast loop), so\n // there's no \"keep going\" batch to preserve — an unforwarded throw rethrows immediately.\n function callSafeReplay(listener: Listener<unknown>, event: EventKey<T>, value: unknown): void {\n const onError = options?.onError\n ? (err: unknown) =>\n options.onError!({ err, event, payload: value, timestamp: Date.now() } as EmissionErrorContext<T>)\n : undefined;\n\n const result = callSafely(() => listener(value), onError);\n\n if (result.threw) throw result.err;\n }\n\n function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): Unsubscribe {\n if (bus.disposed || opts?.signal?.aborted) return noop;\n\n if (buffers.has(event as string)) {\n const value = buffers.get(event as string) as T[K];\n\n if (opts?.once) {\n callSafeReplay(listener as Listener<unknown>, event, value);\n\n return noop;\n }\n\n callSafeReplay(listener as Listener<unknown>, event, value);\n }\n\n return bus.on(event, listener, opts);\n }\n\n function once<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n opts?: { signal?: AbortSignal },\n ): Unsubscribe {\n return on(event, listener, { once: true, signal: opts?.signal });\n }\n\n function current<K extends EventKey<T>>(event: K): T[K] | undefined {\n return buffers.has(event as string) ? (buffers.get(event as string) as T[K]) : undefined;\n }\n\n function reset(event?: EventKey<T>): void {\n if (event !== undefined) buffers.delete(event as string);\n else buffers.clear();\n }\n\n function snapshot(): Partial<T> {\n const result: Partial<T> = {};\n\n for (const [key, value] of buffers) {\n // Guard against a `__proto__`/`constructor`/`prototype` event name hijacking result's\n // own prototype via the bracket-assignment accessor — see _prototype.ts.\n if (isUnsafeObjectKey(key)) continue;\n\n (result as Record<string, unknown>)[key] = value;\n }\n\n return result;\n }\n\n function dispose(): void {\n bus.dispose();\n buffers.clear();\n }\n\n const delegate = makeBusDelegate<T>(bus) as BehaviorBus<T>;\n\n delegate.current = current;\n delegate.dispose = dispose;\n delegate.on = on;\n delegate.once = once;\n delegate.reset = reset;\n delegate.snapshot = snapshot;\n delegate[Symbol.dispose] = dispose;\n\n return delegate;\n}\n"],"mappings":"iHAkCA,SAAgB,EACd,EACA,EACgB,CAGhB,IAAM,EAAU,IAAI,IAAqB,OAAO,QAAQ,GAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAG,KAAO,IAAM,IAAA,EAAS,CAAC,EAInG,EAAM,EAAA,UAAa,CACvB,GAAG,EACH,aAAc,EAAoB,IAAqB,CACrD,EAAQ,IAAI,EAAiB,CAAO,CACtC,CACF,CAA0B,EAK1B,SAAS,EAAe,EAA6B,EAAoB,EAAsB,
|
|
1
|
+
{"version":3,"file":"behavior-bus.cjs","names":[],"sources":["../src/behavior-bus.ts"],"sourcesContent":["import type { InternalBusOptions } from './bus';\nimport type {\n BehaviorBus,\n BehaviorBusOptions,\n BehaviorInitial,\n EmissionErrorContext,\n EventKey,\n EventMap,\n Listener,\n SubscribeOptions,\n Unsubscribe,\n} from './types';\n\nimport { makeBusDelegate } from './_delegate';\nimport { isUnsafeObjectKey } from './_prototype';\nimport { callSafely } from './_safe';\nimport { createBus, noop } from './bus';\n\n/**\n * Creates a bus that replays the last known value for each event to new subscribers.\n *\n * When a listener subscribes via `on()` or `once()`, it immediately receives the current\n * buffered value for that event (if any have been emitted or were provided as initial values).\n * `events()`, `wait()`, and `waitAny()` behave like a regular bus — no replay.\n *\n * @param initial - Optional map of event names to their starting values.\n * @param options - Standard bus options.\n *\n * @example\n * const bus = createBehaviorBus<{ count: number }>({ count: 0 });\n * bus.on('count', (n) => console.log(n)); // logs 0 immediately\n * bus.emit('count', 1);\n * bus.on('count', (n) => console.log(n)); // logs 1 immediately (latest value)\n */\nexport function createBehaviorBus<T extends EventMap>(\n initial?: BehaviorInitial<T>,\n options?: BehaviorBusOptions<T>,\n): BehaviorBus<T> {\n // Flat buffer: one value per event key.\n // Seeded from initial values; updated via _onDispatch when dispatch actually runs.\n const buffers = new Map<string, unknown>(Object.entries(initial ?? {}).filter(([, v]) => v !== undefined));\n\n // _onDispatch fires after middleware passes (dispatch guaranteed to run).\n // This replaces the sentinel-middleware + mutable-flag pattern.\n const bus = createBus<T>({\n ...options,\n _onDispatch: (event: EventKey<T>, payload: unknown) => {\n buffers.set(event as string, payload);\n },\n } as InternalBusOptions<T>);\n\n // Wrap the listener call during synchronous replay so a throw routes through onError when set.\n // Only one listener is replayed per call here (unlike bus.ts's dispatch() broadcast loop), so\n // there's no \"keep going\" batch to preserve — an unforwarded throw rethrows immediately.\n function callSafeReplay(listener: Listener<unknown>, event: EventKey<T>, value: unknown): void {\n const onError = options?.onError\n ? (err: unknown) =>\n options.onError!({ err, event, payload: value, timestamp: Date.now() } as EmissionErrorContext<T>)\n : undefined;\n\n const result = callSafely(() => listener(value), onError);\n\n if (result.threw) throw result.err;\n }\n\n function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): Unsubscribe {\n if (bus.disposed || opts?.signal?.aborted) return noop;\n\n if (buffers.has(event as string)) {\n const value = buffers.get(event as string) as T[K];\n\n if (opts?.once) {\n callSafeReplay(listener as Listener<unknown>, event, value);\n\n return noop;\n }\n\n callSafeReplay(listener as Listener<unknown>, event, value);\n }\n\n return bus.on(event, listener, opts);\n }\n\n function once<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n opts?: { signal?: AbortSignal },\n ): Unsubscribe {\n return on(event, listener, { once: true, signal: opts?.signal });\n }\n\n function current<K extends EventKey<T>>(event: K): T[K] | undefined {\n return buffers.has(event as string) ? (buffers.get(event as string) as T[K]) : undefined;\n }\n\n function reset(event?: EventKey<T>): void {\n if (event !== undefined) buffers.delete(event as string);\n else buffers.clear();\n }\n\n function snapshot(): Partial<T> {\n const result: Partial<T> = {};\n\n for (const [key, value] of buffers) {\n // Guard against a `__proto__`/`constructor`/`prototype` event name hijacking result's\n // own prototype via the bracket-assignment accessor — see _prototype.ts.\n if (isUnsafeObjectKey(key)) continue;\n\n (result as Record<string, unknown>)[key] = value;\n }\n\n return result;\n }\n\n function dispose(): void {\n bus.dispose();\n buffers.clear();\n }\n\n const delegate = makeBusDelegate<T>(bus) as BehaviorBus<T>;\n\n delegate.current = current;\n delegate.dispose = dispose;\n delegate.on = on;\n delegate.once = once;\n delegate.reset = reset;\n delegate.snapshot = snapshot;\n delegate[Symbol.dispose] = dispose;\n\n return delegate;\n}\n"],"mappings":"iHAkCA,SAAgB,EACd,EACA,EACgB,CAGhB,IAAM,EAAU,IAAI,IAAqB,OAAO,QAAQ,GAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAG,KAAO,IAAM,IAAA,EAAS,CAAC,EAInG,EAAM,EAAA,UAAa,CACvB,GAAG,EACH,aAAc,EAAoB,IAAqB,CACrD,EAAQ,IAAI,EAAiB,CAAO,CACtC,CACF,CAA0B,EAK1B,SAAS,EAAe,EAA6B,EAAoB,EAAsB,CAC7F,IAAM,EAAU,GAAS,QACpB,GACC,EAAQ,QAAS,CAAE,MAAK,QAAO,QAAS,EAAO,UAAW,KAAK,IAAI,CAAE,CAA4B,EACnG,IAAA,GAEE,EAAS,EAAA,eAAiB,EAAS,CAAK,EAAG,CAAO,EAExD,GAAI,EAAO,MAAO,MAAM,EAAO,GACjC,CAEA,SAAS,EAA0B,EAAU,EAA0B,EAAsC,CAC3G,GAAI,EAAI,UAAY,GAAM,QAAQ,QAAS,OAAO,EAAA,KAElD,GAAI,EAAQ,IAAI,CAAe,EAAG,CAChC,IAAM,EAAQ,EAAQ,IAAI,CAAe,EAEzC,GAAI,GAAM,KAGR,OAFA,EAAe,EAA+B,EAAO,CAAK,EAEnD,EAAA,KAGT,EAAe,EAA+B,EAAO,CAAK,CAC5D,CAEA,OAAO,EAAI,GAAG,EAAO,EAAU,CAAI,CACrC,CAEA,SAAS,EACP,EACA,EACA,EACa,CACb,OAAO,EAAG,EAAO,EAAU,CAAE,KAAM,GAAM,OAAQ,GAAM,MAAO,CAAC,CACjE,CAEA,SAAS,EAA+B,EAA4B,CAClE,OAAO,EAAQ,IAAI,CAAe,EAAK,EAAQ,IAAI,CAAe,EAAa,IAAA,EACjF,CAEA,SAAS,EAAM,EAA2B,CACpC,IAAU,IAAA,GACT,EAAQ,MAAM,EADM,EAAQ,OAAO,CAAe,CAEzD,CAEA,SAAS,GAAuB,CAC9B,IAAM,EAAqB,CAAC,EAE5B,IAAK,GAAM,CAAC,EAAK,KAAU,EAGrB,EAAA,kBAAkB,CAAG,IAEzB,EAAoC,GAAO,GAG7C,OAAO,CACT,CAEA,SAAS,GAAgB,CACvB,EAAI,QAAQ,EACZ,EAAQ,MAAM,CAChB,CAEA,IAAM,EAAW,EAAA,gBAAmB,CAAG,EAUvC,MARA,GAAS,QAAU,EACnB,EAAS,QAAU,EACnB,EAAS,GAAK,EACd,EAAS,KAAO,EAChB,EAAS,MAAQ,EACjB,EAAS,SAAW,EACpB,EAAS,OAAO,SAAW,EAEpB,CACT"}
|
package/dist/behavior-bus.js
CHANGED
|
@@ -11,13 +11,13 @@ function a(a, o) {
|
|
|
11
11
|
}
|
|
12
12
|
});
|
|
13
13
|
function l(e, t, r) {
|
|
14
|
-
let i =
|
|
14
|
+
let i = o?.onError ? (e) => o.onError({
|
|
15
15
|
err: e,
|
|
16
16
|
event: t,
|
|
17
17
|
payload: r,
|
|
18
18
|
timestamp: Date.now()
|
|
19
|
-
}) : void 0);
|
|
20
|
-
if (
|
|
19
|
+
}) : void 0, a = n(() => e(r), i);
|
|
20
|
+
if (a.threw) throw a.err;
|
|
21
21
|
}
|
|
22
22
|
function u(e, t, n) {
|
|
23
23
|
if (c.disposed || n?.signal?.aborted) return i;
|
package/dist/behavior-bus.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"behavior-bus.js","names":[],"sources":["../src/behavior-bus.ts"],"sourcesContent":["import type { InternalBusOptions } from './bus';\nimport type {\n BehaviorBus,\n BehaviorBusOptions,\n BehaviorInitial,\n EmissionErrorContext,\n EventKey,\n EventMap,\n Listener,\n SubscribeOptions,\n Unsubscribe,\n} from './types';\n\nimport { makeBusDelegate } from './_delegate';\nimport { isUnsafeObjectKey } from './_prototype';\nimport { callSafely } from './_safe';\nimport { createBus, noop } from './bus';\n\n/**\n * Creates a bus that replays the last known value for each event to new subscribers.\n *\n * When a listener subscribes via `on()` or `once()`, it immediately receives the current\n * buffered value for that event (if any have been emitted or were provided as initial values).\n * `events()`, `wait()`, and `waitAny()` behave like a regular bus — no replay.\n *\n * @param initial - Optional map of event names to their starting values.\n * @param options - Standard bus options.\n *\n * @example\n * const bus = createBehaviorBus<{ count: number }>({ count: 0 });\n * bus.on('count', (n) => console.log(n)); // logs 0 immediately\n * bus.emit('count', 1);\n * bus.on('count', (n) => console.log(n)); // logs 1 immediately (latest value)\n */\nexport function createBehaviorBus<T extends EventMap>(\n initial?: BehaviorInitial<T>,\n options?: BehaviorBusOptions<T>,\n): BehaviorBus<T> {\n // Flat buffer: one value per event key.\n // Seeded from initial values; updated via _onDispatch when dispatch actually runs.\n const buffers = new Map<string, unknown>(Object.entries(initial ?? {}).filter(([, v]) => v !== undefined));\n\n // _onDispatch fires after middleware passes (dispatch guaranteed to run).\n // This replaces the sentinel-middleware + mutable-flag pattern.\n const bus = createBus<T>({\n ...options,\n _onDispatch: (event: EventKey<T>, payload: unknown) => {\n buffers.set(event as string, payload);\n },\n } as InternalBusOptions<T>);\n\n // Wrap the listener call during synchronous replay so a throw routes through onError when set.\n // Only one listener is replayed per call here (unlike bus.ts's dispatch() broadcast loop), so\n // there's no \"keep going\" batch to preserve — an unforwarded throw rethrows immediately.\n function callSafeReplay(listener: Listener<unknown>, event: EventKey<T>, value: unknown): void {\n const onError = options?.onError\n ? (err: unknown) =>\n options.onError!({ err, event, payload: value, timestamp: Date.now() } as EmissionErrorContext<T>)\n : undefined;\n\n const result = callSafely(() => listener(value), onError);\n\n if (result.threw) throw result.err;\n }\n\n function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): Unsubscribe {\n if (bus.disposed || opts?.signal?.aborted) return noop;\n\n if (buffers.has(event as string)) {\n const value = buffers.get(event as string) as T[K];\n\n if (opts?.once) {\n callSafeReplay(listener as Listener<unknown>, event, value);\n\n return noop;\n }\n\n callSafeReplay(listener as Listener<unknown>, event, value);\n }\n\n return bus.on(event, listener, opts);\n }\n\n function once<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n opts?: { signal?: AbortSignal },\n ): Unsubscribe {\n return on(event, listener, { once: true, signal: opts?.signal });\n }\n\n function current<K extends EventKey<T>>(event: K): T[K] | undefined {\n return buffers.has(event as string) ? (buffers.get(event as string) as T[K]) : undefined;\n }\n\n function reset(event?: EventKey<T>): void {\n if (event !== undefined) buffers.delete(event as string);\n else buffers.clear();\n }\n\n function snapshot(): Partial<T> {\n const result: Partial<T> = {};\n\n for (const [key, value] of buffers) {\n // Guard against a `__proto__`/`constructor`/`prototype` event name hijacking result's\n // own prototype via the bracket-assignment accessor — see _prototype.ts.\n if (isUnsafeObjectKey(key)) continue;\n\n (result as Record<string, unknown>)[key] = value;\n }\n\n return result;\n }\n\n function dispose(): void {\n bus.dispose();\n buffers.clear();\n }\n\n const delegate = makeBusDelegate<T>(bus) as BehaviorBus<T>;\n\n delegate.current = current;\n delegate.dispose = dispose;\n delegate.on = on;\n delegate.once = once;\n delegate.reset = reset;\n delegate.snapshot = snapshot;\n delegate[Symbol.dispose] = dispose;\n\n return delegate;\n}\n"],"mappings":";;;;;AAkCA,SAAgB,EACd,GACA,GACgB;CAGhB,IAAM,IAAU,IAAI,IAAqB,OAAO,QAAQ,KAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,OAAO,MAAM,KAAA,CAAS,CAAC,GAInG,IAAM,EAAa;EACvB,GAAG;EACH,cAAc,GAAoB,MAAqB;GACrD,EAAQ,IAAI,GAAiB,CAAO;EACtC;CACF,CAA0B;CAK1B,SAAS,EAAe,GAA6B,GAAoB,GAAsB;
|
|
1
|
+
{"version":3,"file":"behavior-bus.js","names":[],"sources":["../src/behavior-bus.ts"],"sourcesContent":["import type { InternalBusOptions } from './bus';\nimport type {\n BehaviorBus,\n BehaviorBusOptions,\n BehaviorInitial,\n EmissionErrorContext,\n EventKey,\n EventMap,\n Listener,\n SubscribeOptions,\n Unsubscribe,\n} from './types';\n\nimport { makeBusDelegate } from './_delegate';\nimport { isUnsafeObjectKey } from './_prototype';\nimport { callSafely } from './_safe';\nimport { createBus, noop } from './bus';\n\n/**\n * Creates a bus that replays the last known value for each event to new subscribers.\n *\n * When a listener subscribes via `on()` or `once()`, it immediately receives the current\n * buffered value for that event (if any have been emitted or were provided as initial values).\n * `events()`, `wait()`, and `waitAny()` behave like a regular bus — no replay.\n *\n * @param initial - Optional map of event names to their starting values.\n * @param options - Standard bus options.\n *\n * @example\n * const bus = createBehaviorBus<{ count: number }>({ count: 0 });\n * bus.on('count', (n) => console.log(n)); // logs 0 immediately\n * bus.emit('count', 1);\n * bus.on('count', (n) => console.log(n)); // logs 1 immediately (latest value)\n */\nexport function createBehaviorBus<T extends EventMap>(\n initial?: BehaviorInitial<T>,\n options?: BehaviorBusOptions<T>,\n): BehaviorBus<T> {\n // Flat buffer: one value per event key.\n // Seeded from initial values; updated via _onDispatch when dispatch actually runs.\n const buffers = new Map<string, unknown>(Object.entries(initial ?? {}).filter(([, v]) => v !== undefined));\n\n // _onDispatch fires after middleware passes (dispatch guaranteed to run).\n // This replaces the sentinel-middleware + mutable-flag pattern.\n const bus = createBus<T>({\n ...options,\n _onDispatch: (event: EventKey<T>, payload: unknown) => {\n buffers.set(event as string, payload);\n },\n } as InternalBusOptions<T>);\n\n // Wrap the listener call during synchronous replay so a throw routes through onError when set.\n // Only one listener is replayed per call here (unlike bus.ts's dispatch() broadcast loop), so\n // there's no \"keep going\" batch to preserve — an unforwarded throw rethrows immediately.\n function callSafeReplay(listener: Listener<unknown>, event: EventKey<T>, value: unknown): void {\n const onError = options?.onError\n ? (err: unknown) =>\n options.onError!({ err, event, payload: value, timestamp: Date.now() } as EmissionErrorContext<T>)\n : undefined;\n\n const result = callSafely(() => listener(value), onError);\n\n if (result.threw) throw result.err;\n }\n\n function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): Unsubscribe {\n if (bus.disposed || opts?.signal?.aborted) return noop;\n\n if (buffers.has(event as string)) {\n const value = buffers.get(event as string) as T[K];\n\n if (opts?.once) {\n callSafeReplay(listener as Listener<unknown>, event, value);\n\n return noop;\n }\n\n callSafeReplay(listener as Listener<unknown>, event, value);\n }\n\n return bus.on(event, listener, opts);\n }\n\n function once<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n opts?: { signal?: AbortSignal },\n ): Unsubscribe {\n return on(event, listener, { once: true, signal: opts?.signal });\n }\n\n function current<K extends EventKey<T>>(event: K): T[K] | undefined {\n return buffers.has(event as string) ? (buffers.get(event as string) as T[K]) : undefined;\n }\n\n function reset(event?: EventKey<T>): void {\n if (event !== undefined) buffers.delete(event as string);\n else buffers.clear();\n }\n\n function snapshot(): Partial<T> {\n const result: Partial<T> = {};\n\n for (const [key, value] of buffers) {\n // Guard against a `__proto__`/`constructor`/`prototype` event name hijacking result's\n // own prototype via the bracket-assignment accessor — see _prototype.ts.\n if (isUnsafeObjectKey(key)) continue;\n\n (result as Record<string, unknown>)[key] = value;\n }\n\n return result;\n }\n\n function dispose(): void {\n bus.dispose();\n buffers.clear();\n }\n\n const delegate = makeBusDelegate<T>(bus) as BehaviorBus<T>;\n\n delegate.current = current;\n delegate.dispose = dispose;\n delegate.on = on;\n delegate.once = once;\n delegate.reset = reset;\n delegate.snapshot = snapshot;\n delegate[Symbol.dispose] = dispose;\n\n return delegate;\n}\n"],"mappings":";;;;;AAkCA,SAAgB,EACd,GACA,GACgB;CAGhB,IAAM,IAAU,IAAI,IAAqB,OAAO,QAAQ,KAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,OAAO,MAAM,KAAA,CAAS,CAAC,GAInG,IAAM,EAAa;EACvB,GAAG;EACH,cAAc,GAAoB,MAAqB;GACrD,EAAQ,IAAI,GAAiB,CAAO;EACtC;CACF,CAA0B;CAK1B,SAAS,EAAe,GAA6B,GAAoB,GAAsB;EAC7F,IAAM,IAAU,GAAS,WACpB,MACC,EAAQ,QAAS;GAAE;GAAK;GAAO,SAAS;GAAO,WAAW,KAAK,IAAI;EAAE,CAA4B,IACnG,KAAA,GAEE,IAAS,QAAiB,EAAS,CAAK,GAAG,CAAO;EAExD,IAAI,EAAO,OAAO,MAAM,EAAO;CACjC;CAEA,SAAS,EAA0B,GAAU,GAA0B,GAAsC;EAC3G,IAAI,EAAI,YAAY,GAAM,QAAQ,SAAS,OAAO;EAElD,IAAI,EAAQ,IAAI,CAAe,GAAG;GAChC,IAAM,IAAQ,EAAQ,IAAI,CAAe;GAEzC,IAAI,GAAM,MAGR,OAFA,EAAe,GAA+B,GAAO,CAAK,GAEnD;GAGT,EAAe,GAA+B,GAAO,CAAK;EAC5D;EAEA,OAAO,EAAI,GAAG,GAAO,GAAU,CAAI;CACrC;CAEA,SAAS,EACP,GACA,GACA,GACa;EACb,OAAO,EAAG,GAAO,GAAU;GAAE,MAAM;GAAM,QAAQ,GAAM;EAAO,CAAC;CACjE;CAEA,SAAS,EAA+B,GAA4B;EAClE,OAAO,EAAQ,IAAI,CAAe,IAAK,EAAQ,IAAI,CAAe,IAAa,KAAA;CACjF;CAEA,SAAS,EAAM,GAA2B;EACxC,AAAI,MAAU,KAAA,IACT,EAAQ,MAAM,IADM,EAAQ,OAAO,CAAe;CAEzD;CAEA,SAAS,IAAuB;EAC9B,IAAM,IAAqB,CAAC;EAE5B,KAAK,IAAM,CAAC,GAAK,MAAU,GAGrB,EAAkB,CAAG,MAEzB,EAAoC,KAAO;EAG7C,OAAO;CACT;CAEA,SAAS,IAAgB;EAEvB,AADA,EAAI,QAAQ,GACZ,EAAQ,MAAM;CAChB;CAEA,IAAM,IAAW,EAAmB,CAAG;CAUvC,OARA,EAAS,UAAU,GACnB,EAAS,UAAU,GACnB,EAAS,KAAK,GACd,EAAS,OAAO,GAChB,EAAS,QAAQ,GACjB,EAAS,WAAW,GACpB,EAAS,OAAO,WAAW,GAEpB;AACT"}
|
package/dist/bus.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./_safe.cjs")
|
|
1
|
+
const e=require("./_safe.cjs");require("./_dev.cjs");const t=require("./errors.cjs");var n=()=>{};function r(e,t){if(e.aborted)return e;if(t.aborted)return t;let n=new AbortController,r=()=>n.abort(e.reason),i=()=>n.abort(t.reason);return e.addEventListener(`abort`,r,{once:!0}),t.addEventListener(`abort`,i,{once:!0}),n.signal.addEventListener(`abort`,()=>{e.removeEventListener(`abort`,r),t.removeEventListener(`abort`,i)},{once:!0}),n.signal}function i(e,...t){return t.length===0?e:t.reduce(r,e)}function a(e,t){return Object.assign(e,{[Symbol.asyncDispose]:t})}function o(r){let o=new Map,s=new Set,c=new AbortController,l=r?.name,u=r?.maxListeners,d=r?.logger?.debug,f=d&&l?e=>d(`${e} (${l})`):d;r?.logger;let p=r?.logger?.warn,m=l?` (${l})`:``;function h(e){p&&p(e)}function g(e){return e?i(c.signal,e):c.signal}function _(t,n,i,a){let o=r?.onError?e=>r.onError({err:e,event:n,payload:i,timestamp:a}):void 0;return e.callSafely(t,o)}function v(e,t,r,{offLog:i,onLog:a,onRemove:o}){if(r.aborted)return n;let s=!1;function c(){s||(s=!0,e.delete(l),o?.(),r.removeEventListener(`abort`,c),f?.(`[herald:sub] ${i} — ${e.size} listener(s) remaining`))}let l=t(c);return e.add(l),r.addEventListener(`abort`,c,{once:!0}),f?.(`[herald:sub] ${a} — ${e.size} listener(s)`),u!==void 0&&e.size>u&&h(`${a} has ${e.size} listeners, exceeding maxListeners (${u}). Possible memory leak.${m}`),c}function y(e,t,n){let r=o.get(e);r||(r=new Set,o.set(e,r));let i=r;return v(i,e=>({fn:t,unsub:e}),n,{offLog:`off("${e}")`,onLog:`on("${e}")`,onRemove:()=>{i.size===0&&o.delete(e)}})}function b(e,t){return v(s,t=>({fn:e,unsub:t}),t,{offLog:`onAny off`,onLog:`onAny`})}function x(e,t,r){let i={unsub:n};return i.unsub=y(e,e=>{i.unsub(),t(e)},r),i.unsub}function S(e,t){let r={unsub:n};return r.unsub=b((t,n)=>{r.unsub(),e(t,n)},t),r.unsub}function C(e,t,n){let r=g(n?.signal);return n?.once?x(e,t,r):y(e,t,r)}function w(e,t,n){return x(e,t,g(n?.signal))}function T(e,t){let n=g(t?.signal);return t?.once?S(e,n):b(e,n)}function E(e,t){let n=g(t?.signal);return n.aborted?Promise.reject(n.reason):new Promise((t,r)=>{function i(){r(n.reason)}x(e,e=>{n.removeEventListener(`abort`,i),t(e)},n),n.addEventListener(`abort`,i,{once:!0})})}function D(e,n){let r=n?.maxBuffer??1/0;if(!(r>0))throw new t.HeraldConfigError(`maxBuffer must be a positive number`);let i=g(n?.signal);if(i.aborted)return a((async function*(){})(),async()=>{});let o=[],s,c=y(e,e=>{o.length>=r&&o.shift(),o.push(e),s?.()},i);async function*l(){try{for(;!i.aborted;){if(o.length){yield o.shift();continue}let{promise:e,resolve:t}=Promise.withResolvers(),n=()=>{t()};s=t,i.addEventListener(`abort`,n,{once:!0}),await e,i.removeEventListener(`abort`,n),s=void 0}}finally{c()}}let u=l();return a(u,async()=>{c(),await u.return(void 0)})}function O(e,t,n){r?._onDispatch?.(e,t);let i=0,a,c=o.get(e);if(c?.size)for(let r of[...c]){let o=_(()=>r.fn(t),e,t,n);o.threw&&!a&&(a={err:o.err}),i++}if(s.size)for(let r of[...s]){let o=_(()=>r.fn(e,t),e,t,n);o.threw&&!a&&(a={err:o.err}),i++}if(a)throw a.err;return i}function k(e,...t){if(c.signal.aborted)return 0;let n=t[0],i=Date.now();if(r?.validatePayload)try{r.validatePayload(e,n)}catch(t){if(r?.onError)return r.onError({err:t,event:e,payload:n,timestamp:i}),0;throw t}if(f){let t=o.get(e)?.size??0,n=s.size;f(`[herald:emit] emit("${e}") — ${t+n} listener(s) (${t} specific, ${n} wildcard)`)}let a=r?.middleware;if(a?.length){let t=0,r=0;function l(){let o=r++;o<a.length?a[o](e,n,l):o===a.length&&(t=O(e,n,i))}return l(),t}return O(e,n,i)}function A(e){if(e!==void 0)return o.get(e)?.size??0;let t=0;for(let e of o.values())t+=e.size;return t}function j(){return s.size}function M(){return[...o.keys()]}function N(e,n){if(e.length<2)throw new t.HeraldConfigError(`waitAny() requires at least 2 event keys`);let r=g(n?.signal);return r.aborted?Promise.reject(r.reason):new Promise((t,n)=>{let a=new AbortController,o=i(r,a.signal);function s(){a.abort(),n(r.reason)}r.addEventListener(`abort`,s,{once:!0});for(let n of e)x(n,e=>{r.removeEventListener(`abort`,s),a.abort(),t({event:n,payload:e})},o)})}function P(){c.signal.aborted||(f?.(`[herald:lifecycle] dispose()`),c.abort(new t.BusDisposedError(l)),o.clear(),s.clear())}return{get disposalSignal(){return c.signal},dispose:P,get disposed(){return c.signal.aborted},emit:k,eventNames:M,events:D,listenerCount:A,on:C,onAny:T,once:w,[Symbol.dispose]:P,wait:E,waitAny:N,wildcardCount:j}}exports.combineSignals=i,exports.createBus=o,exports.noop=n;
|
|
2
2
|
//# sourceMappingURL=bus.cjs.map
|
package/dist/bus.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bus.cjs","names":[],"sources":["../src/bus.ts"],"sourcesContent":["import type {\n Bus,\n BusOptions,\n EmissionErrorContext,\n EventKey,\n EventMap,\n EventStream,\n Listener,\n SubscribeOptions,\n Unsubscribe,\n WaitAnyResult,\n} from './types';\n\nimport { warn as _internalWarn } from './_dev';\nimport { type SafeCallResult, callSafely } from './_safe';\nimport { BusDisposedError, HeraldConfigError } from './errors';\n\n// Module-scoped noop — shared across all bus instances to avoid per-bus allocation.\n// @internal — exported only for sibling internal modules; stripped from public declarations via stripInternal.\n/** @internal */\nexport const noop = () => {};\n\n/** @internal */\nfunction mergeTwo(a: AbortSignal, b: AbortSignal): AbortSignal {\n if (a.aborted) return a;\n\n if (b.aborted) return b;\n\n const ctrl = new AbortController();\n const onA = (): void => ctrl.abort(a.reason);\n const onB = (): void => ctrl.abort(b.reason);\n\n a.addEventListener('abort', onA, { once: true });\n b.addEventListener('abort', onB, { once: true });\n ctrl.signal.addEventListener(\n 'abort',\n () => {\n a.removeEventListener('abort', onA);\n b.removeEventListener('abort', onB);\n },\n { once: true },\n );\n\n return ctrl.signal;\n}\n\n/**\n * Returns a signal that aborts as soon as any of the provided signals abort.\n * With a single argument, returns it directly (no allocation).\n * Registers and cleans up its own event listeners — no leaks when no signal fires.\n *\n * @example\n * const signal = combineSignals(timeoutSignal, bus.disposalSignal);\n * bus.on('event', handler, { signal });\n *\n * @example\n * // Three signals — no nesting required\n * const signal = combineSignals(userSignal, timeoutSignal, bus.disposalSignal);\n */\nexport function combineSignals(first: AbortSignal, ...rest: AbortSignal[]): AbortSignal {\n if (rest.length === 0) return first;\n\n return rest.reduce(mergeTwo, first);\n}\n\n// Each registration gets a unique Entry object, allowing the same listener function\n// to be registered multiple times independently (aligns with Node EventEmitter / mitt).\ntype Entry = { fn: Listener<unknown>; unsub: () => void };\ntype WildcardEntry = { fn: (event: string, payload: unknown) => void; unsub: () => void };\n\ntype RegisterEntryOpts = { offLog: string; onLog: string; onRemove?: () => void };\n\n// makeEventStream wraps an AsyncGenerator with AsyncDisposable.\nfunction makeEventStream<V>(gen: AsyncGenerator<V>, onDispose: () => Promise<void>): EventStream<V> {\n return Object.assign(gen, {\n [Symbol.asyncDispose]: onDispose,\n }) as unknown as EventStream<V>;\n}\n\n/** @internal */\nexport type InternalBusOptions<T extends EventMap> = BusOptions<T> & {\n /** @internal Called after middleware passes, before listeners run. Used by BehaviorBus. */\n _onDispatch?: (event: EventKey<T>, payload: unknown) => void;\n};\n\nexport function createBus<T extends EventMap>(options?: InternalBusOptions<T>): Bus<T> {\n // Per-event set of Entry objects. Set identity prevents accidental dedup of entries;\n // the same fn can appear in multiple entries with independent lifetimes.\n const listeners = new Map<string, Set<Entry>>();\n const wildcards = new Set<WildcardEntry>();\n const disposeController = new AbortController();\n const busName = options?.name;\n const maxListeners = options?.maxListeners;\n const rawDebug = options?.logger?.debug;\n const logDebug = rawDebug && busName ? (msg: string) => rawDebug(`${msg} (${busName})`) : rawDebug;\n const hasLogger = options?.logger !== undefined;\n const customLogWarn = options?.logger?.warn;\n const busTag = busName ? ` (${busName})` : '';\n\n function doWarn(msg: string): void {\n if (customLogWarn) {\n customLogWarn(msg);\n } else if (!hasLogger) {\n _internalWarn(msg);\n }\n }\n\n function mergeSignal(signal?: AbortSignal): AbortSignal {\n return signal ? combineSignals(disposeController.signal, signal) : disposeController.signal;\n }\n\n // callSafe is defined once per bus (not per emit) — avoids re-allocating on every emission.\n // Captures options.onError via closure. Used in emit() for both specific and wildcard loops.\n // Does not rethrow directly — see dispatch(), which continues the broadcast to every remaining\n // listener (including wildcards) before rethrowing the first captured error, if any.\n function callSafe(fn: () => void, event: EventKey<T>, payload: unknown, timestamp: number): SafeCallResult {\n const onError = options?.onError\n ? (err: unknown) => options.onError!({ err, event, payload, timestamp } as EmissionErrorContext<T>)\n : undefined;\n\n return callSafely(fn, onError);\n }\n\n // registerEntry opts object — self-documenting call sites.\n function registerEntry<E extends { unsub: () => void }>(\n container: Set<E>,\n makeEntry: (unsub: () => void) => E,\n signal: AbortSignal,\n { offLog, onLog, onRemove }: RegisterEntryOpts,\n ): () => void {\n if (signal.aborted) return noop;\n\n // Boolean guard makes unsub idempotent — a second call after re-registration would\n // otherwise see an empty container and incorrectly delete the outer map entry.\n let called = false;\n\n function unsub() {\n if (called) return;\n\n called = true;\n container.delete(entry);\n onRemove?.();\n signal.removeEventListener('abort', unsub);\n\n logDebug?.(`[herald:sub] ${offLog} — ${container.size} listener(s) remaining`);\n }\n\n // Function declaration is hoisted so `entry` can reference `unsub` directly.\n const entry = makeEntry(unsub);\n\n container.add(entry);\n signal.addEventListener('abort', unsub, { once: true });\n\n logDebug?.(`[herald:sub] ${onLog} — ${container.size} listener(s)`);\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>>(event: K, listener: Listener<T[K]>, signal: AbortSignal): () => void {\n let set = listeners.get(event);\n\n if (!set) {\n set = new Set();\n listeners.set(event, set);\n }\n\n // Capture the set reference so unsub can safely delete from it even after\n // the event key has been removed from the outer map.\n const capturedSet = set;\n\n return registerEntry(capturedSet, (unsub) => ({ fn: listener as Listener<unknown>, unsub }), signal, {\n offLog: `off(\"${event}\")`,\n onLog: `on(\"${event}\")`,\n onRemove: () => {\n if (capturedSet.size === 0) listeners.delete(event);\n },\n });\n }\n\n function onAnyWithSignal(listener: (event: EventKey<T>, payload: unknown) => void, signal: AbortSignal): () => void {\n return registerEntry(\n wildcards,\n (unsub) => ({ fn: listener as (event: string, payload: unknown) => void, unsub }),\n signal,\n { offLog: 'onAny off', onLog: 'onAny' },\n );\n }\n\n // Use a const ref object to hold the unsub handle — avoids the forward-reference that\n // TypeScript cannot prove safe with `const unsub = f(() => unsub)`. The `ref` binding never\n // changes (only its property is mutated), satisfying prefer-const. By the time the inner\n // callback fires (only possible after onWithSignal returns), ref.unsub is the real handle.\n function onceWithSignal<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, signal: AbortSignal): () => 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 );\n\n return ref.unsub;\n }\n\n // onAny with once — fires the wildcard listener exactly once, then auto-removes.\n function onAnyWithOnce(listener: (event: EventKey<T>, payload: unknown) => void, signal: AbortSignal): () => void {\n const ref = { unsub: noop as Unsubscribe };\n\n ref.unsub = onAnyWithSignal((event, payload) => {\n ref.unsub();\n listener(event, payload);\n }, signal);\n\n return ref.unsub;\n }\n\n function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): () => void {\n const signal = mergeSignal(opts?.signal);\n\n if (opts?.once) return onceWithSignal(event, listener, signal);\n\n return onWithSignal(event, listener, signal);\n }\n\n // once() and onAny() take an options object — consistent with on(), extensible for future options.\n function once<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n opts?: { signal?: AbortSignal },\n ): () => void {\n return onceWithSignal(event, listener, mergeSignal(opts?.signal));\n }\n\n function onAny(listener: (event: EventKey<T>, payload: unknown) => void, opts?: SubscribeOptions): () => void {\n const signal = mergeSignal(opts?.signal);\n\n if (opts?.once) return onAnyWithOnce(listener, signal);\n\n return onAnyWithSignal(listener, signal);\n }\n\n function wait<K extends EventKey<T>>(event: K, opts?: { signal?: AbortSignal }): Promise<T[K]> {\n const activeSignal = mergeSignal(opts?.signal);\n\n if (activeSignal.aborted) return Promise.reject(activeSignal.reason);\n\n return new Promise<T[K]>((resolve, reject) => {\n function onAbort() {\n reject(activeSignal.reason);\n }\n\n onceWithSignal(\n event,\n (payload) => {\n activeSignal.removeEventListener('abort', onAbort);\n resolve(payload);\n },\n activeSignal,\n );\n\n activeSignal.addEventListener('abort', onAbort, { once: true });\n });\n }\n\n // events() subscribes eagerly — the listener is registered when events() is called, not when\n // the first .next() runs. This ensures events emitted before iteration begins are buffered.\n // maxBuffer is validated synchronously so callers get a RangeError at call time.\n function events<K extends EventKey<T>>(\n event: K,\n opts?: { maxBuffer?: number; signal?: AbortSignal },\n ): EventStream<T[K]> {\n const maxBuffer = opts?.maxBuffer ?? Infinity;\n\n if (!(maxBuffer > 0)) throw new HeraldConfigError('maxBuffer must be a positive number');\n\n const activeSignal = mergeSignal(opts?.signal);\n\n if (activeSignal.aborted) {\n const empty = (async function* (): AsyncGenerator<T[K]> {})();\n\n return makeEventStream(empty, async (): Promise<void> => {});\n }\n\n const queue: T[K][] = [];\n let wake: (() => void) | undefined;\n\n const unsub = onWithSignal(\n event,\n (payload) => {\n if (queue.length >= maxBuffer) queue.shift();\n\n queue.push(payload);\n wake?.();\n },\n activeSignal,\n );\n\n async function* generate(): AsyncGenerator<T[K]> {\n try {\n while (!activeSignal.aborted) {\n if (queue.length) {\n yield queue.shift()!;\n continue;\n }\n\n const { promise, resolve } = Promise.withResolvers<void>();\n const abortHandler = (): void => {\n resolve();\n };\n\n wake = resolve;\n activeSignal.addEventListener('abort', abortHandler, { once: true });\n await promise;\n activeSignal.removeEventListener('abort', abortHandler);\n wake = undefined;\n }\n } finally {\n unsub();\n }\n }\n\n const gen = generate();\n\n // Symbol.asyncDispose calls unsub() directly because gen.return() only runs the finally\n // block when the generator has been started (at least one next() call). The unsub guard\n // (called = false in registerEntry) makes this idempotent.\n return makeEventStream(gen, async (): Promise<void> => {\n unsub();\n await gen.return(undefined as unknown as T[K]);\n });\n }\n\n // dispatch is defined at createBus() scope (once per bus, not per emit call) — consistent with\n // callSafe. Receives event/payload/timestamp as arguments so it can be invoked from both the\n // direct path and the middleware chain without capturing per-emit locals in a closure.\n function dispatch(event: EventKey<T>, payload: unknown, timestamp: number): number {\n options?._onDispatch?.(event, payload);\n\n let count = 0;\n // Only the first unforwarded error is kept — every listener still runs (see callSafe's\n // doc comment) — then it's rethrown once the whole broadcast (specific + wildcard) is done.\n let firstError: { err: unknown } | undefined;\n const set = listeners.get(event);\n\n if (set?.size) {\n for (const entry of [...set]) {\n const result = callSafe(() => entry.fn(payload), event, payload, timestamp);\n\n if (result.threw && !firstError) firstError = { err: result.err };\n\n count++;\n }\n }\n\n if (wildcards.size) {\n for (const entry of [...wildcards]) {\n const result = callSafe(() => entry.fn(event, payload), event, payload, timestamp);\n\n if (result.threw && !firstError) firstError = { err: result.err };\n\n count++;\n }\n }\n\n if (firstError) throw firstError.err;\n\n return count;\n }\n\n // emit() returns the number of listeners invoked (specific + wildcard).\n // Returns 0 if bus is disposed, middleware blocked dispatch, or validatePayload rejected.\n // validatePayload runs first, then middleware, then listeners.\n function emit<K extends EventKey<T>>(event: K, ...args: T[K] extends void ? [] : [payload: T[K]]): number {\n if (disposeController.signal.aborted) return 0;\n\n const payload = (args as unknown[])[0];\n const timestamp = Date.now();\n\n if (options?.validatePayload) {\n try {\n options.validatePayload(event, payload as T[K]);\n } catch (err) {\n if (options?.onError) {\n options.onError({ err, event, payload, timestamp } as EmissionErrorContext<T>);\n\n return 0;\n }\n\n throw err;\n }\n }\n\n if (logDebug) {\n const specific = listeners.get(event)?.size ?? 0;\n const wild = wildcards.size;\n\n logDebug(\n `[herald:emit] emit(\"${event}\") — ${specific + wild} listener(s) (${specific} specific, ${wild} wildcard)`,\n );\n }\n\n // Middleware pipeline — each middleware calls next() to proceed.\n const middleware = options?.middleware;\n\n if (middleware?.length) {\n let dispatched = 0;\n let i = 0;\n\n // Guard prevents a misbehaving middleware from calling next() twice and\n // triggering a double-dispatch to listeners. Note: a middleware calling next()\n // more than twice can still invoke downstream middleware multiple times.\n function next(): void {\n const idx = i++;\n\n if (idx < middleware!.length) middleware;\n else if (idx === middleware!.length) dispatched = dispatch(event, payload, timestamp);\n }\n\n next();\n\n return dispatched;\n }\n\n return dispatch(event, payload, timestamp);\n }\n\n // listenerCount counts specific-event listeners only.\n // wildcardCount() is the separate accessor for onAny listeners.\n function listenerCount(event?: EventKey<T>): number {\n if (event !== undefined) return listeners.get(event)?.size ?? 0;\n\n let total = 0;\n\n for (const set of listeners.values()) total += set.size;\n\n return total;\n }\n\n function wildcardCount(): number {\n return wildcards.size;\n }\n\n function eventNames(): EventKey<T>[] {\n return [...listeners.keys()] as EventKey<T>[];\n }\n\n function waitAny<K extends readonly [EventKey<T>, EventKey<T>, ...EventKey<T>[]]>(\n eventList: K,\n opts?: { signal?: AbortSignal },\n ): Promise<WaitAnyResult<T, K>> {\n if (eventList.length < 2) throw new HeraldConfigError('waitAny() requires at least 2 event keys');\n\n const activeSignal = mergeSignal(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 = combineSignals(activeSignal, raceController.signal);\n\n function onAbort() {\n raceController.abort();\n reject(activeSignal.reason);\n }\n\n activeSignal.addEventListener('abort', onAbort, { once: true });\n\n for (const event of eventList) {\n onceWithSignal(\n event as EventKey<T>,\n (payload) => {\n activeSignal.removeEventListener('abort', onAbort);\n raceController.abort();\n resolve({ event, payload } as WaitAnyResult<T, K>);\n },\n raceSignal,\n );\n }\n });\n }\n\n function dispose(): void {\n if (disposeController.signal.aborted) return;\n\n logDebug?.('[herald:lifecycle] dispose()');\n\n disposeController.abort(new BusDisposedError(busName));\n // disposeController.abort() fires all unsub handlers synchronously, which\n // removes every entry and deletes empty keys. By here both maps are already\n // empty. clear() is a cheap defensive measure against any future code path\n // that bypasses the signal (e.g. a direct listeners.set() before a guard).\n listeners.clear();\n wildcards.clear();\n }\n\n return {\n get disposalSignal() {\n return disposeController.signal;\n },\n dispose,\n get disposed() {\n return disposeController.signal.aborted;\n },\n emit,\n eventNames,\n events,\n listenerCount,\n on,\n onAny,\n once,\n [Symbol.dispose]: dispose,\n wait,\n waitAny,\n wildcardCount,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bus.cjs","names":[],"sources":["../src/bus.ts"],"sourcesContent":["import type {\n Bus,\n BusOptions,\n EmissionErrorContext,\n EventKey,\n EventMap,\n EventStream,\n Listener,\n SubscribeOptions,\n Unsubscribe,\n WaitAnyResult,\n} from './types';\n\nimport { warn as _internalWarn } from './_dev';\nimport { type SafeCallResult, callSafely } from './_safe';\nimport { BusDisposedError, HeraldConfigError } from './errors';\n\n// Module-scoped noop — shared across all bus instances to avoid per-bus allocation.\n// @internal — exported only for sibling internal modules; stripped from public declarations via stripInternal.\n/** @internal */\nexport const noop = () => {};\n\n/** @internal */\nfunction mergeTwo(a: AbortSignal, b: AbortSignal): AbortSignal {\n if (a.aborted) return a;\n\n if (b.aborted) return b;\n\n const ctrl = new AbortController();\n const onA = (): void => ctrl.abort(a.reason);\n const onB = (): void => ctrl.abort(b.reason);\n\n a.addEventListener('abort', onA, { once: true });\n b.addEventListener('abort', onB, { once: true });\n ctrl.signal.addEventListener(\n 'abort',\n () => {\n a.removeEventListener('abort', onA);\n b.removeEventListener('abort', onB);\n },\n { once: true },\n );\n\n return ctrl.signal;\n}\n\n/**\n * Returns a signal that aborts as soon as any of the provided signals abort.\n * With a single argument, returns it directly (no allocation).\n * Registers and cleans up its own event listeners — no leaks when no signal fires.\n *\n * @example\n * const signal = combineSignals(timeoutSignal, bus.disposalSignal);\n * bus.on('event', handler, { signal });\n *\n * @example\n * // Three signals — no nesting required\n * const signal = combineSignals(userSignal, timeoutSignal, bus.disposalSignal);\n */\nexport function combineSignals(first: AbortSignal, ...rest: AbortSignal[]): AbortSignal {\n if (rest.length === 0) return first;\n\n return rest.reduce(mergeTwo, first);\n}\n\n// Each registration gets a unique Entry object, allowing the same listener function\n// to be registered multiple times independently (aligns with Node EventEmitter / mitt).\ntype Entry = { fn: Listener<unknown>; unsub: () => void };\ntype WildcardEntry = { fn: (event: string, payload: unknown) => void; unsub: () => void };\n\ntype RegisterEntryOpts = { offLog: string; onLog: string; onRemove?: () => void };\n\n// makeEventStream wraps an AsyncGenerator with AsyncDisposable.\nfunction makeEventStream<V>(gen: AsyncGenerator<V>, onDispose: () => Promise<void>): EventStream<V> {\n return Object.assign(gen, {\n [Symbol.asyncDispose]: onDispose,\n }) as unknown as EventStream<V>;\n}\n\n/** @internal */\nexport type InternalBusOptions<T extends EventMap> = BusOptions<T> & {\n /** @internal Called after middleware passes, before listeners run. Used by BehaviorBus. */\n _onDispatch?: (event: EventKey<T>, payload: unknown) => void;\n};\n\nexport function createBus<T extends EventMap>(options?: InternalBusOptions<T>): Bus<T> {\n // Per-event set of Entry objects. Set identity prevents accidental dedup of entries;\n // the same fn can appear in multiple entries with independent lifetimes.\n const listeners = new Map<string, Set<Entry>>();\n const wildcards = new Set<WildcardEntry>();\n const disposeController = new AbortController();\n const busName = options?.name;\n const maxListeners = options?.maxListeners;\n const rawDebug = options?.logger?.debug;\n const logDebug = rawDebug && busName ? (msg: string) => rawDebug(`${msg} (${busName})`) : rawDebug;\n const hasLogger = options?.logger !== undefined;\n const customLogWarn = options?.logger?.warn;\n const busTag = busName ? ` (${busName})` : '';\n\n function doWarn(msg: string): void {\n if (customLogWarn) {\n customLogWarn(msg);\n } else if (!hasLogger) {\n _internalWarn(msg);\n }\n }\n\n function mergeSignal(signal?: AbortSignal): AbortSignal {\n return signal ? combineSignals(disposeController.signal, signal) : disposeController.signal;\n }\n\n // callSafe is defined once per bus (not per emit) — avoids re-allocating on every emission.\n // Captures options.onError via closure. Used in emit() for both specific and wildcard loops.\n // Does not rethrow directly — see dispatch(), which continues the broadcast to every remaining\n // listener (including wildcards) before rethrowing the first captured error, if any.\n function callSafe(fn: () => void, event: EventKey<T>, payload: unknown, timestamp: number): SafeCallResult {\n const onError = options?.onError\n ? (err: unknown) => options.onError!({ err, event, payload, timestamp } as EmissionErrorContext<T>)\n : undefined;\n\n return callSafely(fn, onError);\n }\n\n // registerEntry opts object — self-documenting call sites.\n function registerEntry<E extends { unsub: () => void }>(\n container: Set<E>,\n makeEntry: (unsub: () => void) => E,\n signal: AbortSignal,\n { offLog, onLog, onRemove }: RegisterEntryOpts,\n ): () => void {\n if (signal.aborted) return noop;\n\n // Boolean guard makes unsub idempotent — a second call after re-registration would\n // otherwise see an empty container and incorrectly delete the outer map entry.\n let called = false;\n\n function unsub() {\n if (called) return;\n\n called = true;\n container.delete(entry);\n onRemove?.();\n signal.removeEventListener('abort', unsub);\n\n logDebug?.(`[herald:sub] ${offLog} — ${container.size} listener(s) remaining`);\n }\n\n // Function declaration is hoisted so `entry` can reference `unsub` directly.\n const entry = makeEntry(unsub);\n\n container.add(entry);\n signal.addEventListener('abort', unsub, { once: true });\n\n logDebug?.(`[herald:sub] ${onLog} — ${container.size} listener(s)`);\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>>(event: K, listener: Listener<T[K]>, signal: AbortSignal): () => void {\n let set = listeners.get(event);\n\n if (!set) {\n set = new Set();\n listeners.set(event, set);\n }\n\n // Capture the set reference so unsub can safely delete from it even after\n // the event key has been removed from the outer map.\n const capturedSet = set;\n\n return registerEntry(capturedSet, (unsub) => ({ fn: listener as Listener<unknown>, unsub }), signal, {\n offLog: `off(\"${event}\")`,\n onLog: `on(\"${event}\")`,\n onRemove: () => {\n if (capturedSet.size === 0) listeners.delete(event);\n },\n });\n }\n\n function onAnyWithSignal(listener: (event: EventKey<T>, payload: unknown) => void, signal: AbortSignal): () => void {\n return registerEntry(\n wildcards,\n (unsub) => ({ fn: listener as (event: string, payload: unknown) => void, unsub }),\n signal,\n { offLog: 'onAny off', onLog: 'onAny' },\n );\n }\n\n // Use a const ref object to hold the unsub handle — avoids the forward-reference that\n // TypeScript cannot prove safe with `const unsub = f(() => unsub)`. The `ref` binding never\n // changes (only its property is mutated), satisfying prefer-const. By the time the inner\n // callback fires (only possible after onWithSignal returns), ref.unsub is the real handle.\n function onceWithSignal<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, signal: AbortSignal): () => 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 );\n\n return ref.unsub;\n }\n\n // onAny with once — fires the wildcard listener exactly once, then auto-removes.\n function onAnyWithOnce(listener: (event: EventKey<T>, payload: unknown) => void, signal: AbortSignal): () => void {\n const ref = { unsub: noop as Unsubscribe };\n\n ref.unsub = onAnyWithSignal((event, payload) => {\n ref.unsub();\n listener(event, payload);\n }, signal);\n\n return ref.unsub;\n }\n\n function on<K extends EventKey<T>>(event: K, listener: Listener<T[K]>, opts?: SubscribeOptions): () => void {\n const signal = mergeSignal(opts?.signal);\n\n if (opts?.once) return onceWithSignal(event, listener, signal);\n\n return onWithSignal(event, listener, signal);\n }\n\n // once() and onAny() take an options object — consistent with on(), extensible for future options.\n function once<K extends EventKey<T>>(\n event: K,\n listener: Listener<T[K]>,\n opts?: { signal?: AbortSignal },\n ): () => void {\n return onceWithSignal(event, listener, mergeSignal(opts?.signal));\n }\n\n function onAny(listener: (event: EventKey<T>, payload: unknown) => void, opts?: SubscribeOptions): () => void {\n const signal = mergeSignal(opts?.signal);\n\n if (opts?.once) return onAnyWithOnce(listener, signal);\n\n return onAnyWithSignal(listener, signal);\n }\n\n function wait<K extends EventKey<T>>(event: K, opts?: { signal?: AbortSignal }): Promise<T[K]> {\n const activeSignal = mergeSignal(opts?.signal);\n\n if (activeSignal.aborted) return Promise.reject(activeSignal.reason);\n\n return new Promise<T[K]>((resolve, reject) => {\n function onAbort() {\n reject(activeSignal.reason);\n }\n\n onceWithSignal(\n event,\n (payload) => {\n activeSignal.removeEventListener('abort', onAbort);\n resolve(payload);\n },\n activeSignal,\n );\n\n activeSignal.addEventListener('abort', onAbort, { once: true });\n });\n }\n\n // events() subscribes eagerly — the listener is registered when events() is called, not when\n // the first .next() runs. This ensures events emitted before iteration begins are buffered.\n // maxBuffer is validated synchronously so callers get a RangeError at call time.\n function events<K extends EventKey<T>>(\n event: K,\n opts?: { maxBuffer?: number; signal?: AbortSignal },\n ): EventStream<T[K]> {\n const maxBuffer = opts?.maxBuffer ?? Infinity;\n\n if (!(maxBuffer > 0)) throw new HeraldConfigError('maxBuffer must be a positive number');\n\n const activeSignal = mergeSignal(opts?.signal);\n\n if (activeSignal.aborted) {\n const empty = (async function* (): AsyncGenerator<T[K]> {})();\n\n return makeEventStream(empty, async (): Promise<void> => {});\n }\n\n const queue: T[K][] = [];\n let wake: (() => void) | undefined;\n\n const unsub = onWithSignal(\n event,\n (payload) => {\n if (queue.length >= maxBuffer) queue.shift();\n\n queue.push(payload);\n wake?.();\n },\n activeSignal,\n );\n\n async function* generate(): AsyncGenerator<T[K]> {\n try {\n while (!activeSignal.aborted) {\n if (queue.length) {\n yield queue.shift()!;\n continue;\n }\n\n const { promise, resolve } = Promise.withResolvers<void>();\n const abortHandler = (): void => {\n resolve();\n };\n\n wake = resolve;\n activeSignal.addEventListener('abort', abortHandler, { once: true });\n await promise;\n activeSignal.removeEventListener('abort', abortHandler);\n wake = undefined;\n }\n } finally {\n unsub();\n }\n }\n\n const gen = generate();\n\n // Symbol.asyncDispose calls unsub() directly because gen.return() only runs the finally\n // block when the generator has been started (at least one next() call). The unsub guard\n // (called = false in registerEntry) makes this idempotent.\n return makeEventStream(gen, async (): Promise<void> => {\n unsub();\n await gen.return(undefined as unknown as T[K]);\n });\n }\n\n // dispatch is defined at createBus() scope (once per bus, not per emit call) — consistent with\n // callSafe. Receives event/payload/timestamp as arguments so it can be invoked from both the\n // direct path and the middleware chain without capturing per-emit locals in a closure.\n function dispatch(event: EventKey<T>, payload: unknown, timestamp: number): number {\n options?._onDispatch?.(event, payload);\n\n let count = 0;\n // Only the first unforwarded error is kept — every listener still runs (see callSafe's\n // doc comment) — then it's rethrown once the whole broadcast (specific + wildcard) is done.\n let firstError: { err: unknown } | undefined;\n const set = listeners.get(event);\n\n if (set?.size) {\n for (const entry of [...set]) {\n const result = callSafe(() => entry.fn(payload), event, payload, timestamp);\n\n if (result.threw && !firstError) firstError = { err: result.err };\n\n count++;\n }\n }\n\n if (wildcards.size) {\n for (const entry of [...wildcards]) {\n const result = callSafe(() => entry.fn(event, payload), event, payload, timestamp);\n\n if (result.threw && !firstError) firstError = { err: result.err };\n\n count++;\n }\n }\n\n if (firstError) throw firstError.err;\n\n return count;\n }\n\n // emit() returns the number of listeners invoked (specific + wildcard).\n // Returns 0 if bus is disposed, middleware blocked dispatch, or validatePayload rejected.\n // validatePayload runs first, then middleware, then listeners.\n function emit<K extends EventKey<T>>(event: K, ...args: T[K] extends void ? [] : [payload: T[K]]): number {\n if (disposeController.signal.aborted) return 0;\n\n const payload = (args as unknown[])[0];\n const timestamp = Date.now();\n\n if (options?.validatePayload) {\n try {\n options.validatePayload(event, payload as T[K]);\n } catch (err) {\n if (options?.onError) {\n options.onError({ err, event, payload, timestamp } as EmissionErrorContext<T>);\n\n return 0;\n }\n\n throw err;\n }\n }\n\n if (logDebug) {\n const specific = listeners.get(event)?.size ?? 0;\n const wild = wildcards.size;\n\n logDebug(\n `[herald:emit] emit(\"${event}\") — ${specific + wild} listener(s) (${specific} specific, ${wild} wildcard)`,\n );\n }\n\n // Middleware pipeline — each middleware calls next() to proceed.\n const middleware = options?.middleware;\n\n if (middleware?.length) {\n let dispatched = 0;\n let i = 0;\n\n // Guard prevents a misbehaving middleware from calling next() twice and\n // triggering a double-dispatch to listeners. Note: a middleware calling next()\n // more than twice can still invoke downstream middleware multiple times.\n function next(): void {\n const idx = i++;\n\n if (idx < middleware!.length) middleware;\n else if (idx === middleware!.length) dispatched = dispatch(event, payload, timestamp);\n }\n\n next();\n\n return dispatched;\n }\n\n return dispatch(event, payload, timestamp);\n }\n\n // listenerCount counts specific-event listeners only.\n // wildcardCount() is the separate accessor for onAny listeners.\n function listenerCount(event?: EventKey<T>): number {\n if (event !== undefined) return listeners.get(event)?.size ?? 0;\n\n let total = 0;\n\n for (const set of listeners.values()) total += set.size;\n\n return total;\n }\n\n function wildcardCount(): number {\n return wildcards.size;\n }\n\n function eventNames(): EventKey<T>[] {\n return [...listeners.keys()] as EventKey<T>[];\n }\n\n function waitAny<K extends readonly [EventKey<T>, EventKey<T>, ...EventKey<T>[]]>(\n eventList: K,\n opts?: { signal?: AbortSignal },\n ): Promise<WaitAnyResult<T, K>> {\n if (eventList.length < 2) throw new HeraldConfigError('waitAny() requires at least 2 event keys');\n\n const activeSignal = mergeSignal(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 = combineSignals(activeSignal, raceController.signal);\n\n function onAbort() {\n raceController.abort();\n reject(activeSignal.reason);\n }\n\n activeSignal.addEventListener('abort', onAbort, { once: true });\n\n for (const event of eventList) {\n onceWithSignal(\n event as EventKey<T>,\n (payload) => {\n activeSignal.removeEventListener('abort', onAbort);\n raceController.abort();\n resolve({ event, payload } as WaitAnyResult<T, K>);\n },\n raceSignal,\n );\n }\n });\n }\n\n function dispose(): void {\n if (disposeController.signal.aborted) return;\n\n logDebug?.('[herald:lifecycle] dispose()');\n\n disposeController.abort(new BusDisposedError(busName));\n // disposeController.abort() fires all unsub handlers synchronously, which\n // removes every entry and deletes empty keys. By here both maps are already\n // empty. clear() is a cheap defensive measure against any future code path\n // that bypasses the signal (e.g. a direct listeners.set() before a guard).\n listeners.clear();\n wildcards.clear();\n }\n\n return {\n get disposalSignal() {\n return disposeController.signal;\n },\n dispose,\n get disposed() {\n return disposeController.signal.aborted;\n },\n emit,\n eventNames,\n events,\n listenerCount,\n on,\n onAny,\n once,\n [Symbol.dispose]: dispose,\n wait,\n waitAny,\n wildcardCount,\n };\n}\n"],"mappings":"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"}
|
package/dist/bus.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { callSafely as e } from "./_safe.js";
|
|
2
|
-
import
|
|
3
|
-
import { BusDisposedError as
|
|
2
|
+
import "./_dev.js";
|
|
3
|
+
import { BusDisposedError as t, HeraldConfigError as n } from "./errors.js";
|
|
4
4
|
//#region src/bus.ts
|
|
5
|
-
var
|
|
6
|
-
function
|
|
5
|
+
var r = () => {};
|
|
6
|
+
function i(e, t) {
|
|
7
7
|
if (e.aborted) return e;
|
|
8
8
|
if (t.aborted) return t;
|
|
9
9
|
let n = new AbortController(), r = () => n.abort(e.reason), i = () => n.abort(t.reason);
|
|
@@ -11,54 +11,57 @@ function a(e, t) {
|
|
|
11
11
|
e.removeEventListener("abort", r), t.removeEventListener("abort", i);
|
|
12
12
|
}, { once: !0 }), n.signal;
|
|
13
13
|
}
|
|
14
|
-
function
|
|
15
|
-
return t.length === 0 ? e : t.reduce(
|
|
14
|
+
function a(e, ...t) {
|
|
15
|
+
return t.length === 0 ? e : t.reduce(i, e);
|
|
16
16
|
}
|
|
17
|
-
function
|
|
17
|
+
function o(e, t) {
|
|
18
18
|
return Object.assign(e, { [Symbol.asyncDispose]: t });
|
|
19
19
|
}
|
|
20
|
-
function
|
|
21
|
-
let
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
function s(i) {
|
|
21
|
+
let s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Set(), l = new AbortController(), u = i?.name, d = i?.maxListeners, f = i?.logger?.debug, p = f && u ? (e) => f(`${e} (${u})`) : f;
|
|
22
|
+
i?.logger;
|
|
23
|
+
let m = i?.logger?.warn, h = u ? ` (${u})` : "";
|
|
24
|
+
function g(e) {
|
|
25
|
+
m && m(e);
|
|
26
|
+
}
|
|
27
|
+
function _(e) {
|
|
28
|
+
return e ? a(l.signal, e) : l.signal;
|
|
29
|
+
}
|
|
30
|
+
function v(t, n, r, a) {
|
|
31
|
+
let o = i?.onError ? (e) => i.onError({
|
|
30
32
|
err: e,
|
|
31
33
|
event: n,
|
|
32
34
|
payload: r,
|
|
33
|
-
timestamp:
|
|
34
|
-
}) : void 0
|
|
35
|
+
timestamp: a
|
|
36
|
+
}) : void 0;
|
|
37
|
+
return e(t, o);
|
|
35
38
|
}
|
|
36
|
-
function
|
|
37
|
-
if (n.aborted) return
|
|
39
|
+
function y(e, t, n, { offLog: i, onLog: a, onRemove: o }) {
|
|
40
|
+
if (n.aborted) return r;
|
|
38
41
|
let s = !1;
|
|
39
42
|
function c() {
|
|
40
|
-
s || (s = !0, e.delete(l), o?.(), n.removeEventListener("abort", c),
|
|
43
|
+
s || (s = !0, e.delete(l), o?.(), n.removeEventListener("abort", c), p?.(`[herald:sub] ${i} — ${e.size} listener(s) remaining`));
|
|
41
44
|
}
|
|
42
45
|
let l = t(c);
|
|
43
|
-
return e.add(l), n.addEventListener("abort", c, { once: !0 }),
|
|
46
|
+
return e.add(l), n.addEventListener("abort", c, { once: !0 }), p?.(`[herald:sub] ${a} — ${e.size} listener(s)`), d !== void 0 && e.size > d && g(`${a} has ${e.size} listeners, exceeding maxListeners (${d}). Possible memory leak.${h}`), c;
|
|
44
47
|
}
|
|
45
|
-
function
|
|
46
|
-
let r =
|
|
47
|
-
r || (r = /* @__PURE__ */ new Set(),
|
|
48
|
+
function b(e, t, n) {
|
|
49
|
+
let r = s.get(e);
|
|
50
|
+
r || (r = /* @__PURE__ */ new Set(), s.set(e, r));
|
|
48
51
|
let i = r;
|
|
49
|
-
return
|
|
52
|
+
return y(i, (e) => ({
|
|
50
53
|
fn: t,
|
|
51
54
|
unsub: e
|
|
52
55
|
}), n, {
|
|
53
56
|
offLog: `off("${e}")`,
|
|
54
57
|
onLog: `on("${e}")`,
|
|
55
58
|
onRemove: () => {
|
|
56
|
-
i.size === 0 &&
|
|
59
|
+
i.size === 0 && s.delete(e);
|
|
57
60
|
}
|
|
58
61
|
});
|
|
59
62
|
}
|
|
60
|
-
function
|
|
61
|
-
return
|
|
63
|
+
function x(e, t) {
|
|
64
|
+
return y(c, (t) => ({
|
|
62
65
|
fn: e,
|
|
63
66
|
unsub: t
|
|
64
67
|
}), t, {
|
|
@@ -66,47 +69,47 @@ function c(a) {
|
|
|
66
69
|
onLog: "onAny"
|
|
67
70
|
});
|
|
68
71
|
}
|
|
69
|
-
function
|
|
70
|
-
let
|
|
71
|
-
return
|
|
72
|
-
|
|
73
|
-
}, n),
|
|
74
|
-
}
|
|
75
|
-
function
|
|
76
|
-
let n = { unsub:
|
|
77
|
-
return n.unsub =
|
|
72
|
+
function S(e, t, n) {
|
|
73
|
+
let i = { unsub: r };
|
|
74
|
+
return i.unsub = b(e, (e) => {
|
|
75
|
+
i.unsub(), t(e);
|
|
76
|
+
}, n), i.unsub;
|
|
77
|
+
}
|
|
78
|
+
function C(e, t) {
|
|
79
|
+
let n = { unsub: r };
|
|
80
|
+
return n.unsub = x((t, r) => {
|
|
78
81
|
n.unsub(), e(t, r);
|
|
79
82
|
}, t), n.unsub;
|
|
80
83
|
}
|
|
81
|
-
function
|
|
82
|
-
let r =
|
|
83
|
-
return n?.once ?
|
|
84
|
+
function w(e, t, n) {
|
|
85
|
+
let r = _(n?.signal);
|
|
86
|
+
return n?.once ? S(e, t, r) : b(e, t, r);
|
|
84
87
|
}
|
|
85
|
-
function
|
|
86
|
-
return
|
|
88
|
+
function T(e, t, n) {
|
|
89
|
+
return S(e, t, _(n?.signal));
|
|
87
90
|
}
|
|
88
|
-
function
|
|
89
|
-
let n =
|
|
90
|
-
return t?.once ?
|
|
91
|
+
function E(e, t) {
|
|
92
|
+
let n = _(t?.signal);
|
|
93
|
+
return t?.once ? C(e, n) : x(e, n);
|
|
91
94
|
}
|
|
92
|
-
function
|
|
93
|
-
let n =
|
|
95
|
+
function D(e, t) {
|
|
96
|
+
let n = _(t?.signal);
|
|
94
97
|
return n.aborted ? Promise.reject(n.reason) : new Promise((t, r) => {
|
|
95
98
|
function i() {
|
|
96
99
|
r(n.reason);
|
|
97
100
|
}
|
|
98
|
-
|
|
101
|
+
S(e, (e) => {
|
|
99
102
|
n.removeEventListener("abort", i), t(e);
|
|
100
103
|
}, n), n.addEventListener("abort", i, { once: !0 });
|
|
101
104
|
});
|
|
102
105
|
}
|
|
103
|
-
function
|
|
104
|
-
let
|
|
105
|
-
if (!(
|
|
106
|
-
let i =
|
|
107
|
-
if (i.aborted) return
|
|
108
|
-
let a = [],
|
|
109
|
-
a.length >=
|
|
106
|
+
function O(e, t) {
|
|
107
|
+
let r = t?.maxBuffer ?? Infinity;
|
|
108
|
+
if (!(r > 0)) throw new n("maxBuffer must be a positive number");
|
|
109
|
+
let i = _(t?.signal);
|
|
110
|
+
if (i.aborted) return o((async function* () {})(), async () => {});
|
|
111
|
+
let a = [], s, c = b(e, (e) => {
|
|
112
|
+
a.length >= r && a.shift(), a.push(e), s?.();
|
|
110
113
|
}, i);
|
|
111
114
|
async function* l() {
|
|
112
115
|
try {
|
|
@@ -118,38 +121,38 @@ function c(a) {
|
|
|
118
121
|
let { promise: e, resolve: t } = Promise.withResolvers(), n = () => {
|
|
119
122
|
t();
|
|
120
123
|
};
|
|
121
|
-
|
|
124
|
+
s = t, i.addEventListener("abort", n, { once: !0 }), await e, i.removeEventListener("abort", n), s = void 0;
|
|
122
125
|
}
|
|
123
126
|
} finally {
|
|
124
127
|
c();
|
|
125
128
|
}
|
|
126
129
|
}
|
|
127
130
|
let u = l();
|
|
128
|
-
return
|
|
131
|
+
return o(u, async () => {
|
|
129
132
|
c(), await u.return(void 0);
|
|
130
133
|
});
|
|
131
134
|
}
|
|
132
|
-
function
|
|
133
|
-
|
|
134
|
-
let r = 0,
|
|
135
|
-
if (o?.size) for (let
|
|
136
|
-
let o =
|
|
137
|
-
o.threw && !
|
|
135
|
+
function k(e, t, n) {
|
|
136
|
+
i?._onDispatch?.(e, t);
|
|
137
|
+
let r = 0, a, o = s.get(e);
|
|
138
|
+
if (o?.size) for (let i of [...o]) {
|
|
139
|
+
let o = v(() => i.fn(t), e, t, n);
|
|
140
|
+
o.threw && !a && (a = { err: o.err }), r++;
|
|
138
141
|
}
|
|
139
|
-
if (
|
|
140
|
-
let o =
|
|
141
|
-
o.threw && !
|
|
142
|
+
if (c.size) for (let i of [...c]) {
|
|
143
|
+
let o = v(() => i.fn(e, t), e, t, n);
|
|
144
|
+
o.threw && !a && (a = { err: o.err }), r++;
|
|
142
145
|
}
|
|
143
|
-
if (
|
|
146
|
+
if (a) throw a.err;
|
|
144
147
|
return r;
|
|
145
148
|
}
|
|
146
|
-
function
|
|
147
|
-
if (
|
|
149
|
+
function A(e, ...t) {
|
|
150
|
+
if (l.signal.aborted) return 0;
|
|
148
151
|
let n = t[0], r = Date.now();
|
|
149
|
-
if (
|
|
150
|
-
|
|
152
|
+
if (i?.validatePayload) try {
|
|
153
|
+
i.validatePayload(e, n);
|
|
151
154
|
} catch (t) {
|
|
152
|
-
if (
|
|
155
|
+
if (i?.onError) return i.onError({
|
|
153
156
|
err: t,
|
|
154
157
|
event: e,
|
|
155
158
|
payload: n,
|
|
@@ -157,75 +160,75 @@ function c(a) {
|
|
|
157
160
|
}), 0;
|
|
158
161
|
throw t;
|
|
159
162
|
}
|
|
160
|
-
if (
|
|
161
|
-
let t =
|
|
162
|
-
|
|
163
|
+
if (p) {
|
|
164
|
+
let t = s.get(e)?.size ?? 0, n = c.size;
|
|
165
|
+
p(`[herald:emit] emit("${e}") — ${t + n} listener(s) (${t} specific, ${n} wildcard)`);
|
|
163
166
|
}
|
|
164
|
-
let
|
|
165
|
-
if (
|
|
166
|
-
let t = 0,
|
|
167
|
+
let a = i?.middleware;
|
|
168
|
+
if (a?.length) {
|
|
169
|
+
let t = 0, i = 0;
|
|
167
170
|
function o() {
|
|
168
|
-
let s =
|
|
169
|
-
s <
|
|
171
|
+
let s = i++;
|
|
172
|
+
s < a.length ? a[s](e, n, o) : s === a.length && (t = k(e, n, r));
|
|
170
173
|
}
|
|
171
174
|
return o(), t;
|
|
172
175
|
}
|
|
173
|
-
return
|
|
176
|
+
return k(e, n, r);
|
|
174
177
|
}
|
|
175
|
-
function
|
|
176
|
-
if (e !== void 0) return
|
|
178
|
+
function j(e) {
|
|
179
|
+
if (e !== void 0) return s.get(e)?.size ?? 0;
|
|
177
180
|
let t = 0;
|
|
178
|
-
for (let e of
|
|
181
|
+
for (let e of s.values()) t += e.size;
|
|
179
182
|
return t;
|
|
180
183
|
}
|
|
181
|
-
function
|
|
182
|
-
return
|
|
184
|
+
function M() {
|
|
185
|
+
return c.size;
|
|
183
186
|
}
|
|
184
|
-
function
|
|
185
|
-
return [...
|
|
187
|
+
function N() {
|
|
188
|
+
return [...s.keys()];
|
|
186
189
|
}
|
|
187
|
-
function
|
|
188
|
-
if (e.length < 2) throw new
|
|
189
|
-
let
|
|
190
|
-
return
|
|
191
|
-
let i = new AbortController(),
|
|
190
|
+
function P(e, t) {
|
|
191
|
+
if (e.length < 2) throw new n("waitAny() requires at least 2 event keys");
|
|
192
|
+
let r = _(t?.signal);
|
|
193
|
+
return r.aborted ? Promise.reject(r.reason) : new Promise((t, n) => {
|
|
194
|
+
let i = new AbortController(), o = a(r, i.signal);
|
|
192
195
|
function s() {
|
|
193
|
-
i.abort(), r
|
|
196
|
+
i.abort(), n(r.reason);
|
|
194
197
|
}
|
|
195
|
-
|
|
196
|
-
for (let
|
|
197
|
-
|
|
198
|
-
event:
|
|
198
|
+
r.addEventListener("abort", s, { once: !0 });
|
|
199
|
+
for (let n of e) S(n, (e) => {
|
|
200
|
+
r.removeEventListener("abort", s), i.abort(), t({
|
|
201
|
+
event: n,
|
|
199
202
|
payload: e
|
|
200
203
|
});
|
|
201
|
-
},
|
|
204
|
+
}, o);
|
|
202
205
|
});
|
|
203
206
|
}
|
|
204
|
-
function
|
|
205
|
-
|
|
207
|
+
function F() {
|
|
208
|
+
l.signal.aborted || (p?.("[herald:lifecycle] dispose()"), l.abort(new t(u)), s.clear(), c.clear());
|
|
206
209
|
}
|
|
207
210
|
return {
|
|
208
211
|
get disposalSignal() {
|
|
209
|
-
return
|
|
212
|
+
return l.signal;
|
|
210
213
|
},
|
|
211
|
-
dispose:
|
|
214
|
+
dispose: F,
|
|
212
215
|
get disposed() {
|
|
213
|
-
return
|
|
216
|
+
return l.signal.aborted;
|
|
214
217
|
},
|
|
215
|
-
emit:
|
|
216
|
-
eventNames:
|
|
217
|
-
events:
|
|
218
|
-
listenerCount:
|
|
219
|
-
on:
|
|
220
|
-
onAny:
|
|
221
|
-
once:
|
|
222
|
-
[Symbol.dispose]:
|
|
223
|
-
wait:
|
|
224
|
-
waitAny:
|
|
225
|
-
wildcardCount:
|
|
218
|
+
emit: A,
|
|
219
|
+
eventNames: N,
|
|
220
|
+
events: O,
|
|
221
|
+
listenerCount: j,
|
|
222
|
+
on: w,
|
|
223
|
+
onAny: E,
|
|
224
|
+
once: T,
|
|
225
|
+
[Symbol.dispose]: F,
|
|
226
|
+
wait: D,
|
|
227
|
+
waitAny: P,
|
|
228
|
+
wildcardCount: M
|
|
226
229
|
};
|
|
227
230
|
}
|
|
228
231
|
//#endregion
|
|
229
|
-
export {
|
|
232
|
+
export { a as combineSignals, s as createBus, r as noop };
|
|
230
233
|
|
|
231
234
|
//# sourceMappingURL=bus.js.map
|