aieventjs 0.5.8 → 0.5.9
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/README.md +2 -2
- package/README_ZHTW.md +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/llms-full.txt +8 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Small, strict, typed event emitter with ai*js lifecycle conventions: `on()` returns unsubscribe, `once` is built in, `AbortSignal` is first-class, wildcard handlers are supported, and `dispose()` is idempotent.
|
|
4
4
|
|
|
5
|
-
> **Status: 0.5.
|
|
5
|
+
> **Status: 0.5.9 - stable 1.0-track surface.** The root entry is the public API.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -49,7 +49,7 @@ events.dispose();
|
|
|
49
49
|
- Default error policy is mitt-like: the first throwing handler aborts dispatch. Use `captureHandlerErrors` or per-handler `captureErrors` to swallow/report and continue.
|
|
50
50
|
- Wildcard handlers receive `(type, payload)`, not just payload.
|
|
51
51
|
- Use `on("*", handler, { once: true })` for wildcard-once. `once("*")` is intentionally not part of the typed public overload.
|
|
52
|
-
- `throttleMs` uses `
|
|
52
|
+
- `throttleMs` uses `performance.now()` (monotonic); system-clock corrections do not affect throttle windows.
|
|
53
53
|
- `sampleRate` is wildcard-only and uses `Math.random()` per dispatch.
|
|
54
54
|
- `dispose()` is permanent; post-dispose APIs throw `EmitterDisposedError` except cleanup calls that are no-ops by design.
|
|
55
55
|
|
package/README_ZHTW.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var E=class extends Error{name="EmitterError"},
|
|
1
|
+
'use strict';var E=class extends Error{name="EmitterError"},k=class extends Error{name="EmitterDisposedError"};function O(d,c){let o=d.findIndex(i=>i.u===c);if(o>=0){let i=d[o];i!==void 0&&(i.c?.(),i.c=void 0),d.splice(o,1);}}function H(d){for(let c of d)c.c?.(),c.c=void 0;}function y(d,c,o){d.push(c);let i=()=>{let f=d.indexOf(c);f>=0&&d.splice(f,1),c.c?.(),c.c=void 0;};if(o!==void 0){let f=()=>i();o.addEventListener("abort",f,{once:true}),c.c=()=>o.removeEventListener("abort",f);}return i}function z(d){let c=d?.captureHandlerErrors,o=new Map,i=[],f=false;function p(){if(f)throw new k("aieventjs: emitter has been disposed")}function W(e){let r=o.get(e);return r===void 0&&(r=[],o.set(e,r)),r}function b(e,r,t){p();let s=t?.sampleRate,u=t?.throttleMs;if(e==="*"){if(t?.captureErrors!==void 0)throw new E("aieventjs: captureErrors invalid on *")}else if(s!==void 0)throw new E("aieventjs: sampleRate wildcard-only");if(s!==void 0&&(!Number.isFinite(s)||s<=0||s>1))throw new E("aieventjs: sampleRate must be in (0,1]");if(u!==void 0&&(!Number.isFinite(u)||u<0))throw new E("aieventjs: throttleMs must be >= 0");let l=t?.signal;if(l?.aborted)return ()=>{};if(e==="*"){let v=r;if(t?.once){let g=y(i,{h:(h,S)=>{g(),v(h,S);},u:v,c:void 0,r:s,tm:u},l);return g}return y(i,{h:v,u:v,c:void 0,r:s,tm:u},l)}let n=r,a=t?.captureErrors,m=W(e),A=()=>{!m.length&&o.get(e)===m&&o.delete(e);};if(t?.once){let v,w=()=>{v(),A();};return v=y(m,{h:h=>{w(),n(h);},u:n,c:void 0,ce:a,tm:u},l),w}let P=y(m,{h:n,u:n,c:void 0,ce:a,tm:u},l);return ()=>{P(),A();}}function R(e,r){return b(e,r,{once:true})}function M(e,r){if(p(),e==="*"){r===void 0?(H(i),i.length=0):O(i,r);return}let t=o.get(e);t!==void 0&&(r===void 0?(H(t),t.length=0,o.delete(e)):(O(t,r),t.length||o.delete(e)));}function x(e,r,t,s){if(e===void 0||e===false)throw r;if(typeof e=="function")try{e(r,t,s);}catch{}}function j(e,r){p();let t=e,s=r,u=(o.get(t)??[]).slice(),l=i.slice();for(let n of u){if(n.tm){let a=performance.now();if(n.ts!==void 0&&a-n.ts<n.tm)continue;n.ts=a;}try{n.h(s);}catch(a){x(n.ce!==void 0?n.ce:c,a,t,s);}}for(let n of l)if(!(n.r!==void 0&&Math.random()>=n.r)){if(n.tm){let a=performance.now();if(n.ts!==void 0&&a-n.ts<n.tm)continue;n.ts=a;}try{n.h(t,s);}catch(a){x(c,a,t,s);}}}function K(){for(let e of o.values())H(e),e.length=0;H(i),o.clear(),i.length=0;}return {on:b,once:R,off:M,emit:j,clear(){p(),K();},dispose(){f||(K(),f=true);},get disposed(){return f},get _mapSize(){return o.size}}}exports.EmitterDisposedError=k;exports.EmitterError=E;exports.createEmitter=z;//# sourceMappingURL=index.cjs.map
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.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","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 * Per-handler leading-edge throttle. Minimum milliseconds between successive\n * calls to this handler. The first dispatch after subscription always fires;\n * subsequent dispatches within `throttleMs` are dropped (not queued).\n * Uses `performance.now()` (monotonic). 0 = no throttle. Non-finite or\n * negative values are rejected at `on()` time.\n *\n * Valid on both typed and wildcard `\"*\"` subscriptions (since v0.5.3); each\n * handler keeps its own throttle clock. Useful for per-event HUD throttling,\n * e.g. a `credits/change` event that fires every frame.\n *\n * @remarks\n * The throttle clock uses `performance.now()`, which is monotonic and\n * unaffected by system-clock corrections (NTP step-backs, manual adjustments).\n * This ensures handlers are never silently muted by a wall-clock regression.\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 * @remarks\n * **`\"*\"` is not a valid `type` argument for `once()`.** The wildcard is\n * handled by the `on(\"*\", handler, { once: true })` overload instead.\n * The explicit rejection overload below ensures `once(\"*\", ...)` is a\n * compile-time error (handler typed as `never`). (EVT-B-02)\n */\n /** @internal — compile-time rejection: `once(\"*\", handler)` is a type error. */\n once(type: \"*\", handler: never): never;\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` set on a typed subscription; `sampleRate` outside `(0, 1]`; or\n * `throttleMs` non-finite or 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 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 (typed or wildcard; v0.5.3)\n ts?: number | undefined; // last call timestamp — mutated during dispatch (throttle clock)\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 * @remarks\n * Declare the event map with a `type` alias, not an `interface`. The `Events`\n * generic is constrained to `Record<string, unknown>`, and a *plain* TypeScript\n * `interface` has no implicit index signature, so it fails the constraint with\n * *\"Index signature for type 'string' is missing in type ...\"*. A `type` object\n * literal satisfies the constraint structurally. (An `interface` with an explicit\n * index signature or `extends Record<string, unknown>` also compiles, but widens\n * `keyof Events` to `string`, losing strict event-name checking.)\n *\n * ```ts\n * // ❌ interface — fails the Record<string, unknown> constraint\n * interface Events { \"user:login\": { id: string } }\n * const bus = createEmitter<Events>(); // TS2344\n *\n * // ✅ type — satisfies the constraint\n * type Events = { \"user:login\": { id: string } };\n * const bus = createEmitter<Events>();\n * ```\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 // v0.5.3: throttleMs is now valid on typed handlers too (per-handler clock);\n // sampleRate remains wildcard-only.\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 }\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 tm: tm2,\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, tm: tm2 }, 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 arr.length = 0;\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 if (e.tm) {\n const now = performance.now();\n if (e.ts !== undefined && now - e.ts < e.tm) continue;\n e.ts = now;\n }\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 = performance.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()) {\n flush(a);\n a.length = 0;\n }\n flush(w);\n t.clear();\n w.length = 0;\n }\n\n return {\n on: on as Emitter<Events>[\"on\"],\n once: once as Emitter<Events>[\"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","i","e","flush","sub","sig","rm","fn","createEmitter","opts","cap","t","w","d","ck","ga","k","a","on","type","handler","o","sr","tm2","tp","p","ce","prune","unsub","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 * Per-handler leading-edge throttle. Minimum milliseconds between successive\n * calls to this handler. The first dispatch after subscription always fires;\n * subsequent dispatches within `throttleMs` are dropped (not queued).\n * Uses `performance.now()` (monotonic). 0 = no throttle. Non-finite or\n * negative values are rejected at `on()` time.\n *\n * Valid on both typed and wildcard `\"*\"` subscriptions (since v0.5.3); each\n * handler keeps its own throttle clock. Useful for per-event HUD throttling,\n * e.g. a `credits/change` event that fires every frame.\n *\n * @remarks\n * The throttle clock uses `performance.now()`, which is monotonic and\n * unaffected by system-clock corrections (NTP step-backs, manual adjustments).\n * This ensures handlers are never silently muted by a wall-clock regression.\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 * @remarks\n * **`\"*\"` is not a valid `type` argument for `once()`.** The wildcard is\n * handled by the `on(\"*\", handler, { once: true })` overload instead.\n * The explicit rejection overload below ensures `once(\"*\", ...)` is a\n * compile-time error (handler typed as `never`). (EVT-B-02)\n */\n /** @internal — compile-time rejection: `once(\"*\", handler)` is a type error. */\n once(type: \"*\", handler: never): never;\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` set on a typed subscription; `sampleRate` outside `(0, 1]`; or\n * `throttleMs` non-finite or 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 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 (typed or wildcard; v0.5.3)\n ts?: number | undefined; // last call timestamp — mutated during dispatch (throttle clock)\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 * @remarks\n * Declare the event map with a `type` alias, not an `interface`. The `Events`\n * generic is constrained to `Record<string, unknown>`, and a *plain* TypeScript\n * `interface` has no implicit index signature, so it fails the constraint with\n * *\"Index signature for type 'string' is missing in type ...\"*. A `type` object\n * literal satisfies the constraint structurally. (An `interface` with an explicit\n * index signature or `extends Record<string, unknown>` also compiles, but widens\n * `keyof Events` to `string`, losing strict event-name checking.)\n *\n * ```ts\n * // ❌ interface — fails the Record<string, unknown> constraint\n * interface Events { \"user:login\": { id: string } }\n * const bus = createEmitter<Events>(); // TS2344\n *\n * // ✅ type — satisfies the constraint\n * type Events = { \"user:login\": { id: string } };\n * const bus = createEmitter<Events>();\n * ```\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 // v0.5.3: throttleMs is now valid on typed handlers too (per-handler clock);\n // sampleRate remains wildcard-only.\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 }\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 const arr = ga(type);\n const prune = () => {\n // Identity guard: only delete the key when `arr` is STILL the array\n // currently mapped. ga() mints a NEW array when a deleted key is\n // re-subscribed, so a stale/double unsub of the original handler must\n // not prune the live re-subscribed key (idempotency).\n if (!arr.length && t.get(type) === arr) t.delete(type);\n };\n if (o?.once) {\n let unsub!: () => void;\n const rm = () => {\n unsub();\n prune();\n };\n const e: E<AH> = {\n h: (p) => {\n rm();\n fn(p);\n },\n u: fn,\n c: undefined,\n ce: ce,\n tm: tm2,\n };\n unsub = sub(arr, e, sig);\n return rm;\n }\n const unsub = sub(arr, { h: fn, u: fn, c: undefined, ce: ce, tm: tm2 }, sig);\n return () => {\n unsub();\n prune();\n };\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 arr.length = 0;\n t.delete(type);\n } else {\n rmByUser(arr, handler as AH);\n if (!arr.length) t.delete(type);\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 if (e.tm) {\n const now = performance.now();\n if (e.ts !== undefined && now - e.ts < e.tm) continue;\n e.ts = now;\n }\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 = performance.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()) {\n flush(a);\n a.length = 0;\n }\n flush(w);\n t.clear();\n w.length = 0;\n }\n\n // _mapSize: test-only observation seam (not on the public Emitter interface).\n // Casted away at the return type; exposes t.size for Map-pruning regression tests.\n return {\n on: on as Emitter<Events>[\"on\"],\n once: once as Emitter<Events>[\"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 get _mapSize() {\n return t.size;\n },\n } as unknown as Emitter<Events>;\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var E=class extends Error{name="EmitterError"},
|
|
1
|
+
var E=class extends Error{name="EmitterError"},k=class extends Error{name="EmitterDisposedError"};function O(d,c){let o=d.findIndex(i=>i.u===c);if(o>=0){let i=d[o];i!==void 0&&(i.c?.(),i.c=void 0),d.splice(o,1);}}function H(d){for(let c of d)c.c?.(),c.c=void 0;}function y(d,c,o){d.push(c);let i=()=>{let f=d.indexOf(c);f>=0&&d.splice(f,1),c.c?.(),c.c=void 0;};if(o!==void 0){let f=()=>i();o.addEventListener("abort",f,{once:true}),c.c=()=>o.removeEventListener("abort",f);}return i}function z(d){let c=d?.captureHandlerErrors,o=new Map,i=[],f=false;function p(){if(f)throw new k("aieventjs: emitter has been disposed")}function W(e){let r=o.get(e);return r===void 0&&(r=[],o.set(e,r)),r}function b(e,r,t){p();let s=t?.sampleRate,u=t?.throttleMs;if(e==="*"){if(t?.captureErrors!==void 0)throw new E("aieventjs: captureErrors invalid on *")}else if(s!==void 0)throw new E("aieventjs: sampleRate wildcard-only");if(s!==void 0&&(!Number.isFinite(s)||s<=0||s>1))throw new E("aieventjs: sampleRate must be in (0,1]");if(u!==void 0&&(!Number.isFinite(u)||u<0))throw new E("aieventjs: throttleMs must be >= 0");let l=t?.signal;if(l?.aborted)return ()=>{};if(e==="*"){let v=r;if(t?.once){let g=y(i,{h:(h,S)=>{g(),v(h,S);},u:v,c:void 0,r:s,tm:u},l);return g}return y(i,{h:v,u:v,c:void 0,r:s,tm:u},l)}let n=r,a=t?.captureErrors,m=W(e),A=()=>{!m.length&&o.get(e)===m&&o.delete(e);};if(t?.once){let v,w=()=>{v(),A();};return v=y(m,{h:h=>{w(),n(h);},u:n,c:void 0,ce:a,tm:u},l),w}let P=y(m,{h:n,u:n,c:void 0,ce:a,tm:u},l);return ()=>{P(),A();}}function R(e,r){return b(e,r,{once:true})}function M(e,r){if(p(),e==="*"){r===void 0?(H(i),i.length=0):O(i,r);return}let t=o.get(e);t!==void 0&&(r===void 0?(H(t),t.length=0,o.delete(e)):(O(t,r),t.length||o.delete(e)));}function x(e,r,t,s){if(e===void 0||e===false)throw r;if(typeof e=="function")try{e(r,t,s);}catch{}}function j(e,r){p();let t=e,s=r,u=(o.get(t)??[]).slice(),l=i.slice();for(let n of u){if(n.tm){let a=performance.now();if(n.ts!==void 0&&a-n.ts<n.tm)continue;n.ts=a;}try{n.h(s);}catch(a){x(n.ce!==void 0?n.ce:c,a,t,s);}}for(let n of l)if(!(n.r!==void 0&&Math.random()>=n.r)){if(n.tm){let a=performance.now();if(n.ts!==void 0&&a-n.ts<n.tm)continue;n.ts=a;}try{n.h(t,s);}catch(a){x(c,a,t,s);}}}function K(){for(let e of o.values())H(e),e.length=0;H(i),o.clear(),i.length=0;}return {on:b,once:R,off:M,emit:j,clear(){p(),K();},dispose(){f||(K(),f=true);},get disposed(){return f},get _mapSize(){return o.size}}}export{k as EmitterDisposedError,E as EmitterError,z 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","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 * Per-handler leading-edge throttle. Minimum milliseconds between successive\n * calls to this handler. The first dispatch after subscription always fires;\n * subsequent dispatches within `throttleMs` are dropped (not queued).\n * Uses `performance.now()` (monotonic). 0 = no throttle. Non-finite or\n * negative values are rejected at `on()` time.\n *\n * Valid on both typed and wildcard `\"*\"` subscriptions (since v0.5.3); each\n * handler keeps its own throttle clock. Useful for per-event HUD throttling,\n * e.g. a `credits/change` event that fires every frame.\n *\n * @remarks\n * The throttle clock uses `performance.now()`, which is monotonic and\n * unaffected by system-clock corrections (NTP step-backs, manual adjustments).\n * This ensures handlers are never silently muted by a wall-clock regression.\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 * @remarks\n * **`\"*\"` is not a valid `type` argument for `once()`.** The wildcard is\n * handled by the `on(\"*\", handler, { once: true })` overload instead.\n * The explicit rejection overload below ensures `once(\"*\", ...)` is a\n * compile-time error (handler typed as `never`). (EVT-B-02)\n */\n /** @internal — compile-time rejection: `once(\"*\", handler)` is a type error. */\n once(type: \"*\", handler: never): never;\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` set on a typed subscription; `sampleRate` outside `(0, 1]`; or\n * `throttleMs` non-finite or 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 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 (typed or wildcard; v0.5.3)\n ts?: number | undefined; // last call timestamp — mutated during dispatch (throttle clock)\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 * @remarks\n * Declare the event map with a `type` alias, not an `interface`. The `Events`\n * generic is constrained to `Record<string, unknown>`, and a *plain* TypeScript\n * `interface` has no implicit index signature, so it fails the constraint with\n * *\"Index signature for type 'string' is missing in type ...\"*. A `type` object\n * literal satisfies the constraint structurally. (An `interface` with an explicit\n * index signature or `extends Record<string, unknown>` also compiles, but widens\n * `keyof Events` to `string`, losing strict event-name checking.)\n *\n * ```ts\n * // ❌ interface — fails the Record<string, unknown> constraint\n * interface Events { \"user:login\": { id: string } }\n * const bus = createEmitter<Events>(); // TS2344\n *\n * // ✅ type — satisfies the constraint\n * type Events = { \"user:login\": { id: string } };\n * const bus = createEmitter<Events>();\n * ```\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 // v0.5.3: throttleMs is now valid on typed handlers too (per-handler clock);\n // sampleRate remains wildcard-only.\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 }\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 tm: tm2,\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, tm: tm2 }, 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 arr.length = 0;\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 if (e.tm) {\n const now = performance.now();\n if (e.ts !== undefined && now - e.ts < e.tm) continue;\n e.ts = now;\n }\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 = performance.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()) {\n flush(a);\n a.length = 0;\n }\n flush(w);\n t.clear();\n w.length = 0;\n }\n\n return {\n on: on as Emitter<Events>[\"on\"],\n once: once as Emitter<Events>[\"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","i","e","flush","sub","sig","rm","fn","createEmitter","opts","cap","t","w","d","ck","ga","k","a","on","type","handler","o","sr","tm2","tp","p","ce","prune","unsub","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 * Per-handler leading-edge throttle. Minimum milliseconds between successive\n * calls to this handler. The first dispatch after subscription always fires;\n * subsequent dispatches within `throttleMs` are dropped (not queued).\n * Uses `performance.now()` (monotonic). 0 = no throttle. Non-finite or\n * negative values are rejected at `on()` time.\n *\n * Valid on both typed and wildcard `\"*\"` subscriptions (since v0.5.3); each\n * handler keeps its own throttle clock. Useful for per-event HUD throttling,\n * e.g. a `credits/change` event that fires every frame.\n *\n * @remarks\n * The throttle clock uses `performance.now()`, which is monotonic and\n * unaffected by system-clock corrections (NTP step-backs, manual adjustments).\n * This ensures handlers are never silently muted by a wall-clock regression.\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 * @remarks\n * **`\"*\"` is not a valid `type` argument for `once()`.** The wildcard is\n * handled by the `on(\"*\", handler, { once: true })` overload instead.\n * The explicit rejection overload below ensures `once(\"*\", ...)` is a\n * compile-time error (handler typed as `never`). (EVT-B-02)\n */\n /** @internal — compile-time rejection: `once(\"*\", handler)` is a type error. */\n once(type: \"*\", handler: never): never;\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` set on a typed subscription; `sampleRate` outside `(0, 1]`; or\n * `throttleMs` non-finite or 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 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 (typed or wildcard; v0.5.3)\n ts?: number | undefined; // last call timestamp — mutated during dispatch (throttle clock)\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 * @remarks\n * Declare the event map with a `type` alias, not an `interface`. The `Events`\n * generic is constrained to `Record<string, unknown>`, and a *plain* TypeScript\n * `interface` has no implicit index signature, so it fails the constraint with\n * *\"Index signature for type 'string' is missing in type ...\"*. A `type` object\n * literal satisfies the constraint structurally. (An `interface` with an explicit\n * index signature or `extends Record<string, unknown>` also compiles, but widens\n * `keyof Events` to `string`, losing strict event-name checking.)\n *\n * ```ts\n * // ❌ interface — fails the Record<string, unknown> constraint\n * interface Events { \"user:login\": { id: string } }\n * const bus = createEmitter<Events>(); // TS2344\n *\n * // ✅ type — satisfies the constraint\n * type Events = { \"user:login\": { id: string } };\n * const bus = createEmitter<Events>();\n * ```\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 // v0.5.3: throttleMs is now valid on typed handlers too (per-handler clock);\n // sampleRate remains wildcard-only.\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 }\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 const arr = ga(type);\n const prune = () => {\n // Identity guard: only delete the key when `arr` is STILL the array\n // currently mapped. ga() mints a NEW array when a deleted key is\n // re-subscribed, so a stale/double unsub of the original handler must\n // not prune the live re-subscribed key (idempotency).\n if (!arr.length && t.get(type) === arr) t.delete(type);\n };\n if (o?.once) {\n let unsub!: () => void;\n const rm = () => {\n unsub();\n prune();\n };\n const e: E<AH> = {\n h: (p) => {\n rm();\n fn(p);\n },\n u: fn,\n c: undefined,\n ce: ce,\n tm: tm2,\n };\n unsub = sub(arr, e, sig);\n return rm;\n }\n const unsub = sub(arr, { h: fn, u: fn, c: undefined, ce: ce, tm: tm2 }, sig);\n return () => {\n unsub();\n prune();\n };\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 arr.length = 0;\n t.delete(type);\n } else {\n rmByUser(arr, handler as AH);\n if (!arr.length) t.delete(type);\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 if (e.tm) {\n const now = performance.now();\n if (e.ts !== undefined && now - e.ts < e.tm) continue;\n e.ts = now;\n }\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 = performance.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()) {\n flush(a);\n a.length = 0;\n }\n flush(w);\n t.clear();\n w.length = 0;\n }\n\n // _mapSize: test-only observation seam (not on the public Emitter interface).\n // Casted away at the return type; exposes t.size for Map-pruning regression tests.\n return {\n on: on as Emitter<Events>[\"on\"],\n once: once as Emitter<Events>[\"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 get _mapSize() {\n return t.size;\n },\n } as unknown as Emitter<Events>;\n}\n"]}
|
package/llms-full.txt
CHANGED
|
@@ -15,7 +15,7 @@ The short index lives at `llms.txt` (see https://llmstxt.org/).
|
|
|
15
15
|
|
|
16
16
|
Small, strict, typed event emitter with ai*js lifecycle conventions: `on()` returns unsubscribe, `once` is built in, `AbortSignal` is first-class, wildcard handlers are supported, and `dispose()` is idempotent.
|
|
17
17
|
|
|
18
|
-
> **Status: 0.5.
|
|
18
|
+
> **Status: 0.5.9 - stable 1.0-track surface.** The root entry is the public API.
|
|
19
19
|
|
|
20
20
|
## Install
|
|
21
21
|
|
|
@@ -62,7 +62,7 @@ events.dispose();
|
|
|
62
62
|
- Default error policy is mitt-like: the first throwing handler aborts dispatch. Use `captureHandlerErrors` or per-handler `captureErrors` to swallow/report and continue.
|
|
63
63
|
- Wildcard handlers receive `(type, payload)`, not just payload.
|
|
64
64
|
- Use `on("*", handler, { once: true })` for wildcard-once. `once("*")` is intentionally not part of the typed public overload.
|
|
65
|
-
- `throttleMs` uses `
|
|
65
|
+
- `throttleMs` uses `performance.now()` (monotonic); system-clock corrections do not affect throttle windows.
|
|
66
66
|
- `sampleRate` is wildcard-only and uses `Math.random()` per dispatch.
|
|
67
67
|
- `dispose()` is permanent; post-dispose APIs throw `EmitterDisposedError` except cleanup calls that are no-ops by design.
|
|
68
68
|
|
|
@@ -88,6 +88,11 @@ All notable changes to aieventjs are summarized here.
|
|
|
88
88
|
|
|
89
89
|
## [Unreleased]
|
|
90
90
|
|
|
91
|
+
## [0.5.9] - 2026-06-29
|
|
92
|
+
|
|
93
|
+
- Fixed: per-handler unsubscribe now prunes the empty handler array from the typed-handler map (no unbounded growth on high-cardinality / churning event names), with a Map-identity guard so a stale or double unsubscribe after re-subscribing cannot delete a live key.
|
|
94
|
+
- Docs: `throttleMs` is documented as monotonic (`performance.now()`); removed the stale wall-clock caveat.
|
|
95
|
+
|
|
91
96
|
## [0.5.8] - 2026-06-14
|
|
92
97
|
|
|
93
98
|
- Fixed: per-handler `throttleMs` now uses the monotonic `performance.now()` clock instead of `Date.now()`, so a wall-clock regression can no longer silently mute throttled handlers.
|
|
@@ -130,12 +135,11 @@ All notable changes to aieventjs are summarized here.
|
|
|
130
135
|
- Handler lists are snapshotted before dispatch.
|
|
131
136
|
- Default handler errors propagate; capture options can swallow/report.
|
|
132
137
|
- `AbortSignal` removes subscriptions and pre-aborted signals do not register.
|
|
133
|
-
- `throttleMs` uses `
|
|
138
|
+
- `throttleMs` uses `performance.now()` (monotonic) and is unaffected by system-clock corrections.
|
|
134
139
|
|
|
135
140
|
## Drafts
|
|
136
141
|
|
|
137
142
|
- Async handler tracking is not implemented.
|
|
138
|
-
- A future minor may switch throttle timing to monotonic time or add a runtime guard around wildcard `once()`.
|
|
139
143
|
|
|
140
144
|
---
|
|
141
145
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aieventjs",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.9",
|
|
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",
|