aieventjs 0.4.0 → 0.5.1

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 ysl
3
+ Copyright (c) 2026 yshengliao
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -10,13 +10,13 @@
10
10
 
11
11
  Part of the [ai\*js micro-runtime ecosystem](https://github.com/yshengliao) — see also [aifsmjs](https://github.com/yshengliao/aifsmjs) (FSM), [aiecsjs](https://github.com/yshengliao/aiecsjs) (ECS), [aibridgejs](https://github.com/yshengliao/aibridgejs) (cross-context RPC), [aipooljs](https://github.com/yshengliao/aipooljs) (object pool), [aiquadtreejs](https://github.com/yshengliao/aiquadtreejs) (spatial partitioning), and [aiaudiojs](https://github.com/yshengliao/aiaudiojs) (Web Audio shell).
12
12
 
13
- > **Status: 0.4.0.** Full implementation shipped; all methods are live. Coverage ≥ 95/90/100/100; ~1050 B gzip (budget 1100 B).
13
+ > **Status: 0.5.1.** Full implementation shipped; all methods are live. Coverage ≥ 95/90/100/100; ~1050 B gzip (budget 1100 B).
14
14
 
15
15
  ---
16
16
 
17
17
  ## Why aieventjs
18
18
 
19
- Why not just use `mitt`? Honest answer: `mitt` is the right choice for many projects — it's MIT, ~282 B gzipped, and the API is genuinely well-shaped. We evaluated it and chose to write from scratch instead. Three reasons (full evaluation in [LEARNINGS.md](../LEARNINGS.md)):
19
+ Why not just use `mitt`? Honest answer: `mitt` is the right choice for many projects — it's MIT, ~282 B gzipped, and the API is genuinely well-shaped. We evaluated it and chose to write from scratch instead. Three reasons:
20
20
 
21
21
  - **mitt has been unmaintained since 2023-07-04.** The PRs the community most wants — `unsubscribe`-returning `on()`, `AbortSignal`, `sideEffects: false`, nodenext compatibility — are all open and untouched. Forking would mean shipping a copy with our name on it; the upstream couldn't accept improvements back even if we wanted.
22
22
  - **The implementation is ~35 lines of pure logic.** "Fork and improve" doesn't really exist at that size class — any non-trivial change is a rewrite, and the cost of carrying the upstream copyright notice exceeds the benefit.
package/README_ZHTW.md CHANGED
@@ -10,13 +10,13 @@
10
10
 
11
11
  隸屬 [ai\*js micro-runtime 生態系](https://github.com/yshengliao) ─ 另見 [aifsmjs](https://github.com/yshengliao/aifsmjs)(FSM)、[aiecsjs](https://github.com/yshengliao/aiecsjs)(ECS)、[aibridgejs](https://github.com/yshengliao/aibridgejs)(cross-context RPC)、[aipooljs](https://github.com/yshengliao/aipooljs)(物件池)、[aiquadtreejs](https://github.com/yshengliao/aiquadtreejs)(空間分割)、[aiaudiojs](https://github.com/yshengliao/aiaudiojs)(Web Audio 薄殼)。
12
12
 
13
- > **狀態:0.0.1 scaffold。** 下方 API surface 已凍結;實作在 0.1.0 落地。目前 `createEmitter` 被呼叫會直接 `throw "not implemented"`。
13
+ > **狀態:0.5.1。** 完整實作已上線、所有 method 皆可用。Coverage ≥ 95/90/100/100;~1050 B gzip(budget 1100 B)。
14
14
 
15
15
  ---
16
16
 
17
17
  ## 為什麼有 aieventjs
18
18
 
19
- 為什麼不直接用 `mitt`?老實說 `mitt` 對很多專案來說是正確選擇 ── MIT、~282 bytes gzip、API 本身造型很好。我們評估過之後選擇自寫。三個理由(完整評估在 [LEARNINGS.md](../LEARNINGS.md)):
19
+ 為什麼不直接用 `mitt`?老實說 `mitt` 對很多專案來說是正確選擇 ── MIT、~282 bytes gzip、API 本身造型很好。我們評估過之後選擇自寫。三個理由:
20
20
 
21
21
  - **mitt 自 2023-07-04 起停止維護。** 社群最想要的 PR ── `on()` 回傳 unsubscribe、`AbortSignal`、`sideEffects: false`、nodenext 相容 ── 全部 open 但沒人處理。fork 等於我們扛一份「上面寫人家名字」的副本,且就算改進了上游也接不回去。
22
22
  - **實作是 ~35 行純邏輯。** 那種尺寸沒有「fork 然後改良」這回事 ── 任何非 trivial 修改都等於重寫;繼承上游 copyright notice 的成本超過效益。
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var v=class extends Error{name="EmitterError"},h=class extends Error{name="EmitterDisposedError"};function b(s,d){let i=s.findIndex(o=>o.u===d);if(i>=0){let o=s[i];o!==void 0&&(o.c?.(),o.c=void 0),s.splice(i,1);}}function y(s){for(let d of s)d.c?.(),d.c=void 0;}function m(s,d,i){s.push(d);let o=()=>{let a=s.indexOf(d);a>=0&&s.splice(a,1),d.c?.(),d.c=void 0;};if(i!==void 0){let a=()=>o();i.addEventListener("abort",a,{once:true}),d.c=()=>i.removeEventListener("abort",a);}return o}function j(s){let d=s?.captureHandlerErrors,i=new Map,o=[],a=false;function p(){if(a)throw new h("aieventjs: emitter has been disposed")}function g(e){let n=i.get(e);return n===void 0&&(n=[],i.set(e,n)),n}function k(e,n,t){p();let c=t?.sampleRate,u=t?.throttleMs;if(e==="*"){if(t?.captureErrors!==void 0)throw new v("aieventjs: captureErrors invalid on *")}else {if(c!==void 0)throw new v("aieventjs: sampleRate wildcard-only");if(u!==void 0)throw new v("aieventjs: throttleMs wildcard-only")}if(c!==void 0&&(c<=0||c>1))throw new v("aieventjs: sampleRate must be in (0,1]");if(u!==void 0&&u<0)throw new v("aieventjs: throttleMs must be >= 0");let l=t?.signal;if(l?.aborted)return ()=>{};if(e==="*"){let E=n;if(t?.once){let H=m(o,{h:(R,M)=>{H(),E(R,M);},u:E,c:void 0,r:c,tm:u},l);return H}return m(o,{h:E,u:E,c:void 0,r:c,tm:u},l)}let r=n,f=t?.captureErrors;if(t?.once){let E={h:H=>{w(),r(H);},u:r,c:void 0,ce:f},w=m(g(e),E,l);return w}return m(g(e),{h:r,u:r,c:void 0,ce:f},l)}function A(e,n){return k(e,n,{once:true})}function O(e,n){if(p(),e==="*"){n===void 0?(y(o),o.length=0):b(o,n);return}let t=i.get(e);t!==void 0&&(n===void 0?(y(t),i.delete(e)):b(t,n));}function x(e,n,t,c){if(e===void 0||e===false)throw n;if(typeof e=="function")try{e(n,t,c);}catch{}}function W(e,n){p();let t=e,c=n,u=(i.get(t)??[]).slice(),l=o.slice();for(let r of u)try{r.h(c);}catch(f){x(r.ce!==void 0?r.ce:d,f,t,c);}for(let r of l)if(!(r.r!==void 0&&Math.random()>=r.r)){if(r.tm){let f=Date.now();if(r.ts!==void 0&&f-r.ts<r.tm)continue;r.ts=f;}try{r.h(t,c);}catch(f){x(d,f,t,c);}}}function K(){for(let e of i.values())y(e);y(o),i.clear(),o.length=0;}return {on:k,once:A,off:O,emit:W,clear(){p(),K();},dispose(){a||(K(),a=true);},get disposed(){return a}}}exports.EmitterDisposedError=h;exports.EmitterError=v;exports.createEmitter=j;//# sourceMappingURL=index.cjs.map
1
+ 'use strict';var v=class extends Error{name="EmitterError"},h=class extends Error{name="EmitterDisposedError"};function K(d,c){let i=d.findIndex(o=>o.u===c);if(i>=0){let o=d[i];o!==void 0&&(o.c?.(),o.c=void 0),d.splice(i,1);}}function y(d){for(let c of d)c.c?.(),c.c=void 0;}function m(d,c,i){d.push(c);let o=()=>{let a=d.indexOf(c);a>=0&&d.splice(a,1),c.c?.(),c.c=void 0;};if(i!==void 0){let a=()=>o();i.addEventListener("abort",a,{once:true}),c.c=()=>i.removeEventListener("abort",a);}return o}function j(d){let c=d?.captureHandlerErrors,i=new Map,o=[],a=false;function p(){if(a)throw new h("aieventjs: emitter has been disposed")}function g(e){let n=i.get(e);return n===void 0&&(n=[],i.set(e,n)),n}function k(e,n,t){p();let s=t?.sampleRate,u=t?.throttleMs;if(e==="*"){if(t?.captureErrors!==void 0)throw new v("aieventjs: captureErrors invalid on *")}else {if(s!==void 0)throw new v("aieventjs: sampleRate wildcard-only");if(u!==void 0)throw new v("aieventjs: throttleMs wildcard-only")}if(s!==void 0&&(!Number.isFinite(s)||s<=0||s>1))throw new v("aieventjs: sampleRate must be in (0,1]");if(u!==void 0&&(!Number.isFinite(u)||u<0))throw new v("aieventjs: throttleMs must be >= 0");let l=t?.signal;if(l?.aborted)return ()=>{};if(e==="*"){let E=n;if(t?.once){let H=m(o,{h:(R,M)=>{H(),E(R,M);},u:E,c:void 0,r:s,tm:u},l);return H}return m(o,{h:E,u:E,c:void 0,r:s,tm:u},l)}let r=n,f=t?.captureErrors;if(t?.once){let E={h:H=>{w(),r(H);},u:r,c:void 0,ce:f},w=m(g(e),E,l);return w}return m(g(e),{h:r,u:r,c:void 0,ce:f},l)}function A(e,n){return k(e,n,{once:true})}function O(e,n){if(p(),e==="*"){n===void 0?(y(o),o.length=0):K(o,n);return}let t=i.get(e);t!==void 0&&(n===void 0?(y(t),i.delete(e)):K(t,n));}function x(e,n,t,s){if(e===void 0||e===false)throw n;if(typeof e=="function")try{e(n,t,s);}catch{}}function W(e,n){p();let t=e,s=n,u=(i.get(t)??[]).slice(),l=o.slice();for(let r of u)try{r.h(s);}catch(f){x(r.ce!==void 0?r.ce:c,f,t,s);}for(let r of l)if(!(r.r!==void 0&&Math.random()>=r.r)){if(r.tm){let f=Date.now();if(r.ts!==void 0&&f-r.ts<r.tm)continue;r.ts=f;}try{r.h(t,s);}catch(f){x(c,f,t,s);}}}function b(){for(let e of i.values())y(e);y(o),i.clear(),o.length=0;}return {on:k,once:A,off:O,emit:W,clear(){p(),b();},dispose(){a||(b(),a=true);},get disposed(){return a}}}exports.EmitterDisposedError=h;exports.EmitterError=v;exports.createEmitter=j;//# sourceMappingURL=index.cjs.map
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["EmitterError","EmitterDisposedError","rmByUser","arr","user","e","flush","sub","sig","rm","i","fn","createEmitter","opts","cap","t","w","d","ck","ga","k","a","on","type","handler","o","sr","tm2","tp","p","ce","once","off","ap","pol","err","emit","payload","ts","ws","now","purge"],"mappings":"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","file":"index.cjs","sourcesContent":["// aieventjs — small, strict, typed event emitter for the ai*js family.\n//\n// v0.1.0: full implementation of the frozen API surface. Mitt-compatible\n// snapshot semantics, wildcard \"*\" handler, AbortSignal integration, once,\n// idempotent dispose, destructurable methods (no `this`).\n\n/**\n * Configuration for {@link createEmitter}. Controls the default error\n * policy for handlers thrown during `emit()`; per-handler\n * {@link OnOptions.captureErrors} overrides this default.\n *\n * @public\n */\nexport interface EmitterOptions {\n /**\n * Default error policy for all handlers when they throw during emit().\n *\n * - undefined / false (default) — first throw aborts dispatch (mitt-compatible).\n * - true — swallow; dispatch continues over all handlers in the snapshot.\n * - (err, type, payload) => void — invoked with the unknown error, the\n * event name as string, and the payload as unknown. If this callback\n * itself throws, the error is silently ignored.\n *\n * Per-subscription OnOptions.captureErrors overrides this for that handler.\n */\n captureHandlerErrors?: boolean | ((err: unknown, type: string, payload: unknown) => void);\n}\n\n/**\n * Handler invoked for a single typed event.\n *\n * @public\n */\nexport type EventHandler<Payload> = (payload: Payload) => void;\n\n/**\n * Handler invoked for the wildcard `\"*\"` subscription. Receives the actual\n * event type alongside the payload.\n *\n * @public\n */\nexport type WildcardHandler<Events extends Record<string, unknown>> = <K extends keyof Events>(\n type: K,\n payload: Events[K],\n) => void;\n\n/**\n * Subscription options accepted by {@link Emitter.on}.\n *\n * @public\n */\nexport interface OnOptions {\n /**\n * Aborting this signal removes the handler. The same effect as calling\n * the returned unsubscribe function. Pre-aborted signals never register.\n */\n signal?: AbortSignal;\n\n /** Auto-remove the handler after the first dispatch. Equivalent to `once()`. */\n once?: boolean;\n\n /**\n * Override emitter-level captureHandlerErrors for this handler.\n * - undefined — fall through to emitter-level.\n * - false — force re-throw, even when emitter-level is true / callback.\n * - true — swallow.\n * - (err, type, payload) => void — same semantics as the emitter-level callback.\n *\n * Throws EmitterError if set on a wildcard \"*\" subscription.\n * @invariant does not break snapshot-before-iterate semantics.\n */\n captureErrors?: boolean | ((err: unknown, type: string, payload: unknown) => void);\n\n /**\n * Wildcard \"*\" only. Probability in (0, 1] that a dispatch reaches this\n * handler. Math.random() is sampled per dispatch. Values <= 0 or > 1 are\n * rejected at on() time.\n *\n * Throws EmitterError if set on a typed handler.\n */\n sampleRate?: number;\n\n /**\n * Wildcard \"*\" only. Minimum milliseconds between successive calls.\n * Leading-edge: the first dispatch after subscription always fires;\n * subsequent dispatches within `throttleMs` are dropped (not queued).\n * Uses Date.now(). 0 = no throttle. Negative values are rejected.\n *\n * Throws EmitterError if set on a typed handler.\n */\n throttleMs?: number;\n}\n\n/**\n * Strongly-typed event emitter. Subscribe with {@link Emitter.on} (returns\n * an unsubscribe function), dispatch with {@link Emitter.emit}, dispose\n * with {@link Emitter.dispose} when finished.\n *\n * @typeParam Events — a string-keyed map from event name to payload type.\n * @public\n */\nexport interface Emitter<Events extends Record<string, unknown>> {\n /**\n * Subscribe to a single event type. Returns an unsubscribe function;\n * calling it (or aborting `opts.signal`) removes the handler.\n */\n on<K extends keyof Events>(\n type: K,\n handler: EventHandler<Events[K]>,\n opts?: OnOptions,\n ): () => void;\n\n /**\n * Subscribe to every event with a single handler that receives\n * `(type, payload)`. Wildcard handlers fire AFTER type-matched\n * handlers — same ordering as `mitt`.\n */\n on(type: \"*\", handler: WildcardHandler<Events>, opts?: OnOptions): () => void;\n\n /**\n * Subscribe and auto-remove after the first dispatch. Equivalent to\n * `on(type, handler, { once: true })`.\n */\n once<K extends keyof Events>(type: K, handler: EventHandler<Events[K]>): () => void;\n\n /**\n * Imperative unsubscribe. Prefer the unsubscribe function returned by\n * `on()` — it's faster (no reference lookup) and survives renames.\n * If `handler` is omitted, removes every handler for `type`.\n */\n off<K extends keyof Events>(type: K, handler?: EventHandler<Events[K]>): void;\n\n /**\n * Imperative wildcard unsubscribe.\n */\n off(type: \"*\", handler?: WildcardHandler<Events>): void;\n\n /**\n * Dispatch synchronously. Handlers receive `payload`; wildcard handlers\n * receive `(type, payload)`. Handler lists are snapshotted before iteration,\n * so removing a handler inside its own callback does not skip subsequent\n * handlers. By default, the first throwing handler aborts the dispatch;\n * set EmitterOptions.captureHandlerErrors (or per-handler OnOptions.captureErrors)\n * to swallow or report errors and continue.\n */\n emit<K extends keyof Events>(type: K, payload: Events[K]): void;\n\n /**\n * Remove every handler for every event (including wildcards). The\n * emitter remains usable. Use {@link dispose} for permanent teardown.\n */\n clear(): void;\n\n /**\n * Idempotent teardown. Drops every handler; subsequent `on` / `once` /\n * `emit` / `off` / `clear` throw {@link EmitterDisposedError}.\n */\n dispose(): void;\n\n /** `true` once {@link dispose} has been called. */\n readonly disposed: boolean;\n}\n\n/**\n * Recoverable emitter error. Thrown by `on()` when `OnOptions` violates a\n * precondition: `captureErrors` set on a wildcard `\"*\"` subscription;\n * `sampleRate` / `throttleMs` set on a typed subscription; `sampleRate`\n * outside `(0, 1]`; or `throttleMs` negative.\n *\n * @public\n */\nexport class EmitterError extends Error {\n override readonly name = \"EmitterError\";\n}\n\n/**\n * Thrown by any emitter method called after {@link Emitter.dispose}.\n *\n * @public\n */\nexport class EmitterDisposedError extends Error {\n override readonly name = \"EmitterDisposedError\";\n}\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\n// Mutable `c` field (not optional `?:`) avoids exactOptionalPropertyTypes TS2412\n// when assigning undefined. Short field names reduce minified output size.\ntype ErrorPolicy = boolean | ((err: unknown, type: string, payload: unknown) => void);\n\ninterface E<H> {\n h: H; // handler (may be a once-wrapper)\n c: (() => void) | undefined; // abortCleanup\n u: H; // user-provided handler (off matching)\n // v0.3.0: per-handler error policy and wildcard throttle/sample state.\n // Fields typed as `T | undefined` (not just `T`) so that exactOptionalPropertyTypes\n // permits assigning `undefined` in object literals (avoids TS2375).\n ce?: ErrorPolicy | undefined; // captureErrors override (typed only)\n r?: number | undefined; // sampleRate (wildcard only)\n tm?: number | undefined; // throttleMs (wildcard only)\n ts?: number | undefined; // last call timestamp — mutated during dispatch (wildcard only)\n}\n\ntype AH = EventHandler<unknown>;\ntype WH = WildcardHandler<Record<string, unknown>>;\n\n// Remove one entry by user-identity from an array; run its abort cleanup.\nfunction rmByUser<H>(arr: E<H>[], user: H): void {\n const i = arr.findIndex((e) => e.u === user);\n if (i >= 0) {\n const e = arr[i];\n if (e !== undefined) {\n e.c?.();\n e.c = undefined;\n }\n arr.splice(i, 1);\n }\n}\n\n// Flush all abort cleanups from an array (for clear / dispose).\nfunction flush<H>(arr: E<H>[]): void {\n for (const e of arr) {\n e.c?.();\n e.c = undefined;\n }\n}\n\n// Push entry onto arr, wire AbortSignal, return unsubscribe.\nfunction sub<H>(arr: E<H>[], e: E<H>, sig: AbortSignal | undefined): () => void {\n arr.push(e);\n const rm = () => {\n const i = arr.indexOf(e);\n if (i >= 0) arr.splice(i, 1);\n e.c?.();\n e.c = undefined;\n };\n if (sig !== undefined) {\n const fn = () => rm();\n sig.addEventListener(\"abort\", fn, { once: true });\n e.c = () => sig.removeEventListener(\"abort\", fn);\n }\n return rm;\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Construct a strongly-typed event emitter.\n *\n * @example\n * ```ts\n * import { createEmitter } from \"aieventjs\";\n *\n * type Events = {\n * \"user:login\": { id: string };\n * \"user:logout\": void;\n * };\n *\n * const bus = createEmitter<Events>();\n *\n * const off = bus.on(\"user:login\", (u) => console.log(\"hi\", u.id));\n * bus.emit(\"user:login\", { id: \"alice\" });\n * off();\n *\n * bus.on(\"*\", (type, payload) => console.log(\"event\", type, payload));\n * ```\n *\n * @public\n */\nexport function createEmitter<Events extends Record<string, unknown> = Record<string, unknown>>(\n opts?: EmitterOptions,\n): Emitter<Events> {\n const cap = opts?.captureHandlerErrors;\n\n const t: Map<string, E<AH>[]> = new Map();\n const w: E<WH>[] = [];\n let d = false;\n\n function ck(): void {\n if (d) throw new EmitterDisposedError(\"aieventjs: emitter has been disposed\");\n }\n\n // Get or create typed handler array for a key.\n function ga(k: string): E<AH>[] {\n let a = t.get(k);\n if (a === undefined) {\n a = [];\n t.set(k, a);\n }\n return a;\n }\n\n function on(type: string | \"*\", handler: AH | WH, o?: OnOptions): () => void {\n ck();\n // v0.3.0 guards: cross-domain options + range checks\n const sr = o?.sampleRate;\n const tm2 = o?.throttleMs;\n if (type === \"*\") {\n if (o?.captureErrors !== undefined)\n throw new EmitterError(\"aieventjs: captureErrors invalid on *\");\n } else {\n if (sr !== undefined) throw new EmitterError(\"aieventjs: sampleRate wildcard-only\");\n if (tm2 !== undefined) throw new EmitterError(\"aieventjs: throttleMs wildcard-only\");\n }\n if (sr !== undefined && (sr <= 0 || sr > 1))\n throw new EmitterError(\"aieventjs: sampleRate must be in (0,1]\");\n if (tm2 !== undefined && tm2 < 0) throw new EmitterError(\"aieventjs: throttleMs must be >= 0\");\n const sig = o?.signal;\n if (sig?.aborted) return () => {};\n\n if (type === \"*\") {\n const fn = handler as WH;\n if (o?.once) {\n const e: E<WH> = {\n h: (tp, p) => {\n rm();\n fn(tp, p);\n },\n u: fn,\n c: undefined,\n r: sr,\n tm: tm2,\n };\n const rm = sub(w, e, sig);\n return rm;\n }\n return sub(w, { h: fn, u: fn, c: undefined, r: sr, tm: tm2 }, sig);\n }\n\n const fn = handler as AH;\n const ce = o?.captureErrors;\n if (o?.once) {\n const e: E<AH> = {\n h: (p) => {\n rm();\n fn(p);\n },\n u: fn,\n c: undefined,\n ce: ce,\n };\n const rm = sub(ga(type), e, sig);\n return rm;\n }\n return sub(ga(type), { h: fn, u: fn, c: undefined, ce: ce }, sig);\n }\n\n function once<K extends keyof Events>(type: K, handler: EventHandler<Events[K]>): () => void {\n return on(type as string, handler as AH, { once: true });\n }\n\n function off(type: string | \"*\", handler?: AH | WH): void {\n ck();\n if (type === \"*\") {\n if (handler === undefined) {\n flush(w);\n w.length = 0;\n } else {\n rmByUser(w, handler as WH);\n }\n return;\n }\n const arr = t.get(type);\n if (arr === undefined) return;\n if (handler === undefined) {\n flush(arr);\n t.delete(type);\n } else {\n rmByUser(arr, handler as AH);\n }\n }\n\n // Inline error policy handler — policy undefined/false → re-throw; true → swallow;\n // function → invoke and swallow; if callback throws, ignore silently.\n function ap(pol: ErrorPolicy | undefined, err: unknown, k: string, p: unknown): void {\n if (pol === undefined || pol === false) throw err;\n if (typeof pol === \"function\")\n try {\n pol(err, k, p);\n } catch {\n /* silent */\n }\n }\n\n function emit<K extends keyof Events>(type: K, payload: Events[K]): void {\n ck();\n // Both slices happen BEFORE any handler call (snapshot-before-iterate).\n const k = type as string;\n const p = payload as unknown;\n const ts = (t.get(k) ?? []).slice();\n const ws = w.slice();\n for (const e of ts) {\n try {\n e.h(p);\n } catch (err) {\n ap(e.ce !== undefined ? e.ce : cap, err, k, p);\n }\n }\n for (const e of ws) {\n if (e.r !== undefined && Math.random() >= e.r) continue;\n if (e.tm) {\n const now = Date.now();\n if (e.ts !== undefined && now - e.ts < e.tm) continue;\n e.ts = now;\n }\n try {\n e.h(k, p as never);\n } catch (err) {\n ap(cap, err, k, p);\n }\n }\n }\n\n function purge(): void {\n for (const a of t.values()) flush(a);\n flush(w);\n t.clear();\n w.length = 0;\n }\n\n return {\n on: on as Emitter<Events>[\"on\"],\n once,\n off: off as Emitter<Events>[\"off\"],\n emit,\n clear() {\n ck();\n purge();\n },\n dispose() {\n if (!d) {\n purge();\n d = true;\n }\n },\n get disposed() {\n return d;\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["EmitterError","EmitterDisposedError","rmByUser","arr","user","e","flush","sub","sig","rm","i","fn","createEmitter","opts","cap","t","w","d","ck","ga","k","a","on","type","handler","o","sr","tm2","tp","p","ce","once","off","ap","pol","err","emit","payload","ts","ws","now","purge"],"mappings":"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","file":"index.cjs","sourcesContent":["// aieventjs — small, strict, typed event emitter for the ai*js family.\n//\n// v0.1.0: full implementation of the frozen API surface. Mitt-compatible\n// snapshot semantics, wildcard \"*\" handler, AbortSignal integration, once,\n// idempotent dispose, destructurable methods (no `this`).\n\n/**\n * Configuration for {@link createEmitter}. Controls the default error\n * policy for handlers thrown during `emit()`; per-handler\n * {@link OnOptions.captureErrors} overrides this default.\n *\n * @public\n */\nexport interface EmitterOptions {\n /**\n * Default error policy for all handlers when they throw during emit().\n *\n * - undefined / false (default) — first throw aborts dispatch (mitt-compatible).\n * - true — swallow; dispatch continues over all handlers in the snapshot.\n * - (err, type, payload) => void — invoked with the unknown error, the\n * event name as string, and the payload as unknown. If this callback\n * itself throws, the error is silently ignored.\n *\n * Per-subscription OnOptions.captureErrors overrides this for that handler.\n */\n captureHandlerErrors?: boolean | ((err: unknown, type: string, payload: unknown) => void);\n}\n\n/**\n * Handler invoked for a single typed event.\n *\n * @public\n */\nexport type EventHandler<Payload> = (payload: Payload) => void;\n\n/**\n * Handler invoked for the wildcard `\"*\"` subscription. Receives the actual\n * event type alongside the payload.\n *\n * @public\n */\nexport type WildcardHandler<Events extends Record<string, unknown>> = <K extends keyof Events>(\n type: K,\n payload: Events[K],\n) => void;\n\n/**\n * Subscription options accepted by {@link Emitter.on}.\n *\n * @public\n */\nexport interface OnOptions {\n /**\n * Aborting this signal removes the handler. The same effect as calling\n * the returned unsubscribe function. Pre-aborted signals never register.\n */\n signal?: AbortSignal;\n\n /** Auto-remove the handler after the first dispatch. Equivalent to `once()`. */\n once?: boolean;\n\n /**\n * Override emitter-level captureHandlerErrors for this handler.\n * - undefined — fall through to emitter-level.\n * - false — force re-throw, even when emitter-level is true / callback.\n * - true — swallow.\n * - (err, type, payload) => void — same semantics as the emitter-level callback.\n *\n * Throws EmitterError if set on a wildcard \"*\" subscription.\n * @invariant does not break snapshot-before-iterate semantics.\n */\n captureErrors?: boolean | ((err: unknown, type: string, payload: unknown) => void);\n\n /**\n * Wildcard \"*\" only. Probability in (0, 1] that a dispatch reaches this\n * handler. Math.random() is sampled per dispatch. Values <= 0 or > 1 are\n * rejected at on() time.\n *\n * Throws EmitterError if set on a typed handler.\n */\n sampleRate?: number;\n\n /**\n * Wildcard \"*\" only. Minimum milliseconds between successive calls.\n * Leading-edge: the first dispatch after subscription always fires;\n * subsequent dispatches within `throttleMs` are dropped (not queued).\n * Uses Date.now(). 0 = no throttle. Negative values are rejected.\n *\n * Throws EmitterError if set on a typed handler.\n */\n throttleMs?: number;\n}\n\n/**\n * Strongly-typed event emitter. Subscribe with {@link Emitter.on} (returns\n * an unsubscribe function), dispatch with {@link Emitter.emit}, dispose\n * with {@link Emitter.dispose} when finished.\n *\n * @typeParam Events — a string-keyed map from event name to payload type.\n * @public\n */\nexport interface Emitter<Events extends Record<string, unknown>> {\n /**\n * Subscribe to a single event type. Returns an unsubscribe function;\n * calling it (or aborting `opts.signal`) removes the handler.\n */\n on<K extends keyof Events>(\n type: K,\n handler: EventHandler<Events[K]>,\n opts?: OnOptions,\n ): () => void;\n\n /**\n * Subscribe to every event with a single handler that receives\n * `(type, payload)`. Wildcard handlers fire AFTER type-matched\n * handlers — same ordering as `mitt`.\n */\n on(type: \"*\", handler: WildcardHandler<Events>, opts?: OnOptions): () => void;\n\n /**\n * Subscribe and auto-remove after the first dispatch. Equivalent to\n * `on(type, handler, { once: true })`.\n */\n once<K extends keyof Events>(type: K, handler: EventHandler<Events[K]>): () => void;\n\n /**\n * Imperative unsubscribe. Prefer the unsubscribe function returned by\n * `on()` — it's faster (no reference lookup) and survives renames.\n * If `handler` is omitted, removes every handler for `type`.\n */\n off<K extends keyof Events>(type: K, handler?: EventHandler<Events[K]>): void;\n\n /**\n * Imperative wildcard unsubscribe.\n */\n off(type: \"*\", handler?: WildcardHandler<Events>): void;\n\n /**\n * Dispatch synchronously. Handlers receive `payload`; wildcard handlers\n * receive `(type, payload)`. Handler lists are snapshotted before iteration,\n * so removing a handler inside its own callback does not skip subsequent\n * handlers. By default, the first throwing handler aborts the dispatch;\n * set EmitterOptions.captureHandlerErrors (or per-handler OnOptions.captureErrors)\n * to swallow or report errors and continue.\n */\n emit<K extends keyof Events>(type: K, payload: Events[K]): void;\n\n /**\n * Remove every handler for every event (including wildcards). The\n * emitter remains usable. Use {@link dispose} for permanent teardown.\n */\n clear(): void;\n\n /**\n * Idempotent teardown. Drops every handler; subsequent `on` / `once` /\n * `emit` / `off` / `clear` throw {@link EmitterDisposedError}.\n */\n dispose(): void;\n\n /** `true` once {@link dispose} has been called. */\n readonly disposed: boolean;\n}\n\n/**\n * Recoverable emitter error. Thrown by `on()` when `OnOptions` violates a\n * precondition: `captureErrors` set on a wildcard `\"*\"` subscription;\n * `sampleRate` / `throttleMs` set on a typed subscription; `sampleRate`\n * outside `(0, 1]`; or `throttleMs` negative.\n *\n * @public\n */\nexport class EmitterError extends Error {\n override readonly name = \"EmitterError\";\n}\n\n/**\n * Thrown by any emitter method called after {@link Emitter.dispose}.\n *\n * @public\n */\nexport class EmitterDisposedError extends Error {\n override readonly name = \"EmitterDisposedError\";\n}\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\n// Mutable `c` field (not optional `?:`) avoids exactOptionalPropertyTypes TS2412\n// when assigning undefined. Short field names reduce minified output size.\ntype ErrorPolicy = boolean | ((err: unknown, type: string, payload: unknown) => void);\n\ninterface E<H> {\n h: H; // handler (may be a once-wrapper)\n c: (() => void) | undefined; // abortCleanup\n u: H; // user-provided handler (off matching)\n // v0.3.0: per-handler error policy and wildcard throttle/sample state.\n // Fields typed as `T | undefined` (not just `T`) so that exactOptionalPropertyTypes\n // permits assigning `undefined` in object literals (avoids TS2375).\n ce?: ErrorPolicy | undefined; // captureErrors override (typed only)\n r?: number | undefined; // sampleRate (wildcard only)\n tm?: number | undefined; // throttleMs (wildcard only)\n ts?: number | undefined; // last call timestamp — mutated during dispatch (wildcard only)\n}\n\ntype AH = EventHandler<unknown>;\ntype WH = WildcardHandler<Record<string, unknown>>;\n\n// Remove one entry by user-identity from an array; run its abort cleanup.\nfunction rmByUser<H>(arr: E<H>[], user: H): void {\n const i = arr.findIndex((e) => e.u === user);\n if (i >= 0) {\n const e = arr[i];\n if (e !== undefined) {\n e.c?.();\n e.c = undefined;\n }\n arr.splice(i, 1);\n }\n}\n\n// Flush all abort cleanups from an array (for clear / dispose).\nfunction flush<H>(arr: E<H>[]): void {\n for (const e of arr) {\n e.c?.();\n e.c = undefined;\n }\n}\n\n// Push entry onto arr, wire AbortSignal, return unsubscribe.\nfunction sub<H>(arr: E<H>[], e: E<H>, sig: AbortSignal | undefined): () => void {\n arr.push(e);\n const rm = () => {\n const i = arr.indexOf(e);\n if (i >= 0) arr.splice(i, 1);\n e.c?.();\n e.c = undefined;\n };\n if (sig !== undefined) {\n const fn = () => rm();\n sig.addEventListener(\"abort\", fn, { once: true });\n e.c = () => sig.removeEventListener(\"abort\", fn);\n }\n return rm;\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Construct a strongly-typed event emitter.\n *\n * @example\n * ```ts\n * import { createEmitter } from \"aieventjs\";\n *\n * type Events = {\n * \"user:login\": { id: string };\n * \"user:logout\": void;\n * };\n *\n * const bus = createEmitter<Events>();\n *\n * const off = bus.on(\"user:login\", (u) => console.log(\"hi\", u.id));\n * bus.emit(\"user:login\", { id: \"alice\" });\n * off();\n *\n * bus.on(\"*\", (type, payload) => console.log(\"event\", type, payload));\n * ```\n *\n * @public\n */\nexport function createEmitter<Events extends Record<string, unknown> = Record<string, unknown>>(\n opts?: EmitterOptions,\n): Emitter<Events> {\n const cap = opts?.captureHandlerErrors;\n\n const t: Map<string, E<AH>[]> = new Map();\n const w: E<WH>[] = [];\n let d = false;\n\n function ck(): void {\n if (d) throw new EmitterDisposedError(\"aieventjs: emitter has been disposed\");\n }\n\n // Get or create typed handler array for a key.\n function ga(k: string): E<AH>[] {\n let a = t.get(k);\n if (a === undefined) {\n a = [];\n t.set(k, a);\n }\n return a;\n }\n\n function on(type: string | \"*\", handler: AH | WH, o?: OnOptions): () => void {\n ck();\n // v0.3.0 guards: cross-domain options + range checks\n const sr = o?.sampleRate;\n const tm2 = o?.throttleMs;\n if (type === \"*\") {\n if (o?.captureErrors !== undefined)\n throw new EmitterError(\"aieventjs: captureErrors invalid on *\");\n } else {\n if (sr !== undefined) throw new EmitterError(\"aieventjs: sampleRate wildcard-only\");\n if (tm2 !== undefined) throw new EmitterError(\"aieventjs: throttleMs wildcard-only\");\n }\n if (sr !== undefined && (!Number.isFinite(sr) || sr <= 0 || sr > 1))\n throw new EmitterError(\"aieventjs: sampleRate must be in (0,1]\");\n if (tm2 !== undefined && (!Number.isFinite(tm2) || tm2 < 0))\n throw new EmitterError(\"aieventjs: throttleMs must be >= 0\");\n const sig = o?.signal;\n if (sig?.aborted) return () => {};\n\n if (type === \"*\") {\n const fn = handler as WH;\n if (o?.once) {\n const e: E<WH> = {\n h: (tp, p) => {\n rm();\n fn(tp, p);\n },\n u: fn,\n c: undefined,\n r: sr,\n tm: tm2,\n };\n const rm = sub(w, e, sig);\n return rm;\n }\n return sub(w, { h: fn, u: fn, c: undefined, r: sr, tm: tm2 }, sig);\n }\n\n const fn = handler as AH;\n const ce = o?.captureErrors;\n if (o?.once) {\n const e: E<AH> = {\n h: (p) => {\n rm();\n fn(p);\n },\n u: fn,\n c: undefined,\n ce: ce,\n };\n const rm = sub(ga(type), e, sig);\n return rm;\n }\n return sub(ga(type), { h: fn, u: fn, c: undefined, ce: ce }, sig);\n }\n\n function once<K extends keyof Events>(type: K, handler: EventHandler<Events[K]>): () => void {\n return on(type as string, handler as AH, { once: true });\n }\n\n function off(type: string | \"*\", handler?: AH | WH): void {\n ck();\n if (type === \"*\") {\n if (handler === undefined) {\n flush(w);\n w.length = 0;\n } else {\n rmByUser(w, handler as WH);\n }\n return;\n }\n const arr = t.get(type);\n if (arr === undefined) return;\n if (handler === undefined) {\n flush(arr);\n t.delete(type);\n } else {\n rmByUser(arr, handler as AH);\n }\n }\n\n // Inline error policy handler — policy undefined/false → re-throw; true → swallow;\n // function → invoke and swallow; if callback throws, ignore silently.\n function ap(pol: ErrorPolicy | undefined, err: unknown, k: string, p: unknown): void {\n if (pol === undefined || pol === false) throw err;\n if (typeof pol === \"function\")\n try {\n pol(err, k, p);\n } catch {\n /* silent */\n }\n }\n\n function emit<K extends keyof Events>(type: K, payload: Events[K]): void {\n ck();\n // Both slices happen BEFORE any handler call (snapshot-before-iterate).\n const k = type as string;\n const p = payload as unknown;\n const ts = (t.get(k) ?? []).slice();\n const ws = w.slice();\n for (const e of ts) {\n try {\n e.h(p);\n } catch (err) {\n ap(e.ce !== undefined ? e.ce : cap, err, k, p);\n }\n }\n for (const e of ws) {\n if (e.r !== undefined && Math.random() >= e.r) continue;\n if (e.tm) {\n const now = Date.now();\n if (e.ts !== undefined && now - e.ts < e.tm) continue;\n e.ts = now;\n }\n try {\n e.h(k, p as never);\n } catch (err) {\n ap(cap, err, k, p);\n }\n }\n }\n\n function purge(): void {\n for (const a of t.values()) flush(a);\n flush(w);\n t.clear();\n w.length = 0;\n }\n\n return {\n on: on as Emitter<Events>[\"on\"],\n once,\n off: off as Emitter<Events>[\"off\"],\n emit,\n clear() {\n ck();\n purge();\n },\n dispose() {\n if (!d) {\n purge();\n d = true;\n }\n },\n get disposed() {\n return d;\n },\n };\n}\n"]}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- var v=class extends Error{name="EmitterError"},h=class extends Error{name="EmitterDisposedError"};function b(s,d){let i=s.findIndex(o=>o.u===d);if(i>=0){let o=s[i];o!==void 0&&(o.c?.(),o.c=void 0),s.splice(i,1);}}function y(s){for(let d of s)d.c?.(),d.c=void 0;}function m(s,d,i){s.push(d);let o=()=>{let a=s.indexOf(d);a>=0&&s.splice(a,1),d.c?.(),d.c=void 0;};if(i!==void 0){let a=()=>o();i.addEventListener("abort",a,{once:true}),d.c=()=>i.removeEventListener("abort",a);}return o}function j(s){let d=s?.captureHandlerErrors,i=new Map,o=[],a=false;function p(){if(a)throw new h("aieventjs: emitter has been disposed")}function g(e){let n=i.get(e);return n===void 0&&(n=[],i.set(e,n)),n}function k(e,n,t){p();let c=t?.sampleRate,u=t?.throttleMs;if(e==="*"){if(t?.captureErrors!==void 0)throw new v("aieventjs: captureErrors invalid on *")}else {if(c!==void 0)throw new v("aieventjs: sampleRate wildcard-only");if(u!==void 0)throw new v("aieventjs: throttleMs wildcard-only")}if(c!==void 0&&(c<=0||c>1))throw new v("aieventjs: sampleRate must be in (0,1]");if(u!==void 0&&u<0)throw new v("aieventjs: throttleMs must be >= 0");let l=t?.signal;if(l?.aborted)return ()=>{};if(e==="*"){let E=n;if(t?.once){let H=m(o,{h:(R,M)=>{H(),E(R,M);},u:E,c:void 0,r:c,tm:u},l);return H}return m(o,{h:E,u:E,c:void 0,r:c,tm:u},l)}let r=n,f=t?.captureErrors;if(t?.once){let E={h:H=>{w(),r(H);},u:r,c:void 0,ce:f},w=m(g(e),E,l);return w}return m(g(e),{h:r,u:r,c:void 0,ce:f},l)}function A(e,n){return k(e,n,{once:true})}function O(e,n){if(p(),e==="*"){n===void 0?(y(o),o.length=0):b(o,n);return}let t=i.get(e);t!==void 0&&(n===void 0?(y(t),i.delete(e)):b(t,n));}function x(e,n,t,c){if(e===void 0||e===false)throw n;if(typeof e=="function")try{e(n,t,c);}catch{}}function W(e,n){p();let t=e,c=n,u=(i.get(t)??[]).slice(),l=o.slice();for(let r of u)try{r.h(c);}catch(f){x(r.ce!==void 0?r.ce:d,f,t,c);}for(let r of l)if(!(r.r!==void 0&&Math.random()>=r.r)){if(r.tm){let f=Date.now();if(r.ts!==void 0&&f-r.ts<r.tm)continue;r.ts=f;}try{r.h(t,c);}catch(f){x(d,f,t,c);}}}function K(){for(let e of i.values())y(e);y(o),i.clear(),o.length=0;}return {on:k,once:A,off:O,emit:W,clear(){p(),K();},dispose(){a||(K(),a=true);},get disposed(){return a}}}export{h as EmitterDisposedError,v as EmitterError,j as createEmitter};//# sourceMappingURL=index.js.map
1
+ var v=class extends Error{name="EmitterError"},h=class extends Error{name="EmitterDisposedError"};function K(d,c){let i=d.findIndex(o=>o.u===c);if(i>=0){let o=d[i];o!==void 0&&(o.c?.(),o.c=void 0),d.splice(i,1);}}function y(d){for(let c of d)c.c?.(),c.c=void 0;}function m(d,c,i){d.push(c);let o=()=>{let a=d.indexOf(c);a>=0&&d.splice(a,1),c.c?.(),c.c=void 0;};if(i!==void 0){let a=()=>o();i.addEventListener("abort",a,{once:true}),c.c=()=>i.removeEventListener("abort",a);}return o}function j(d){let c=d?.captureHandlerErrors,i=new Map,o=[],a=false;function p(){if(a)throw new h("aieventjs: emitter has been disposed")}function g(e){let n=i.get(e);return n===void 0&&(n=[],i.set(e,n)),n}function k(e,n,t){p();let s=t?.sampleRate,u=t?.throttleMs;if(e==="*"){if(t?.captureErrors!==void 0)throw new v("aieventjs: captureErrors invalid on *")}else {if(s!==void 0)throw new v("aieventjs: sampleRate wildcard-only");if(u!==void 0)throw new v("aieventjs: throttleMs wildcard-only")}if(s!==void 0&&(!Number.isFinite(s)||s<=0||s>1))throw new v("aieventjs: sampleRate must be in (0,1]");if(u!==void 0&&(!Number.isFinite(u)||u<0))throw new v("aieventjs: throttleMs must be >= 0");let l=t?.signal;if(l?.aborted)return ()=>{};if(e==="*"){let E=n;if(t?.once){let H=m(o,{h:(R,M)=>{H(),E(R,M);},u:E,c:void 0,r:s,tm:u},l);return H}return m(o,{h:E,u:E,c:void 0,r:s,tm:u},l)}let r=n,f=t?.captureErrors;if(t?.once){let E={h:H=>{w(),r(H);},u:r,c:void 0,ce:f},w=m(g(e),E,l);return w}return m(g(e),{h:r,u:r,c:void 0,ce:f},l)}function A(e,n){return k(e,n,{once:true})}function O(e,n){if(p(),e==="*"){n===void 0?(y(o),o.length=0):K(o,n);return}let t=i.get(e);t!==void 0&&(n===void 0?(y(t),i.delete(e)):K(t,n));}function x(e,n,t,s){if(e===void 0||e===false)throw n;if(typeof e=="function")try{e(n,t,s);}catch{}}function W(e,n){p();let t=e,s=n,u=(i.get(t)??[]).slice(),l=o.slice();for(let r of u)try{r.h(s);}catch(f){x(r.ce!==void 0?r.ce:c,f,t,s);}for(let r of l)if(!(r.r!==void 0&&Math.random()>=r.r)){if(r.tm){let f=Date.now();if(r.ts!==void 0&&f-r.ts<r.tm)continue;r.ts=f;}try{r.h(t,s);}catch(f){x(c,f,t,s);}}}function b(){for(let e of i.values())y(e);y(o),i.clear(),o.length=0;}return {on:k,once:A,off:O,emit:W,clear(){p(),b();},dispose(){a||(b(),a=true);},get disposed(){return a}}}export{h as EmitterDisposedError,v as EmitterError,j as createEmitter};//# sourceMappingURL=index.js.map
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["EmitterError","EmitterDisposedError","rmByUser","arr","user","e","flush","sub","sig","rm","i","fn","createEmitter","opts","cap","t","w","d","ck","ga","k","a","on","type","handler","o","sr","tm2","tp","p","ce","once","off","ap","pol","err","emit","payload","ts","ws","now","purge"],"mappings":"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","file":"index.js","sourcesContent":["// aieventjs — small, strict, typed event emitter for the ai*js family.\n//\n// v0.1.0: full implementation of the frozen API surface. Mitt-compatible\n// snapshot semantics, wildcard \"*\" handler, AbortSignal integration, once,\n// idempotent dispose, destructurable methods (no `this`).\n\n/**\n * Configuration for {@link createEmitter}. Controls the default error\n * policy for handlers thrown during `emit()`; per-handler\n * {@link OnOptions.captureErrors} overrides this default.\n *\n * @public\n */\nexport interface EmitterOptions {\n /**\n * Default error policy for all handlers when they throw during emit().\n *\n * - undefined / false (default) — first throw aborts dispatch (mitt-compatible).\n * - true — swallow; dispatch continues over all handlers in the snapshot.\n * - (err, type, payload) => void — invoked with the unknown error, the\n * event name as string, and the payload as unknown. If this callback\n * itself throws, the error is silently ignored.\n *\n * Per-subscription OnOptions.captureErrors overrides this for that handler.\n */\n captureHandlerErrors?: boolean | ((err: unknown, type: string, payload: unknown) => void);\n}\n\n/**\n * Handler invoked for a single typed event.\n *\n * @public\n */\nexport type EventHandler<Payload> = (payload: Payload) => void;\n\n/**\n * Handler invoked for the wildcard `\"*\"` subscription. Receives the actual\n * event type alongside the payload.\n *\n * @public\n */\nexport type WildcardHandler<Events extends Record<string, unknown>> = <K extends keyof Events>(\n type: K,\n payload: Events[K],\n) => void;\n\n/**\n * Subscription options accepted by {@link Emitter.on}.\n *\n * @public\n */\nexport interface OnOptions {\n /**\n * Aborting this signal removes the handler. The same effect as calling\n * the returned unsubscribe function. Pre-aborted signals never register.\n */\n signal?: AbortSignal;\n\n /** Auto-remove the handler after the first dispatch. Equivalent to `once()`. */\n once?: boolean;\n\n /**\n * Override emitter-level captureHandlerErrors for this handler.\n * - undefined — fall through to emitter-level.\n * - false — force re-throw, even when emitter-level is true / callback.\n * - true — swallow.\n * - (err, type, payload) => void — same semantics as the emitter-level callback.\n *\n * Throws EmitterError if set on a wildcard \"*\" subscription.\n * @invariant does not break snapshot-before-iterate semantics.\n */\n captureErrors?: boolean | ((err: unknown, type: string, payload: unknown) => void);\n\n /**\n * Wildcard \"*\" only. Probability in (0, 1] that a dispatch reaches this\n * handler. Math.random() is sampled per dispatch. Values <= 0 or > 1 are\n * rejected at on() time.\n *\n * Throws EmitterError if set on a typed handler.\n */\n sampleRate?: number;\n\n /**\n * Wildcard \"*\" only. Minimum milliseconds between successive calls.\n * Leading-edge: the first dispatch after subscription always fires;\n * subsequent dispatches within `throttleMs` are dropped (not queued).\n * Uses Date.now(). 0 = no throttle. Negative values are rejected.\n *\n * Throws EmitterError if set on a typed handler.\n */\n throttleMs?: number;\n}\n\n/**\n * Strongly-typed event emitter. Subscribe with {@link Emitter.on} (returns\n * an unsubscribe function), dispatch with {@link Emitter.emit}, dispose\n * with {@link Emitter.dispose} when finished.\n *\n * @typeParam Events — a string-keyed map from event name to payload type.\n * @public\n */\nexport interface Emitter<Events extends Record<string, unknown>> {\n /**\n * Subscribe to a single event type. Returns an unsubscribe function;\n * calling it (or aborting `opts.signal`) removes the handler.\n */\n on<K extends keyof Events>(\n type: K,\n handler: EventHandler<Events[K]>,\n opts?: OnOptions,\n ): () => void;\n\n /**\n * Subscribe to every event with a single handler that receives\n * `(type, payload)`. Wildcard handlers fire AFTER type-matched\n * handlers — same ordering as `mitt`.\n */\n on(type: \"*\", handler: WildcardHandler<Events>, opts?: OnOptions): () => void;\n\n /**\n * Subscribe and auto-remove after the first dispatch. Equivalent to\n * `on(type, handler, { once: true })`.\n */\n once<K extends keyof Events>(type: K, handler: EventHandler<Events[K]>): () => void;\n\n /**\n * Imperative unsubscribe. Prefer the unsubscribe function returned by\n * `on()` — it's faster (no reference lookup) and survives renames.\n * If `handler` is omitted, removes every handler for `type`.\n */\n off<K extends keyof Events>(type: K, handler?: EventHandler<Events[K]>): void;\n\n /**\n * Imperative wildcard unsubscribe.\n */\n off(type: \"*\", handler?: WildcardHandler<Events>): void;\n\n /**\n * Dispatch synchronously. Handlers receive `payload`; wildcard handlers\n * receive `(type, payload)`. Handler lists are snapshotted before iteration,\n * so removing a handler inside its own callback does not skip subsequent\n * handlers. By default, the first throwing handler aborts the dispatch;\n * set EmitterOptions.captureHandlerErrors (or per-handler OnOptions.captureErrors)\n * to swallow or report errors and continue.\n */\n emit<K extends keyof Events>(type: K, payload: Events[K]): void;\n\n /**\n * Remove every handler for every event (including wildcards). The\n * emitter remains usable. Use {@link dispose} for permanent teardown.\n */\n clear(): void;\n\n /**\n * Idempotent teardown. Drops every handler; subsequent `on` / `once` /\n * `emit` / `off` / `clear` throw {@link EmitterDisposedError}.\n */\n dispose(): void;\n\n /** `true` once {@link dispose} has been called. */\n readonly disposed: boolean;\n}\n\n/**\n * Recoverable emitter error. Thrown by `on()` when `OnOptions` violates a\n * precondition: `captureErrors` set on a wildcard `\"*\"` subscription;\n * `sampleRate` / `throttleMs` set on a typed subscription; `sampleRate`\n * outside `(0, 1]`; or `throttleMs` negative.\n *\n * @public\n */\nexport class EmitterError extends Error {\n override readonly name = \"EmitterError\";\n}\n\n/**\n * Thrown by any emitter method called after {@link Emitter.dispose}.\n *\n * @public\n */\nexport class EmitterDisposedError extends Error {\n override readonly name = \"EmitterDisposedError\";\n}\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\n// Mutable `c` field (not optional `?:`) avoids exactOptionalPropertyTypes TS2412\n// when assigning undefined. Short field names reduce minified output size.\ntype ErrorPolicy = boolean | ((err: unknown, type: string, payload: unknown) => void);\n\ninterface E<H> {\n h: H; // handler (may be a once-wrapper)\n c: (() => void) | undefined; // abortCleanup\n u: H; // user-provided handler (off matching)\n // v0.3.0: per-handler error policy and wildcard throttle/sample state.\n // Fields typed as `T | undefined` (not just `T`) so that exactOptionalPropertyTypes\n // permits assigning `undefined` in object literals (avoids TS2375).\n ce?: ErrorPolicy | undefined; // captureErrors override (typed only)\n r?: number | undefined; // sampleRate (wildcard only)\n tm?: number | undefined; // throttleMs (wildcard only)\n ts?: number | undefined; // last call timestamp — mutated during dispatch (wildcard only)\n}\n\ntype AH = EventHandler<unknown>;\ntype WH = WildcardHandler<Record<string, unknown>>;\n\n// Remove one entry by user-identity from an array; run its abort cleanup.\nfunction rmByUser<H>(arr: E<H>[], user: H): void {\n const i = arr.findIndex((e) => e.u === user);\n if (i >= 0) {\n const e = arr[i];\n if (e !== undefined) {\n e.c?.();\n e.c = undefined;\n }\n arr.splice(i, 1);\n }\n}\n\n// Flush all abort cleanups from an array (for clear / dispose).\nfunction flush<H>(arr: E<H>[]): void {\n for (const e of arr) {\n e.c?.();\n e.c = undefined;\n }\n}\n\n// Push entry onto arr, wire AbortSignal, return unsubscribe.\nfunction sub<H>(arr: E<H>[], e: E<H>, sig: AbortSignal | undefined): () => void {\n arr.push(e);\n const rm = () => {\n const i = arr.indexOf(e);\n if (i >= 0) arr.splice(i, 1);\n e.c?.();\n e.c = undefined;\n };\n if (sig !== undefined) {\n const fn = () => rm();\n sig.addEventListener(\"abort\", fn, { once: true });\n e.c = () => sig.removeEventListener(\"abort\", fn);\n }\n return rm;\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Construct a strongly-typed event emitter.\n *\n * @example\n * ```ts\n * import { createEmitter } from \"aieventjs\";\n *\n * type Events = {\n * \"user:login\": { id: string };\n * \"user:logout\": void;\n * };\n *\n * const bus = createEmitter<Events>();\n *\n * const off = bus.on(\"user:login\", (u) => console.log(\"hi\", u.id));\n * bus.emit(\"user:login\", { id: \"alice\" });\n * off();\n *\n * bus.on(\"*\", (type, payload) => console.log(\"event\", type, payload));\n * ```\n *\n * @public\n */\nexport function createEmitter<Events extends Record<string, unknown> = Record<string, unknown>>(\n opts?: EmitterOptions,\n): Emitter<Events> {\n const cap = opts?.captureHandlerErrors;\n\n const t: Map<string, E<AH>[]> = new Map();\n const w: E<WH>[] = [];\n let d = false;\n\n function ck(): void {\n if (d) throw new EmitterDisposedError(\"aieventjs: emitter has been disposed\");\n }\n\n // Get or create typed handler array for a key.\n function ga(k: string): E<AH>[] {\n let a = t.get(k);\n if (a === undefined) {\n a = [];\n t.set(k, a);\n }\n return a;\n }\n\n function on(type: string | \"*\", handler: AH | WH, o?: OnOptions): () => void {\n ck();\n // v0.3.0 guards: cross-domain options + range checks\n const sr = o?.sampleRate;\n const tm2 = o?.throttleMs;\n if (type === \"*\") {\n if (o?.captureErrors !== undefined)\n throw new EmitterError(\"aieventjs: captureErrors invalid on *\");\n } else {\n if (sr !== undefined) throw new EmitterError(\"aieventjs: sampleRate wildcard-only\");\n if (tm2 !== undefined) throw new EmitterError(\"aieventjs: throttleMs wildcard-only\");\n }\n if (sr !== undefined && (sr <= 0 || sr > 1))\n throw new EmitterError(\"aieventjs: sampleRate must be in (0,1]\");\n if (tm2 !== undefined && tm2 < 0) throw new EmitterError(\"aieventjs: throttleMs must be >= 0\");\n const sig = o?.signal;\n if (sig?.aborted) return () => {};\n\n if (type === \"*\") {\n const fn = handler as WH;\n if (o?.once) {\n const e: E<WH> = {\n h: (tp, p) => {\n rm();\n fn(tp, p);\n },\n u: fn,\n c: undefined,\n r: sr,\n tm: tm2,\n };\n const rm = sub(w, e, sig);\n return rm;\n }\n return sub(w, { h: fn, u: fn, c: undefined, r: sr, tm: tm2 }, sig);\n }\n\n const fn = handler as AH;\n const ce = o?.captureErrors;\n if (o?.once) {\n const e: E<AH> = {\n h: (p) => {\n rm();\n fn(p);\n },\n u: fn,\n c: undefined,\n ce: ce,\n };\n const rm = sub(ga(type), e, sig);\n return rm;\n }\n return sub(ga(type), { h: fn, u: fn, c: undefined, ce: ce }, sig);\n }\n\n function once<K extends keyof Events>(type: K, handler: EventHandler<Events[K]>): () => void {\n return on(type as string, handler as AH, { once: true });\n }\n\n function off(type: string | \"*\", handler?: AH | WH): void {\n ck();\n if (type === \"*\") {\n if (handler === undefined) {\n flush(w);\n w.length = 0;\n } else {\n rmByUser(w, handler as WH);\n }\n return;\n }\n const arr = t.get(type);\n if (arr === undefined) return;\n if (handler === undefined) {\n flush(arr);\n t.delete(type);\n } else {\n rmByUser(arr, handler as AH);\n }\n }\n\n // Inline error policy handler — policy undefined/false → re-throw; true → swallow;\n // function → invoke and swallow; if callback throws, ignore silently.\n function ap(pol: ErrorPolicy | undefined, err: unknown, k: string, p: unknown): void {\n if (pol === undefined || pol === false) throw err;\n if (typeof pol === \"function\")\n try {\n pol(err, k, p);\n } catch {\n /* silent */\n }\n }\n\n function emit<K extends keyof Events>(type: K, payload: Events[K]): void {\n ck();\n // Both slices happen BEFORE any handler call (snapshot-before-iterate).\n const k = type as string;\n const p = payload as unknown;\n const ts = (t.get(k) ?? []).slice();\n const ws = w.slice();\n for (const e of ts) {\n try {\n e.h(p);\n } catch (err) {\n ap(e.ce !== undefined ? e.ce : cap, err, k, p);\n }\n }\n for (const e of ws) {\n if (e.r !== undefined && Math.random() >= e.r) continue;\n if (e.tm) {\n const now = Date.now();\n if (e.ts !== undefined && now - e.ts < e.tm) continue;\n e.ts = now;\n }\n try {\n e.h(k, p as never);\n } catch (err) {\n ap(cap, err, k, p);\n }\n }\n }\n\n function purge(): void {\n for (const a of t.values()) flush(a);\n flush(w);\n t.clear();\n w.length = 0;\n }\n\n return {\n on: on as Emitter<Events>[\"on\"],\n once,\n off: off as Emitter<Events>[\"off\"],\n emit,\n clear() {\n ck();\n purge();\n },\n dispose() {\n if (!d) {\n purge();\n d = true;\n }\n },\n get disposed() {\n return d;\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["EmitterError","EmitterDisposedError","rmByUser","arr","user","e","flush","sub","sig","rm","i","fn","createEmitter","opts","cap","t","w","d","ck","ga","k","a","on","type","handler","o","sr","tm2","tp","p","ce","once","off","ap","pol","err","emit","payload","ts","ws","now","purge"],"mappings":"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","file":"index.js","sourcesContent":["// aieventjs — small, strict, typed event emitter for the ai*js family.\n//\n// v0.1.0: full implementation of the frozen API surface. Mitt-compatible\n// snapshot semantics, wildcard \"*\" handler, AbortSignal integration, once,\n// idempotent dispose, destructurable methods (no `this`).\n\n/**\n * Configuration for {@link createEmitter}. Controls the default error\n * policy for handlers thrown during `emit()`; per-handler\n * {@link OnOptions.captureErrors} overrides this default.\n *\n * @public\n */\nexport interface EmitterOptions {\n /**\n * Default error policy for all handlers when they throw during emit().\n *\n * - undefined / false (default) — first throw aborts dispatch (mitt-compatible).\n * - true — swallow; dispatch continues over all handlers in the snapshot.\n * - (err, type, payload) => void — invoked with the unknown error, the\n * event name as string, and the payload as unknown. If this callback\n * itself throws, the error is silently ignored.\n *\n * Per-subscription OnOptions.captureErrors overrides this for that handler.\n */\n captureHandlerErrors?: boolean | ((err: unknown, type: string, payload: unknown) => void);\n}\n\n/**\n * Handler invoked for a single typed event.\n *\n * @public\n */\nexport type EventHandler<Payload> = (payload: Payload) => void;\n\n/**\n * Handler invoked for the wildcard `\"*\"` subscription. Receives the actual\n * event type alongside the payload.\n *\n * @public\n */\nexport type WildcardHandler<Events extends Record<string, unknown>> = <K extends keyof Events>(\n type: K,\n payload: Events[K],\n) => void;\n\n/**\n * Subscription options accepted by {@link Emitter.on}.\n *\n * @public\n */\nexport interface OnOptions {\n /**\n * Aborting this signal removes the handler. The same effect as calling\n * the returned unsubscribe function. Pre-aborted signals never register.\n */\n signal?: AbortSignal;\n\n /** Auto-remove the handler after the first dispatch. Equivalent to `once()`. */\n once?: boolean;\n\n /**\n * Override emitter-level captureHandlerErrors for this handler.\n * - undefined — fall through to emitter-level.\n * - false — force re-throw, even when emitter-level is true / callback.\n * - true — swallow.\n * - (err, type, payload) => void — same semantics as the emitter-level callback.\n *\n * Throws EmitterError if set on a wildcard \"*\" subscription.\n * @invariant does not break snapshot-before-iterate semantics.\n */\n captureErrors?: boolean | ((err: unknown, type: string, payload: unknown) => void);\n\n /**\n * Wildcard \"*\" only. Probability in (0, 1] that a dispatch reaches this\n * handler. Math.random() is sampled per dispatch. Values <= 0 or > 1 are\n * rejected at on() time.\n *\n * Throws EmitterError if set on a typed handler.\n */\n sampleRate?: number;\n\n /**\n * Wildcard \"*\" only. Minimum milliseconds between successive calls.\n * Leading-edge: the first dispatch after subscription always fires;\n * subsequent dispatches within `throttleMs` are dropped (not queued).\n * Uses Date.now(). 0 = no throttle. Negative values are rejected.\n *\n * Throws EmitterError if set on a typed handler.\n */\n throttleMs?: number;\n}\n\n/**\n * Strongly-typed event emitter. Subscribe with {@link Emitter.on} (returns\n * an unsubscribe function), dispatch with {@link Emitter.emit}, dispose\n * with {@link Emitter.dispose} when finished.\n *\n * @typeParam Events — a string-keyed map from event name to payload type.\n * @public\n */\nexport interface Emitter<Events extends Record<string, unknown>> {\n /**\n * Subscribe to a single event type. Returns an unsubscribe function;\n * calling it (or aborting `opts.signal`) removes the handler.\n */\n on<K extends keyof Events>(\n type: K,\n handler: EventHandler<Events[K]>,\n opts?: OnOptions,\n ): () => void;\n\n /**\n * Subscribe to every event with a single handler that receives\n * `(type, payload)`. Wildcard handlers fire AFTER type-matched\n * handlers — same ordering as `mitt`.\n */\n on(type: \"*\", handler: WildcardHandler<Events>, opts?: OnOptions): () => void;\n\n /**\n * Subscribe and auto-remove after the first dispatch. Equivalent to\n * `on(type, handler, { once: true })`.\n */\n once<K extends keyof Events>(type: K, handler: EventHandler<Events[K]>): () => void;\n\n /**\n * Imperative unsubscribe. Prefer the unsubscribe function returned by\n * `on()` — it's faster (no reference lookup) and survives renames.\n * If `handler` is omitted, removes every handler for `type`.\n */\n off<K extends keyof Events>(type: K, handler?: EventHandler<Events[K]>): void;\n\n /**\n * Imperative wildcard unsubscribe.\n */\n off(type: \"*\", handler?: WildcardHandler<Events>): void;\n\n /**\n * Dispatch synchronously. Handlers receive `payload`; wildcard handlers\n * receive `(type, payload)`. Handler lists are snapshotted before iteration,\n * so removing a handler inside its own callback does not skip subsequent\n * handlers. By default, the first throwing handler aborts the dispatch;\n * set EmitterOptions.captureHandlerErrors (or per-handler OnOptions.captureErrors)\n * to swallow or report errors and continue.\n */\n emit<K extends keyof Events>(type: K, payload: Events[K]): void;\n\n /**\n * Remove every handler for every event (including wildcards). The\n * emitter remains usable. Use {@link dispose} for permanent teardown.\n */\n clear(): void;\n\n /**\n * Idempotent teardown. Drops every handler; subsequent `on` / `once` /\n * `emit` / `off` / `clear` throw {@link EmitterDisposedError}.\n */\n dispose(): void;\n\n /** `true` once {@link dispose} has been called. */\n readonly disposed: boolean;\n}\n\n/**\n * Recoverable emitter error. Thrown by `on()` when `OnOptions` violates a\n * precondition: `captureErrors` set on a wildcard `\"*\"` subscription;\n * `sampleRate` / `throttleMs` set on a typed subscription; `sampleRate`\n * outside `(0, 1]`; or `throttleMs` negative.\n *\n * @public\n */\nexport class EmitterError extends Error {\n override readonly name = \"EmitterError\";\n}\n\n/**\n * Thrown by any emitter method called after {@link Emitter.dispose}.\n *\n * @public\n */\nexport class EmitterDisposedError extends Error {\n override readonly name = \"EmitterDisposedError\";\n}\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\n// Mutable `c` field (not optional `?:`) avoids exactOptionalPropertyTypes TS2412\n// when assigning undefined. Short field names reduce minified output size.\ntype ErrorPolicy = boolean | ((err: unknown, type: string, payload: unknown) => void);\n\ninterface E<H> {\n h: H; // handler (may be a once-wrapper)\n c: (() => void) | undefined; // abortCleanup\n u: H; // user-provided handler (off matching)\n // v0.3.0: per-handler error policy and wildcard throttle/sample state.\n // Fields typed as `T | undefined` (not just `T`) so that exactOptionalPropertyTypes\n // permits assigning `undefined` in object literals (avoids TS2375).\n ce?: ErrorPolicy | undefined; // captureErrors override (typed only)\n r?: number | undefined; // sampleRate (wildcard only)\n tm?: number | undefined; // throttleMs (wildcard only)\n ts?: number | undefined; // last call timestamp — mutated during dispatch (wildcard only)\n}\n\ntype AH = EventHandler<unknown>;\ntype WH = WildcardHandler<Record<string, unknown>>;\n\n// Remove one entry by user-identity from an array; run its abort cleanup.\nfunction rmByUser<H>(arr: E<H>[], user: H): void {\n const i = arr.findIndex((e) => e.u === user);\n if (i >= 0) {\n const e = arr[i];\n if (e !== undefined) {\n e.c?.();\n e.c = undefined;\n }\n arr.splice(i, 1);\n }\n}\n\n// Flush all abort cleanups from an array (for clear / dispose).\nfunction flush<H>(arr: E<H>[]): void {\n for (const e of arr) {\n e.c?.();\n e.c = undefined;\n }\n}\n\n// Push entry onto arr, wire AbortSignal, return unsubscribe.\nfunction sub<H>(arr: E<H>[], e: E<H>, sig: AbortSignal | undefined): () => void {\n arr.push(e);\n const rm = () => {\n const i = arr.indexOf(e);\n if (i >= 0) arr.splice(i, 1);\n e.c?.();\n e.c = undefined;\n };\n if (sig !== undefined) {\n const fn = () => rm();\n sig.addEventListener(\"abort\", fn, { once: true });\n e.c = () => sig.removeEventListener(\"abort\", fn);\n }\n return rm;\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Construct a strongly-typed event emitter.\n *\n * @example\n * ```ts\n * import { createEmitter } from \"aieventjs\";\n *\n * type Events = {\n * \"user:login\": { id: string };\n * \"user:logout\": void;\n * };\n *\n * const bus = createEmitter<Events>();\n *\n * const off = bus.on(\"user:login\", (u) => console.log(\"hi\", u.id));\n * bus.emit(\"user:login\", { id: \"alice\" });\n * off();\n *\n * bus.on(\"*\", (type, payload) => console.log(\"event\", type, payload));\n * ```\n *\n * @public\n */\nexport function createEmitter<Events extends Record<string, unknown> = Record<string, unknown>>(\n opts?: EmitterOptions,\n): Emitter<Events> {\n const cap = opts?.captureHandlerErrors;\n\n const t: Map<string, E<AH>[]> = new Map();\n const w: E<WH>[] = [];\n let d = false;\n\n function ck(): void {\n if (d) throw new EmitterDisposedError(\"aieventjs: emitter has been disposed\");\n }\n\n // Get or create typed handler array for a key.\n function ga(k: string): E<AH>[] {\n let a = t.get(k);\n if (a === undefined) {\n a = [];\n t.set(k, a);\n }\n return a;\n }\n\n function on(type: string | \"*\", handler: AH | WH, o?: OnOptions): () => void {\n ck();\n // v0.3.0 guards: cross-domain options + range checks\n const sr = o?.sampleRate;\n const tm2 = o?.throttleMs;\n if (type === \"*\") {\n if (o?.captureErrors !== undefined)\n throw new EmitterError(\"aieventjs: captureErrors invalid on *\");\n } else {\n if (sr !== undefined) throw new EmitterError(\"aieventjs: sampleRate wildcard-only\");\n if (tm2 !== undefined) throw new EmitterError(\"aieventjs: throttleMs wildcard-only\");\n }\n if (sr !== undefined && (!Number.isFinite(sr) || sr <= 0 || sr > 1))\n throw new EmitterError(\"aieventjs: sampleRate must be in (0,1]\");\n if (tm2 !== undefined && (!Number.isFinite(tm2) || tm2 < 0))\n throw new EmitterError(\"aieventjs: throttleMs must be >= 0\");\n const sig = o?.signal;\n if (sig?.aborted) return () => {};\n\n if (type === \"*\") {\n const fn = handler as WH;\n if (o?.once) {\n const e: E<WH> = {\n h: (tp, p) => {\n rm();\n fn(tp, p);\n },\n u: fn,\n c: undefined,\n r: sr,\n tm: tm2,\n };\n const rm = sub(w, e, sig);\n return rm;\n }\n return sub(w, { h: fn, u: fn, c: undefined, r: sr, tm: tm2 }, sig);\n }\n\n const fn = handler as AH;\n const ce = o?.captureErrors;\n if (o?.once) {\n const e: E<AH> = {\n h: (p) => {\n rm();\n fn(p);\n },\n u: fn,\n c: undefined,\n ce: ce,\n };\n const rm = sub(ga(type), e, sig);\n return rm;\n }\n return sub(ga(type), { h: fn, u: fn, c: undefined, ce: ce }, sig);\n }\n\n function once<K extends keyof Events>(type: K, handler: EventHandler<Events[K]>): () => void {\n return on(type as string, handler as AH, { once: true });\n }\n\n function off(type: string | \"*\", handler?: AH | WH): void {\n ck();\n if (type === \"*\") {\n if (handler === undefined) {\n flush(w);\n w.length = 0;\n } else {\n rmByUser(w, handler as WH);\n }\n return;\n }\n const arr = t.get(type);\n if (arr === undefined) return;\n if (handler === undefined) {\n flush(arr);\n t.delete(type);\n } else {\n rmByUser(arr, handler as AH);\n }\n }\n\n // Inline error policy handler — policy undefined/false → re-throw; true → swallow;\n // function → invoke and swallow; if callback throws, ignore silently.\n function ap(pol: ErrorPolicy | undefined, err: unknown, k: string, p: unknown): void {\n if (pol === undefined || pol === false) throw err;\n if (typeof pol === \"function\")\n try {\n pol(err, k, p);\n } catch {\n /* silent */\n }\n }\n\n function emit<K extends keyof Events>(type: K, payload: Events[K]): void {\n ck();\n // Both slices happen BEFORE any handler call (snapshot-before-iterate).\n const k = type as string;\n const p = payload as unknown;\n const ts = (t.get(k) ?? []).slice();\n const ws = w.slice();\n for (const e of ts) {\n try {\n e.h(p);\n } catch (err) {\n ap(e.ce !== undefined ? e.ce : cap, err, k, p);\n }\n }\n for (const e of ws) {\n if (e.r !== undefined && Math.random() >= e.r) continue;\n if (e.tm) {\n const now = Date.now();\n if (e.ts !== undefined && now - e.ts < e.tm) continue;\n e.ts = now;\n }\n try {\n e.h(k, p as never);\n } catch (err) {\n ap(cap, err, k, p);\n }\n }\n }\n\n function purge(): void {\n for (const a of t.values()) flush(a);\n flush(w);\n t.clear();\n w.length = 0;\n }\n\n return {\n on: on as Emitter<Events>[\"on\"],\n once,\n off: off as Emitter<Events>[\"off\"],\n emit,\n clear() {\n ck();\n purge();\n },\n dispose() {\n if (!d) {\n purge();\n d = true;\n }\n },\n get disposed() {\n return d;\n },\n };\n}\n"]}
package/llms-full.txt CHANGED
@@ -23,13 +23,13 @@ The short index lives at `llms.txt` (see https://llmstxt.org/).
23
23
 
24
24
  Part of the [ai\*js micro-runtime ecosystem](https://github.com/yshengliao) — see also [aifsmjs](https://github.com/yshengliao/aifsmjs) (FSM), [aiecsjs](https://github.com/yshengliao/aiecsjs) (ECS), [aibridgejs](https://github.com/yshengliao/aibridgejs) (cross-context RPC), [aipooljs](https://github.com/yshengliao/aipooljs) (object pool), [aiquadtreejs](https://github.com/yshengliao/aiquadtreejs) (spatial partitioning), and [aiaudiojs](https://github.com/yshengliao/aiaudiojs) (Web Audio shell).
25
25
 
26
- > **Status: 0.4.0.** Full implementation shipped; all methods are live. Coverage ≥ 95/90/100/100; ~1050 B gzip (budget 1100 B).
26
+ > **Status: 0.5.1.** Full implementation shipped; all methods are live. Coverage ≥ 95/90/100/100; ~1050 B gzip (budget 1100 B).
27
27
 
28
28
  ---
29
29
 
30
30
  ## Why aieventjs
31
31
 
32
- Why not just use `mitt`? Honest answer: `mitt` is the right choice for many projects — it's MIT, ~282 B gzipped, and the API is genuinely well-shaped. We evaluated it and chose to write from scratch instead. Three reasons (full evaluation in [LEARNINGS.md](../LEARNINGS.md)):
32
+ Why not just use `mitt`? Honest answer: `mitt` is the right choice for many projects — it's MIT, ~282 B gzipped, and the API is genuinely well-shaped. We evaluated it and chose to write from scratch instead. Three reasons:
33
33
 
34
34
  - **mitt has been unmaintained since 2023-07-04.** The PRs the community most wants — `unsubscribe`-returning `on()`, `AbortSignal`, `sideEffects: false`, nodenext compatibility — are all open and untouched. Forking would mean shipping a copy with our name on it; the upstream couldn't accept improvements back even if we wanted.
35
35
  - **The implementation is ~35 lines of pure logic.** "Fork and improve" doesn't really exist at that size class — any non-trivial change is a rewrite, and the cost of carrying the upstream copyright notice exceeds the benefit.
@@ -182,6 +182,27 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
182
182
 
183
183
  ## [Unreleased]
184
184
 
185
+ ## [0.5.1] - 2026-06-02
186
+
187
+ ### Fixed
188
+ - `NaN` sampleRate and `NaN` throttleMs now throw `EmitterError` at `on()` time.
189
+ Previously, `NaN <= 0` and `NaN > 1` both evaluate to `false`, so a `NaN`
190
+ sampleRate silently passed validation and degraded to always-fire semantics;
191
+ similarly `NaN < 0` is `false`, so a `NaN` throttleMs passed and degraded to
192
+ no-throttle. Both guards now include `Number.isFinite()` as the first check,
193
+ consistent with the documented contract that invalid values throw `EmitterError`.
194
+
195
+ ### Tests
196
+ - Added regression tests locking in `NaN` rejection for both `sampleRate` and
197
+ `throttleMs` (wildcard-throttle.test.ts §A6, §B4).
198
+ - Added regression tests confirming that a `once` handler that throws is still
199
+ removed and does not re-fire on the next emit — for both typed and wildcard
200
+ once subscriptions (emitter.test.ts §C2a, §C2b).
201
+ - Added regression tests for post-dispose guard coverage: `off()` after
202
+ `dispose()` throws `EmitterDisposedError`; `clear()` after `dispose()` throws
203
+ `EmitterDisposedError`; the unsubscribe function returned by `on()` is a safe
204
+ no-op (does not throw) after `dispose()` (emitter.test.ts §H2a, §H2b, §H2c).
205
+
185
206
  ## [0.4.0] - 2026-05-29
186
207
 
187
208
  Dependency hygiene + stability freeze. No runtime API addition; `dist/` is byte-identical to 0.3.1 (no `src/` change). Consumer-facing behaviour is unchanged.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aieventjs",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "description": "Small, strict, typed event emitter — on() returns an unsubscribe function, once is built-in, AbortSignal is first-class, dispose() is idempotent, wildcard '*' handlers preserved. Mitt-shaped API; ai*js conventions everywhere else.",
5
5
  "keywords": [
6
6
  "event-emitter",
@@ -13,7 +13,7 @@
13
13
  "typescript",
14
14
  "esm"
15
15
  ],
16
- "author": "ysl <ysl@sheng.page>",
16
+ "author": "yshengliao",
17
17
  "license": "MIT",
18
18
  "homepage": "https://github.com/yshengliao/aieventjs#readme",
19
19
  "repository": {