hookified 2.2.0 → 3.0.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/README.md +18 -1
- package/dist/browser/index.global.js +34 -11
- package/dist/browser/index.global.js.map +1 -1
- package/dist/browser/index.js +34 -11
- package/dist/browser/index.js.map +1 -1
- package/dist/node/index.cjs +30 -7
- package/dist/node/index.d.cts +9 -0
- package/dist/node/index.d.ts +9 -0
- package/dist/node/index.js +30 -7
- package/package.json +28 -25
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
# Features
|
|
13
13
|
- Simple replacement for EventEmitter
|
|
14
14
|
- Async / Sync Middleware Hooks for Your Methods
|
|
15
|
-
- ESM / CJS with Types
|
|
15
|
+
- ESM / CJS with Types
|
|
16
16
|
- Browser Support and Delivered via CDN
|
|
17
17
|
- Ability to throw errors in hooks
|
|
18
18
|
- Ability to pass in a logger (such as Pino) for errors
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
# Table of Contents
|
|
29
29
|
- [Installation](#installation)
|
|
30
30
|
- [Usage](#usage)
|
|
31
|
+
- [Migrating from v2 to v3](#migrating-from-v2-to-v3)
|
|
31
32
|
- [Migrating from v1 to v2](#migrating-from-v1-to-v2)
|
|
32
33
|
- [Using it in the Browser](#using-it-in-the-browser)
|
|
33
34
|
- [Hooks](#hooks)
|
|
@@ -1363,6 +1364,22 @@ This shows how on par `hookified` is to the native `EventEmitter` and popular `e
|
|
|
1363
1364
|
|
|
1364
1365
|
_Note: the `EventEmitter` version is Nodejs versioning._
|
|
1365
1366
|
|
|
1367
|
+
# Migrating from v2 to v3
|
|
1368
|
+
|
|
1369
|
+
v3 has no API changes. The only breaking change is the minimum Node.js version requirement.
|
|
1370
|
+
|
|
1371
|
+
## Breaking Changes
|
|
1372
|
+
|
|
1373
|
+
| Change | Summary |
|
|
1374
|
+
|---|---|
|
|
1375
|
+
| Node.js version | Minimum required version is now `>=22.18.0` (previously no `engines` constraint) |
|
|
1376
|
+
|
|
1377
|
+
### Node.js >=22.18.0 required
|
|
1378
|
+
|
|
1379
|
+
The `engines` field in `package.json` now requires Node.js 22.18.0 or later. Node.js 20 reached end-of-life in April 2026.
|
|
1380
|
+
|
|
1381
|
+
**Migration:** Upgrade to Node.js 22 LTS or Node.js 24+. No code changes are required — the library API is identical to v2.
|
|
1382
|
+
|
|
1366
1383
|
# Migrating from v1 to v2
|
|
1367
1384
|
|
|
1368
1385
|
## Quick Guide
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
var Hookified = (function(exports) {
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
//#region \0@oxc-project+runtime@0.
|
|
3
|
+
//#region \0@oxc-project+runtime@0.135.0/helpers/esm/typeof.js
|
|
4
4
|
function _typeof(o) {
|
|
5
5
|
"@babel/helpers - typeof";
|
|
6
6
|
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
|
|
@@ -10,7 +10,7 @@ var Hookified = (function(exports) {
|
|
|
10
10
|
}, _typeof(o);
|
|
11
11
|
}
|
|
12
12
|
//#endregion
|
|
13
|
-
//#region \0@oxc-project+runtime@0.
|
|
13
|
+
//#region \0@oxc-project+runtime@0.135.0/helpers/esm/toPrimitive.js
|
|
14
14
|
function toPrimitive(t, r) {
|
|
15
15
|
if ("object" != _typeof(t) || !t) return t;
|
|
16
16
|
var e = t[Symbol.toPrimitive];
|
|
@@ -22,13 +22,13 @@ var Hookified = (function(exports) {
|
|
|
22
22
|
return ("string" === r ? String : Number)(t);
|
|
23
23
|
}
|
|
24
24
|
//#endregion
|
|
25
|
-
//#region \0@oxc-project+runtime@0.
|
|
25
|
+
//#region \0@oxc-project+runtime@0.135.0/helpers/esm/toPropertyKey.js
|
|
26
26
|
function toPropertyKey(t) {
|
|
27
27
|
var i = toPrimitive(t, "string");
|
|
28
28
|
return "symbol" == _typeof(i) ? i : i + "";
|
|
29
29
|
}
|
|
30
30
|
//#endregion
|
|
31
|
-
//#region \0@oxc-project+runtime@0.
|
|
31
|
+
//#region \0@oxc-project+runtime@0.135.0/helpers/esm/defineProperty.js
|
|
32
32
|
function _defineProperty(e, r, t) {
|
|
33
33
|
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
34
34
|
value: t,
|
|
@@ -106,6 +106,7 @@ var Hookified = (function(exports) {
|
|
|
106
106
|
this.off(eventName, onceListener);
|
|
107
107
|
listener(...arguments_);
|
|
108
108
|
};
|
|
109
|
+
onceListener._originalListener = listener;
|
|
109
110
|
this.on(eventName, onceListener);
|
|
110
111
|
return this;
|
|
111
112
|
}
|
|
@@ -166,6 +167,7 @@ var Hookified = (function(exports) {
|
|
|
166
167
|
this.off(eventName, onceListener);
|
|
167
168
|
listener(...arguments_);
|
|
168
169
|
};
|
|
170
|
+
onceListener._originalListener = listener;
|
|
169
171
|
this.prependListener(eventName, onceListener);
|
|
170
172
|
return this;
|
|
171
173
|
}
|
|
@@ -219,6 +221,19 @@ var Hookified = (function(exports) {
|
|
|
219
221
|
return this;
|
|
220
222
|
}
|
|
221
223
|
/**
|
|
224
|
+
* Determines whether a stored listener matches the listener provided to off().
|
|
225
|
+
* A match occurs when the references are identical, or when the stored listener
|
|
226
|
+
* is a once-wrapper whose original listener equals the provided reference.
|
|
227
|
+
* @param {EventListener} stored - the listener currently stored
|
|
228
|
+
* @param {EventListener} target - the listener passed to off()
|
|
229
|
+
* @returns {boolean} true if the stored listener should be removed
|
|
230
|
+
*/
|
|
231
|
+
matchesListener(stored, target) {
|
|
232
|
+
if (stored === target) return true;
|
|
233
|
+
const original = stored._originalListener;
|
|
234
|
+
return original !== void 0 && original === target;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
222
237
|
* Removes a listener for a specific event
|
|
223
238
|
* @param {string | symbol} event
|
|
224
239
|
* @param {EventListener} listener
|
|
@@ -228,10 +243,11 @@ var Hookified = (function(exports) {
|
|
|
228
243
|
const entry = this._eventListeners.get(event);
|
|
229
244
|
if (entry === void 0) return this;
|
|
230
245
|
if (typeof entry === "function") {
|
|
231
|
-
if (entry
|
|
246
|
+
if (this.matchesListener(entry, listener)) this._eventListeners.delete(event);
|
|
232
247
|
return this;
|
|
233
248
|
}
|
|
234
|
-
|
|
249
|
+
let index = entry.indexOf(listener);
|
|
250
|
+
if (index === -1) index = entry.findIndex((stored) => this.matchesListener(stored, listener));
|
|
235
251
|
if (index !== -1) if (entry.length === 2) this._eventListeners.set(event, entry[1 - index]);
|
|
236
252
|
else if (entry.length === 1) this._eventListeners.delete(event);
|
|
237
253
|
else entry.splice(index, 1);
|
|
@@ -252,10 +268,11 @@ var Hookified = (function(exports) {
|
|
|
252
268
|
else if (argumentLength === 2) entry(arguments_[0], arguments_[1]);
|
|
253
269
|
else entry(...arguments_);
|
|
254
270
|
else {
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
else
|
|
271
|
+
const listeners = entry.slice();
|
|
272
|
+
const len = listeners.length;
|
|
273
|
+
for (let i = 0; i < len; i++) if (argumentLength === 1) listeners[i](arguments_[0]);
|
|
274
|
+
else if (argumentLength === 2) listeners[i](arguments_[0], arguments_[1]);
|
|
275
|
+
else listeners[i](...arguments_);
|
|
259
276
|
}
|
|
260
277
|
result = true;
|
|
261
278
|
}
|
|
@@ -714,6 +731,7 @@ var Hookified = (function(exports) {
|
|
|
714
731
|
});
|
|
715
732
|
return hook.handler(...arguments_);
|
|
716
733
|
};
|
|
734
|
+
wrappedHandler._originalHandler = hook.handler;
|
|
717
735
|
return this.onHook({
|
|
718
736
|
id: hook.id,
|
|
719
737
|
event: hook.event,
|
|
@@ -737,6 +755,7 @@ var Hookified = (function(exports) {
|
|
|
737
755
|
});
|
|
738
756
|
return hook.handler(...arguments_);
|
|
739
757
|
};
|
|
758
|
+
wrappedHandler._originalHandler = hook.handler;
|
|
740
759
|
this.onHook({
|
|
741
760
|
id: hook.id,
|
|
742
761
|
event: hook.event,
|
|
@@ -752,7 +771,11 @@ var Hookified = (function(exports) {
|
|
|
752
771
|
this.validateHookName(hook.event);
|
|
753
772
|
const eventHandlers = this._hooks.get(hook.event);
|
|
754
773
|
if (eventHandlers) {
|
|
755
|
-
|
|
774
|
+
let index = eventHandlers.findIndex((h) => h.handler === hook.handler);
|
|
775
|
+
if (index === -1) index = eventHandlers.findIndex((h) => {
|
|
776
|
+
const original = h.handler._originalHandler;
|
|
777
|
+
return original !== void 0 && original === hook.handler;
|
|
778
|
+
});
|
|
756
779
|
if (index !== -1) {
|
|
757
780
|
eventHandlers.splice(index, 1);
|
|
758
781
|
if (eventHandlers.length === 0) this._hooks.delete(hook.event);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.global.js","names":[],"sources":["../../src/eventified.ts","../../src/hooks/hook.ts","../../src/hooks/parallel-hook.ts","../../src/hooks/waterfall-hook.ts","../../src/index.ts"],"sourcesContent":["// biome-ignore-all lint/suspicious/noExplicitAny: this is for event emitter compatibility\nimport type {\n\tEventEmitterOptions,\n\tEventListener,\n\tIEventEmitter,\n\tLogger,\n} from \"./types.js\";\n\nexport type { EventEmitterOptions, EventListener, IEventEmitter };\n\nconst ERROR_EVENT = \"error\";\n\nexport class Eventified implements IEventEmitter {\n\tprivate readonly _eventListeners: Map<\n\t\tstring | symbol,\n\t\tEventListener | EventListener[]\n\t>;\n\tprivate _maxListeners: number;\n\tprivate _eventLogger?: Logger;\n\tprivate _throwOnEmitError = false;\n\tprivate _throwOnEmptyListeners = true;\n\n\tconstructor(options?: EventEmitterOptions) {\n\t\tthis._eventListeners = new Map<\n\t\t\tstring | symbol,\n\t\t\tEventListener | EventListener[]\n\t\t>();\n\t\tthis._maxListeners = 0; // Default is 0 (unlimited)\n\n\t\tthis._eventLogger = options?.eventLogger;\n\n\t\tif (options?.throwOnEmitError !== undefined) {\n\t\t\tthis._throwOnEmitError = options.throwOnEmitError;\n\t\t}\n\n\t\tif (options?.throwOnEmptyListeners !== undefined) {\n\t\t\tthis._throwOnEmptyListeners = options.throwOnEmptyListeners;\n\t\t}\n\t}\n\n\t/**\n\t * Gets the event logger\n\t * @returns {Logger}\n\t */\n\tpublic get eventLogger(): Logger | undefined {\n\t\treturn this._eventLogger;\n\t}\n\n\t/**\n\t * Sets the event logger\n\t * @param {Logger} eventLogger\n\t */\n\tpublic set eventLogger(eventLogger: Logger | undefined) {\n\t\tthis._eventLogger = eventLogger;\n\t}\n\n\t/**\n\t * Gets whether an error should be thrown when an emit throws an error. Default is false and only emits an error event.\n\t * @returns {boolean}\n\t */\n\tpublic get throwOnEmitError(): boolean {\n\t\treturn this._throwOnEmitError;\n\t}\n\n\t/**\n\t * Sets whether an error should be thrown when an emit throws an error. Default is false and only emits an error event.\n\t * @param {boolean} value\n\t */\n\tpublic set throwOnEmitError(value: boolean) {\n\t\tthis._throwOnEmitError = value;\n\t}\n\n\t/**\n\t * Gets whether an error should be thrown when emitting 'error' event with no listeners. Default is false.\n\t * @returns {boolean}\n\t */\n\tpublic get throwOnEmptyListeners(): boolean {\n\t\treturn this._throwOnEmptyListeners;\n\t}\n\n\t/**\n\t * Sets whether an error should be thrown when emitting 'error' event with no listeners. Default is false.\n\t * @param {boolean} value\n\t */\n\tpublic set throwOnEmptyListeners(value: boolean) {\n\t\tthis._throwOnEmptyListeners = value;\n\t}\n\n\t/**\n\t * Adds a handler function for a specific event that will run only once\n\t * @param {string | symbol} eventName\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic once(\n\t\teventName: string | symbol,\n\t\tlistener: EventListener,\n\t): IEventEmitter {\n\t\tconst onceListener: EventListener = (...arguments_: any[]) => {\n\t\t\tthis.off(eventName as string, onceListener);\n\t\t\tlistener(...arguments_);\n\t\t};\n\n\t\tthis.on(eventName as string, onceListener);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets the number of listeners for a specific event. If no event is provided, it returns the total number of listeners\n\t * @param {string} eventName The event name. Not required\n\t * @returns {number} The number of listeners\n\t */\n\tpublic listenerCount(eventName?: string | symbol): number {\n\t\tif (eventName === undefined) {\n\t\t\tlet count = 0;\n\t\t\tfor (const entry of this._eventListeners.values()) {\n\t\t\t\tcount += typeof entry === \"function\" ? 1 : entry.length;\n\t\t\t}\n\n\t\t\treturn count;\n\t\t}\n\n\t\tconst entry = this._eventListeners.get(eventName);\n\t\tif (entry === undefined) {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn typeof entry === \"function\" ? 1 : entry.length;\n\t}\n\n\t/**\n\t * Gets an array of event names\n\t * @returns {Array<string | symbol>} An array of event names\n\t */\n\tpublic eventNames(): Array<string | symbol> {\n\t\treturn [...this._eventListeners.keys()];\n\t}\n\n\t/**\n\t * Gets an array of listeners for a specific event. If no event is provided, it returns all listeners\n\t * @param {string} [event] (Optional) The event name\n\t * @returns {EventListener[]} An array of listeners\n\t */\n\tpublic rawListeners(event?: string | symbol): EventListener[] {\n\t\tif (event === undefined) {\n\t\t\treturn this.getAllListeners();\n\t\t}\n\n\t\tconst entry = this._eventListeners.get(event);\n\t\tif (entry === undefined) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn typeof entry === \"function\" ? [entry] : entry;\n\t}\n\n\t/**\n\t * Prepends a listener to the beginning of the listeners array for the specified event\n\t * @param {string | symbol} eventName\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic prependListener(\n\t\teventName: string | symbol,\n\t\tlistener: EventListener,\n\t): IEventEmitter {\n\t\tconst existing = this._eventListeners.get(eventName);\n\n\t\tif (existing === undefined) {\n\t\t\tthis._eventListeners.set(eventName, listener);\n\t\t} else if (typeof existing === \"function\") {\n\t\t\tthis._eventListeners.set(eventName, [listener, existing]);\n\t\t} else {\n\t\t\texisting.unshift(listener);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Prepends a one-time listener to the beginning of the listeners array for the specified event\n\t * @param {string | symbol} eventName\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic prependOnceListener(\n\t\teventName: string | symbol,\n\t\tlistener: EventListener,\n\t): IEventEmitter {\n\t\tconst onceListener: EventListener = (...arguments_: any[]) => {\n\t\t\tthis.off(eventName as string, onceListener);\n\t\t\tlistener(...arguments_);\n\t\t};\n\n\t\tthis.prependListener(eventName as string, onceListener);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets the maximum number of listeners that can be added for a single event\n\t * @returns {number} The maximum number of listeners\n\t */\n\tpublic maxListeners(): number {\n\t\treturn this._maxListeners;\n\t}\n\n\t/**\n\t * Adds a listener for a specific event. It is an alias for the on() method\n\t * @param {string | symbol} event\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic addListener(\n\t\tevent: string | symbol,\n\t\tlistener: EventListener,\n\t): IEventEmitter {\n\t\tthis.on(event, listener);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds a listener for a specific event\n\t * @param {string | symbol} event\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic on(event: string | symbol, listener: EventListener): IEventEmitter {\n\t\tconst existing = this._eventListeners.get(event);\n\n\t\tif (existing === undefined) {\n\t\t\tthis._eventListeners.set(event, listener);\n\t\t\treturn this;\n\t\t}\n\n\t\tif (typeof existing === \"function\") {\n\t\t\tconst arr = [existing, listener];\n\t\t\tthis._eventListeners.set(event, arr);\n\t\t\tif (this._maxListeners > 0 && arr.length > this._maxListeners) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`MaxListenersExceededWarning: Possible event memory leak detected. ${arr.length} ${event as string} listeners added. Use setMaxListeners() to increase limit.`,\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\texisting.push(listener);\n\t\t\tif (this._maxListeners > 0 && existing.length > this._maxListeners) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`MaxListenersExceededWarning: Possible event memory leak detected. ${existing.length} ${event as string} listeners added. Use setMaxListeners() to increase limit.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes a listener for a specific event. It is an alias for the off() method\n\t * @param {string | symbol} event\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic removeListener(event: string, listener: EventListener): IEventEmitter {\n\t\tthis.off(event, listener);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes a listener for a specific event\n\t * @param {string | symbol} event\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic off(event: string | symbol, listener: EventListener): IEventEmitter {\n\t\tconst entry = this._eventListeners.get(event);\n\t\tif (entry === undefined) {\n\t\t\treturn this;\n\t\t}\n\n\t\tif (typeof entry === \"function\") {\n\t\t\tif (entry === listener) {\n\t\t\t\tthis._eventListeners.delete(event);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tconst index = entry.indexOf(listener);\n\t\tif (index !== -1) {\n\t\t\tif (entry.length === 2) {\n\t\t\t\tthis._eventListeners.set(event, entry[1 - index]);\n\t\t\t\t/* v8 ignore start -- @preserve: single-element arrays are stored as functions */\n\t\t\t} else if (entry.length === 1) {\n\t\t\t\tthis._eventListeners.delete(event);\n\t\t\t\t/* v8 ignore stop */\n\t\t\t} else {\n\t\t\t\tentry.splice(index, 1);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Calls all listeners for a specific event\n\t * @param {string | symbol} event\n\t * @param arguments_ The arguments to pass to the listeners\n\t * @returns {boolean} Returns true if the event had listeners, false otherwise\n\t */\n\tpublic emit(event: string | symbol, ...arguments_: any[]): boolean {\n\t\tlet result = false;\n\t\tconst entry = this._eventListeners.get(event);\n\t\tconst argumentLength = arguments_.length;\n\n\t\tif (entry !== undefined) {\n\t\t\tif (typeof entry === \"function\") {\n\t\t\t\tif (argumentLength === 1) {\n\t\t\t\t\tentry(arguments_[0]);\n\t\t\t\t} else if (argumentLength === 2) {\n\t\t\t\t\tentry(arguments_[0], arguments_[1]);\n\t\t\t\t} else {\n\t\t\t\t\tentry(...arguments_);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst len = entry.length;\n\t\t\t\tfor (let i = 0; i < len; i++) {\n\t\t\t\t\tif (argumentLength === 1) {\n\t\t\t\t\t\tentry[i](arguments_[0]);\n\t\t\t\t\t} else if (argumentLength === 2) {\n\t\t\t\t\t\tentry[i](arguments_[0], arguments_[1]);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tentry[i](...arguments_);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tresult = true;\n\t\t}\n\n\t\t// send it to the logger\n\t\tif (this._eventLogger) {\n\t\t\tthis.sendToEventLogger(event, arguments_);\n\t\t}\n\n\t\tif (!result && event === ERROR_EVENT) {\n\t\t\tconst error =\n\t\t\t\targuments_[0] instanceof Error\n\t\t\t\t\t? arguments_[0]\n\t\t\t\t\t: new Error(`${arguments_[0]}`);\n\n\t\t\tif (this._throwOnEmitError || this._throwOnEmptyListeners) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Gets all listeners for a specific event. If no event is provided, it returns all listeners\n\t * @param {string} [event] (Optional) The event name\n\t * @returns {EventListener[]} An array of listeners\n\t */\n\tpublic listeners(event: string | symbol): EventListener[] {\n\t\tconst entry = this._eventListeners.get(event);\n\t\tif (entry === undefined) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn typeof entry === \"function\" ? [entry] : entry;\n\t}\n\n\t/**\n\t * Removes all listeners for a specific event. If no event is provided, it removes all listeners\n\t * @param {string} [event] (Optional) The event name\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic removeAllListeners(event?: string | symbol): IEventEmitter {\n\t\tif (event !== undefined) {\n\t\t\tthis._eventListeners.delete(event);\n\t\t} else {\n\t\t\tthis._eventListeners.clear();\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the maximum number of listeners that can be added for a single event\n\t * @param {number} n The maximum number of listeners\n\t * @returns {void}\n\t */\n\tpublic setMaxListeners(n: number): void {\n\t\tthis._maxListeners = n < 0 ? 0 : n;\n\t}\n\n\t/**\n\t * Gets all listeners\n\t * @returns {EventListener[]} An array of listeners\n\t */\n\tpublic getAllListeners(): EventListener[] {\n\t\tconst result: EventListener[] = [];\n\t\tfor (const entry of this._eventListeners.values()) {\n\t\t\tif (typeof entry === \"function\") {\n\t\t\t\tresult.push(entry);\n\t\t\t} else {\n\t\t\t\tfor (let i = 0; i < entry.length; i++) {\n\t\t\t\t\tresult.push(entry[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Sends a log message using the configured logger based on the event name\n\t * @param {string | symbol} eventName - The event name that determines the log level\n\t * @param {unknown} data - The data to log\n\t */\n\tprivate sendToEventLogger(eventName: string | symbol, data: any): void {\n\t\t/* v8 ignore next 3 -- @preserve: guarded by caller */\n\t\tif (!this._eventLogger) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet message: string;\n\t\t/* v8 ignore next -- @preserve */\n\t\tif (typeof data === \"string\") {\n\t\t\tmessage = data;\n\t\t} else if (\n\t\t\tArray.isArray(data) &&\n\t\t\tdata.length > 0 &&\n\t\t\tdata[0] instanceof Error\n\t\t) {\n\t\t\tmessage = data[0].message;\n\t\t\t/* v8 ignore next -- @preserve */\n\t\t} else if (data instanceof Error) {\n\t\t\tmessage = data.message;\n\t\t} else if (\n\t\t\tArray.isArray(data) &&\n\t\t\tdata.length > 0 &&\n\t\t\ttypeof data[0]?.message === \"string\"\n\t\t) {\n\t\t\tmessage = data[0].message;\n\t\t} else {\n\t\t\tmessage = JSON.stringify(data);\n\t\t}\n\n\t\tswitch (eventName) {\n\t\t\tcase \"error\": {\n\t\t\t\tthis._eventLogger.error?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"warn\": {\n\t\t\t\tthis._eventLogger.warn?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"trace\": {\n\t\t\t\tthis._eventLogger.trace?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"debug\": {\n\t\t\t\tthis._eventLogger.debug?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"fatal\": {\n\t\t\t\tthis._eventLogger.fatal?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\tthis._eventLogger.info?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n","import type { HookFn, IHook } from \"../types.js\";\n\n/**\n * Concrete implementation of the IHook interface.\n * Provides a convenient class-based way to create hook entries.\n */\nexport class Hook implements IHook {\n\tpublic id?: string;\n\tpublic event: string;\n\tpublic handler: HookFn;\n\n\t/**\n\t * Creates a new Hook instance\n\t * @param {string} event - The event name for the hook\n\t * @param {HookFn} handler - The handler function for the hook\n\t * @param {string} [id] - Optional unique identifier for the hook\n\t */\n\tconstructor(event: string, handler: HookFn, id?: string) {\n\t\tthis.id = id;\n\t\tthis.event = event;\n\t\tthis.handler = handler;\n\t}\n}\n","import type {\n\tHookFn,\n\tIParallelHook,\n\tParallelHookFinalFn,\n\tParallelHookFn,\n\tParallelHookResult,\n} from \"../types.js\";\n\n/**\n * A ParallelHook fans a single invocation out to many registered hook\n * functions concurrently via Promise.allSettled, then calls a final\n * handler with the aggregated results — including failures — keyed by\n * the hook function reference for direct lookup. Each hook receives only\n * the original arguments; hooks do not see each other's results.\n *\n * Implements IHook for compatibility with Hookified.onHook(); the final\n * handler is called regardless of whether the parallel hook is invoked\n * directly or through Hookified.hook().\n *\n * Generics tighten the per-hook signature when every hook in the set\n * accepts the same `initialArgs` and returns the same result type.\n * Both default to `any` for backwards compatibility.\n *\n * @template TArgs - The shape of `initialArgs` passed to every hook\n * @template TResult - The result type each hook returns\n */\n// biome-ignore lint/suspicious/noExplicitAny: defaults preserve untyped use\nexport class ParallelHook<TArgs = any, TResult = any>\n\timplements IParallelHook<TArgs, TResult>\n{\n\tpublic id?: string;\n\tpublic event: string;\n\tpublic handler: HookFn;\n\tpublic hooks: ParallelHookFn<TArgs, TResult>[];\n\n\tprivate readonly _finalHandler: ParallelHookFinalFn<TArgs, TResult>;\n\n\t/**\n\t * Creates a new ParallelHook instance\n\t * @param {string} event - The event name for the hook\n\t * @param {ParallelHookFinalFn<TArgs, TResult>} finalHandler - Called once with `{ initialArgs, results }` after all parallel hooks settle\n\t * @param {string} [id] - Optional unique identifier for the hook\n\t */\n\tconstructor(\n\t\tevent: string,\n\t\tfinalHandler: ParallelHookFinalFn<TArgs, TResult>,\n\t\tid?: string,\n\t) {\n\t\tthis.id = id;\n\t\tthis.event = event;\n\t\tthis.hooks = [];\n\t\tthis._finalHandler = finalHandler;\n\n\t\t// biome-ignore lint/suspicious/noExplicitAny: this is for any parameter compatibility\n\t\tthis.handler = async (...arguments_: any[]) => {\n\t\t\tconst initialArgs: TArgs = (\n\t\t\t\targuments_.length === 1 ? arguments_[0] : arguments_\n\t\t\t) as TArgs;\n\n\t\t\t// Snapshot hooks at invocation time so concurrent addHook/removeHook\n\t\t\t// calls during the awaited Promise.allSettled cannot desync the\n\t\t\t// settled-index → hook mapping below.\n\t\t\tconst snapshot = [...this.hooks];\n\n\t\t\tconst settled = await Promise.allSettled(\n\t\t\t\tsnapshot.map((hook) =>\n\t\t\t\t\tPromise.resolve().then(() => hook({ initialArgs })),\n\t\t\t\t),\n\t\t\t);\n\n\t\t\tconst results = new Map<\n\t\t\t\tParallelHookFn<TArgs, TResult>,\n\t\t\t\tParallelHookResult<TResult>\n\t\t\t>();\n\t\t\tsnapshot.forEach((hook, index) => {\n\t\t\t\tconst outcome = settled[index];\n\t\t\t\tresults.set(\n\t\t\t\t\thook,\n\t\t\t\t\toutcome.status === \"fulfilled\"\n\t\t\t\t\t\t? { status: \"fulfilled\", result: outcome.value }\n\t\t\t\t\t\t: { status: \"rejected\", reason: outcome.reason },\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tawait this._finalHandler({ initialArgs, results });\n\t\t};\n\t}\n\n\t/**\n\t * Adds a hook function to the parallel set\n\t * @param {ParallelHookFn<TArgs, TResult>} hook - The hook function to add\n\t */\n\tpublic addHook(hook: ParallelHookFn<TArgs, TResult>): void {\n\t\tthis.hooks.push(hook);\n\t}\n\n\t/**\n\t * Removes a specific hook function from the parallel set\n\t * @param {ParallelHookFn<TArgs, TResult>} hook - The hook function to remove\n\t * @returns {boolean} true if the hook was found and removed\n\t */\n\tpublic removeHook(hook: ParallelHookFn<TArgs, TResult>): boolean {\n\t\tconst index = this.hooks.indexOf(hook);\n\t\tif (index !== -1) {\n\t\t\tthis.hooks.splice(index, 1);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n}\n","import type {\n\tHookFn,\n\tIWaterfallHook,\n\tWaterfallHookFn,\n\tWaterfallHookResult,\n} from \"../types.js\";\n\n/**\n * A WaterfallHook chains multiple hook functions sequentially,\n * where each hook receives a context with the previous result,\n * initial arguments, and accumulated results. After all hooks\n * have executed, the final handler receives the transformed result.\n * Implements IHook for compatibility with Hookified.onHook().\n */\nexport class WaterfallHook implements IWaterfallHook {\n\tpublic id?: string;\n\tpublic event: string;\n\tpublic handler: HookFn;\n\tpublic hooks: WaterfallHookFn[];\n\n\tprivate readonly _finalHandler: WaterfallHookFn;\n\n\t/**\n\t * Creates a new WaterfallHook instance\n\t * @param {string} event - The event name for the hook\n\t * @param {WaterfallHookFn} finalHandler - The final handler function that receives the transformed result\n\t * @param {string} [id] - Optional unique identifier for the hook\n\t */\n\tconstructor(event: string, finalHandler: WaterfallHookFn, id?: string) {\n\t\tthis.id = id;\n\t\tthis.event = event;\n\t\tthis.hooks = [];\n\t\tthis._finalHandler = finalHandler;\n\n\t\t// biome-ignore lint/suspicious/noExplicitAny: this is for any parameter compatibility\n\t\tthis.handler = async (...arguments_: any[]) => {\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: waterfall result type varies through the chain\n\t\t\tconst initialArgs: any =\n\t\t\t\targuments_.length === 1 ? arguments_[0] : arguments_;\n\t\t\tconst results: WaterfallHookResult[] = [];\n\n\t\t\tfor (const hook of this.hooks) {\n\t\t\t\tconst result = await hook({ initialArgs, results: [...results] });\n\t\t\t\tresults.push({ hook, result });\n\t\t\t}\n\n\t\t\tawait this._finalHandler({ initialArgs, results: [...results] });\n\t\t};\n\t}\n\n\t/**\n\t * Adds a hook function to the end of the waterfall chain\n\t * @param {WaterfallHookFn} hook - The hook function to add\n\t */\n\tpublic addHook(hook: WaterfallHookFn): void {\n\t\tthis.hooks.push(hook);\n\t}\n\n\t/**\n\t * Removes a specific hook function from the waterfall chain\n\t * @param {WaterfallHookFn} hook - The hook function to remove\n\t * @returns {boolean} true if the hook was found and removed\n\t */\n\tpublic removeHook(hook: WaterfallHookFn): boolean {\n\t\tconst index = this.hooks.indexOf(hook);\n\t\tif (index !== -1) {\n\t\t\tthis.hooks.splice(index, 1);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n}\n","import { Eventified } from \"./eventified.js\";\nimport type {\n\tHookFn,\n\tHookifiedOptions,\n\tIHook,\n\tIWaterfallHook,\n\tOnHookOptions,\n\tPrependHookOptions,\n\tWaterfallHookContext,\n\tWaterfallHookFn,\n\tWaterfallHookResult,\n} from \"./types.js\";\n\nexport type {\n\tHookFn,\n\tHookifiedOptions,\n\tIHook,\n\tIWaterfallHook,\n\tOnHookOptions,\n\tPrependHookOptions,\n\tWaterfallHookContext,\n\tWaterfallHookFn,\n\tWaterfallHookResult,\n};\n\nexport class Hookified extends Eventified {\n\tprivate readonly _hooks: Map<string, IHook[]>;\n\tprivate _throwOnHookError = false;\n\tprivate _enforceBeforeAfter = false;\n\tprivate _deprecatedHooks: Map<string, string>;\n\tprivate _allowDeprecated = true;\n\tprivate _useHookClone = true;\n\n\tconstructor(options?: HookifiedOptions) {\n\t\tsuper({\n\t\t\teventLogger: options?.eventLogger,\n\t\t\tthrowOnEmitError: options?.throwOnEmitError,\n\t\t\tthrowOnEmptyListeners: options?.throwOnEmptyListeners,\n\t\t});\n\t\tthis._hooks = new Map();\n\t\tthis._deprecatedHooks = options?.deprecatedHooks\n\t\t\t? new Map(options.deprecatedHooks)\n\t\t\t: new Map();\n\n\t\tif (options?.throwOnHookError !== undefined) {\n\t\t\tthis._throwOnHookError = options.throwOnHookError;\n\t\t}\n\n\t\tif (options?.enforceBeforeAfter !== undefined) {\n\t\t\tthis._enforceBeforeAfter = options.enforceBeforeAfter;\n\t\t}\n\n\t\tif (options?.allowDeprecated !== undefined) {\n\t\t\tthis._allowDeprecated = options.allowDeprecated;\n\t\t}\n\n\t\tif (options?.useHookClone !== undefined) {\n\t\t\tthis._useHookClone = options.useHookClone;\n\t\t}\n\t}\n\n\t/**\n\t * Gets all hooks\n\t * @returns {Map<string, IHook[]>}\n\t */\n\tpublic get hooks() {\n\t\treturn this._hooks;\n\t}\n\n\t/**\n\t * Gets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.\n\t * @returns {boolean}\n\t */\n\tpublic get throwOnHookError() {\n\t\treturn this._throwOnHookError;\n\t}\n\n\t/**\n\t * Sets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.\n\t * @param {boolean} value\n\t */\n\tpublic set throwOnHookError(value) {\n\t\tthis._throwOnHookError = value;\n\t}\n\n\t/**\n\t * Gets whether to enforce that all hook names start with 'before' or 'after'. Default is false.\n\t * @returns {boolean}\n\t * @default false\n\t */\n\tpublic get enforceBeforeAfter() {\n\t\treturn this._enforceBeforeAfter;\n\t}\n\n\t/**\n\t * Sets whether to enforce that all hook names start with 'before' or 'after'. Default is false.\n\t * @param {boolean} value\n\t */\n\tpublic set enforceBeforeAfter(value) {\n\t\tthis._enforceBeforeAfter = value;\n\t}\n\n\t/**\n\t * Gets the map of deprecated hook names to deprecation messages.\n\t * @returns {Map<string, string>}\n\t */\n\tpublic get deprecatedHooks() {\n\t\treturn this._deprecatedHooks;\n\t}\n\n\t/**\n\t * Sets the map of deprecated hook names to deprecation messages.\n\t * @param {Map<string, string>} value\n\t */\n\tpublic set deprecatedHooks(value) {\n\t\tthis._deprecatedHooks = value;\n\t}\n\n\t/**\n\t * Gets whether deprecated hooks are allowed to be registered and executed. Default is true.\n\t * @returns {boolean}\n\t */\n\tpublic get allowDeprecated() {\n\t\treturn this._allowDeprecated;\n\t}\n\n\t/**\n\t * Sets whether deprecated hooks are allowed to be registered and executed. Default is true.\n\t * @param {boolean} value\n\t */\n\tpublic set allowDeprecated(value) {\n\t\tthis._allowDeprecated = value;\n\t}\n\n\t/**\n\t * Gets whether hook objects are cloned before storing. Default is true.\n\t * @returns {boolean}\n\t */\n\tpublic get useHookClone() {\n\t\treturn this._useHookClone;\n\t}\n\n\t/**\n\t * Sets whether hook objects are cloned before storing. Default is true.\n\t * When false, the original IHook reference is stored directly.\n\t * @param {boolean} value\n\t */\n\tpublic set useHookClone(value) {\n\t\tthis._useHookClone = value;\n\t}\n\n\t/**\n\t * Adds a handler function for a specific event.\n\t * Supports both object and legacy signatures:\n\t * onHook({ event, handler }, options?)\n\t * onHook(event, handler)\n\t * To register multiple hooks at once, use {@link onHooks}.\n\t * @param {IHook | string} hookOrEvent - the hook object or event name\n\t * @param {OnHookOptions | HookFn} [optionsOrHandler] - options (when using object form) or handler function (when using string form)\n\t * @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation\n\t */\n\tpublic onHook(hook: IHook, options?: OnHookOptions): IHook | undefined;\n\tpublic onHook(event: string, handler: HookFn): IHook | undefined;\n\tpublic onHook(\n\t\thookOrEvent: IHook | string,\n\t\toptionsOrHandler?: OnHookOptions | HookFn,\n\t): IHook | undefined {\n\t\tlet hook: IHook;\n\t\tlet options: OnHookOptions | undefined;\n\n\t\tif (typeof hookOrEvent === \"string\") {\n\t\t\tif (typeof optionsOrHandler !== \"function\") {\n\t\t\t\tthrow new TypeError(\n\t\t\t\t\t\"When calling onHook(event, handler), the second argument must be a function\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\thook = { event: hookOrEvent, handler: optionsOrHandler };\n\t\t\toptions = undefined;\n\t\t} else {\n\t\t\thook = hookOrEvent;\n\t\t\toptions = optionsOrHandler as OnHookOptions | undefined;\n\t\t}\n\t\tthis.validateHookName(hook.event);\n\t\tif (!this.checkDeprecatedHook(hook.event)) {\n\t\t\treturn undefined; // Skip registration if deprecated hooks are not allowed\n\t\t}\n\n\t\tconst shouldClone = options?.useHookClone ?? this._useHookClone;\n\t\tconst entry: IHook = shouldClone\n\t\t\t? { id: hook.id, event: hook.event, handler: hook.handler }\n\t\t\t: hook;\n\n\t\tentry.id = entry.id ?? crypto.randomUUID();\n\n\t\tconst eventHandlers = this._hooks.get(hook.event);\n\t\tif (eventHandlers) {\n\t\t\t// Check for duplicate id — replace in-place if found\n\t\t\tconst existingIndex = eventHandlers.findIndex((h) => h.id === entry.id);\n\t\t\tif (existingIndex !== -1) {\n\t\t\t\teventHandlers[existingIndex] = entry;\n\t\t\t} else {\n\t\t\t\tconst position = options?.position ?? \"Bottom\";\n\t\t\t\tif (position === \"Top\") {\n\t\t\t\t\teventHandlers.unshift(entry);\n\t\t\t\t} else if (position === \"Bottom\") {\n\t\t\t\t\teventHandlers.push(entry);\n\t\t\t\t} else {\n\t\t\t\t\tconst index = Math.max(0, Math.min(position, eventHandlers.length));\n\t\t\t\t\teventHandlers.splice(index, 0, entry);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthis._hooks.set(hook.event, [entry]);\n\t\t}\n\n\t\treturn entry;\n\t}\n\n\t/**\n\t * Alias for onHook. This is provided for compatibility with other libraries that use the `addHook` method.\n\t * @param {string} event - the event name\n\t * @param {HookFn} handler - the handler function\n\t * @returns {void}\n\t */\n\tpublic addHook(event: string, handler: HookFn) {\n\t\tthis.onHook({ event, handler });\n\t}\n\n\t/**\n\t * Adds handler functions for specific events\n\t * @param {Array<IHook>} hooks\n\t * @param {OnHookOptions} [options] - optional per-call options (e.g., useHookClone override, position)\n\t * @returns {void}\n\t */\n\tpublic onHooks(hooks: IHook[], options?: OnHookOptions) {\n\t\tfor (const hook of hooks) {\n\t\t\tthis.onHook(hook, options);\n\t\t}\n\t}\n\n\t/**\n\t * Adds a handler function for a specific event that runs before all other handlers.\n\t * Equivalent to calling `onHook(hook, { position: \"Top\" })`.\n\t * @param {IHook} hook - the hook containing event name and handler\n\t * @param {PrependHookOptions} [options] - optional per-call options (e.g., useHookClone override)\n\t * @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation\n\t */\n\tpublic prependHook(\n\t\thook: IHook,\n\t\toptions?: PrependHookOptions,\n\t): IHook | undefined {\n\t\treturn this.onHook(hook, { ...options, position: \"Top\" });\n\t}\n\n\t/**\n\t * Adds a handler that only executes once for a specific event before all other handlers.\n\t * Equivalent to calling `onHook` with a self-removing wrapper and `{ position: \"Top\" }`.\n\t * @param {IHook} hook - the hook containing event name and handler\n\t * @param {PrependHookOptions} [options] - optional per-call options (e.g., useHookClone override)\n\t * @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation\n\t */\n\tpublic prependOnceHook(\n\t\thook: IHook,\n\t\toptions?: PrependHookOptions,\n\t): IHook | undefined {\n\t\t// biome-ignore lint/suspicious/noExplicitAny: this is for any parameter compatibility\n\t\tconst wrappedHandler = async (...arguments_: any[]) => {\n\t\t\tthis.removeHook({ event: hook.event, handler: wrappedHandler });\n\t\t\treturn hook.handler(...arguments_);\n\t\t};\n\n\t\treturn this.onHook(\n\t\t\t{ id: hook.id, event: hook.event, handler: wrappedHandler },\n\t\t\t{ ...options, position: \"Top\" },\n\t\t);\n\t}\n\n\t/**\n\t * Adds a handler that only executes once for a specific event\n\t * @param {IHook} hook - the hook containing event name and handler\n\t */\n\tpublic onceHook(hook: IHook) {\n\t\tthis.validateHookName(hook.event);\n\t\tif (!this.checkDeprecatedHook(hook.event)) {\n\t\t\treturn; // Skip registration if deprecated hooks are not allowed\n\t\t}\n\t\t// biome-ignore lint/suspicious/noExplicitAny: this is for any parameter compatibility\n\t\tconst wrappedHandler = async (...arguments_: any[]) => {\n\t\t\tthis.removeHook({ event: hook.event, handler: wrappedHandler });\n\t\t\treturn hook.handler(...arguments_);\n\t\t};\n\n\t\tthis.onHook({ id: hook.id, event: hook.event, handler: wrappedHandler });\n\t}\n\n\t/**\n\t * Removes a handler function for a specific event\n\t * @param {IHook} hook - the hook containing event name and handler to remove\n\t * @returns {IHook | undefined} the removed hook, or undefined if not found\n\t */\n\tpublic removeHook(hook: IHook): IHook | undefined {\n\t\tthis.validateHookName(hook.event);\n\t\tconst eventHandlers = this._hooks.get(hook.event);\n\t\tif (eventHandlers) {\n\t\t\tconst index = eventHandlers.findIndex((h) => h.handler === hook.handler);\n\t\t\tif (index !== -1) {\n\t\t\t\teventHandlers.splice(index, 1);\n\t\t\t\tif (eventHandlers.length === 0) {\n\t\t\t\t\tthis._hooks.delete(hook.event);\n\t\t\t\t}\n\n\t\t\t\treturn { event: hook.event, handler: hook.handler };\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Removes multiple hook handlers\n\t * @param {Array<IHook>} hooks\n\t * @returns {IHook[]} the hooks that were successfully removed\n\t */\n\tpublic removeHooks(hooks: IHook[]): IHook[] {\n\t\tconst removed: IHook[] = [];\n\t\tfor (const hook of hooks) {\n\t\t\tconst result = this.removeHook(hook);\n\t\t\tif (result) {\n\t\t\t\tremoved.push(result);\n\t\t\t}\n\t\t}\n\n\t\treturn removed;\n\t}\n\n\t/**\n\t * Calls all handlers for a specific event\n\t * @param {string} event\n\t * @param {T[]} arguments_\n\t * @returns {Promise<void>}\n\t */\n\tpublic async hook<T>(event: string, ...arguments_: T[]) {\n\t\tthis.validateHookName(event);\n\t\tif (!this.checkDeprecatedHook(event)) {\n\t\t\treturn; // Skip execution if deprecated hooks are not allowed\n\t\t}\n\t\tconst eventHandlers = this._hooks.get(event);\n\t\tif (eventHandlers) {\n\t\t\tfor (const hook of [...eventHandlers]) {\n\t\t\t\ttry {\n\t\t\t\t\tawait hook.handler(...arguments_);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst message = `${event}: ${(error as Error).message}`;\n\t\t\t\t\tthis.emit(\"error\", new Error(message));\n\n\t\t\t\t\tif (this._throwOnHookError) {\n\t\t\t\t\t\tthrow new Error(message);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Calls all synchronous handlers for a specific event.\n\t * Async handlers (declared with `async` keyword) are silently skipped.\n\t *\n\t * Note: The `hook` method is preferred as it executes both sync and async functions.\n\t * Use `hookSync` only when you specifically need synchronous execution.\n\t * @param {string} event\n\t * @param {T[]} arguments_\n\t * @returns {void}\n\t */\n\tpublic hookSync<T>(event: string, ...arguments_: T[]): void {\n\t\tthis.validateHookName(event);\n\t\tif (!this.checkDeprecatedHook(event)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst eventHandlers = this._hooks.get(event);\n\t\tif (eventHandlers) {\n\t\t\tfor (const hook of [...eventHandlers]) {\n\t\t\t\t// Skip async functions silently\n\t\t\t\tif (hook.handler.constructor.name === \"AsyncFunction\") {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\thook.handler(...arguments_);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst message = `${event}: ${(error as Error).message}`;\n\t\t\t\t\tthis.emit(\"error\", new Error(message));\n\n\t\t\t\t\tif (this._throwOnHookError) {\n\t\t\t\t\t\tthrow new Error(message);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Prepends the word `before` to your hook. Example is event is `test`, the before hook is `before:test`.\n\t * @param {string} event - The event name\n\t * @param {T[]} arguments_ - The arguments to pass to the hook\n\t */\n\tpublic async beforeHook<T>(event: string, ...arguments_: T[]) {\n\t\tawait this.hook(`before:${event}`, ...arguments_);\n\t}\n\n\t/**\n\t * Prepends the word `after` to your hook. Example is event is `test`, the after hook is `after:test`.\n\t * @param {string} event - The event name\n\t * @param {T[]} arguments_ - The arguments to pass to the hook\n\t */\n\tpublic async afterHook<T>(event: string, ...arguments_: T[]) {\n\t\tawait this.hook(`after:${event}`, ...arguments_);\n\t}\n\n\t/**\n\t * Calls all handlers for a specific event. This is an alias for `hook` and is provided for\n\t * compatibility with other libraries that use the `callHook` method.\n\t * @param {string} event\n\t * @param {T[]} arguments_\n\t * @returns {Promise<void>}\n\t */\n\tpublic async callHook<T>(event: string, ...arguments_: T[]) {\n\t\tawait this.hook(event, ...arguments_);\n\t}\n\n\t/**\n\t * Gets all hooks for a specific event\n\t * @param {string} event\n\t * @returns {IHook[]}\n\t */\n\tpublic getHooks(event: string) {\n\t\tthis.validateHookName(event);\n\t\treturn this._hooks.get(event);\n\t}\n\n\t/**\n\t * Gets a specific hook by id, searching across all events\n\t * @param {string} id - the hook id\n\t * @returns {IHook | undefined} the hook if found, or undefined\n\t */\n\tpublic getHook(id: string): IHook | undefined {\n\t\tfor (const eventHandlers of this._hooks.values()) {\n\t\t\tconst found = eventHandlers.find((h) => h.id === id);\n\t\t\tif (found) {\n\t\t\t\treturn found;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Removes one or more hooks by id, searching across all events\n\t * @param {string | string[]} id - the hook id or array of hook ids to remove\n\t * @returns {IHook | IHook[] | undefined} the removed hook(s), or undefined/empty array if not found\n\t */\n\tpublic removeHookById(id: string | string[]): IHook | IHook[] | undefined {\n\t\tif (Array.isArray(id)) {\n\t\t\tconst removed: IHook[] = [];\n\t\t\tfor (const singleId of id) {\n\t\t\t\tconst result = this.removeHookById(singleId);\n\t\t\t\tif (result && !Array.isArray(result)) {\n\t\t\t\t\tremoved.push(result);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn removed;\n\t\t}\n\n\t\tfor (const [event, eventHandlers] of this._hooks.entries()) {\n\t\t\tconst index = eventHandlers.findIndex((h) => h.id === id);\n\t\t\tif (index !== -1) {\n\t\t\t\tconst [removed] = eventHandlers.splice(index, 1);\n\t\t\t\tif (eventHandlers.length === 0) {\n\t\t\t\t\tthis._hooks.delete(event);\n\t\t\t\t}\n\n\t\t\t\treturn removed;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Removes all hooks\n\t * @returns {void}\n\t */\n\tpublic clearHooks() {\n\t\tthis._hooks.clear();\n\t}\n\n\t/**\n\t * Removes all hooks for a specific event and returns the removed hooks.\n\t * @param {string} event - The event name to remove hooks for.\n\t * @returns {IHook[]} the hooks that were removed\n\t */\n\tpublic removeEventHooks(event: string): IHook[] {\n\t\tthis.validateHookName(event);\n\t\tconst eventHandlers = this._hooks.get(event);\n\t\tif (eventHandlers) {\n\t\t\tconst removed = [...eventHandlers];\n\t\t\tthis._hooks.delete(event);\n\t\t\treturn removed;\n\t\t}\n\n\t\treturn [];\n\t}\n\n\t/**\n\t * Validates hook event name if enforceBeforeAfter is enabled\n\t * @param {string} event - The event name to validate\n\t * @throws {Error} If enforceBeforeAfter is true and event doesn't start with 'before' or 'after'\n\t */\n\tprivate validateHookName(event: string): void {\n\t\tif (this._enforceBeforeAfter) {\n\t\t\tconst eventValue = event.trim().toLocaleLowerCase();\n\t\t\tif (!eventValue.startsWith(\"before\") && !eventValue.startsWith(\"after\")) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Hook event \"${event}\" must start with \"before\" or \"after\" when enforceBeforeAfter is enabled`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks if a hook is deprecated and emits a warning if it is\n\t * @param {string} event - The event name to check\n\t * @returns {boolean} - Returns true if the hook should proceed, false if it should be blocked\n\t */\n\tprivate checkDeprecatedHook(event: string): boolean {\n\t\tif (this._deprecatedHooks.has(event)) {\n\t\t\tconst message = this._deprecatedHooks.get(event);\n\t\t\tconst warningMessage = `Hook \"${event}\" is deprecated${message ? `: ${message}` : \"\"}`;\n\n\t\t\t// Emit deprecation warning event\n\t\t\tthis.emit(\"warn\", { hook: event, message: warningMessage });\n\n\t\t\t// Return false if deprecated hooks are not allowed\n\t\t\treturn this._allowDeprecated;\n\t\t}\n\t\treturn true;\n\t}\n}\n\nexport { Eventified } from \"./eventified.js\";\nexport { Hook } from \"./hooks/hook.js\";\nexport { ParallelHook } from \"./hooks/parallel-hook.js\";\nexport { WaterfallHook } from \"./hooks/waterfall-hook.js\";\nexport type {\n\tEventEmitterOptions,\n\tEventListener,\n\tIEventEmitter,\n\tIParallelHook,\n\tLogger,\n\tParallelHookContext,\n\tParallelHookFinalContext,\n\tParallelHookFinalFn,\n\tParallelHookFn,\n\tParallelHookResult,\n} from \"./types.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAUA,MAAM,cAAc;CAEpB,IAAa,aAAb,MAAiD;EAUhD,YAAY,SAA+B;yBAT1B,mBAAA,KAAA,EAGf;yBACM,iBAAA,KAAA,EAAsB;yBACtB,gBAAA,KAAA,EAAsB;yBACtB,qBAAoB,MAAM;yBAC1B,0BAAyB,KAAK;AAGrC,QAAK,kCAAkB,IAAI,KAGxB;AACH,QAAK,gBAAgB;AAErB,QAAK,eAAe,SAAS;AAE7B,OAAI,SAAS,qBAAqB,KAAA,EACjC,MAAK,oBAAoB,QAAQ;AAGlC,OAAI,SAAS,0BAA0B,KAAA,EACtC,MAAK,yBAAyB,QAAQ;;;;;;EAQxC,IAAW,cAAkC;AAC5C,UAAO,KAAK;;;;;;EAOb,IAAW,YAAY,aAAiC;AACvD,QAAK,eAAe;;;;;;EAOrB,IAAW,mBAA4B;AACtC,UAAO,KAAK;;;;;;EAOb,IAAW,iBAAiB,OAAgB;AAC3C,QAAK,oBAAoB;;;;;;EAO1B,IAAW,wBAAiC;AAC3C,UAAO,KAAK;;;;;;EAOb,IAAW,sBAAsB,OAAgB;AAChD,QAAK,yBAAyB;;;;;;;;EAS/B,KACC,WACA,UACgB;GAChB,MAAM,gBAA+B,GAAG,eAAsB;AAC7D,SAAK,IAAI,WAAqB,aAAa;AAC3C,aAAS,GAAG,WAAW;;AAGxB,QAAK,GAAG,WAAqB,aAAa;AAC1C,UAAO;;;;;;;EAQR,cAAqB,WAAqC;AACzD,OAAI,cAAc,KAAA,GAAW;IAC5B,IAAI,QAAQ;AACZ,SAAK,MAAM,SAAS,KAAK,gBAAgB,QAAQ,CAChD,UAAS,OAAO,UAAU,aAAa,IAAI,MAAM;AAGlD,WAAO;;GAGR,MAAM,QAAQ,KAAK,gBAAgB,IAAI,UAAU;AACjD,OAAI,UAAU,KAAA,EACb,QAAO;AAGR,UAAO,OAAO,UAAU,aAAa,IAAI,MAAM;;;;;;EAOhD,aAA4C;AAC3C,UAAO,CAAC,GAAG,KAAK,gBAAgB,MAAM,CAAC;;;;;;;EAQxC,aAAoB,OAA0C;AAC7D,OAAI,UAAU,KAAA,EACb,QAAO,KAAK,iBAAiB;GAG9B,MAAM,QAAQ,KAAK,gBAAgB,IAAI,MAAM;AAC7C,OAAI,UAAU,KAAA,EACb,QAAO,EAAE;AAGV,UAAO,OAAO,UAAU,aAAa,CAAC,MAAM,GAAG;;;;;;;;EAShD,gBACC,WACA,UACgB;GAChB,MAAM,WAAW,KAAK,gBAAgB,IAAI,UAAU;AAEpD,OAAI,aAAa,KAAA,EAChB,MAAK,gBAAgB,IAAI,WAAW,SAAS;YACnC,OAAO,aAAa,WAC9B,MAAK,gBAAgB,IAAI,WAAW,CAAC,UAAU,SAAS,CAAC;OAEzD,UAAS,QAAQ,SAAS;AAG3B,UAAO;;;;;;;;EASR,oBACC,WACA,UACgB;GAChB,MAAM,gBAA+B,GAAG,eAAsB;AAC7D,SAAK,IAAI,WAAqB,aAAa;AAC3C,aAAS,GAAG,WAAW;;AAGxB,QAAK,gBAAgB,WAAqB,aAAa;AACvD,UAAO;;;;;;EAOR,eAA8B;AAC7B,UAAO,KAAK;;;;;;;;EASb,YACC,OACA,UACgB;AAChB,QAAK,GAAG,OAAO,SAAS;AACxB,UAAO;;;;;;;;EASR,GAAU,OAAwB,UAAwC;GACzE,MAAM,WAAW,KAAK,gBAAgB,IAAI,MAAM;AAEhD,OAAI,aAAa,KAAA,GAAW;AAC3B,SAAK,gBAAgB,IAAI,OAAO,SAAS;AACzC,WAAO;;AAGR,OAAI,OAAO,aAAa,YAAY;IACnC,MAAM,MAAM,CAAC,UAAU,SAAS;AAChC,SAAK,gBAAgB,IAAI,OAAO,IAAI;AACpC,QAAI,KAAK,gBAAgB,KAAK,IAAI,SAAS,KAAK,cAC/C,SAAQ,KACP,qEAAqE,IAAI,OAAO,GAAG,MAAgB,4DACnG;UAEI;AACN,aAAS,KAAK,SAAS;AACvB,QAAI,KAAK,gBAAgB,KAAK,SAAS,SAAS,KAAK,cACpD,SAAQ,KACP,qEAAqE,SAAS,OAAO,GAAG,MAAgB,4DACxG;;AAIH,UAAO;;;;;;;;EASR,eAAsB,OAAe,UAAwC;AAC5E,QAAK,IAAI,OAAO,SAAS;AACzB,UAAO;;;;;;;;EASR,IAAW,OAAwB,UAAwC;GAC1E,MAAM,QAAQ,KAAK,gBAAgB,IAAI,MAAM;AAC7C,OAAI,UAAU,KAAA,EACb,QAAO;AAGR,OAAI,OAAO,UAAU,YAAY;AAChC,QAAI,UAAU,SACb,MAAK,gBAAgB,OAAO,MAAM;AAGnC,WAAO;;GAGR,MAAM,QAAQ,MAAM,QAAQ,SAAS;AACrC,OAAI,UAAU,GACb,KAAI,MAAM,WAAW,EACpB,MAAK,gBAAgB,IAAI,OAAO,MAAM,IAAI,OAAO;YAEvC,MAAM,WAAW,EAC3B,MAAK,gBAAgB,OAAO,MAAM;OAGlC,OAAM,OAAO,OAAO,EAAE;AAIxB,UAAO;;;;;;;;EASR,KAAY,OAAwB,GAAG,YAA4B;GAClE,IAAI,SAAS;GACb,MAAM,QAAQ,KAAK,gBAAgB,IAAI,MAAM;GAC7C,MAAM,iBAAiB,WAAW;AAElC,OAAI,UAAU,KAAA,GAAW;AACxB,QAAI,OAAO,UAAU,WACpB,KAAI,mBAAmB,EACtB,OAAM,WAAW,GAAG;aACV,mBAAmB,EAC7B,OAAM,WAAW,IAAI,WAAW,GAAG;QAEnC,OAAM,GAAG,WAAW;SAEf;KACN,MAAM,MAAM,MAAM;AAClB,UAAK,IAAI,IAAI,GAAG,IAAI,KAAK,IACxB,KAAI,mBAAmB,EACtB,OAAM,GAAG,WAAW,GAAG;cACb,mBAAmB,EAC7B,OAAM,GAAG,WAAW,IAAI,WAAW,GAAG;SAEtC,OAAM,GAAG,GAAG,WAAW;;AAK1B,aAAS;;AAIV,OAAI,KAAK,aACR,MAAK,kBAAkB,OAAO,WAAW;AAG1C,OAAI,CAAC,UAAU,UAAU,aAAa;IACrC,MAAM,QACL,WAAW,cAAc,QACtB,WAAW,qBACX,IAAI,MAAM,GAAG,WAAW,KAAK;AAEjC,QAAI,KAAK,qBAAqB,KAAK,uBAClC,OAAM;;AAIR,UAAO;;;;;;;EAQR,UAAiB,OAAyC;GACzD,MAAM,QAAQ,KAAK,gBAAgB,IAAI,MAAM;AAC7C,OAAI,UAAU,KAAA,EACb,QAAO,EAAE;AAGV,UAAO,OAAO,UAAU,aAAa,CAAC,MAAM,GAAG;;;;;;;EAQhD,mBAA0B,OAAwC;AACjE,OAAI,UAAU,KAAA,EACb,MAAK,gBAAgB,OAAO,MAAM;OAElC,MAAK,gBAAgB,OAAO;AAG7B,UAAO;;;;;;;EAQR,gBAAuB,GAAiB;AACvC,QAAK,gBAAgB,IAAI,IAAI,IAAI;;;;;;EAOlC,kBAA0C;GACzC,MAAM,SAA0B,EAAE;AAClC,QAAK,MAAM,SAAS,KAAK,gBAAgB,QAAQ,CAChD,KAAI,OAAO,UAAU,WACpB,QAAO,KAAK,MAAM;OAElB,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,IACjC,QAAO,KAAK,MAAM,GAAG;AAKxB,UAAO;;;;;;;EAQR,kBAA0B,WAA4B,MAAiB;;AAEtE,OAAI,CAAC,KAAK,aACT;GAGD,IAAI;;AAEJ,OAAI,OAAO,SAAS,SACnB,WAAU;YAEV,MAAM,QAAQ,KAAK,IACnB,KAAK,SAAS,KACd,KAAK,cAAc,MAEnB,WAAU,KAAK,GAAG;YAER,gBAAgB,MAC1B,WAAU,KAAK;YAEf,MAAM,QAAQ,KAAK,IACnB,KAAK,SAAS,KACd,OAAO,KAAK,IAAI,YAAY,SAE5B,WAAU,KAAK,GAAG;OAElB,WAAU,KAAK,UAAU,KAAK;AAG/B,WAAQ,WAAR;IACC,KAAK;AACJ,UAAK,aAAa,QAAQ,SAAS;MAAE,OAAO;MAAW;MAAM,CAAC;AAC9D;IAGD,KAAK;AACJ,UAAK,aAAa,OAAO,SAAS;MAAE,OAAO;MAAW;MAAM,CAAC;AAC7D;IAGD,KAAK;AACJ,UAAK,aAAa,QAAQ,SAAS;MAAE,OAAO;MAAW;MAAM,CAAC;AAC9D;IAGD,KAAK;AACJ,UAAK,aAAa,QAAQ,SAAS;MAAE,OAAO;MAAW;MAAM,CAAC;AAC9D;IAGD,KAAK;AACJ,UAAK,aAAa,QAAQ,SAAS;MAAE,OAAO;MAAW;MAAM,CAAC;AAC9D;IAGD;AACC,UAAK,aAAa,OAAO,SAAS;MAAE,OAAO;MAAW;MAAM,CAAC;AAC7D;;;;;;;;;;CCrdJ,IAAa,OAAb,MAAmC;;;;;;;EAWlC,YAAY,OAAe,SAAiB,IAAa;yBAVlD,MAAA,KAAA,EAAY;yBACZ,SAAA,KAAA,EAAc;yBACd,WAAA,KAAA,EAAgB;AAStB,QAAK,KAAK;AACV,QAAK,QAAQ;AACb,QAAK,UAAU;;;;;;;;;;;;;;;;;;;;;;;CCOjB,IAAa,eAAb,MAEA;;;;;;;EAcC,YACC,OACA,cACA,IACC;yBAjBK,MAAA,KAAA,EAAY;yBACZ,SAAA,KAAA,EAAc;yBACd,WAAA,KAAA,EAAgB;yBAChB,SAAA,KAAA,EAAwC;yBAE9B,iBAAA,KAAA,EAAmD;AAanE,QAAK,KAAK;AACV,QAAK,QAAQ;AACb,QAAK,QAAQ,EAAE;AACf,QAAK,gBAAgB;AAGrB,QAAK,UAAU,OAAO,GAAG,eAAsB;IAC9C,MAAM,cACL,WAAW,WAAW,IAAI,WAAW,KAAK;IAM3C,MAAM,WAAW,CAAC,GAAG,KAAK,MAAM;IAEhC,MAAM,UAAU,MAAM,QAAQ,WAC7B,SAAS,KAAK,SACb,QAAQ,SAAS,CAAC,WAAW,KAAK,EAAE,aAAa,CAAC,CAAC,CACnD,CACD;IAED,MAAM,0BAAU,IAAI,KAGjB;AACH,aAAS,SAAS,MAAM,UAAU;KACjC,MAAM,UAAU,QAAQ;AACxB,aAAQ,IACP,MACA,QAAQ,WAAW,cAChB;MAAE,QAAQ;MAAa,QAAQ,QAAQ;MAAO,GAC9C;MAAE,QAAQ;MAAY,QAAQ,QAAQ;MAAQ,CACjD;MACA;AAEF,UAAM,KAAK,cAAc;KAAE;KAAa;KAAS,CAAC;;;;;;;EAQpD,QAAe,MAA4C;AAC1D,QAAK,MAAM,KAAK,KAAK;;;;;;;EAQtB,WAAkB,MAA+C;GAChE,MAAM,QAAQ,KAAK,MAAM,QAAQ,KAAK;AACtC,OAAI,UAAU,IAAI;AACjB,SAAK,MAAM,OAAO,OAAO,EAAE;AAC3B,WAAO;;AAGR,UAAO;;;;;;;;;;;;CC9FT,IAAa,gBAAb,MAAqD;;;;;;;EAcpD,YAAY,OAAe,cAA+B,IAAa;yBAbhE,MAAA,KAAA,EAAY;yBACZ,SAAA,KAAA,EAAc;yBACd,WAAA,KAAA,EAAgB;yBAChB,SAAA,KAAA,EAAyB;yBAEf,iBAAA,KAAA,EAA+B;AAS/C,QAAK,KAAK;AACV,QAAK,QAAQ;AACb,QAAK,QAAQ,EAAE;AACf,QAAK,gBAAgB;AAGrB,QAAK,UAAU,OAAO,GAAG,eAAsB;IAE9C,MAAM,cACL,WAAW,WAAW,IAAI,WAAW,KAAK;IAC3C,MAAM,UAAiC,EAAE;AAEzC,SAAK,MAAM,QAAQ,KAAK,OAAO;KAC9B,MAAM,SAAS,MAAM,KAAK;MAAE;MAAa,SAAS,CAAC,GAAG,QAAQ;MAAE,CAAC;AACjE,aAAQ,KAAK;MAAE;MAAM;MAAQ,CAAC;;AAG/B,UAAM,KAAK,cAAc;KAAE;KAAa,SAAS,CAAC,GAAG,QAAQ;KAAE,CAAC;;;;;;;EAQlE,QAAe,MAA6B;AAC3C,QAAK,MAAM,KAAK,KAAK;;;;;;;EAQtB,WAAkB,MAAgC;GACjD,MAAM,QAAQ,KAAK,MAAM,QAAQ,KAAK;AACtC,OAAI,UAAU,IAAI;AACjB,SAAK,MAAM,OAAO,OAAO,EAAE;AAC3B,WAAO;;AAGR,UAAO;;;;;CC7CT,IAAa,YAAb,cAA+B,WAAW;EAQzC,YAAY,SAA4B;AACvC,SAAM;IACL,aAAa,SAAS;IACtB,kBAAkB,SAAS;IAC3B,uBAAuB,SAAS;IAChC,CAAC;yBAZc,UAAA,KAAA,EAA6B;yBACtC,qBAAoB,MAAM;yBAC1B,uBAAsB,MAAM;yBAC5B,oBAAA,KAAA,EAAsC;yBACtC,oBAAmB,KAAK;yBACxB,iBAAgB,KAAK;AAQ5B,QAAK,yBAAS,IAAI,KAAK;AACvB,QAAK,mBAAmB,SAAS,kBAC9B,IAAI,IAAI,QAAQ,gBAAgB,mBAChC,IAAI,KAAK;AAEZ,OAAI,SAAS,qBAAqB,KAAA,EACjC,MAAK,oBAAoB,QAAQ;AAGlC,OAAI,SAAS,uBAAuB,KAAA,EACnC,MAAK,sBAAsB,QAAQ;AAGpC,OAAI,SAAS,oBAAoB,KAAA,EAChC,MAAK,mBAAmB,QAAQ;AAGjC,OAAI,SAAS,iBAAiB,KAAA,EAC7B,MAAK,gBAAgB,QAAQ;;;;;;EAQ/B,IAAW,QAAQ;AAClB,UAAO,KAAK;;;;;;EAOb,IAAW,mBAAmB;AAC7B,UAAO,KAAK;;;;;;EAOb,IAAW,iBAAiB,OAAO;AAClC,QAAK,oBAAoB;;;;;;;EAQ1B,IAAW,qBAAqB;AAC/B,UAAO,KAAK;;;;;;EAOb,IAAW,mBAAmB,OAAO;AACpC,QAAK,sBAAsB;;;;;;EAO5B,IAAW,kBAAkB;AAC5B,UAAO,KAAK;;;;;;EAOb,IAAW,gBAAgB,OAAO;AACjC,QAAK,mBAAmB;;;;;;EAOzB,IAAW,kBAAkB;AAC5B,UAAO,KAAK;;;;;;EAOb,IAAW,gBAAgB,OAAO;AACjC,QAAK,mBAAmB;;;;;;EAOzB,IAAW,eAAe;AACzB,UAAO,KAAK;;;;;;;EAQb,IAAW,aAAa,OAAO;AAC9B,QAAK,gBAAgB;;EAetB,OACC,aACA,kBACoB;GACpB,IAAI;GACJ,IAAI;AAEJ,OAAI,OAAO,gBAAgB,UAAU;AACpC,QAAI,OAAO,qBAAqB,WAC/B,OAAM,IAAI,UACT,8EACA;AAGF,WAAO;KAAE,OAAO;KAAa,SAAS;KAAkB;AACxD,cAAU,KAAA;UACJ;AACN,WAAO;AACP,cAAU;;AAEX,QAAK,iBAAiB,KAAK,MAAM;AACjC,OAAI,CAAC,KAAK,oBAAoB,KAAK,MAAM,CACxC;GAID,MAAM,QADc,SAAS,gBAAgB,KAAK,gBAE/C;IAAE,IAAI,KAAK;IAAI,OAAO,KAAK;IAAO,SAAS,KAAK;IAAS,GACzD;AAEH,SAAM,KAAK,MAAM,MAAM,OAAO,YAAY;GAE1C,MAAM,gBAAgB,KAAK,OAAO,IAAI,KAAK,MAAM;AACjD,OAAI,eAAe;IAElB,MAAM,gBAAgB,cAAc,WAAW,MAAM,EAAE,OAAO,MAAM,GAAG;AACvE,QAAI,kBAAkB,GACrB,eAAc,iBAAiB;SACzB;KACN,MAAM,WAAW,SAAS,YAAY;AACtC,SAAI,aAAa,MAChB,eAAc,QAAQ,MAAM;cAClB,aAAa,SACvB,eAAc,KAAK,MAAM;UACnB;MACN,MAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,UAAU,cAAc,OAAO,CAAC;AACnE,oBAAc,OAAO,OAAO,GAAG,MAAM;;;SAIvC,MAAK,OAAO,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC;AAGrC,UAAO;;;;;;;;EASR,QAAe,OAAe,SAAiB;AAC9C,QAAK,OAAO;IAAE;IAAO;IAAS,CAAC;;;;;;;;EAShC,QAAe,OAAgB,SAAyB;AACvD,QAAK,MAAM,QAAQ,MAClB,MAAK,OAAO,MAAM,QAAQ;;;;;;;;;EAW5B,YACC,MACA,SACoB;AACpB,UAAO,KAAK,OAAO,MAAM;IAAE,GAAG;IAAS,UAAU;IAAO,CAAC;;;;;;;;;EAU1D,gBACC,MACA,SACoB;GAEpB,MAAM,iBAAiB,OAAO,GAAG,eAAsB;AACtD,SAAK,WAAW;KAAE,OAAO,KAAK;KAAO,SAAS;KAAgB,CAAC;AAC/D,WAAO,KAAK,QAAQ,GAAG,WAAW;;AAGnC,UAAO,KAAK,OACX;IAAE,IAAI,KAAK;IAAI,OAAO,KAAK;IAAO,SAAS;IAAgB,EAC3D;IAAE,GAAG;IAAS,UAAU;IAAO,CAC/B;;;;;;EAOF,SAAgB,MAAa;AAC5B,QAAK,iBAAiB,KAAK,MAAM;AACjC,OAAI,CAAC,KAAK,oBAAoB,KAAK,MAAM,CACxC;GAGD,MAAM,iBAAiB,OAAO,GAAG,eAAsB;AACtD,SAAK,WAAW;KAAE,OAAO,KAAK;KAAO,SAAS;KAAgB,CAAC;AAC/D,WAAO,KAAK,QAAQ,GAAG,WAAW;;AAGnC,QAAK,OAAO;IAAE,IAAI,KAAK;IAAI,OAAO,KAAK;IAAO,SAAS;IAAgB,CAAC;;;;;;;EAQzE,WAAkB,MAAgC;AACjD,QAAK,iBAAiB,KAAK,MAAM;GACjC,MAAM,gBAAgB,KAAK,OAAO,IAAI,KAAK,MAAM;AACjD,OAAI,eAAe;IAClB,MAAM,QAAQ,cAAc,WAAW,MAAM,EAAE,YAAY,KAAK,QAAQ;AACxE,QAAI,UAAU,IAAI;AACjB,mBAAc,OAAO,OAAO,EAAE;AAC9B,SAAI,cAAc,WAAW,EAC5B,MAAK,OAAO,OAAO,KAAK,MAAM;AAG/B,YAAO;MAAE,OAAO,KAAK;MAAO,SAAS,KAAK;MAAS;;;;;;;;;EAYtD,YAAmB,OAAyB;GAC3C,MAAM,UAAmB,EAAE;AAC3B,QAAK,MAAM,QAAQ,OAAO;IACzB,MAAM,SAAS,KAAK,WAAW,KAAK;AACpC,QAAI,OACH,SAAQ,KAAK,OAAO;;AAItB,UAAO;;;;;;;;EASR,MAAa,KAAQ,OAAe,GAAG,YAAiB;AACvD,QAAK,iBAAiB,MAAM;AAC5B,OAAI,CAAC,KAAK,oBAAoB,MAAM,CACnC;GAED,MAAM,gBAAgB,KAAK,OAAO,IAAI,MAAM;AAC5C,OAAI,cACH,MAAK,MAAM,QAAQ,CAAC,GAAG,cAAc,CACpC,KAAI;AACH,UAAM,KAAK,QAAQ,GAAG,WAAW;YACzB,OAAO;IACf,MAAM,UAAU,GAAG,MAAM,IAAK,MAAgB;AAC9C,SAAK,KAAK,SAAS,IAAI,MAAM,QAAQ,CAAC;AAEtC,QAAI,KAAK,kBACR,OAAM,IAAI,MAAM,QAAQ;;;;;;;;;;;;;EAiB7B,SAAmB,OAAe,GAAG,YAAuB;AAC3D,QAAK,iBAAiB,MAAM;AAC5B,OAAI,CAAC,KAAK,oBAAoB,MAAM,CACnC;GAGD,MAAM,gBAAgB,KAAK,OAAO,IAAI,MAAM;AAC5C,OAAI,cACH,MAAK,MAAM,QAAQ,CAAC,GAAG,cAAc,EAAE;AAEtC,QAAI,KAAK,QAAQ,YAAY,SAAS,gBACrC;AAGD,QAAI;AACH,UAAK,QAAQ,GAAG,WAAW;aACnB,OAAO;KACf,MAAM,UAAU,GAAG,MAAM,IAAK,MAAgB;AAC9C,UAAK,KAAK,SAAS,IAAI,MAAM,QAAQ,CAAC;AAEtC,SAAI,KAAK,kBACR,OAAM,IAAI,MAAM,QAAQ;;;;;;;;;EAY7B,MAAa,WAAc,OAAe,GAAG,YAAiB;AAC7D,SAAM,KAAK,KAAK,UAAU,SAAS,GAAG,WAAW;;;;;;;EAQlD,MAAa,UAAa,OAAe,GAAG,YAAiB;AAC5D,SAAM,KAAK,KAAK,SAAS,SAAS,GAAG,WAAW;;;;;;;;;EAUjD,MAAa,SAAY,OAAe,GAAG,YAAiB;AAC3D,SAAM,KAAK,KAAK,OAAO,GAAG,WAAW;;;;;;;EAQtC,SAAgB,OAAe;AAC9B,QAAK,iBAAiB,MAAM;AAC5B,UAAO,KAAK,OAAO,IAAI,MAAM;;;;;;;EAQ9B,QAAe,IAA+B;AAC7C,QAAK,MAAM,iBAAiB,KAAK,OAAO,QAAQ,EAAE;IACjD,MAAM,QAAQ,cAAc,MAAM,MAAM,EAAE,OAAO,GAAG;AACpD,QAAI,MACH,QAAO;;;;;;;;EAYV,eAAsB,IAAoD;AACzE,OAAI,MAAM,QAAQ,GAAG,EAAE;IACtB,MAAM,UAAmB,EAAE;AAC3B,SAAK,MAAM,YAAY,IAAI;KAC1B,MAAM,SAAS,KAAK,eAAe,SAAS;AAC5C,SAAI,UAAU,CAAC,MAAM,QAAQ,OAAO,CACnC,SAAQ,KAAK,OAAO;;AAItB,WAAO;;AAGR,QAAK,MAAM,CAAC,OAAO,kBAAkB,KAAK,OAAO,SAAS,EAAE;IAC3D,MAAM,QAAQ,cAAc,WAAW,MAAM,EAAE,OAAO,GAAG;AACzD,QAAI,UAAU,IAAI;KACjB,MAAM,CAAC,WAAW,cAAc,OAAO,OAAO,EAAE;AAChD,SAAI,cAAc,WAAW,EAC5B,MAAK,OAAO,OAAO,MAAM;AAG1B,YAAO;;;;;;;;EAWV,aAAoB;AACnB,QAAK,OAAO,OAAO;;;;;;;EAQpB,iBAAwB,OAAwB;AAC/C,QAAK,iBAAiB,MAAM;GAC5B,MAAM,gBAAgB,KAAK,OAAO,IAAI,MAAM;AAC5C,OAAI,eAAe;IAClB,MAAM,UAAU,CAAC,GAAG,cAAc;AAClC,SAAK,OAAO,OAAO,MAAM;AACzB,WAAO;;AAGR,UAAO,EAAE;;;;;;;EAQV,iBAAyB,OAAqB;AAC7C,OAAI,KAAK,qBAAqB;IAC7B,MAAM,aAAa,MAAM,MAAM,CAAC,mBAAmB;AACnD,QAAI,CAAC,WAAW,WAAW,SAAS,IAAI,CAAC,WAAW,WAAW,QAAQ,CACtE,OAAM,IAAI,MACT,eAAe,MAAM,0EACrB;;;;;;;;EAUJ,oBAA4B,OAAwB;AACnD,OAAI,KAAK,iBAAiB,IAAI,MAAM,EAAE;IACrC,MAAM,UAAU,KAAK,iBAAiB,IAAI,MAAM;IAChD,MAAM,iBAAiB,SAAS,MAAM,iBAAiB,UAAU,KAAK,YAAY;AAGlF,SAAK,KAAK,QAAQ;KAAE,MAAM;KAAO,SAAS;KAAgB,CAAC;AAG3D,WAAO,KAAK;;AAEb,UAAO"}
|
|
1
|
+
{"version":3,"file":"index.global.js","names":[],"sources":["../../src/eventified.ts","../../src/hooks/hook.ts","../../src/hooks/parallel-hook.ts","../../src/hooks/waterfall-hook.ts","../../src/index.ts"],"sourcesContent":["// biome-ignore-all lint/suspicious/noExplicitAny: this is for event emitter compatibility\nimport type {\n\tEventEmitterOptions,\n\tEventListener,\n\tIEventEmitter,\n\tLogger,\n} from \"./types.js\";\n\nexport type { EventEmitterOptions, EventListener, IEventEmitter };\n\nconst ERROR_EVENT = \"error\";\n\nexport class Eventified implements IEventEmitter {\n\tprivate readonly _eventListeners: Map<\n\t\tstring | symbol,\n\t\tEventListener | EventListener[]\n\t>;\n\tprivate _maxListeners: number;\n\tprivate _eventLogger?: Logger;\n\tprivate _throwOnEmitError = false;\n\tprivate _throwOnEmptyListeners = true;\n\n\tconstructor(options?: EventEmitterOptions) {\n\t\tthis._eventListeners = new Map<\n\t\t\tstring | symbol,\n\t\t\tEventListener | EventListener[]\n\t\t>();\n\t\tthis._maxListeners = 0; // Default is 0 (unlimited)\n\n\t\tthis._eventLogger = options?.eventLogger;\n\n\t\tif (options?.throwOnEmitError !== undefined) {\n\t\t\tthis._throwOnEmitError = options.throwOnEmitError;\n\t\t}\n\n\t\tif (options?.throwOnEmptyListeners !== undefined) {\n\t\t\tthis._throwOnEmptyListeners = options.throwOnEmptyListeners;\n\t\t}\n\t}\n\n\t/**\n\t * Gets the event logger\n\t * @returns {Logger}\n\t */\n\tpublic get eventLogger(): Logger | undefined {\n\t\treturn this._eventLogger;\n\t}\n\n\t/**\n\t * Sets the event logger\n\t * @param {Logger} eventLogger\n\t */\n\tpublic set eventLogger(eventLogger: Logger | undefined) {\n\t\tthis._eventLogger = eventLogger;\n\t}\n\n\t/**\n\t * Gets whether an error should be thrown when an emit throws an error. Default is false and only emits an error event.\n\t * @returns {boolean}\n\t */\n\tpublic get throwOnEmitError(): boolean {\n\t\treturn this._throwOnEmitError;\n\t}\n\n\t/**\n\t * Sets whether an error should be thrown when an emit throws an error. Default is false and only emits an error event.\n\t * @param {boolean} value\n\t */\n\tpublic set throwOnEmitError(value: boolean) {\n\t\tthis._throwOnEmitError = value;\n\t}\n\n\t/**\n\t * Gets whether an error should be thrown when emitting 'error' event with no listeners. Default is false.\n\t * @returns {boolean}\n\t */\n\tpublic get throwOnEmptyListeners(): boolean {\n\t\treturn this._throwOnEmptyListeners;\n\t}\n\n\t/**\n\t * Sets whether an error should be thrown when emitting 'error' event with no listeners. Default is false.\n\t * @param {boolean} value\n\t */\n\tpublic set throwOnEmptyListeners(value: boolean) {\n\t\tthis._throwOnEmptyListeners = value;\n\t}\n\n\t/**\n\t * Adds a handler function for a specific event that will run only once\n\t * @param {string | symbol} eventName\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic once(\n\t\teventName: string | symbol,\n\t\tlistener: EventListener,\n\t): IEventEmitter {\n\t\tconst onceListener: EventListener = (...arguments_: any[]) => {\n\t\t\tthis.off(eventName as string, onceListener);\n\t\t\tlistener(...arguments_);\n\t\t};\n\n\t\t// Keep a reference to the original listener so that off()/removeListener()\n\t\t// can remove the once wrapper when called with the original reference.\n\t\t(onceListener as any)._originalListener = listener;\n\n\t\tthis.on(eventName as string, onceListener);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets the number of listeners for a specific event. If no event is provided, it returns the total number of listeners\n\t * @param {string} eventName The event name. Not required\n\t * @returns {number} The number of listeners\n\t */\n\tpublic listenerCount(eventName?: string | symbol): number {\n\t\tif (eventName === undefined) {\n\t\t\tlet count = 0;\n\t\t\tfor (const entry of this._eventListeners.values()) {\n\t\t\t\tcount += typeof entry === \"function\" ? 1 : entry.length;\n\t\t\t}\n\n\t\t\treturn count;\n\t\t}\n\n\t\tconst entry = this._eventListeners.get(eventName);\n\t\tif (entry === undefined) {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn typeof entry === \"function\" ? 1 : entry.length;\n\t}\n\n\t/**\n\t * Gets an array of event names\n\t * @returns {Array<string | symbol>} An array of event names\n\t */\n\tpublic eventNames(): Array<string | symbol> {\n\t\treturn [...this._eventListeners.keys()];\n\t}\n\n\t/**\n\t * Gets an array of listeners for a specific event. If no event is provided, it returns all listeners\n\t * @param {string} [event] (Optional) The event name\n\t * @returns {EventListener[]} An array of listeners\n\t */\n\tpublic rawListeners(event?: string | symbol): EventListener[] {\n\t\tif (event === undefined) {\n\t\t\treturn this.getAllListeners();\n\t\t}\n\n\t\tconst entry = this._eventListeners.get(event);\n\t\tif (entry === undefined) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn typeof entry === \"function\" ? [entry] : entry;\n\t}\n\n\t/**\n\t * Prepends a listener to the beginning of the listeners array for the specified event\n\t * @param {string | symbol} eventName\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic prependListener(\n\t\teventName: string | symbol,\n\t\tlistener: EventListener,\n\t): IEventEmitter {\n\t\tconst existing = this._eventListeners.get(eventName);\n\n\t\tif (existing === undefined) {\n\t\t\tthis._eventListeners.set(eventName, listener);\n\t\t} else if (typeof existing === \"function\") {\n\t\t\tthis._eventListeners.set(eventName, [listener, existing]);\n\t\t} else {\n\t\t\texisting.unshift(listener);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Prepends a one-time listener to the beginning of the listeners array for the specified event\n\t * @param {string | symbol} eventName\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic prependOnceListener(\n\t\teventName: string | symbol,\n\t\tlistener: EventListener,\n\t): IEventEmitter {\n\t\tconst onceListener: EventListener = (...arguments_: any[]) => {\n\t\t\tthis.off(eventName as string, onceListener);\n\t\t\tlistener(...arguments_);\n\t\t};\n\n\t\t// Keep a reference to the original listener so that off()/removeListener()\n\t\t// can remove the once wrapper when called with the original reference.\n\t\t(onceListener as any)._originalListener = listener;\n\n\t\tthis.prependListener(eventName as string, onceListener);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets the maximum number of listeners that can be added for a single event\n\t * @returns {number} The maximum number of listeners\n\t */\n\tpublic maxListeners(): number {\n\t\treturn this._maxListeners;\n\t}\n\n\t/**\n\t * Adds a listener for a specific event. It is an alias for the on() method\n\t * @param {string | symbol} event\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic addListener(\n\t\tevent: string | symbol,\n\t\tlistener: EventListener,\n\t): IEventEmitter {\n\t\tthis.on(event, listener);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds a listener for a specific event\n\t * @param {string | symbol} event\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic on(event: string | symbol, listener: EventListener): IEventEmitter {\n\t\tconst existing = this._eventListeners.get(event);\n\n\t\tif (existing === undefined) {\n\t\t\tthis._eventListeners.set(event, listener);\n\t\t\treturn this;\n\t\t}\n\n\t\tif (typeof existing === \"function\") {\n\t\t\tconst arr = [existing, listener];\n\t\t\tthis._eventListeners.set(event, arr);\n\t\t\tif (this._maxListeners > 0 && arr.length > this._maxListeners) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`MaxListenersExceededWarning: Possible event memory leak detected. ${arr.length} ${event as string} listeners added. Use setMaxListeners() to increase limit.`,\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\texisting.push(listener);\n\t\t\tif (this._maxListeners > 0 && existing.length > this._maxListeners) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`MaxListenersExceededWarning: Possible event memory leak detected. ${existing.length} ${event as string} listeners added. Use setMaxListeners() to increase limit.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes a listener for a specific event. It is an alias for the off() method\n\t * @param {string | symbol} event\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic removeListener(event: string, listener: EventListener): IEventEmitter {\n\t\tthis.off(event, listener);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Determines whether a stored listener matches the listener provided to off().\n\t * A match occurs when the references are identical, or when the stored listener\n\t * is a once-wrapper whose original listener equals the provided reference.\n\t * @param {EventListener} stored - the listener currently stored\n\t * @param {EventListener} target - the listener passed to off()\n\t * @returns {boolean} true if the stored listener should be removed\n\t */\n\tprivate matchesListener(\n\t\tstored: EventListener,\n\t\ttarget: EventListener,\n\t): boolean {\n\t\tif (stored === target) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Only treat this as a once-wrapper match when an original listener was\n\t\t// actually recorded. Without this guard, calling off() with an undefined\n\t\t// target would match any normal listener (whose _originalListener is also\n\t\t// undefined) and remove it.\n\t\tconst original = (stored as any)._originalListener;\n\t\treturn original !== undefined && original === target;\n\t}\n\n\t/**\n\t * Removes a listener for a specific event\n\t * @param {string | symbol} event\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic off(event: string | symbol, listener: EventListener): IEventEmitter {\n\t\tconst entry = this._eventListeners.get(event);\n\t\tif (entry === undefined) {\n\t\t\treturn this;\n\t\t}\n\n\t\tif (typeof entry === \"function\") {\n\t\t\tif (this.matchesListener(entry, listener)) {\n\t\t\t\tthis._eventListeners.delete(event);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\t// Prefer an exact reference match before falling back to once-wrapper\n\t\t// matching, so a normal listener is never left behind when an identical\n\t\t// once-wrapper happens to precede it in the array.\n\t\tlet index = entry.indexOf(listener);\n\t\tif (index === -1) {\n\t\t\tindex = entry.findIndex((stored) =>\n\t\t\t\tthis.matchesListener(stored, listener),\n\t\t\t);\n\t\t}\n\n\t\tif (index !== -1) {\n\t\t\tif (entry.length === 2) {\n\t\t\t\tthis._eventListeners.set(event, entry[1 - index]);\n\t\t\t\t/* v8 ignore start -- @preserve: single-element arrays are stored as functions */\n\t\t\t} else if (entry.length === 1) {\n\t\t\t\tthis._eventListeners.delete(event);\n\t\t\t\t/* v8 ignore stop */\n\t\t\t} else {\n\t\t\t\tentry.splice(index, 1);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Calls all listeners for a specific event\n\t * @param {string | symbol} event\n\t * @param arguments_ The arguments to pass to the listeners\n\t * @returns {boolean} Returns true if the event had listeners, false otherwise\n\t */\n\tpublic emit(event: string | symbol, ...arguments_: any[]): boolean {\n\t\tlet result = false;\n\t\tconst entry = this._eventListeners.get(event);\n\t\tconst argumentLength = arguments_.length;\n\n\t\tif (entry !== undefined) {\n\t\t\tif (typeof entry === \"function\") {\n\t\t\t\tif (argumentLength === 1) {\n\t\t\t\t\tentry(arguments_[0]);\n\t\t\t\t} else if (argumentLength === 2) {\n\t\t\t\t\tentry(arguments_[0], arguments_[1]);\n\t\t\t\t} else {\n\t\t\t\t\tentry(...arguments_);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Iterate a snapshot so listeners removed (or added) during the\n\t\t\t\t// emit — e.g. a once wrapper removing itself, or a listener calling\n\t\t\t\t// off() — cannot corrupt the in-flight iteration. This matches\n\t\t\t\t// Node's EventEmitter behavior. The single-listener fast path above\n\t\t\t\t// needs no copy since it cannot be mid-iteration mutated.\n\t\t\t\tconst listeners = entry.slice();\n\t\t\t\tconst len = listeners.length;\n\t\t\t\tfor (let i = 0; i < len; i++) {\n\t\t\t\t\tif (argumentLength === 1) {\n\t\t\t\t\t\tlisteners[i](arguments_[0]);\n\t\t\t\t\t} else if (argumentLength === 2) {\n\t\t\t\t\t\tlisteners[i](arguments_[0], arguments_[1]);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlisteners[i](...arguments_);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tresult = true;\n\t\t}\n\n\t\t// send it to the logger\n\t\tif (this._eventLogger) {\n\t\t\tthis.sendToEventLogger(event, arguments_);\n\t\t}\n\n\t\tif (!result && event === ERROR_EVENT) {\n\t\t\tconst error =\n\t\t\t\targuments_[0] instanceof Error\n\t\t\t\t\t? arguments_[0]\n\t\t\t\t\t: new Error(`${arguments_[0]}`);\n\n\t\t\tif (this._throwOnEmitError || this._throwOnEmptyListeners) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Gets all listeners for a specific event. If no event is provided, it returns all listeners\n\t * @param {string} [event] (Optional) The event name\n\t * @returns {EventListener[]} An array of listeners\n\t */\n\tpublic listeners(event: string | symbol): EventListener[] {\n\t\tconst entry = this._eventListeners.get(event);\n\t\tif (entry === undefined) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn typeof entry === \"function\" ? [entry] : entry;\n\t}\n\n\t/**\n\t * Removes all listeners for a specific event. If no event is provided, it removes all listeners\n\t * @param {string} [event] (Optional) The event name\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic removeAllListeners(event?: string | symbol): IEventEmitter {\n\t\tif (event !== undefined) {\n\t\t\tthis._eventListeners.delete(event);\n\t\t} else {\n\t\t\tthis._eventListeners.clear();\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the maximum number of listeners that can be added for a single event\n\t * @param {number} n The maximum number of listeners\n\t * @returns {void}\n\t */\n\tpublic setMaxListeners(n: number): void {\n\t\tthis._maxListeners = n < 0 ? 0 : n;\n\t}\n\n\t/**\n\t * Gets all listeners\n\t * @returns {EventListener[]} An array of listeners\n\t */\n\tpublic getAllListeners(): EventListener[] {\n\t\tconst result: EventListener[] = [];\n\t\tfor (const entry of this._eventListeners.values()) {\n\t\t\tif (typeof entry === \"function\") {\n\t\t\t\tresult.push(entry);\n\t\t\t} else {\n\t\t\t\tfor (let i = 0; i < entry.length; i++) {\n\t\t\t\t\tresult.push(entry[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Sends a log message using the configured logger based on the event name\n\t * @param {string | symbol} eventName - The event name that determines the log level\n\t * @param {unknown} data - The data to log\n\t */\n\tprivate sendToEventLogger(eventName: string | symbol, data: any): void {\n\t\t/* v8 ignore next 3 -- @preserve: guarded by caller */\n\t\tif (!this._eventLogger) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet message: string;\n\t\t/* v8 ignore next -- @preserve */\n\t\tif (typeof data === \"string\") {\n\t\t\tmessage = data;\n\t\t} else if (\n\t\t\tArray.isArray(data) &&\n\t\t\tdata.length > 0 &&\n\t\t\tdata[0] instanceof Error\n\t\t) {\n\t\t\tmessage = data[0].message;\n\t\t\t/* v8 ignore next -- @preserve */\n\t\t} else if (data instanceof Error) {\n\t\t\tmessage = data.message;\n\t\t} else if (\n\t\t\tArray.isArray(data) &&\n\t\t\tdata.length > 0 &&\n\t\t\ttypeof data[0]?.message === \"string\"\n\t\t) {\n\t\t\tmessage = data[0].message;\n\t\t} else {\n\t\t\tmessage = JSON.stringify(data);\n\t\t}\n\n\t\tswitch (eventName) {\n\t\t\tcase \"error\": {\n\t\t\t\tthis._eventLogger.error?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"warn\": {\n\t\t\t\tthis._eventLogger.warn?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"trace\": {\n\t\t\t\tthis._eventLogger.trace?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"debug\": {\n\t\t\t\tthis._eventLogger.debug?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"fatal\": {\n\t\t\t\tthis._eventLogger.fatal?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\tthis._eventLogger.info?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n","import type { HookFn, IHook } from \"../types.js\";\n\n/**\n * Concrete implementation of the IHook interface.\n * Provides a convenient class-based way to create hook entries.\n */\nexport class Hook implements IHook {\n\tpublic id?: string;\n\tpublic event: string;\n\tpublic handler: HookFn;\n\n\t/**\n\t * Creates a new Hook instance\n\t * @param {string} event - The event name for the hook\n\t * @param {HookFn} handler - The handler function for the hook\n\t * @param {string} [id] - Optional unique identifier for the hook\n\t */\n\tconstructor(event: string, handler: HookFn, id?: string) {\n\t\tthis.id = id;\n\t\tthis.event = event;\n\t\tthis.handler = handler;\n\t}\n}\n","import type {\n\tHookFn,\n\tIParallelHook,\n\tParallelHookFinalFn,\n\tParallelHookFn,\n\tParallelHookResult,\n} from \"../types.js\";\n\n/**\n * A ParallelHook fans a single invocation out to many registered hook\n * functions concurrently via Promise.allSettled, then calls a final\n * handler with the aggregated results — including failures — keyed by\n * the hook function reference for direct lookup. Each hook receives only\n * the original arguments; hooks do not see each other's results.\n *\n * Implements IHook for compatibility with Hookified.onHook(); the final\n * handler is called regardless of whether the parallel hook is invoked\n * directly or through Hookified.hook().\n *\n * Generics tighten the per-hook signature when every hook in the set\n * accepts the same `initialArgs` and returns the same result type.\n * Both default to `any` for backwards compatibility.\n *\n * @template TArgs - The shape of `initialArgs` passed to every hook\n * @template TResult - The result type each hook returns\n */\n// biome-ignore lint/suspicious/noExplicitAny: defaults preserve untyped use\nexport class ParallelHook<TArgs = any, TResult = any>\n\timplements IParallelHook<TArgs, TResult>\n{\n\tpublic id?: string;\n\tpublic event: string;\n\tpublic handler: HookFn;\n\tpublic hooks: ParallelHookFn<TArgs, TResult>[];\n\n\tprivate readonly _finalHandler: ParallelHookFinalFn<TArgs, TResult>;\n\n\t/**\n\t * Creates a new ParallelHook instance\n\t * @param {string} event - The event name for the hook\n\t * @param {ParallelHookFinalFn<TArgs, TResult>} finalHandler - Called once with `{ initialArgs, results }` after all parallel hooks settle\n\t * @param {string} [id] - Optional unique identifier for the hook\n\t */\n\tconstructor(\n\t\tevent: string,\n\t\tfinalHandler: ParallelHookFinalFn<TArgs, TResult>,\n\t\tid?: string,\n\t) {\n\t\tthis.id = id;\n\t\tthis.event = event;\n\t\tthis.hooks = [];\n\t\tthis._finalHandler = finalHandler;\n\n\t\t// biome-ignore lint/suspicious/noExplicitAny: this is for any parameter compatibility\n\t\tthis.handler = async (...arguments_: any[]) => {\n\t\t\tconst initialArgs: TArgs = (\n\t\t\t\targuments_.length === 1 ? arguments_[0] : arguments_\n\t\t\t) as TArgs;\n\n\t\t\t// Snapshot hooks at invocation time so concurrent addHook/removeHook\n\t\t\t// calls during the awaited Promise.allSettled cannot desync the\n\t\t\t// settled-index → hook mapping below.\n\t\t\tconst snapshot = [...this.hooks];\n\n\t\t\tconst settled = await Promise.allSettled(\n\t\t\t\tsnapshot.map((hook) =>\n\t\t\t\t\tPromise.resolve().then(() => hook({ initialArgs })),\n\t\t\t\t),\n\t\t\t);\n\n\t\t\tconst results = new Map<\n\t\t\t\tParallelHookFn<TArgs, TResult>,\n\t\t\t\tParallelHookResult<TResult>\n\t\t\t>();\n\t\t\tsnapshot.forEach((hook, index) => {\n\t\t\t\tconst outcome = settled[index];\n\t\t\t\tresults.set(\n\t\t\t\t\thook,\n\t\t\t\t\toutcome.status === \"fulfilled\"\n\t\t\t\t\t\t? { status: \"fulfilled\", result: outcome.value }\n\t\t\t\t\t\t: { status: \"rejected\", reason: outcome.reason },\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tawait this._finalHandler({ initialArgs, results });\n\t\t};\n\t}\n\n\t/**\n\t * Adds a hook function to the parallel set\n\t * @param {ParallelHookFn<TArgs, TResult>} hook - The hook function to add\n\t */\n\tpublic addHook(hook: ParallelHookFn<TArgs, TResult>): void {\n\t\tthis.hooks.push(hook);\n\t}\n\n\t/**\n\t * Removes a specific hook function from the parallel set\n\t * @param {ParallelHookFn<TArgs, TResult>} hook - The hook function to remove\n\t * @returns {boolean} true if the hook was found and removed\n\t */\n\tpublic removeHook(hook: ParallelHookFn<TArgs, TResult>): boolean {\n\t\tconst index = this.hooks.indexOf(hook);\n\t\tif (index !== -1) {\n\t\t\tthis.hooks.splice(index, 1);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n}\n","import type {\n\tHookFn,\n\tIWaterfallHook,\n\tWaterfallHookFn,\n\tWaterfallHookResult,\n} from \"../types.js\";\n\n/**\n * A WaterfallHook chains multiple hook functions sequentially,\n * where each hook receives a context with the previous result,\n * initial arguments, and accumulated results. After all hooks\n * have executed, the final handler receives the transformed result.\n * Implements IHook for compatibility with Hookified.onHook().\n */\nexport class WaterfallHook implements IWaterfallHook {\n\tpublic id?: string;\n\tpublic event: string;\n\tpublic handler: HookFn;\n\tpublic hooks: WaterfallHookFn[];\n\n\tprivate readonly _finalHandler: WaterfallHookFn;\n\n\t/**\n\t * Creates a new WaterfallHook instance\n\t * @param {string} event - The event name for the hook\n\t * @param {WaterfallHookFn} finalHandler - The final handler function that receives the transformed result\n\t * @param {string} [id] - Optional unique identifier for the hook\n\t */\n\tconstructor(event: string, finalHandler: WaterfallHookFn, id?: string) {\n\t\tthis.id = id;\n\t\tthis.event = event;\n\t\tthis.hooks = [];\n\t\tthis._finalHandler = finalHandler;\n\n\t\t// biome-ignore lint/suspicious/noExplicitAny: this is for any parameter compatibility\n\t\tthis.handler = async (...arguments_: any[]) => {\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: waterfall result type varies through the chain\n\t\t\tconst initialArgs: any =\n\t\t\t\targuments_.length === 1 ? arguments_[0] : arguments_;\n\t\t\tconst results: WaterfallHookResult[] = [];\n\n\t\t\tfor (const hook of this.hooks) {\n\t\t\t\tconst result = await hook({ initialArgs, results: [...results] });\n\t\t\t\tresults.push({ hook, result });\n\t\t\t}\n\n\t\t\tawait this._finalHandler({ initialArgs, results: [...results] });\n\t\t};\n\t}\n\n\t/**\n\t * Adds a hook function to the end of the waterfall chain\n\t * @param {WaterfallHookFn} hook - The hook function to add\n\t */\n\tpublic addHook(hook: WaterfallHookFn): void {\n\t\tthis.hooks.push(hook);\n\t}\n\n\t/**\n\t * Removes a specific hook function from the waterfall chain\n\t * @param {WaterfallHookFn} hook - The hook function to remove\n\t * @returns {boolean} true if the hook was found and removed\n\t */\n\tpublic removeHook(hook: WaterfallHookFn): boolean {\n\t\tconst index = this.hooks.indexOf(hook);\n\t\tif (index !== -1) {\n\t\t\tthis.hooks.splice(index, 1);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n}\n","import { Eventified } from \"./eventified.js\";\nimport type {\n\tHookFn,\n\tHookifiedOptions,\n\tIHook,\n\tIWaterfallHook,\n\tOnHookOptions,\n\tPrependHookOptions,\n\tWaterfallHookContext,\n\tWaterfallHookFn,\n\tWaterfallHookResult,\n} from \"./types.js\";\n\nexport type {\n\tHookFn,\n\tHookifiedOptions,\n\tIHook,\n\tIWaterfallHook,\n\tOnHookOptions,\n\tPrependHookOptions,\n\tWaterfallHookContext,\n\tWaterfallHookFn,\n\tWaterfallHookResult,\n};\n\nexport class Hookified extends Eventified {\n\tprivate readonly _hooks: Map<string, IHook[]>;\n\tprivate _throwOnHookError = false;\n\tprivate _enforceBeforeAfter = false;\n\tprivate _deprecatedHooks: Map<string, string>;\n\tprivate _allowDeprecated = true;\n\tprivate _useHookClone = true;\n\n\tconstructor(options?: HookifiedOptions) {\n\t\tsuper({\n\t\t\teventLogger: options?.eventLogger,\n\t\t\tthrowOnEmitError: options?.throwOnEmitError,\n\t\t\tthrowOnEmptyListeners: options?.throwOnEmptyListeners,\n\t\t});\n\t\tthis._hooks = new Map();\n\t\tthis._deprecatedHooks = options?.deprecatedHooks\n\t\t\t? new Map(options.deprecatedHooks)\n\t\t\t: new Map();\n\n\t\tif (options?.throwOnHookError !== undefined) {\n\t\t\tthis._throwOnHookError = options.throwOnHookError;\n\t\t}\n\n\t\tif (options?.enforceBeforeAfter !== undefined) {\n\t\t\tthis._enforceBeforeAfter = options.enforceBeforeAfter;\n\t\t}\n\n\t\tif (options?.allowDeprecated !== undefined) {\n\t\t\tthis._allowDeprecated = options.allowDeprecated;\n\t\t}\n\n\t\tif (options?.useHookClone !== undefined) {\n\t\t\tthis._useHookClone = options.useHookClone;\n\t\t}\n\t}\n\n\t/**\n\t * Gets all hooks\n\t * @returns {Map<string, IHook[]>}\n\t */\n\tpublic get hooks() {\n\t\treturn this._hooks;\n\t}\n\n\t/**\n\t * Gets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.\n\t * @returns {boolean}\n\t */\n\tpublic get throwOnHookError() {\n\t\treturn this._throwOnHookError;\n\t}\n\n\t/**\n\t * Sets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.\n\t * @param {boolean} value\n\t */\n\tpublic set throwOnHookError(value) {\n\t\tthis._throwOnHookError = value;\n\t}\n\n\t/**\n\t * Gets whether to enforce that all hook names start with 'before' or 'after'. Default is false.\n\t * @returns {boolean}\n\t * @default false\n\t */\n\tpublic get enforceBeforeAfter() {\n\t\treturn this._enforceBeforeAfter;\n\t}\n\n\t/**\n\t * Sets whether to enforce that all hook names start with 'before' or 'after'. Default is false.\n\t * @param {boolean} value\n\t */\n\tpublic set enforceBeforeAfter(value) {\n\t\tthis._enforceBeforeAfter = value;\n\t}\n\n\t/**\n\t * Gets the map of deprecated hook names to deprecation messages.\n\t * @returns {Map<string, string>}\n\t */\n\tpublic get deprecatedHooks() {\n\t\treturn this._deprecatedHooks;\n\t}\n\n\t/**\n\t * Sets the map of deprecated hook names to deprecation messages.\n\t * @param {Map<string, string>} value\n\t */\n\tpublic set deprecatedHooks(value) {\n\t\tthis._deprecatedHooks = value;\n\t}\n\n\t/**\n\t * Gets whether deprecated hooks are allowed to be registered and executed. Default is true.\n\t * @returns {boolean}\n\t */\n\tpublic get allowDeprecated() {\n\t\treturn this._allowDeprecated;\n\t}\n\n\t/**\n\t * Sets whether deprecated hooks are allowed to be registered and executed. Default is true.\n\t * @param {boolean} value\n\t */\n\tpublic set allowDeprecated(value) {\n\t\tthis._allowDeprecated = value;\n\t}\n\n\t/**\n\t * Gets whether hook objects are cloned before storing. Default is true.\n\t * @returns {boolean}\n\t */\n\tpublic get useHookClone() {\n\t\treturn this._useHookClone;\n\t}\n\n\t/**\n\t * Sets whether hook objects are cloned before storing. Default is true.\n\t * When false, the original IHook reference is stored directly.\n\t * @param {boolean} value\n\t */\n\tpublic set useHookClone(value) {\n\t\tthis._useHookClone = value;\n\t}\n\n\t/**\n\t * Adds a handler function for a specific event.\n\t * Supports both object and legacy signatures:\n\t * onHook({ event, handler }, options?)\n\t * onHook(event, handler)\n\t * To register multiple hooks at once, use {@link onHooks}.\n\t * @param {IHook | string} hookOrEvent - the hook object or event name\n\t * @param {OnHookOptions | HookFn} [optionsOrHandler] - options (when using object form) or handler function (when using string form)\n\t * @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation\n\t */\n\tpublic onHook(hook: IHook, options?: OnHookOptions): IHook | undefined;\n\tpublic onHook(event: string, handler: HookFn): IHook | undefined;\n\tpublic onHook(\n\t\thookOrEvent: IHook | string,\n\t\toptionsOrHandler?: OnHookOptions | HookFn,\n\t): IHook | undefined {\n\t\tlet hook: IHook;\n\t\tlet options: OnHookOptions | undefined;\n\n\t\tif (typeof hookOrEvent === \"string\") {\n\t\t\tif (typeof optionsOrHandler !== \"function\") {\n\t\t\t\tthrow new TypeError(\n\t\t\t\t\t\"When calling onHook(event, handler), the second argument must be a function\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\thook = { event: hookOrEvent, handler: optionsOrHandler };\n\t\t\toptions = undefined;\n\t\t} else {\n\t\t\thook = hookOrEvent;\n\t\t\toptions = optionsOrHandler as OnHookOptions | undefined;\n\t\t}\n\t\tthis.validateHookName(hook.event);\n\t\tif (!this.checkDeprecatedHook(hook.event)) {\n\t\t\treturn undefined; // Skip registration if deprecated hooks are not allowed\n\t\t}\n\n\t\tconst shouldClone = options?.useHookClone ?? this._useHookClone;\n\t\tconst entry: IHook = shouldClone\n\t\t\t? { id: hook.id, event: hook.event, handler: hook.handler }\n\t\t\t: hook;\n\n\t\tentry.id = entry.id ?? crypto.randomUUID();\n\n\t\tconst eventHandlers = this._hooks.get(hook.event);\n\t\tif (eventHandlers) {\n\t\t\t// Check for duplicate id — replace in-place if found\n\t\t\tconst existingIndex = eventHandlers.findIndex((h) => h.id === entry.id);\n\t\t\tif (existingIndex !== -1) {\n\t\t\t\teventHandlers[existingIndex] = entry;\n\t\t\t} else {\n\t\t\t\tconst position = options?.position ?? \"Bottom\";\n\t\t\t\tif (position === \"Top\") {\n\t\t\t\t\teventHandlers.unshift(entry);\n\t\t\t\t} else if (position === \"Bottom\") {\n\t\t\t\t\teventHandlers.push(entry);\n\t\t\t\t} else {\n\t\t\t\t\tconst index = Math.max(0, Math.min(position, eventHandlers.length));\n\t\t\t\t\teventHandlers.splice(index, 0, entry);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthis._hooks.set(hook.event, [entry]);\n\t\t}\n\n\t\treturn entry;\n\t}\n\n\t/**\n\t * Alias for onHook. This is provided for compatibility with other libraries that use the `addHook` method.\n\t * @param {string} event - the event name\n\t * @param {HookFn} handler - the handler function\n\t * @returns {void}\n\t */\n\tpublic addHook(event: string, handler: HookFn) {\n\t\tthis.onHook({ event, handler });\n\t}\n\n\t/**\n\t * Adds handler functions for specific events\n\t * @param {Array<IHook>} hooks\n\t * @param {OnHookOptions} [options] - optional per-call options (e.g., useHookClone override, position)\n\t * @returns {void}\n\t */\n\tpublic onHooks(hooks: IHook[], options?: OnHookOptions) {\n\t\tfor (const hook of hooks) {\n\t\t\tthis.onHook(hook, options);\n\t\t}\n\t}\n\n\t/**\n\t * Adds a handler function for a specific event that runs before all other handlers.\n\t * Equivalent to calling `onHook(hook, { position: \"Top\" })`.\n\t * @param {IHook} hook - the hook containing event name and handler\n\t * @param {PrependHookOptions} [options] - optional per-call options (e.g., useHookClone override)\n\t * @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation\n\t */\n\tpublic prependHook(\n\t\thook: IHook,\n\t\toptions?: PrependHookOptions,\n\t): IHook | undefined {\n\t\treturn this.onHook(hook, { ...options, position: \"Top\" });\n\t}\n\n\t/**\n\t * Adds a handler that only executes once for a specific event before all other handlers.\n\t * Equivalent to calling `onHook` with a self-removing wrapper and `{ position: \"Top\" }`.\n\t * @param {IHook} hook - the hook containing event name and handler\n\t * @param {PrependHookOptions} [options] - optional per-call options (e.g., useHookClone override)\n\t * @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation\n\t */\n\tpublic prependOnceHook(\n\t\thook: IHook,\n\t\toptions?: PrependHookOptions,\n\t): IHook | undefined {\n\t\t// biome-ignore lint/suspicious/noExplicitAny: this is for any parameter compatibility\n\t\tconst wrappedHandler = async (...arguments_: any[]) => {\n\t\t\tthis.removeHook({ event: hook.event, handler: wrappedHandler });\n\t\t\treturn hook.handler(...arguments_);\n\t\t};\n\n\t\t// Keep a reference to the original handler so removeHook() can remove the\n\t\t// once wrapper when called with the original handler reference.\n\t\t// biome-ignore lint/suspicious/noExplicitAny: attaching metadata to the wrapper\n\t\t(wrappedHandler as any)._originalHandler = hook.handler;\n\n\t\treturn this.onHook(\n\t\t\t{ id: hook.id, event: hook.event, handler: wrappedHandler },\n\t\t\t{ ...options, position: \"Top\" },\n\t\t);\n\t}\n\n\t/**\n\t * Adds a handler that only executes once for a specific event\n\t * @param {IHook} hook - the hook containing event name and handler\n\t */\n\tpublic onceHook(hook: IHook) {\n\t\tthis.validateHookName(hook.event);\n\t\tif (!this.checkDeprecatedHook(hook.event)) {\n\t\t\treturn; // Skip registration if deprecated hooks are not allowed\n\t\t}\n\t\t// biome-ignore lint/suspicious/noExplicitAny: this is for any parameter compatibility\n\t\tconst wrappedHandler = async (...arguments_: any[]) => {\n\t\t\tthis.removeHook({ event: hook.event, handler: wrappedHandler });\n\t\t\treturn hook.handler(...arguments_);\n\t\t};\n\n\t\t// Keep a reference to the original handler so removeHook() can remove the\n\t\t// once wrapper when called with the original handler reference.\n\t\t// biome-ignore lint/suspicious/noExplicitAny: attaching metadata to the wrapper\n\t\t(wrappedHandler as any)._originalHandler = hook.handler;\n\n\t\tthis.onHook({ id: hook.id, event: hook.event, handler: wrappedHandler });\n\t}\n\n\t/**\n\t * Removes a handler function for a specific event\n\t * @param {IHook} hook - the hook containing event name and handler to remove\n\t * @returns {IHook | undefined} the removed hook, or undefined if not found\n\t */\n\tpublic removeHook(hook: IHook): IHook | undefined {\n\t\tthis.validateHookName(hook.event);\n\t\tconst eventHandlers = this._hooks.get(hook.event);\n\t\tif (eventHandlers) {\n\t\t\t// Prefer an exact handler match before falling back to once-wrapper\n\t\t\t// matching, so a normal hook is never left behind when an identical\n\t\t\t// once-wrapper happens to precede it in the array.\n\t\t\tlet index = eventHandlers.findIndex((h) => h.handler === hook.handler);\n\t\t\tif (index === -1) {\n\t\t\t\tindex = eventHandlers.findIndex((h) => {\n\t\t\t\t\t// Match once-wrappers by their original handler reference. The\n\t\t\t\t\t// undefined guard prevents a normal hook (whose _originalHandler\n\t\t\t\t\t// is also undefined) from matching when hook.handler is undefined.\n\t\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: wrapper metadata lookup\n\t\t\t\t\tconst original = (h.handler as any)._originalHandler;\n\t\t\t\t\treturn original !== undefined && original === hook.handler;\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (index !== -1) {\n\t\t\t\teventHandlers.splice(index, 1);\n\t\t\t\tif (eventHandlers.length === 0) {\n\t\t\t\t\tthis._hooks.delete(hook.event);\n\t\t\t\t}\n\n\t\t\t\treturn { event: hook.event, handler: hook.handler };\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Removes multiple hook handlers\n\t * @param {Array<IHook>} hooks\n\t * @returns {IHook[]} the hooks that were successfully removed\n\t */\n\tpublic removeHooks(hooks: IHook[]): IHook[] {\n\t\tconst removed: IHook[] = [];\n\t\tfor (const hook of hooks) {\n\t\t\tconst result = this.removeHook(hook);\n\t\t\tif (result) {\n\t\t\t\tremoved.push(result);\n\t\t\t}\n\t\t}\n\n\t\treturn removed;\n\t}\n\n\t/**\n\t * Calls all handlers for a specific event\n\t * @param {string} event\n\t * @param {T[]} arguments_\n\t * @returns {Promise<void>}\n\t */\n\tpublic async hook<T>(event: string, ...arguments_: T[]) {\n\t\tthis.validateHookName(event);\n\t\tif (!this.checkDeprecatedHook(event)) {\n\t\t\treturn; // Skip execution if deprecated hooks are not allowed\n\t\t}\n\t\tconst eventHandlers = this._hooks.get(event);\n\t\tif (eventHandlers) {\n\t\t\tfor (const hook of [...eventHandlers]) {\n\t\t\t\ttry {\n\t\t\t\t\tawait hook.handler(...arguments_);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst message = `${event}: ${(error as Error).message}`;\n\t\t\t\t\tthis.emit(\"error\", new Error(message));\n\n\t\t\t\t\tif (this._throwOnHookError) {\n\t\t\t\t\t\tthrow new Error(message);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Calls all synchronous handlers for a specific event.\n\t * Async handlers (declared with `async` keyword) are silently skipped.\n\t *\n\t * Note: The `hook` method is preferred as it executes both sync and async functions.\n\t * Use `hookSync` only when you specifically need synchronous execution.\n\t * @param {string} event\n\t * @param {T[]} arguments_\n\t * @returns {void}\n\t */\n\tpublic hookSync<T>(event: string, ...arguments_: T[]): void {\n\t\tthis.validateHookName(event);\n\t\tif (!this.checkDeprecatedHook(event)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst eventHandlers = this._hooks.get(event);\n\t\tif (eventHandlers) {\n\t\t\tfor (const hook of [...eventHandlers]) {\n\t\t\t\t// Skip async functions silently\n\t\t\t\tif (hook.handler.constructor.name === \"AsyncFunction\") {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\thook.handler(...arguments_);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst message = `${event}: ${(error as Error).message}`;\n\t\t\t\t\tthis.emit(\"error\", new Error(message));\n\n\t\t\t\t\tif (this._throwOnHookError) {\n\t\t\t\t\t\tthrow new Error(message);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Prepends the word `before` to your hook. Example is event is `test`, the before hook is `before:test`.\n\t * @param {string} event - The event name\n\t * @param {T[]} arguments_ - The arguments to pass to the hook\n\t */\n\tpublic async beforeHook<T>(event: string, ...arguments_: T[]) {\n\t\tawait this.hook(`before:${event}`, ...arguments_);\n\t}\n\n\t/**\n\t * Prepends the word `after` to your hook. Example is event is `test`, the after hook is `after:test`.\n\t * @param {string} event - The event name\n\t * @param {T[]} arguments_ - The arguments to pass to the hook\n\t */\n\tpublic async afterHook<T>(event: string, ...arguments_: T[]) {\n\t\tawait this.hook(`after:${event}`, ...arguments_);\n\t}\n\n\t/**\n\t * Calls all handlers for a specific event. This is an alias for `hook` and is provided for\n\t * compatibility with other libraries that use the `callHook` method.\n\t * @param {string} event\n\t * @param {T[]} arguments_\n\t * @returns {Promise<void>}\n\t */\n\tpublic async callHook<T>(event: string, ...arguments_: T[]) {\n\t\tawait this.hook(event, ...arguments_);\n\t}\n\n\t/**\n\t * Gets all hooks for a specific event\n\t * @param {string} event\n\t * @returns {IHook[]}\n\t */\n\tpublic getHooks(event: string) {\n\t\tthis.validateHookName(event);\n\t\treturn this._hooks.get(event);\n\t}\n\n\t/**\n\t * Gets a specific hook by id, searching across all events\n\t * @param {string} id - the hook id\n\t * @returns {IHook | undefined} the hook if found, or undefined\n\t */\n\tpublic getHook(id: string): IHook | undefined {\n\t\tfor (const eventHandlers of this._hooks.values()) {\n\t\t\tconst found = eventHandlers.find((h) => h.id === id);\n\t\t\tif (found) {\n\t\t\t\treturn found;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Removes one or more hooks by id, searching across all events\n\t * @param {string | string[]} id - the hook id or array of hook ids to remove\n\t * @returns {IHook | IHook[] | undefined} the removed hook(s), or undefined/empty array if not found\n\t */\n\tpublic removeHookById(id: string | string[]): IHook | IHook[] | undefined {\n\t\tif (Array.isArray(id)) {\n\t\t\tconst removed: IHook[] = [];\n\t\t\tfor (const singleId of id) {\n\t\t\t\tconst result = this.removeHookById(singleId);\n\t\t\t\tif (result && !Array.isArray(result)) {\n\t\t\t\t\tremoved.push(result);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn removed;\n\t\t}\n\n\t\tfor (const [event, eventHandlers] of this._hooks.entries()) {\n\t\t\tconst index = eventHandlers.findIndex((h) => h.id === id);\n\t\t\tif (index !== -1) {\n\t\t\t\tconst [removed] = eventHandlers.splice(index, 1);\n\t\t\t\tif (eventHandlers.length === 0) {\n\t\t\t\t\tthis._hooks.delete(event);\n\t\t\t\t}\n\n\t\t\t\treturn removed;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Removes all hooks\n\t * @returns {void}\n\t */\n\tpublic clearHooks() {\n\t\tthis._hooks.clear();\n\t}\n\n\t/**\n\t * Removes all hooks for a specific event and returns the removed hooks.\n\t * @param {string} event - The event name to remove hooks for.\n\t * @returns {IHook[]} the hooks that were removed\n\t */\n\tpublic removeEventHooks(event: string): IHook[] {\n\t\tthis.validateHookName(event);\n\t\tconst eventHandlers = this._hooks.get(event);\n\t\tif (eventHandlers) {\n\t\t\tconst removed = [...eventHandlers];\n\t\t\tthis._hooks.delete(event);\n\t\t\treturn removed;\n\t\t}\n\n\t\treturn [];\n\t}\n\n\t/**\n\t * Validates hook event name if enforceBeforeAfter is enabled\n\t * @param {string} event - The event name to validate\n\t * @throws {Error} If enforceBeforeAfter is true and event doesn't start with 'before' or 'after'\n\t */\n\tprivate validateHookName(event: string): void {\n\t\tif (this._enforceBeforeAfter) {\n\t\t\tconst eventValue = event.trim().toLocaleLowerCase();\n\t\t\tif (!eventValue.startsWith(\"before\") && !eventValue.startsWith(\"after\")) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Hook event \"${event}\" must start with \"before\" or \"after\" when enforceBeforeAfter is enabled`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks if a hook is deprecated and emits a warning if it is\n\t * @param {string} event - The event name to check\n\t * @returns {boolean} - Returns true if the hook should proceed, false if it should be blocked\n\t */\n\tprivate checkDeprecatedHook(event: string): boolean {\n\t\tif (this._deprecatedHooks.has(event)) {\n\t\t\tconst message = this._deprecatedHooks.get(event);\n\t\t\tconst warningMessage = `Hook \"${event}\" is deprecated${message ? `: ${message}` : \"\"}`;\n\n\t\t\t// Emit deprecation warning event\n\t\t\tthis.emit(\"warn\", { hook: event, message: warningMessage });\n\n\t\t\t// Return false if deprecated hooks are not allowed\n\t\t\treturn this._allowDeprecated;\n\t\t}\n\t\treturn true;\n\t}\n}\n\nexport { Eventified } from \"./eventified.js\";\nexport { Hook } from \"./hooks/hook.js\";\nexport { ParallelHook } from \"./hooks/parallel-hook.js\";\nexport { WaterfallHook } from \"./hooks/waterfall-hook.js\";\nexport type {\n\tEventEmitterOptions,\n\tEventListener,\n\tIEventEmitter,\n\tIParallelHook,\n\tLogger,\n\tParallelHookContext,\n\tParallelHookFinalContext,\n\tParallelHookFinalFn,\n\tParallelHookFn,\n\tParallelHookResult,\n} from \"./types.js\";\n"],"mappings":"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"}
|
package/dist/browser/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region \0@oxc-project+runtime@0.
|
|
1
|
+
//#region \0@oxc-project+runtime@0.135.0/helpers/esm/typeof.js
|
|
2
2
|
function _typeof(o) {
|
|
3
3
|
"@babel/helpers - typeof";
|
|
4
4
|
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
|
|
@@ -8,7 +8,7 @@ function _typeof(o) {
|
|
|
8
8
|
}, _typeof(o);
|
|
9
9
|
}
|
|
10
10
|
//#endregion
|
|
11
|
-
//#region \0@oxc-project+runtime@0.
|
|
11
|
+
//#region \0@oxc-project+runtime@0.135.0/helpers/esm/toPrimitive.js
|
|
12
12
|
function toPrimitive(t, r) {
|
|
13
13
|
if ("object" != _typeof(t) || !t) return t;
|
|
14
14
|
var e = t[Symbol.toPrimitive];
|
|
@@ -20,13 +20,13 @@ function toPrimitive(t, r) {
|
|
|
20
20
|
return ("string" === r ? String : Number)(t);
|
|
21
21
|
}
|
|
22
22
|
//#endregion
|
|
23
|
-
//#region \0@oxc-project+runtime@0.
|
|
23
|
+
//#region \0@oxc-project+runtime@0.135.0/helpers/esm/toPropertyKey.js
|
|
24
24
|
function toPropertyKey(t) {
|
|
25
25
|
var i = toPrimitive(t, "string");
|
|
26
26
|
return "symbol" == _typeof(i) ? i : i + "";
|
|
27
27
|
}
|
|
28
28
|
//#endregion
|
|
29
|
-
//#region \0@oxc-project+runtime@0.
|
|
29
|
+
//#region \0@oxc-project+runtime@0.135.0/helpers/esm/defineProperty.js
|
|
30
30
|
function _defineProperty(e, r, t) {
|
|
31
31
|
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
32
32
|
value: t,
|
|
@@ -104,6 +104,7 @@ var Eventified = class {
|
|
|
104
104
|
this.off(eventName, onceListener);
|
|
105
105
|
listener(...arguments_);
|
|
106
106
|
};
|
|
107
|
+
onceListener._originalListener = listener;
|
|
107
108
|
this.on(eventName, onceListener);
|
|
108
109
|
return this;
|
|
109
110
|
}
|
|
@@ -164,6 +165,7 @@ var Eventified = class {
|
|
|
164
165
|
this.off(eventName, onceListener);
|
|
165
166
|
listener(...arguments_);
|
|
166
167
|
};
|
|
168
|
+
onceListener._originalListener = listener;
|
|
167
169
|
this.prependListener(eventName, onceListener);
|
|
168
170
|
return this;
|
|
169
171
|
}
|
|
@@ -217,6 +219,19 @@ var Eventified = class {
|
|
|
217
219
|
return this;
|
|
218
220
|
}
|
|
219
221
|
/**
|
|
222
|
+
* Determines whether a stored listener matches the listener provided to off().
|
|
223
|
+
* A match occurs when the references are identical, or when the stored listener
|
|
224
|
+
* is a once-wrapper whose original listener equals the provided reference.
|
|
225
|
+
* @param {EventListener} stored - the listener currently stored
|
|
226
|
+
* @param {EventListener} target - the listener passed to off()
|
|
227
|
+
* @returns {boolean} true if the stored listener should be removed
|
|
228
|
+
*/
|
|
229
|
+
matchesListener(stored, target) {
|
|
230
|
+
if (stored === target) return true;
|
|
231
|
+
const original = stored._originalListener;
|
|
232
|
+
return original !== void 0 && original === target;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
220
235
|
* Removes a listener for a specific event
|
|
221
236
|
* @param {string | symbol} event
|
|
222
237
|
* @param {EventListener} listener
|
|
@@ -226,10 +241,11 @@ var Eventified = class {
|
|
|
226
241
|
const entry = this._eventListeners.get(event);
|
|
227
242
|
if (entry === void 0) return this;
|
|
228
243
|
if (typeof entry === "function") {
|
|
229
|
-
if (entry
|
|
244
|
+
if (this.matchesListener(entry, listener)) this._eventListeners.delete(event);
|
|
230
245
|
return this;
|
|
231
246
|
}
|
|
232
|
-
|
|
247
|
+
let index = entry.indexOf(listener);
|
|
248
|
+
if (index === -1) index = entry.findIndex((stored) => this.matchesListener(stored, listener));
|
|
233
249
|
if (index !== -1) if (entry.length === 2) this._eventListeners.set(event, entry[1 - index]);
|
|
234
250
|
else if (entry.length === 1) this._eventListeners.delete(event);
|
|
235
251
|
else entry.splice(index, 1);
|
|
@@ -250,10 +266,11 @@ var Eventified = class {
|
|
|
250
266
|
else if (argumentLength === 2) entry(arguments_[0], arguments_[1]);
|
|
251
267
|
else entry(...arguments_);
|
|
252
268
|
else {
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
else
|
|
269
|
+
const listeners = entry.slice();
|
|
270
|
+
const len = listeners.length;
|
|
271
|
+
for (let i = 0; i < len; i++) if (argumentLength === 1) listeners[i](arguments_[0]);
|
|
272
|
+
else if (argumentLength === 2) listeners[i](arguments_[0], arguments_[1]);
|
|
273
|
+
else listeners[i](...arguments_);
|
|
257
274
|
}
|
|
258
275
|
result = true;
|
|
259
276
|
}
|
|
@@ -712,6 +729,7 @@ var Hookified = class extends Eventified {
|
|
|
712
729
|
});
|
|
713
730
|
return hook.handler(...arguments_);
|
|
714
731
|
};
|
|
732
|
+
wrappedHandler._originalHandler = hook.handler;
|
|
715
733
|
return this.onHook({
|
|
716
734
|
id: hook.id,
|
|
717
735
|
event: hook.event,
|
|
@@ -735,6 +753,7 @@ var Hookified = class extends Eventified {
|
|
|
735
753
|
});
|
|
736
754
|
return hook.handler(...arguments_);
|
|
737
755
|
};
|
|
756
|
+
wrappedHandler._originalHandler = hook.handler;
|
|
738
757
|
this.onHook({
|
|
739
758
|
id: hook.id,
|
|
740
759
|
event: hook.event,
|
|
@@ -750,7 +769,11 @@ var Hookified = class extends Eventified {
|
|
|
750
769
|
this.validateHookName(hook.event);
|
|
751
770
|
const eventHandlers = this._hooks.get(hook.event);
|
|
752
771
|
if (eventHandlers) {
|
|
753
|
-
|
|
772
|
+
let index = eventHandlers.findIndex((h) => h.handler === hook.handler);
|
|
773
|
+
if (index === -1) index = eventHandlers.findIndex((h) => {
|
|
774
|
+
const original = h.handler._originalHandler;
|
|
775
|
+
return original !== void 0 && original === hook.handler;
|
|
776
|
+
});
|
|
754
777
|
if (index !== -1) {
|
|
755
778
|
eventHandlers.splice(index, 1);
|
|
756
779
|
if (eventHandlers.length === 0) this._hooks.delete(hook.event);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/eventified.ts","../../src/hooks/hook.ts","../../src/hooks/parallel-hook.ts","../../src/hooks/waterfall-hook.ts","../../src/index.ts"],"sourcesContent":["// biome-ignore-all lint/suspicious/noExplicitAny: this is for event emitter compatibility\nimport type {\n\tEventEmitterOptions,\n\tEventListener,\n\tIEventEmitter,\n\tLogger,\n} from \"./types.js\";\n\nexport type { EventEmitterOptions, EventListener, IEventEmitter };\n\nconst ERROR_EVENT = \"error\";\n\nexport class Eventified implements IEventEmitter {\n\tprivate readonly _eventListeners: Map<\n\t\tstring | symbol,\n\t\tEventListener | EventListener[]\n\t>;\n\tprivate _maxListeners: number;\n\tprivate _eventLogger?: Logger;\n\tprivate _throwOnEmitError = false;\n\tprivate _throwOnEmptyListeners = true;\n\n\tconstructor(options?: EventEmitterOptions) {\n\t\tthis._eventListeners = new Map<\n\t\t\tstring | symbol,\n\t\t\tEventListener | EventListener[]\n\t\t>();\n\t\tthis._maxListeners = 0; // Default is 0 (unlimited)\n\n\t\tthis._eventLogger = options?.eventLogger;\n\n\t\tif (options?.throwOnEmitError !== undefined) {\n\t\t\tthis._throwOnEmitError = options.throwOnEmitError;\n\t\t}\n\n\t\tif (options?.throwOnEmptyListeners !== undefined) {\n\t\t\tthis._throwOnEmptyListeners = options.throwOnEmptyListeners;\n\t\t}\n\t}\n\n\t/**\n\t * Gets the event logger\n\t * @returns {Logger}\n\t */\n\tpublic get eventLogger(): Logger | undefined {\n\t\treturn this._eventLogger;\n\t}\n\n\t/**\n\t * Sets the event logger\n\t * @param {Logger} eventLogger\n\t */\n\tpublic set eventLogger(eventLogger: Logger | undefined) {\n\t\tthis._eventLogger = eventLogger;\n\t}\n\n\t/**\n\t * Gets whether an error should be thrown when an emit throws an error. Default is false and only emits an error event.\n\t * @returns {boolean}\n\t */\n\tpublic get throwOnEmitError(): boolean {\n\t\treturn this._throwOnEmitError;\n\t}\n\n\t/**\n\t * Sets whether an error should be thrown when an emit throws an error. Default is false and only emits an error event.\n\t * @param {boolean} value\n\t */\n\tpublic set throwOnEmitError(value: boolean) {\n\t\tthis._throwOnEmitError = value;\n\t}\n\n\t/**\n\t * Gets whether an error should be thrown when emitting 'error' event with no listeners. Default is false.\n\t * @returns {boolean}\n\t */\n\tpublic get throwOnEmptyListeners(): boolean {\n\t\treturn this._throwOnEmptyListeners;\n\t}\n\n\t/**\n\t * Sets whether an error should be thrown when emitting 'error' event with no listeners. Default is false.\n\t * @param {boolean} value\n\t */\n\tpublic set throwOnEmptyListeners(value: boolean) {\n\t\tthis._throwOnEmptyListeners = value;\n\t}\n\n\t/**\n\t * Adds a handler function for a specific event that will run only once\n\t * @param {string | symbol} eventName\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic once(\n\t\teventName: string | symbol,\n\t\tlistener: EventListener,\n\t): IEventEmitter {\n\t\tconst onceListener: EventListener = (...arguments_: any[]) => {\n\t\t\tthis.off(eventName as string, onceListener);\n\t\t\tlistener(...arguments_);\n\t\t};\n\n\t\tthis.on(eventName as string, onceListener);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets the number of listeners for a specific event. If no event is provided, it returns the total number of listeners\n\t * @param {string} eventName The event name. Not required\n\t * @returns {number} The number of listeners\n\t */\n\tpublic listenerCount(eventName?: string | symbol): number {\n\t\tif (eventName === undefined) {\n\t\t\tlet count = 0;\n\t\t\tfor (const entry of this._eventListeners.values()) {\n\t\t\t\tcount += typeof entry === \"function\" ? 1 : entry.length;\n\t\t\t}\n\n\t\t\treturn count;\n\t\t}\n\n\t\tconst entry = this._eventListeners.get(eventName);\n\t\tif (entry === undefined) {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn typeof entry === \"function\" ? 1 : entry.length;\n\t}\n\n\t/**\n\t * Gets an array of event names\n\t * @returns {Array<string | symbol>} An array of event names\n\t */\n\tpublic eventNames(): Array<string | symbol> {\n\t\treturn [...this._eventListeners.keys()];\n\t}\n\n\t/**\n\t * Gets an array of listeners for a specific event. If no event is provided, it returns all listeners\n\t * @param {string} [event] (Optional) The event name\n\t * @returns {EventListener[]} An array of listeners\n\t */\n\tpublic rawListeners(event?: string | symbol): EventListener[] {\n\t\tif (event === undefined) {\n\t\t\treturn this.getAllListeners();\n\t\t}\n\n\t\tconst entry = this._eventListeners.get(event);\n\t\tif (entry === undefined) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn typeof entry === \"function\" ? [entry] : entry;\n\t}\n\n\t/**\n\t * Prepends a listener to the beginning of the listeners array for the specified event\n\t * @param {string | symbol} eventName\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic prependListener(\n\t\teventName: string | symbol,\n\t\tlistener: EventListener,\n\t): IEventEmitter {\n\t\tconst existing = this._eventListeners.get(eventName);\n\n\t\tif (existing === undefined) {\n\t\t\tthis._eventListeners.set(eventName, listener);\n\t\t} else if (typeof existing === \"function\") {\n\t\t\tthis._eventListeners.set(eventName, [listener, existing]);\n\t\t} else {\n\t\t\texisting.unshift(listener);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Prepends a one-time listener to the beginning of the listeners array for the specified event\n\t * @param {string | symbol} eventName\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic prependOnceListener(\n\t\teventName: string | symbol,\n\t\tlistener: EventListener,\n\t): IEventEmitter {\n\t\tconst onceListener: EventListener = (...arguments_: any[]) => {\n\t\t\tthis.off(eventName as string, onceListener);\n\t\t\tlistener(...arguments_);\n\t\t};\n\n\t\tthis.prependListener(eventName as string, onceListener);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets the maximum number of listeners that can be added for a single event\n\t * @returns {number} The maximum number of listeners\n\t */\n\tpublic maxListeners(): number {\n\t\treturn this._maxListeners;\n\t}\n\n\t/**\n\t * Adds a listener for a specific event. It is an alias for the on() method\n\t * @param {string | symbol} event\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic addListener(\n\t\tevent: string | symbol,\n\t\tlistener: EventListener,\n\t): IEventEmitter {\n\t\tthis.on(event, listener);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds a listener for a specific event\n\t * @param {string | symbol} event\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic on(event: string | symbol, listener: EventListener): IEventEmitter {\n\t\tconst existing = this._eventListeners.get(event);\n\n\t\tif (existing === undefined) {\n\t\t\tthis._eventListeners.set(event, listener);\n\t\t\treturn this;\n\t\t}\n\n\t\tif (typeof existing === \"function\") {\n\t\t\tconst arr = [existing, listener];\n\t\t\tthis._eventListeners.set(event, arr);\n\t\t\tif (this._maxListeners > 0 && arr.length > this._maxListeners) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`MaxListenersExceededWarning: Possible event memory leak detected. ${arr.length} ${event as string} listeners added. Use setMaxListeners() to increase limit.`,\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\texisting.push(listener);\n\t\t\tif (this._maxListeners > 0 && existing.length > this._maxListeners) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`MaxListenersExceededWarning: Possible event memory leak detected. ${existing.length} ${event as string} listeners added. Use setMaxListeners() to increase limit.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes a listener for a specific event. It is an alias for the off() method\n\t * @param {string | symbol} event\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic removeListener(event: string, listener: EventListener): IEventEmitter {\n\t\tthis.off(event, listener);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes a listener for a specific event\n\t * @param {string | symbol} event\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic off(event: string | symbol, listener: EventListener): IEventEmitter {\n\t\tconst entry = this._eventListeners.get(event);\n\t\tif (entry === undefined) {\n\t\t\treturn this;\n\t\t}\n\n\t\tif (typeof entry === \"function\") {\n\t\t\tif (entry === listener) {\n\t\t\t\tthis._eventListeners.delete(event);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tconst index = entry.indexOf(listener);\n\t\tif (index !== -1) {\n\t\t\tif (entry.length === 2) {\n\t\t\t\tthis._eventListeners.set(event, entry[1 - index]);\n\t\t\t\t/* v8 ignore start -- @preserve: single-element arrays are stored as functions */\n\t\t\t} else if (entry.length === 1) {\n\t\t\t\tthis._eventListeners.delete(event);\n\t\t\t\t/* v8 ignore stop */\n\t\t\t} else {\n\t\t\t\tentry.splice(index, 1);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Calls all listeners for a specific event\n\t * @param {string | symbol} event\n\t * @param arguments_ The arguments to pass to the listeners\n\t * @returns {boolean} Returns true if the event had listeners, false otherwise\n\t */\n\tpublic emit(event: string | symbol, ...arguments_: any[]): boolean {\n\t\tlet result = false;\n\t\tconst entry = this._eventListeners.get(event);\n\t\tconst argumentLength = arguments_.length;\n\n\t\tif (entry !== undefined) {\n\t\t\tif (typeof entry === \"function\") {\n\t\t\t\tif (argumentLength === 1) {\n\t\t\t\t\tentry(arguments_[0]);\n\t\t\t\t} else if (argumentLength === 2) {\n\t\t\t\t\tentry(arguments_[0], arguments_[1]);\n\t\t\t\t} else {\n\t\t\t\t\tentry(...arguments_);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst len = entry.length;\n\t\t\t\tfor (let i = 0; i < len; i++) {\n\t\t\t\t\tif (argumentLength === 1) {\n\t\t\t\t\t\tentry[i](arguments_[0]);\n\t\t\t\t\t} else if (argumentLength === 2) {\n\t\t\t\t\t\tentry[i](arguments_[0], arguments_[1]);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tentry[i](...arguments_);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tresult = true;\n\t\t}\n\n\t\t// send it to the logger\n\t\tif (this._eventLogger) {\n\t\t\tthis.sendToEventLogger(event, arguments_);\n\t\t}\n\n\t\tif (!result && event === ERROR_EVENT) {\n\t\t\tconst error =\n\t\t\t\targuments_[0] instanceof Error\n\t\t\t\t\t? arguments_[0]\n\t\t\t\t\t: new Error(`${arguments_[0]}`);\n\n\t\t\tif (this._throwOnEmitError || this._throwOnEmptyListeners) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Gets all listeners for a specific event. If no event is provided, it returns all listeners\n\t * @param {string} [event] (Optional) The event name\n\t * @returns {EventListener[]} An array of listeners\n\t */\n\tpublic listeners(event: string | symbol): EventListener[] {\n\t\tconst entry = this._eventListeners.get(event);\n\t\tif (entry === undefined) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn typeof entry === \"function\" ? [entry] : entry;\n\t}\n\n\t/**\n\t * Removes all listeners for a specific event. If no event is provided, it removes all listeners\n\t * @param {string} [event] (Optional) The event name\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic removeAllListeners(event?: string | symbol): IEventEmitter {\n\t\tif (event !== undefined) {\n\t\t\tthis._eventListeners.delete(event);\n\t\t} else {\n\t\t\tthis._eventListeners.clear();\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the maximum number of listeners that can be added for a single event\n\t * @param {number} n The maximum number of listeners\n\t * @returns {void}\n\t */\n\tpublic setMaxListeners(n: number): void {\n\t\tthis._maxListeners = n < 0 ? 0 : n;\n\t}\n\n\t/**\n\t * Gets all listeners\n\t * @returns {EventListener[]} An array of listeners\n\t */\n\tpublic getAllListeners(): EventListener[] {\n\t\tconst result: EventListener[] = [];\n\t\tfor (const entry of this._eventListeners.values()) {\n\t\t\tif (typeof entry === \"function\") {\n\t\t\t\tresult.push(entry);\n\t\t\t} else {\n\t\t\t\tfor (let i = 0; i < entry.length; i++) {\n\t\t\t\t\tresult.push(entry[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Sends a log message using the configured logger based on the event name\n\t * @param {string | symbol} eventName - The event name that determines the log level\n\t * @param {unknown} data - The data to log\n\t */\n\tprivate sendToEventLogger(eventName: string | symbol, data: any): void {\n\t\t/* v8 ignore next 3 -- @preserve: guarded by caller */\n\t\tif (!this._eventLogger) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet message: string;\n\t\t/* v8 ignore next -- @preserve */\n\t\tif (typeof data === \"string\") {\n\t\t\tmessage = data;\n\t\t} else if (\n\t\t\tArray.isArray(data) &&\n\t\t\tdata.length > 0 &&\n\t\t\tdata[0] instanceof Error\n\t\t) {\n\t\t\tmessage = data[0].message;\n\t\t\t/* v8 ignore next -- @preserve */\n\t\t} else if (data instanceof Error) {\n\t\t\tmessage = data.message;\n\t\t} else if (\n\t\t\tArray.isArray(data) &&\n\t\t\tdata.length > 0 &&\n\t\t\ttypeof data[0]?.message === \"string\"\n\t\t) {\n\t\t\tmessage = data[0].message;\n\t\t} else {\n\t\t\tmessage = JSON.stringify(data);\n\t\t}\n\n\t\tswitch (eventName) {\n\t\t\tcase \"error\": {\n\t\t\t\tthis._eventLogger.error?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"warn\": {\n\t\t\t\tthis._eventLogger.warn?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"trace\": {\n\t\t\t\tthis._eventLogger.trace?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"debug\": {\n\t\t\t\tthis._eventLogger.debug?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"fatal\": {\n\t\t\t\tthis._eventLogger.fatal?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\tthis._eventLogger.info?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n","import type { HookFn, IHook } from \"../types.js\";\n\n/**\n * Concrete implementation of the IHook interface.\n * Provides a convenient class-based way to create hook entries.\n */\nexport class Hook implements IHook {\n\tpublic id?: string;\n\tpublic event: string;\n\tpublic handler: HookFn;\n\n\t/**\n\t * Creates a new Hook instance\n\t * @param {string} event - The event name for the hook\n\t * @param {HookFn} handler - The handler function for the hook\n\t * @param {string} [id] - Optional unique identifier for the hook\n\t */\n\tconstructor(event: string, handler: HookFn, id?: string) {\n\t\tthis.id = id;\n\t\tthis.event = event;\n\t\tthis.handler = handler;\n\t}\n}\n","import type {\n\tHookFn,\n\tIParallelHook,\n\tParallelHookFinalFn,\n\tParallelHookFn,\n\tParallelHookResult,\n} from \"../types.js\";\n\n/**\n * A ParallelHook fans a single invocation out to many registered hook\n * functions concurrently via Promise.allSettled, then calls a final\n * handler with the aggregated results — including failures — keyed by\n * the hook function reference for direct lookup. Each hook receives only\n * the original arguments; hooks do not see each other's results.\n *\n * Implements IHook for compatibility with Hookified.onHook(); the final\n * handler is called regardless of whether the parallel hook is invoked\n * directly or through Hookified.hook().\n *\n * Generics tighten the per-hook signature when every hook in the set\n * accepts the same `initialArgs` and returns the same result type.\n * Both default to `any` for backwards compatibility.\n *\n * @template TArgs - The shape of `initialArgs` passed to every hook\n * @template TResult - The result type each hook returns\n */\n// biome-ignore lint/suspicious/noExplicitAny: defaults preserve untyped use\nexport class ParallelHook<TArgs = any, TResult = any>\n\timplements IParallelHook<TArgs, TResult>\n{\n\tpublic id?: string;\n\tpublic event: string;\n\tpublic handler: HookFn;\n\tpublic hooks: ParallelHookFn<TArgs, TResult>[];\n\n\tprivate readonly _finalHandler: ParallelHookFinalFn<TArgs, TResult>;\n\n\t/**\n\t * Creates a new ParallelHook instance\n\t * @param {string} event - The event name for the hook\n\t * @param {ParallelHookFinalFn<TArgs, TResult>} finalHandler - Called once with `{ initialArgs, results }` after all parallel hooks settle\n\t * @param {string} [id] - Optional unique identifier for the hook\n\t */\n\tconstructor(\n\t\tevent: string,\n\t\tfinalHandler: ParallelHookFinalFn<TArgs, TResult>,\n\t\tid?: string,\n\t) {\n\t\tthis.id = id;\n\t\tthis.event = event;\n\t\tthis.hooks = [];\n\t\tthis._finalHandler = finalHandler;\n\n\t\t// biome-ignore lint/suspicious/noExplicitAny: this is for any parameter compatibility\n\t\tthis.handler = async (...arguments_: any[]) => {\n\t\t\tconst initialArgs: TArgs = (\n\t\t\t\targuments_.length === 1 ? arguments_[0] : arguments_\n\t\t\t) as TArgs;\n\n\t\t\t// Snapshot hooks at invocation time so concurrent addHook/removeHook\n\t\t\t// calls during the awaited Promise.allSettled cannot desync the\n\t\t\t// settled-index → hook mapping below.\n\t\t\tconst snapshot = [...this.hooks];\n\n\t\t\tconst settled = await Promise.allSettled(\n\t\t\t\tsnapshot.map((hook) =>\n\t\t\t\t\tPromise.resolve().then(() => hook({ initialArgs })),\n\t\t\t\t),\n\t\t\t);\n\n\t\t\tconst results = new Map<\n\t\t\t\tParallelHookFn<TArgs, TResult>,\n\t\t\t\tParallelHookResult<TResult>\n\t\t\t>();\n\t\t\tsnapshot.forEach((hook, index) => {\n\t\t\t\tconst outcome = settled[index];\n\t\t\t\tresults.set(\n\t\t\t\t\thook,\n\t\t\t\t\toutcome.status === \"fulfilled\"\n\t\t\t\t\t\t? { status: \"fulfilled\", result: outcome.value }\n\t\t\t\t\t\t: { status: \"rejected\", reason: outcome.reason },\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tawait this._finalHandler({ initialArgs, results });\n\t\t};\n\t}\n\n\t/**\n\t * Adds a hook function to the parallel set\n\t * @param {ParallelHookFn<TArgs, TResult>} hook - The hook function to add\n\t */\n\tpublic addHook(hook: ParallelHookFn<TArgs, TResult>): void {\n\t\tthis.hooks.push(hook);\n\t}\n\n\t/**\n\t * Removes a specific hook function from the parallel set\n\t * @param {ParallelHookFn<TArgs, TResult>} hook - The hook function to remove\n\t * @returns {boolean} true if the hook was found and removed\n\t */\n\tpublic removeHook(hook: ParallelHookFn<TArgs, TResult>): boolean {\n\t\tconst index = this.hooks.indexOf(hook);\n\t\tif (index !== -1) {\n\t\t\tthis.hooks.splice(index, 1);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n}\n","import type {\n\tHookFn,\n\tIWaterfallHook,\n\tWaterfallHookFn,\n\tWaterfallHookResult,\n} from \"../types.js\";\n\n/**\n * A WaterfallHook chains multiple hook functions sequentially,\n * where each hook receives a context with the previous result,\n * initial arguments, and accumulated results. After all hooks\n * have executed, the final handler receives the transformed result.\n * Implements IHook for compatibility with Hookified.onHook().\n */\nexport class WaterfallHook implements IWaterfallHook {\n\tpublic id?: string;\n\tpublic event: string;\n\tpublic handler: HookFn;\n\tpublic hooks: WaterfallHookFn[];\n\n\tprivate readonly _finalHandler: WaterfallHookFn;\n\n\t/**\n\t * Creates a new WaterfallHook instance\n\t * @param {string} event - The event name for the hook\n\t * @param {WaterfallHookFn} finalHandler - The final handler function that receives the transformed result\n\t * @param {string} [id] - Optional unique identifier for the hook\n\t */\n\tconstructor(event: string, finalHandler: WaterfallHookFn, id?: string) {\n\t\tthis.id = id;\n\t\tthis.event = event;\n\t\tthis.hooks = [];\n\t\tthis._finalHandler = finalHandler;\n\n\t\t// biome-ignore lint/suspicious/noExplicitAny: this is for any parameter compatibility\n\t\tthis.handler = async (...arguments_: any[]) => {\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: waterfall result type varies through the chain\n\t\t\tconst initialArgs: any =\n\t\t\t\targuments_.length === 1 ? arguments_[0] : arguments_;\n\t\t\tconst results: WaterfallHookResult[] = [];\n\n\t\t\tfor (const hook of this.hooks) {\n\t\t\t\tconst result = await hook({ initialArgs, results: [...results] });\n\t\t\t\tresults.push({ hook, result });\n\t\t\t}\n\n\t\t\tawait this._finalHandler({ initialArgs, results: [...results] });\n\t\t};\n\t}\n\n\t/**\n\t * Adds a hook function to the end of the waterfall chain\n\t * @param {WaterfallHookFn} hook - The hook function to add\n\t */\n\tpublic addHook(hook: WaterfallHookFn): void {\n\t\tthis.hooks.push(hook);\n\t}\n\n\t/**\n\t * Removes a specific hook function from the waterfall chain\n\t * @param {WaterfallHookFn} hook - The hook function to remove\n\t * @returns {boolean} true if the hook was found and removed\n\t */\n\tpublic removeHook(hook: WaterfallHookFn): boolean {\n\t\tconst index = this.hooks.indexOf(hook);\n\t\tif (index !== -1) {\n\t\t\tthis.hooks.splice(index, 1);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n}\n","import { Eventified } from \"./eventified.js\";\nimport type {\n\tHookFn,\n\tHookifiedOptions,\n\tIHook,\n\tIWaterfallHook,\n\tOnHookOptions,\n\tPrependHookOptions,\n\tWaterfallHookContext,\n\tWaterfallHookFn,\n\tWaterfallHookResult,\n} from \"./types.js\";\n\nexport type {\n\tHookFn,\n\tHookifiedOptions,\n\tIHook,\n\tIWaterfallHook,\n\tOnHookOptions,\n\tPrependHookOptions,\n\tWaterfallHookContext,\n\tWaterfallHookFn,\n\tWaterfallHookResult,\n};\n\nexport class Hookified extends Eventified {\n\tprivate readonly _hooks: Map<string, IHook[]>;\n\tprivate _throwOnHookError = false;\n\tprivate _enforceBeforeAfter = false;\n\tprivate _deprecatedHooks: Map<string, string>;\n\tprivate _allowDeprecated = true;\n\tprivate _useHookClone = true;\n\n\tconstructor(options?: HookifiedOptions) {\n\t\tsuper({\n\t\t\teventLogger: options?.eventLogger,\n\t\t\tthrowOnEmitError: options?.throwOnEmitError,\n\t\t\tthrowOnEmptyListeners: options?.throwOnEmptyListeners,\n\t\t});\n\t\tthis._hooks = new Map();\n\t\tthis._deprecatedHooks = options?.deprecatedHooks\n\t\t\t? new Map(options.deprecatedHooks)\n\t\t\t: new Map();\n\n\t\tif (options?.throwOnHookError !== undefined) {\n\t\t\tthis._throwOnHookError = options.throwOnHookError;\n\t\t}\n\n\t\tif (options?.enforceBeforeAfter !== undefined) {\n\t\t\tthis._enforceBeforeAfter = options.enforceBeforeAfter;\n\t\t}\n\n\t\tif (options?.allowDeprecated !== undefined) {\n\t\t\tthis._allowDeprecated = options.allowDeprecated;\n\t\t}\n\n\t\tif (options?.useHookClone !== undefined) {\n\t\t\tthis._useHookClone = options.useHookClone;\n\t\t}\n\t}\n\n\t/**\n\t * Gets all hooks\n\t * @returns {Map<string, IHook[]>}\n\t */\n\tpublic get hooks() {\n\t\treturn this._hooks;\n\t}\n\n\t/**\n\t * Gets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.\n\t * @returns {boolean}\n\t */\n\tpublic get throwOnHookError() {\n\t\treturn this._throwOnHookError;\n\t}\n\n\t/**\n\t * Sets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.\n\t * @param {boolean} value\n\t */\n\tpublic set throwOnHookError(value) {\n\t\tthis._throwOnHookError = value;\n\t}\n\n\t/**\n\t * Gets whether to enforce that all hook names start with 'before' or 'after'. Default is false.\n\t * @returns {boolean}\n\t * @default false\n\t */\n\tpublic get enforceBeforeAfter() {\n\t\treturn this._enforceBeforeAfter;\n\t}\n\n\t/**\n\t * Sets whether to enforce that all hook names start with 'before' or 'after'. Default is false.\n\t * @param {boolean} value\n\t */\n\tpublic set enforceBeforeAfter(value) {\n\t\tthis._enforceBeforeAfter = value;\n\t}\n\n\t/**\n\t * Gets the map of deprecated hook names to deprecation messages.\n\t * @returns {Map<string, string>}\n\t */\n\tpublic get deprecatedHooks() {\n\t\treturn this._deprecatedHooks;\n\t}\n\n\t/**\n\t * Sets the map of deprecated hook names to deprecation messages.\n\t * @param {Map<string, string>} value\n\t */\n\tpublic set deprecatedHooks(value) {\n\t\tthis._deprecatedHooks = value;\n\t}\n\n\t/**\n\t * Gets whether deprecated hooks are allowed to be registered and executed. Default is true.\n\t * @returns {boolean}\n\t */\n\tpublic get allowDeprecated() {\n\t\treturn this._allowDeprecated;\n\t}\n\n\t/**\n\t * Sets whether deprecated hooks are allowed to be registered and executed. Default is true.\n\t * @param {boolean} value\n\t */\n\tpublic set allowDeprecated(value) {\n\t\tthis._allowDeprecated = value;\n\t}\n\n\t/**\n\t * Gets whether hook objects are cloned before storing. Default is true.\n\t * @returns {boolean}\n\t */\n\tpublic get useHookClone() {\n\t\treturn this._useHookClone;\n\t}\n\n\t/**\n\t * Sets whether hook objects are cloned before storing. Default is true.\n\t * When false, the original IHook reference is stored directly.\n\t * @param {boolean} value\n\t */\n\tpublic set useHookClone(value) {\n\t\tthis._useHookClone = value;\n\t}\n\n\t/**\n\t * Adds a handler function for a specific event.\n\t * Supports both object and legacy signatures:\n\t * onHook({ event, handler }, options?)\n\t * onHook(event, handler)\n\t * To register multiple hooks at once, use {@link onHooks}.\n\t * @param {IHook | string} hookOrEvent - the hook object or event name\n\t * @param {OnHookOptions | HookFn} [optionsOrHandler] - options (when using object form) or handler function (when using string form)\n\t * @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation\n\t */\n\tpublic onHook(hook: IHook, options?: OnHookOptions): IHook | undefined;\n\tpublic onHook(event: string, handler: HookFn): IHook | undefined;\n\tpublic onHook(\n\t\thookOrEvent: IHook | string,\n\t\toptionsOrHandler?: OnHookOptions | HookFn,\n\t): IHook | undefined {\n\t\tlet hook: IHook;\n\t\tlet options: OnHookOptions | undefined;\n\n\t\tif (typeof hookOrEvent === \"string\") {\n\t\t\tif (typeof optionsOrHandler !== \"function\") {\n\t\t\t\tthrow new TypeError(\n\t\t\t\t\t\"When calling onHook(event, handler), the second argument must be a function\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\thook = { event: hookOrEvent, handler: optionsOrHandler };\n\t\t\toptions = undefined;\n\t\t} else {\n\t\t\thook = hookOrEvent;\n\t\t\toptions = optionsOrHandler as OnHookOptions | undefined;\n\t\t}\n\t\tthis.validateHookName(hook.event);\n\t\tif (!this.checkDeprecatedHook(hook.event)) {\n\t\t\treturn undefined; // Skip registration if deprecated hooks are not allowed\n\t\t}\n\n\t\tconst shouldClone = options?.useHookClone ?? this._useHookClone;\n\t\tconst entry: IHook = shouldClone\n\t\t\t? { id: hook.id, event: hook.event, handler: hook.handler }\n\t\t\t: hook;\n\n\t\tentry.id = entry.id ?? crypto.randomUUID();\n\n\t\tconst eventHandlers = this._hooks.get(hook.event);\n\t\tif (eventHandlers) {\n\t\t\t// Check for duplicate id — replace in-place if found\n\t\t\tconst existingIndex = eventHandlers.findIndex((h) => h.id === entry.id);\n\t\t\tif (existingIndex !== -1) {\n\t\t\t\teventHandlers[existingIndex] = entry;\n\t\t\t} else {\n\t\t\t\tconst position = options?.position ?? \"Bottom\";\n\t\t\t\tif (position === \"Top\") {\n\t\t\t\t\teventHandlers.unshift(entry);\n\t\t\t\t} else if (position === \"Bottom\") {\n\t\t\t\t\teventHandlers.push(entry);\n\t\t\t\t} else {\n\t\t\t\t\tconst index = Math.max(0, Math.min(position, eventHandlers.length));\n\t\t\t\t\teventHandlers.splice(index, 0, entry);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthis._hooks.set(hook.event, [entry]);\n\t\t}\n\n\t\treturn entry;\n\t}\n\n\t/**\n\t * Alias for onHook. This is provided for compatibility with other libraries that use the `addHook` method.\n\t * @param {string} event - the event name\n\t * @param {HookFn} handler - the handler function\n\t * @returns {void}\n\t */\n\tpublic addHook(event: string, handler: HookFn) {\n\t\tthis.onHook({ event, handler });\n\t}\n\n\t/**\n\t * Adds handler functions for specific events\n\t * @param {Array<IHook>} hooks\n\t * @param {OnHookOptions} [options] - optional per-call options (e.g., useHookClone override, position)\n\t * @returns {void}\n\t */\n\tpublic onHooks(hooks: IHook[], options?: OnHookOptions) {\n\t\tfor (const hook of hooks) {\n\t\t\tthis.onHook(hook, options);\n\t\t}\n\t}\n\n\t/**\n\t * Adds a handler function for a specific event that runs before all other handlers.\n\t * Equivalent to calling `onHook(hook, { position: \"Top\" })`.\n\t * @param {IHook} hook - the hook containing event name and handler\n\t * @param {PrependHookOptions} [options] - optional per-call options (e.g., useHookClone override)\n\t * @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation\n\t */\n\tpublic prependHook(\n\t\thook: IHook,\n\t\toptions?: PrependHookOptions,\n\t): IHook | undefined {\n\t\treturn this.onHook(hook, { ...options, position: \"Top\" });\n\t}\n\n\t/**\n\t * Adds a handler that only executes once for a specific event before all other handlers.\n\t * Equivalent to calling `onHook` with a self-removing wrapper and `{ position: \"Top\" }`.\n\t * @param {IHook} hook - the hook containing event name and handler\n\t * @param {PrependHookOptions} [options] - optional per-call options (e.g., useHookClone override)\n\t * @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation\n\t */\n\tpublic prependOnceHook(\n\t\thook: IHook,\n\t\toptions?: PrependHookOptions,\n\t): IHook | undefined {\n\t\t// biome-ignore lint/suspicious/noExplicitAny: this is for any parameter compatibility\n\t\tconst wrappedHandler = async (...arguments_: any[]) => {\n\t\t\tthis.removeHook({ event: hook.event, handler: wrappedHandler });\n\t\t\treturn hook.handler(...arguments_);\n\t\t};\n\n\t\treturn this.onHook(\n\t\t\t{ id: hook.id, event: hook.event, handler: wrappedHandler },\n\t\t\t{ ...options, position: \"Top\" },\n\t\t);\n\t}\n\n\t/**\n\t * Adds a handler that only executes once for a specific event\n\t * @param {IHook} hook - the hook containing event name and handler\n\t */\n\tpublic onceHook(hook: IHook) {\n\t\tthis.validateHookName(hook.event);\n\t\tif (!this.checkDeprecatedHook(hook.event)) {\n\t\t\treturn; // Skip registration if deprecated hooks are not allowed\n\t\t}\n\t\t// biome-ignore lint/suspicious/noExplicitAny: this is for any parameter compatibility\n\t\tconst wrappedHandler = async (...arguments_: any[]) => {\n\t\t\tthis.removeHook({ event: hook.event, handler: wrappedHandler });\n\t\t\treturn hook.handler(...arguments_);\n\t\t};\n\n\t\tthis.onHook({ id: hook.id, event: hook.event, handler: wrappedHandler });\n\t}\n\n\t/**\n\t * Removes a handler function for a specific event\n\t * @param {IHook} hook - the hook containing event name and handler to remove\n\t * @returns {IHook | undefined} the removed hook, or undefined if not found\n\t */\n\tpublic removeHook(hook: IHook): IHook | undefined {\n\t\tthis.validateHookName(hook.event);\n\t\tconst eventHandlers = this._hooks.get(hook.event);\n\t\tif (eventHandlers) {\n\t\t\tconst index = eventHandlers.findIndex((h) => h.handler === hook.handler);\n\t\t\tif (index !== -1) {\n\t\t\t\teventHandlers.splice(index, 1);\n\t\t\t\tif (eventHandlers.length === 0) {\n\t\t\t\t\tthis._hooks.delete(hook.event);\n\t\t\t\t}\n\n\t\t\t\treturn { event: hook.event, handler: hook.handler };\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Removes multiple hook handlers\n\t * @param {Array<IHook>} hooks\n\t * @returns {IHook[]} the hooks that were successfully removed\n\t */\n\tpublic removeHooks(hooks: IHook[]): IHook[] {\n\t\tconst removed: IHook[] = [];\n\t\tfor (const hook of hooks) {\n\t\t\tconst result = this.removeHook(hook);\n\t\t\tif (result) {\n\t\t\t\tremoved.push(result);\n\t\t\t}\n\t\t}\n\n\t\treturn removed;\n\t}\n\n\t/**\n\t * Calls all handlers for a specific event\n\t * @param {string} event\n\t * @param {T[]} arguments_\n\t * @returns {Promise<void>}\n\t */\n\tpublic async hook<T>(event: string, ...arguments_: T[]) {\n\t\tthis.validateHookName(event);\n\t\tif (!this.checkDeprecatedHook(event)) {\n\t\t\treturn; // Skip execution if deprecated hooks are not allowed\n\t\t}\n\t\tconst eventHandlers = this._hooks.get(event);\n\t\tif (eventHandlers) {\n\t\t\tfor (const hook of [...eventHandlers]) {\n\t\t\t\ttry {\n\t\t\t\t\tawait hook.handler(...arguments_);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst message = `${event}: ${(error as Error).message}`;\n\t\t\t\t\tthis.emit(\"error\", new Error(message));\n\n\t\t\t\t\tif (this._throwOnHookError) {\n\t\t\t\t\t\tthrow new Error(message);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Calls all synchronous handlers for a specific event.\n\t * Async handlers (declared with `async` keyword) are silently skipped.\n\t *\n\t * Note: The `hook` method is preferred as it executes both sync and async functions.\n\t * Use `hookSync` only when you specifically need synchronous execution.\n\t * @param {string} event\n\t * @param {T[]} arguments_\n\t * @returns {void}\n\t */\n\tpublic hookSync<T>(event: string, ...arguments_: T[]): void {\n\t\tthis.validateHookName(event);\n\t\tif (!this.checkDeprecatedHook(event)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst eventHandlers = this._hooks.get(event);\n\t\tif (eventHandlers) {\n\t\t\tfor (const hook of [...eventHandlers]) {\n\t\t\t\t// Skip async functions silently\n\t\t\t\tif (hook.handler.constructor.name === \"AsyncFunction\") {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\thook.handler(...arguments_);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst message = `${event}: ${(error as Error).message}`;\n\t\t\t\t\tthis.emit(\"error\", new Error(message));\n\n\t\t\t\t\tif (this._throwOnHookError) {\n\t\t\t\t\t\tthrow new Error(message);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Prepends the word `before` to your hook. Example is event is `test`, the before hook is `before:test`.\n\t * @param {string} event - The event name\n\t * @param {T[]} arguments_ - The arguments to pass to the hook\n\t */\n\tpublic async beforeHook<T>(event: string, ...arguments_: T[]) {\n\t\tawait this.hook(`before:${event}`, ...arguments_);\n\t}\n\n\t/**\n\t * Prepends the word `after` to your hook. Example is event is `test`, the after hook is `after:test`.\n\t * @param {string} event - The event name\n\t * @param {T[]} arguments_ - The arguments to pass to the hook\n\t */\n\tpublic async afterHook<T>(event: string, ...arguments_: T[]) {\n\t\tawait this.hook(`after:${event}`, ...arguments_);\n\t}\n\n\t/**\n\t * Calls all handlers for a specific event. This is an alias for `hook` and is provided for\n\t * compatibility with other libraries that use the `callHook` method.\n\t * @param {string} event\n\t * @param {T[]} arguments_\n\t * @returns {Promise<void>}\n\t */\n\tpublic async callHook<T>(event: string, ...arguments_: T[]) {\n\t\tawait this.hook(event, ...arguments_);\n\t}\n\n\t/**\n\t * Gets all hooks for a specific event\n\t * @param {string} event\n\t * @returns {IHook[]}\n\t */\n\tpublic getHooks(event: string) {\n\t\tthis.validateHookName(event);\n\t\treturn this._hooks.get(event);\n\t}\n\n\t/**\n\t * Gets a specific hook by id, searching across all events\n\t * @param {string} id - the hook id\n\t * @returns {IHook | undefined} the hook if found, or undefined\n\t */\n\tpublic getHook(id: string): IHook | undefined {\n\t\tfor (const eventHandlers of this._hooks.values()) {\n\t\t\tconst found = eventHandlers.find((h) => h.id === id);\n\t\t\tif (found) {\n\t\t\t\treturn found;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Removes one or more hooks by id, searching across all events\n\t * @param {string | string[]} id - the hook id or array of hook ids to remove\n\t * @returns {IHook | IHook[] | undefined} the removed hook(s), or undefined/empty array if not found\n\t */\n\tpublic removeHookById(id: string | string[]): IHook | IHook[] | undefined {\n\t\tif (Array.isArray(id)) {\n\t\t\tconst removed: IHook[] = [];\n\t\t\tfor (const singleId of id) {\n\t\t\t\tconst result = this.removeHookById(singleId);\n\t\t\t\tif (result && !Array.isArray(result)) {\n\t\t\t\t\tremoved.push(result);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn removed;\n\t\t}\n\n\t\tfor (const [event, eventHandlers] of this._hooks.entries()) {\n\t\t\tconst index = eventHandlers.findIndex((h) => h.id === id);\n\t\t\tif (index !== -1) {\n\t\t\t\tconst [removed] = eventHandlers.splice(index, 1);\n\t\t\t\tif (eventHandlers.length === 0) {\n\t\t\t\t\tthis._hooks.delete(event);\n\t\t\t\t}\n\n\t\t\t\treturn removed;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Removes all hooks\n\t * @returns {void}\n\t */\n\tpublic clearHooks() {\n\t\tthis._hooks.clear();\n\t}\n\n\t/**\n\t * Removes all hooks for a specific event and returns the removed hooks.\n\t * @param {string} event - The event name to remove hooks for.\n\t * @returns {IHook[]} the hooks that were removed\n\t */\n\tpublic removeEventHooks(event: string): IHook[] {\n\t\tthis.validateHookName(event);\n\t\tconst eventHandlers = this._hooks.get(event);\n\t\tif (eventHandlers) {\n\t\t\tconst removed = [...eventHandlers];\n\t\t\tthis._hooks.delete(event);\n\t\t\treturn removed;\n\t\t}\n\n\t\treturn [];\n\t}\n\n\t/**\n\t * Validates hook event name if enforceBeforeAfter is enabled\n\t * @param {string} event - The event name to validate\n\t * @throws {Error} If enforceBeforeAfter is true and event doesn't start with 'before' or 'after'\n\t */\n\tprivate validateHookName(event: string): void {\n\t\tif (this._enforceBeforeAfter) {\n\t\t\tconst eventValue = event.trim().toLocaleLowerCase();\n\t\t\tif (!eventValue.startsWith(\"before\") && !eventValue.startsWith(\"after\")) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Hook event \"${event}\" must start with \"before\" or \"after\" when enforceBeforeAfter is enabled`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks if a hook is deprecated and emits a warning if it is\n\t * @param {string} event - The event name to check\n\t * @returns {boolean} - Returns true if the hook should proceed, false if it should be blocked\n\t */\n\tprivate checkDeprecatedHook(event: string): boolean {\n\t\tif (this._deprecatedHooks.has(event)) {\n\t\t\tconst message = this._deprecatedHooks.get(event);\n\t\t\tconst warningMessage = `Hook \"${event}\" is deprecated${message ? `: ${message}` : \"\"}`;\n\n\t\t\t// Emit deprecation warning event\n\t\t\tthis.emit(\"warn\", { hook: event, message: warningMessage });\n\n\t\t\t// Return false if deprecated hooks are not allowed\n\t\t\treturn this._allowDeprecated;\n\t\t}\n\t\treturn true;\n\t}\n}\n\nexport { Eventified } from \"./eventified.js\";\nexport { Hook } from \"./hooks/hook.js\";\nexport { ParallelHook } from \"./hooks/parallel-hook.js\";\nexport { WaterfallHook } from \"./hooks/waterfall-hook.js\";\nexport type {\n\tEventEmitterOptions,\n\tEventListener,\n\tIEventEmitter,\n\tIParallelHook,\n\tLogger,\n\tParallelHookContext,\n\tParallelHookFinalContext,\n\tParallelHookFinalFn,\n\tParallelHookFn,\n\tParallelHookResult,\n} from \"./types.js\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/eventified.ts","../../src/hooks/hook.ts","../../src/hooks/parallel-hook.ts","../../src/hooks/waterfall-hook.ts","../../src/index.ts"],"sourcesContent":["// biome-ignore-all lint/suspicious/noExplicitAny: this is for event emitter compatibility\nimport type {\n\tEventEmitterOptions,\n\tEventListener,\n\tIEventEmitter,\n\tLogger,\n} from \"./types.js\";\n\nexport type { EventEmitterOptions, EventListener, IEventEmitter };\n\nconst ERROR_EVENT = \"error\";\n\nexport class Eventified implements IEventEmitter {\n\tprivate readonly _eventListeners: Map<\n\t\tstring | symbol,\n\t\tEventListener | EventListener[]\n\t>;\n\tprivate _maxListeners: number;\n\tprivate _eventLogger?: Logger;\n\tprivate _throwOnEmitError = false;\n\tprivate _throwOnEmptyListeners = true;\n\n\tconstructor(options?: EventEmitterOptions) {\n\t\tthis._eventListeners = new Map<\n\t\t\tstring | symbol,\n\t\t\tEventListener | EventListener[]\n\t\t>();\n\t\tthis._maxListeners = 0; // Default is 0 (unlimited)\n\n\t\tthis._eventLogger = options?.eventLogger;\n\n\t\tif (options?.throwOnEmitError !== undefined) {\n\t\t\tthis._throwOnEmitError = options.throwOnEmitError;\n\t\t}\n\n\t\tif (options?.throwOnEmptyListeners !== undefined) {\n\t\t\tthis._throwOnEmptyListeners = options.throwOnEmptyListeners;\n\t\t}\n\t}\n\n\t/**\n\t * Gets the event logger\n\t * @returns {Logger}\n\t */\n\tpublic get eventLogger(): Logger | undefined {\n\t\treturn this._eventLogger;\n\t}\n\n\t/**\n\t * Sets the event logger\n\t * @param {Logger} eventLogger\n\t */\n\tpublic set eventLogger(eventLogger: Logger | undefined) {\n\t\tthis._eventLogger = eventLogger;\n\t}\n\n\t/**\n\t * Gets whether an error should be thrown when an emit throws an error. Default is false and only emits an error event.\n\t * @returns {boolean}\n\t */\n\tpublic get throwOnEmitError(): boolean {\n\t\treturn this._throwOnEmitError;\n\t}\n\n\t/**\n\t * Sets whether an error should be thrown when an emit throws an error. Default is false and only emits an error event.\n\t * @param {boolean} value\n\t */\n\tpublic set throwOnEmitError(value: boolean) {\n\t\tthis._throwOnEmitError = value;\n\t}\n\n\t/**\n\t * Gets whether an error should be thrown when emitting 'error' event with no listeners. Default is false.\n\t * @returns {boolean}\n\t */\n\tpublic get throwOnEmptyListeners(): boolean {\n\t\treturn this._throwOnEmptyListeners;\n\t}\n\n\t/**\n\t * Sets whether an error should be thrown when emitting 'error' event with no listeners. Default is false.\n\t * @param {boolean} value\n\t */\n\tpublic set throwOnEmptyListeners(value: boolean) {\n\t\tthis._throwOnEmptyListeners = value;\n\t}\n\n\t/**\n\t * Adds a handler function for a specific event that will run only once\n\t * @param {string | symbol} eventName\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic once(\n\t\teventName: string | symbol,\n\t\tlistener: EventListener,\n\t): IEventEmitter {\n\t\tconst onceListener: EventListener = (...arguments_: any[]) => {\n\t\t\tthis.off(eventName as string, onceListener);\n\t\t\tlistener(...arguments_);\n\t\t};\n\n\t\t// Keep a reference to the original listener so that off()/removeListener()\n\t\t// can remove the once wrapper when called with the original reference.\n\t\t(onceListener as any)._originalListener = listener;\n\n\t\tthis.on(eventName as string, onceListener);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets the number of listeners for a specific event. If no event is provided, it returns the total number of listeners\n\t * @param {string} eventName The event name. Not required\n\t * @returns {number} The number of listeners\n\t */\n\tpublic listenerCount(eventName?: string | symbol): number {\n\t\tif (eventName === undefined) {\n\t\t\tlet count = 0;\n\t\t\tfor (const entry of this._eventListeners.values()) {\n\t\t\t\tcount += typeof entry === \"function\" ? 1 : entry.length;\n\t\t\t}\n\n\t\t\treturn count;\n\t\t}\n\n\t\tconst entry = this._eventListeners.get(eventName);\n\t\tif (entry === undefined) {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn typeof entry === \"function\" ? 1 : entry.length;\n\t}\n\n\t/**\n\t * Gets an array of event names\n\t * @returns {Array<string | symbol>} An array of event names\n\t */\n\tpublic eventNames(): Array<string | symbol> {\n\t\treturn [...this._eventListeners.keys()];\n\t}\n\n\t/**\n\t * Gets an array of listeners for a specific event. If no event is provided, it returns all listeners\n\t * @param {string} [event] (Optional) The event name\n\t * @returns {EventListener[]} An array of listeners\n\t */\n\tpublic rawListeners(event?: string | symbol): EventListener[] {\n\t\tif (event === undefined) {\n\t\t\treturn this.getAllListeners();\n\t\t}\n\n\t\tconst entry = this._eventListeners.get(event);\n\t\tif (entry === undefined) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn typeof entry === \"function\" ? [entry] : entry;\n\t}\n\n\t/**\n\t * Prepends a listener to the beginning of the listeners array for the specified event\n\t * @param {string | symbol} eventName\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic prependListener(\n\t\teventName: string | symbol,\n\t\tlistener: EventListener,\n\t): IEventEmitter {\n\t\tconst existing = this._eventListeners.get(eventName);\n\n\t\tif (existing === undefined) {\n\t\t\tthis._eventListeners.set(eventName, listener);\n\t\t} else if (typeof existing === \"function\") {\n\t\t\tthis._eventListeners.set(eventName, [listener, existing]);\n\t\t} else {\n\t\t\texisting.unshift(listener);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Prepends a one-time listener to the beginning of the listeners array for the specified event\n\t * @param {string | symbol} eventName\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic prependOnceListener(\n\t\teventName: string | symbol,\n\t\tlistener: EventListener,\n\t): IEventEmitter {\n\t\tconst onceListener: EventListener = (...arguments_: any[]) => {\n\t\t\tthis.off(eventName as string, onceListener);\n\t\t\tlistener(...arguments_);\n\t\t};\n\n\t\t// Keep a reference to the original listener so that off()/removeListener()\n\t\t// can remove the once wrapper when called with the original reference.\n\t\t(onceListener as any)._originalListener = listener;\n\n\t\tthis.prependListener(eventName as string, onceListener);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets the maximum number of listeners that can be added for a single event\n\t * @returns {number} The maximum number of listeners\n\t */\n\tpublic maxListeners(): number {\n\t\treturn this._maxListeners;\n\t}\n\n\t/**\n\t * Adds a listener for a specific event. It is an alias for the on() method\n\t * @param {string | symbol} event\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic addListener(\n\t\tevent: string | symbol,\n\t\tlistener: EventListener,\n\t): IEventEmitter {\n\t\tthis.on(event, listener);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds a listener for a specific event\n\t * @param {string | symbol} event\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic on(event: string | symbol, listener: EventListener): IEventEmitter {\n\t\tconst existing = this._eventListeners.get(event);\n\n\t\tif (existing === undefined) {\n\t\t\tthis._eventListeners.set(event, listener);\n\t\t\treturn this;\n\t\t}\n\n\t\tif (typeof existing === \"function\") {\n\t\t\tconst arr = [existing, listener];\n\t\t\tthis._eventListeners.set(event, arr);\n\t\t\tif (this._maxListeners > 0 && arr.length > this._maxListeners) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`MaxListenersExceededWarning: Possible event memory leak detected. ${arr.length} ${event as string} listeners added. Use setMaxListeners() to increase limit.`,\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\texisting.push(listener);\n\t\t\tif (this._maxListeners > 0 && existing.length > this._maxListeners) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`MaxListenersExceededWarning: Possible event memory leak detected. ${existing.length} ${event as string} listeners added. Use setMaxListeners() to increase limit.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes a listener for a specific event. It is an alias for the off() method\n\t * @param {string | symbol} event\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic removeListener(event: string, listener: EventListener): IEventEmitter {\n\t\tthis.off(event, listener);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Determines whether a stored listener matches the listener provided to off().\n\t * A match occurs when the references are identical, or when the stored listener\n\t * is a once-wrapper whose original listener equals the provided reference.\n\t * @param {EventListener} stored - the listener currently stored\n\t * @param {EventListener} target - the listener passed to off()\n\t * @returns {boolean} true if the stored listener should be removed\n\t */\n\tprivate matchesListener(\n\t\tstored: EventListener,\n\t\ttarget: EventListener,\n\t): boolean {\n\t\tif (stored === target) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Only treat this as a once-wrapper match when an original listener was\n\t\t// actually recorded. Without this guard, calling off() with an undefined\n\t\t// target would match any normal listener (whose _originalListener is also\n\t\t// undefined) and remove it.\n\t\tconst original = (stored as any)._originalListener;\n\t\treturn original !== undefined && original === target;\n\t}\n\n\t/**\n\t * Removes a listener for a specific event\n\t * @param {string | symbol} event\n\t * @param {EventListener} listener\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic off(event: string | symbol, listener: EventListener): IEventEmitter {\n\t\tconst entry = this._eventListeners.get(event);\n\t\tif (entry === undefined) {\n\t\t\treturn this;\n\t\t}\n\n\t\tif (typeof entry === \"function\") {\n\t\t\tif (this.matchesListener(entry, listener)) {\n\t\t\t\tthis._eventListeners.delete(event);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\t// Prefer an exact reference match before falling back to once-wrapper\n\t\t// matching, so a normal listener is never left behind when an identical\n\t\t// once-wrapper happens to precede it in the array.\n\t\tlet index = entry.indexOf(listener);\n\t\tif (index === -1) {\n\t\t\tindex = entry.findIndex((stored) =>\n\t\t\t\tthis.matchesListener(stored, listener),\n\t\t\t);\n\t\t}\n\n\t\tif (index !== -1) {\n\t\t\tif (entry.length === 2) {\n\t\t\t\tthis._eventListeners.set(event, entry[1 - index]);\n\t\t\t\t/* v8 ignore start -- @preserve: single-element arrays are stored as functions */\n\t\t\t} else if (entry.length === 1) {\n\t\t\t\tthis._eventListeners.delete(event);\n\t\t\t\t/* v8 ignore stop */\n\t\t\t} else {\n\t\t\t\tentry.splice(index, 1);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Calls all listeners for a specific event\n\t * @param {string | symbol} event\n\t * @param arguments_ The arguments to pass to the listeners\n\t * @returns {boolean} Returns true if the event had listeners, false otherwise\n\t */\n\tpublic emit(event: string | symbol, ...arguments_: any[]): boolean {\n\t\tlet result = false;\n\t\tconst entry = this._eventListeners.get(event);\n\t\tconst argumentLength = arguments_.length;\n\n\t\tif (entry !== undefined) {\n\t\t\tif (typeof entry === \"function\") {\n\t\t\t\tif (argumentLength === 1) {\n\t\t\t\t\tentry(arguments_[0]);\n\t\t\t\t} else if (argumentLength === 2) {\n\t\t\t\t\tentry(arguments_[0], arguments_[1]);\n\t\t\t\t} else {\n\t\t\t\t\tentry(...arguments_);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Iterate a snapshot so listeners removed (or added) during the\n\t\t\t\t// emit — e.g. a once wrapper removing itself, or a listener calling\n\t\t\t\t// off() — cannot corrupt the in-flight iteration. This matches\n\t\t\t\t// Node's EventEmitter behavior. The single-listener fast path above\n\t\t\t\t// needs no copy since it cannot be mid-iteration mutated.\n\t\t\t\tconst listeners = entry.slice();\n\t\t\t\tconst len = listeners.length;\n\t\t\t\tfor (let i = 0; i < len; i++) {\n\t\t\t\t\tif (argumentLength === 1) {\n\t\t\t\t\t\tlisteners[i](arguments_[0]);\n\t\t\t\t\t} else if (argumentLength === 2) {\n\t\t\t\t\t\tlisteners[i](arguments_[0], arguments_[1]);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlisteners[i](...arguments_);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tresult = true;\n\t\t}\n\n\t\t// send it to the logger\n\t\tif (this._eventLogger) {\n\t\t\tthis.sendToEventLogger(event, arguments_);\n\t\t}\n\n\t\tif (!result && event === ERROR_EVENT) {\n\t\t\tconst error =\n\t\t\t\targuments_[0] instanceof Error\n\t\t\t\t\t? arguments_[0]\n\t\t\t\t\t: new Error(`${arguments_[0]}`);\n\n\t\t\tif (this._throwOnEmitError || this._throwOnEmptyListeners) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Gets all listeners for a specific event. If no event is provided, it returns all listeners\n\t * @param {string} [event] (Optional) The event name\n\t * @returns {EventListener[]} An array of listeners\n\t */\n\tpublic listeners(event: string | symbol): EventListener[] {\n\t\tconst entry = this._eventListeners.get(event);\n\t\tif (entry === undefined) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn typeof entry === \"function\" ? [entry] : entry;\n\t}\n\n\t/**\n\t * Removes all listeners for a specific event. If no event is provided, it removes all listeners\n\t * @param {string} [event] (Optional) The event name\n\t * @returns {IEventEmitter} returns the instance of the class for chaining\n\t */\n\tpublic removeAllListeners(event?: string | symbol): IEventEmitter {\n\t\tif (event !== undefined) {\n\t\t\tthis._eventListeners.delete(event);\n\t\t} else {\n\t\t\tthis._eventListeners.clear();\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the maximum number of listeners that can be added for a single event\n\t * @param {number} n The maximum number of listeners\n\t * @returns {void}\n\t */\n\tpublic setMaxListeners(n: number): void {\n\t\tthis._maxListeners = n < 0 ? 0 : n;\n\t}\n\n\t/**\n\t * Gets all listeners\n\t * @returns {EventListener[]} An array of listeners\n\t */\n\tpublic getAllListeners(): EventListener[] {\n\t\tconst result: EventListener[] = [];\n\t\tfor (const entry of this._eventListeners.values()) {\n\t\t\tif (typeof entry === \"function\") {\n\t\t\t\tresult.push(entry);\n\t\t\t} else {\n\t\t\t\tfor (let i = 0; i < entry.length; i++) {\n\t\t\t\t\tresult.push(entry[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Sends a log message using the configured logger based on the event name\n\t * @param {string | symbol} eventName - The event name that determines the log level\n\t * @param {unknown} data - The data to log\n\t */\n\tprivate sendToEventLogger(eventName: string | symbol, data: any): void {\n\t\t/* v8 ignore next 3 -- @preserve: guarded by caller */\n\t\tif (!this._eventLogger) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet message: string;\n\t\t/* v8 ignore next -- @preserve */\n\t\tif (typeof data === \"string\") {\n\t\t\tmessage = data;\n\t\t} else if (\n\t\t\tArray.isArray(data) &&\n\t\t\tdata.length > 0 &&\n\t\t\tdata[0] instanceof Error\n\t\t) {\n\t\t\tmessage = data[0].message;\n\t\t\t/* v8 ignore next -- @preserve */\n\t\t} else if (data instanceof Error) {\n\t\t\tmessage = data.message;\n\t\t} else if (\n\t\t\tArray.isArray(data) &&\n\t\t\tdata.length > 0 &&\n\t\t\ttypeof data[0]?.message === \"string\"\n\t\t) {\n\t\t\tmessage = data[0].message;\n\t\t} else {\n\t\t\tmessage = JSON.stringify(data);\n\t\t}\n\n\t\tswitch (eventName) {\n\t\t\tcase \"error\": {\n\t\t\t\tthis._eventLogger.error?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"warn\": {\n\t\t\t\tthis._eventLogger.warn?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"trace\": {\n\t\t\t\tthis._eventLogger.trace?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"debug\": {\n\t\t\t\tthis._eventLogger.debug?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"fatal\": {\n\t\t\t\tthis._eventLogger.fatal?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\tthis._eventLogger.info?.(message, { event: eventName, data });\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n","import type { HookFn, IHook } from \"../types.js\";\n\n/**\n * Concrete implementation of the IHook interface.\n * Provides a convenient class-based way to create hook entries.\n */\nexport class Hook implements IHook {\n\tpublic id?: string;\n\tpublic event: string;\n\tpublic handler: HookFn;\n\n\t/**\n\t * Creates a new Hook instance\n\t * @param {string} event - The event name for the hook\n\t * @param {HookFn} handler - The handler function for the hook\n\t * @param {string} [id] - Optional unique identifier for the hook\n\t */\n\tconstructor(event: string, handler: HookFn, id?: string) {\n\t\tthis.id = id;\n\t\tthis.event = event;\n\t\tthis.handler = handler;\n\t}\n}\n","import type {\n\tHookFn,\n\tIParallelHook,\n\tParallelHookFinalFn,\n\tParallelHookFn,\n\tParallelHookResult,\n} from \"../types.js\";\n\n/**\n * A ParallelHook fans a single invocation out to many registered hook\n * functions concurrently via Promise.allSettled, then calls a final\n * handler with the aggregated results — including failures — keyed by\n * the hook function reference for direct lookup. Each hook receives only\n * the original arguments; hooks do not see each other's results.\n *\n * Implements IHook for compatibility with Hookified.onHook(); the final\n * handler is called regardless of whether the parallel hook is invoked\n * directly or through Hookified.hook().\n *\n * Generics tighten the per-hook signature when every hook in the set\n * accepts the same `initialArgs` and returns the same result type.\n * Both default to `any` for backwards compatibility.\n *\n * @template TArgs - The shape of `initialArgs` passed to every hook\n * @template TResult - The result type each hook returns\n */\n// biome-ignore lint/suspicious/noExplicitAny: defaults preserve untyped use\nexport class ParallelHook<TArgs = any, TResult = any>\n\timplements IParallelHook<TArgs, TResult>\n{\n\tpublic id?: string;\n\tpublic event: string;\n\tpublic handler: HookFn;\n\tpublic hooks: ParallelHookFn<TArgs, TResult>[];\n\n\tprivate readonly _finalHandler: ParallelHookFinalFn<TArgs, TResult>;\n\n\t/**\n\t * Creates a new ParallelHook instance\n\t * @param {string} event - The event name for the hook\n\t * @param {ParallelHookFinalFn<TArgs, TResult>} finalHandler - Called once with `{ initialArgs, results }` after all parallel hooks settle\n\t * @param {string} [id] - Optional unique identifier for the hook\n\t */\n\tconstructor(\n\t\tevent: string,\n\t\tfinalHandler: ParallelHookFinalFn<TArgs, TResult>,\n\t\tid?: string,\n\t) {\n\t\tthis.id = id;\n\t\tthis.event = event;\n\t\tthis.hooks = [];\n\t\tthis._finalHandler = finalHandler;\n\n\t\t// biome-ignore lint/suspicious/noExplicitAny: this is for any parameter compatibility\n\t\tthis.handler = async (...arguments_: any[]) => {\n\t\t\tconst initialArgs: TArgs = (\n\t\t\t\targuments_.length === 1 ? arguments_[0] : arguments_\n\t\t\t) as TArgs;\n\n\t\t\t// Snapshot hooks at invocation time so concurrent addHook/removeHook\n\t\t\t// calls during the awaited Promise.allSettled cannot desync the\n\t\t\t// settled-index → hook mapping below.\n\t\t\tconst snapshot = [...this.hooks];\n\n\t\t\tconst settled = await Promise.allSettled(\n\t\t\t\tsnapshot.map((hook) =>\n\t\t\t\t\tPromise.resolve().then(() => hook({ initialArgs })),\n\t\t\t\t),\n\t\t\t);\n\n\t\t\tconst results = new Map<\n\t\t\t\tParallelHookFn<TArgs, TResult>,\n\t\t\t\tParallelHookResult<TResult>\n\t\t\t>();\n\t\t\tsnapshot.forEach((hook, index) => {\n\t\t\t\tconst outcome = settled[index];\n\t\t\t\tresults.set(\n\t\t\t\t\thook,\n\t\t\t\t\toutcome.status === \"fulfilled\"\n\t\t\t\t\t\t? { status: \"fulfilled\", result: outcome.value }\n\t\t\t\t\t\t: { status: \"rejected\", reason: outcome.reason },\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tawait this._finalHandler({ initialArgs, results });\n\t\t};\n\t}\n\n\t/**\n\t * Adds a hook function to the parallel set\n\t * @param {ParallelHookFn<TArgs, TResult>} hook - The hook function to add\n\t */\n\tpublic addHook(hook: ParallelHookFn<TArgs, TResult>): void {\n\t\tthis.hooks.push(hook);\n\t}\n\n\t/**\n\t * Removes a specific hook function from the parallel set\n\t * @param {ParallelHookFn<TArgs, TResult>} hook - The hook function to remove\n\t * @returns {boolean} true if the hook was found and removed\n\t */\n\tpublic removeHook(hook: ParallelHookFn<TArgs, TResult>): boolean {\n\t\tconst index = this.hooks.indexOf(hook);\n\t\tif (index !== -1) {\n\t\t\tthis.hooks.splice(index, 1);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n}\n","import type {\n\tHookFn,\n\tIWaterfallHook,\n\tWaterfallHookFn,\n\tWaterfallHookResult,\n} from \"../types.js\";\n\n/**\n * A WaterfallHook chains multiple hook functions sequentially,\n * where each hook receives a context with the previous result,\n * initial arguments, and accumulated results. After all hooks\n * have executed, the final handler receives the transformed result.\n * Implements IHook for compatibility with Hookified.onHook().\n */\nexport class WaterfallHook implements IWaterfallHook {\n\tpublic id?: string;\n\tpublic event: string;\n\tpublic handler: HookFn;\n\tpublic hooks: WaterfallHookFn[];\n\n\tprivate readonly _finalHandler: WaterfallHookFn;\n\n\t/**\n\t * Creates a new WaterfallHook instance\n\t * @param {string} event - The event name for the hook\n\t * @param {WaterfallHookFn} finalHandler - The final handler function that receives the transformed result\n\t * @param {string} [id] - Optional unique identifier for the hook\n\t */\n\tconstructor(event: string, finalHandler: WaterfallHookFn, id?: string) {\n\t\tthis.id = id;\n\t\tthis.event = event;\n\t\tthis.hooks = [];\n\t\tthis._finalHandler = finalHandler;\n\n\t\t// biome-ignore lint/suspicious/noExplicitAny: this is for any parameter compatibility\n\t\tthis.handler = async (...arguments_: any[]) => {\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: waterfall result type varies through the chain\n\t\t\tconst initialArgs: any =\n\t\t\t\targuments_.length === 1 ? arguments_[0] : arguments_;\n\t\t\tconst results: WaterfallHookResult[] = [];\n\n\t\t\tfor (const hook of this.hooks) {\n\t\t\t\tconst result = await hook({ initialArgs, results: [...results] });\n\t\t\t\tresults.push({ hook, result });\n\t\t\t}\n\n\t\t\tawait this._finalHandler({ initialArgs, results: [...results] });\n\t\t};\n\t}\n\n\t/**\n\t * Adds a hook function to the end of the waterfall chain\n\t * @param {WaterfallHookFn} hook - The hook function to add\n\t */\n\tpublic addHook(hook: WaterfallHookFn): void {\n\t\tthis.hooks.push(hook);\n\t}\n\n\t/**\n\t * Removes a specific hook function from the waterfall chain\n\t * @param {WaterfallHookFn} hook - The hook function to remove\n\t * @returns {boolean} true if the hook was found and removed\n\t */\n\tpublic removeHook(hook: WaterfallHookFn): boolean {\n\t\tconst index = this.hooks.indexOf(hook);\n\t\tif (index !== -1) {\n\t\t\tthis.hooks.splice(index, 1);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n}\n","import { Eventified } from \"./eventified.js\";\nimport type {\n\tHookFn,\n\tHookifiedOptions,\n\tIHook,\n\tIWaterfallHook,\n\tOnHookOptions,\n\tPrependHookOptions,\n\tWaterfallHookContext,\n\tWaterfallHookFn,\n\tWaterfallHookResult,\n} from \"./types.js\";\n\nexport type {\n\tHookFn,\n\tHookifiedOptions,\n\tIHook,\n\tIWaterfallHook,\n\tOnHookOptions,\n\tPrependHookOptions,\n\tWaterfallHookContext,\n\tWaterfallHookFn,\n\tWaterfallHookResult,\n};\n\nexport class Hookified extends Eventified {\n\tprivate readonly _hooks: Map<string, IHook[]>;\n\tprivate _throwOnHookError = false;\n\tprivate _enforceBeforeAfter = false;\n\tprivate _deprecatedHooks: Map<string, string>;\n\tprivate _allowDeprecated = true;\n\tprivate _useHookClone = true;\n\n\tconstructor(options?: HookifiedOptions) {\n\t\tsuper({\n\t\t\teventLogger: options?.eventLogger,\n\t\t\tthrowOnEmitError: options?.throwOnEmitError,\n\t\t\tthrowOnEmptyListeners: options?.throwOnEmptyListeners,\n\t\t});\n\t\tthis._hooks = new Map();\n\t\tthis._deprecatedHooks = options?.deprecatedHooks\n\t\t\t? new Map(options.deprecatedHooks)\n\t\t\t: new Map();\n\n\t\tif (options?.throwOnHookError !== undefined) {\n\t\t\tthis._throwOnHookError = options.throwOnHookError;\n\t\t}\n\n\t\tif (options?.enforceBeforeAfter !== undefined) {\n\t\t\tthis._enforceBeforeAfter = options.enforceBeforeAfter;\n\t\t}\n\n\t\tif (options?.allowDeprecated !== undefined) {\n\t\t\tthis._allowDeprecated = options.allowDeprecated;\n\t\t}\n\n\t\tif (options?.useHookClone !== undefined) {\n\t\t\tthis._useHookClone = options.useHookClone;\n\t\t}\n\t}\n\n\t/**\n\t * Gets all hooks\n\t * @returns {Map<string, IHook[]>}\n\t */\n\tpublic get hooks() {\n\t\treturn this._hooks;\n\t}\n\n\t/**\n\t * Gets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.\n\t * @returns {boolean}\n\t */\n\tpublic get throwOnHookError() {\n\t\treturn this._throwOnHookError;\n\t}\n\n\t/**\n\t * Sets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.\n\t * @param {boolean} value\n\t */\n\tpublic set throwOnHookError(value) {\n\t\tthis._throwOnHookError = value;\n\t}\n\n\t/**\n\t * Gets whether to enforce that all hook names start with 'before' or 'after'. Default is false.\n\t * @returns {boolean}\n\t * @default false\n\t */\n\tpublic get enforceBeforeAfter() {\n\t\treturn this._enforceBeforeAfter;\n\t}\n\n\t/**\n\t * Sets whether to enforce that all hook names start with 'before' or 'after'. Default is false.\n\t * @param {boolean} value\n\t */\n\tpublic set enforceBeforeAfter(value) {\n\t\tthis._enforceBeforeAfter = value;\n\t}\n\n\t/**\n\t * Gets the map of deprecated hook names to deprecation messages.\n\t * @returns {Map<string, string>}\n\t */\n\tpublic get deprecatedHooks() {\n\t\treturn this._deprecatedHooks;\n\t}\n\n\t/**\n\t * Sets the map of deprecated hook names to deprecation messages.\n\t * @param {Map<string, string>} value\n\t */\n\tpublic set deprecatedHooks(value) {\n\t\tthis._deprecatedHooks = value;\n\t}\n\n\t/**\n\t * Gets whether deprecated hooks are allowed to be registered and executed. Default is true.\n\t * @returns {boolean}\n\t */\n\tpublic get allowDeprecated() {\n\t\treturn this._allowDeprecated;\n\t}\n\n\t/**\n\t * Sets whether deprecated hooks are allowed to be registered and executed. Default is true.\n\t * @param {boolean} value\n\t */\n\tpublic set allowDeprecated(value) {\n\t\tthis._allowDeprecated = value;\n\t}\n\n\t/**\n\t * Gets whether hook objects are cloned before storing. Default is true.\n\t * @returns {boolean}\n\t */\n\tpublic get useHookClone() {\n\t\treturn this._useHookClone;\n\t}\n\n\t/**\n\t * Sets whether hook objects are cloned before storing. Default is true.\n\t * When false, the original IHook reference is stored directly.\n\t * @param {boolean} value\n\t */\n\tpublic set useHookClone(value) {\n\t\tthis._useHookClone = value;\n\t}\n\n\t/**\n\t * Adds a handler function for a specific event.\n\t * Supports both object and legacy signatures:\n\t * onHook({ event, handler }, options?)\n\t * onHook(event, handler)\n\t * To register multiple hooks at once, use {@link onHooks}.\n\t * @param {IHook | string} hookOrEvent - the hook object or event name\n\t * @param {OnHookOptions | HookFn} [optionsOrHandler] - options (when using object form) or handler function (when using string form)\n\t * @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation\n\t */\n\tpublic onHook(hook: IHook, options?: OnHookOptions): IHook | undefined;\n\tpublic onHook(event: string, handler: HookFn): IHook | undefined;\n\tpublic onHook(\n\t\thookOrEvent: IHook | string,\n\t\toptionsOrHandler?: OnHookOptions | HookFn,\n\t): IHook | undefined {\n\t\tlet hook: IHook;\n\t\tlet options: OnHookOptions | undefined;\n\n\t\tif (typeof hookOrEvent === \"string\") {\n\t\t\tif (typeof optionsOrHandler !== \"function\") {\n\t\t\t\tthrow new TypeError(\n\t\t\t\t\t\"When calling onHook(event, handler), the second argument must be a function\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\thook = { event: hookOrEvent, handler: optionsOrHandler };\n\t\t\toptions = undefined;\n\t\t} else {\n\t\t\thook = hookOrEvent;\n\t\t\toptions = optionsOrHandler as OnHookOptions | undefined;\n\t\t}\n\t\tthis.validateHookName(hook.event);\n\t\tif (!this.checkDeprecatedHook(hook.event)) {\n\t\t\treturn undefined; // Skip registration if deprecated hooks are not allowed\n\t\t}\n\n\t\tconst shouldClone = options?.useHookClone ?? this._useHookClone;\n\t\tconst entry: IHook = shouldClone\n\t\t\t? { id: hook.id, event: hook.event, handler: hook.handler }\n\t\t\t: hook;\n\n\t\tentry.id = entry.id ?? crypto.randomUUID();\n\n\t\tconst eventHandlers = this._hooks.get(hook.event);\n\t\tif (eventHandlers) {\n\t\t\t// Check for duplicate id — replace in-place if found\n\t\t\tconst existingIndex = eventHandlers.findIndex((h) => h.id === entry.id);\n\t\t\tif (existingIndex !== -1) {\n\t\t\t\teventHandlers[existingIndex] = entry;\n\t\t\t} else {\n\t\t\t\tconst position = options?.position ?? \"Bottom\";\n\t\t\t\tif (position === \"Top\") {\n\t\t\t\t\teventHandlers.unshift(entry);\n\t\t\t\t} else if (position === \"Bottom\") {\n\t\t\t\t\teventHandlers.push(entry);\n\t\t\t\t} else {\n\t\t\t\t\tconst index = Math.max(0, Math.min(position, eventHandlers.length));\n\t\t\t\t\teventHandlers.splice(index, 0, entry);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthis._hooks.set(hook.event, [entry]);\n\t\t}\n\n\t\treturn entry;\n\t}\n\n\t/**\n\t * Alias for onHook. This is provided for compatibility with other libraries that use the `addHook` method.\n\t * @param {string} event - the event name\n\t * @param {HookFn} handler - the handler function\n\t * @returns {void}\n\t */\n\tpublic addHook(event: string, handler: HookFn) {\n\t\tthis.onHook({ event, handler });\n\t}\n\n\t/**\n\t * Adds handler functions for specific events\n\t * @param {Array<IHook>} hooks\n\t * @param {OnHookOptions} [options] - optional per-call options (e.g., useHookClone override, position)\n\t * @returns {void}\n\t */\n\tpublic onHooks(hooks: IHook[], options?: OnHookOptions) {\n\t\tfor (const hook of hooks) {\n\t\t\tthis.onHook(hook, options);\n\t\t}\n\t}\n\n\t/**\n\t * Adds a handler function for a specific event that runs before all other handlers.\n\t * Equivalent to calling `onHook(hook, { position: \"Top\" })`.\n\t * @param {IHook} hook - the hook containing event name and handler\n\t * @param {PrependHookOptions} [options] - optional per-call options (e.g., useHookClone override)\n\t * @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation\n\t */\n\tpublic prependHook(\n\t\thook: IHook,\n\t\toptions?: PrependHookOptions,\n\t): IHook | undefined {\n\t\treturn this.onHook(hook, { ...options, position: \"Top\" });\n\t}\n\n\t/**\n\t * Adds a handler that only executes once for a specific event before all other handlers.\n\t * Equivalent to calling `onHook` with a self-removing wrapper and `{ position: \"Top\" }`.\n\t * @param {IHook} hook - the hook containing event name and handler\n\t * @param {PrependHookOptions} [options] - optional per-call options (e.g., useHookClone override)\n\t * @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation\n\t */\n\tpublic prependOnceHook(\n\t\thook: IHook,\n\t\toptions?: PrependHookOptions,\n\t): IHook | undefined {\n\t\t// biome-ignore lint/suspicious/noExplicitAny: this is for any parameter compatibility\n\t\tconst wrappedHandler = async (...arguments_: any[]) => {\n\t\t\tthis.removeHook({ event: hook.event, handler: wrappedHandler });\n\t\t\treturn hook.handler(...arguments_);\n\t\t};\n\n\t\t// Keep a reference to the original handler so removeHook() can remove the\n\t\t// once wrapper when called with the original handler reference.\n\t\t// biome-ignore lint/suspicious/noExplicitAny: attaching metadata to the wrapper\n\t\t(wrappedHandler as any)._originalHandler = hook.handler;\n\n\t\treturn this.onHook(\n\t\t\t{ id: hook.id, event: hook.event, handler: wrappedHandler },\n\t\t\t{ ...options, position: \"Top\" },\n\t\t);\n\t}\n\n\t/**\n\t * Adds a handler that only executes once for a specific event\n\t * @param {IHook} hook - the hook containing event name and handler\n\t */\n\tpublic onceHook(hook: IHook) {\n\t\tthis.validateHookName(hook.event);\n\t\tif (!this.checkDeprecatedHook(hook.event)) {\n\t\t\treturn; // Skip registration if deprecated hooks are not allowed\n\t\t}\n\t\t// biome-ignore lint/suspicious/noExplicitAny: this is for any parameter compatibility\n\t\tconst wrappedHandler = async (...arguments_: any[]) => {\n\t\t\tthis.removeHook({ event: hook.event, handler: wrappedHandler });\n\t\t\treturn hook.handler(...arguments_);\n\t\t};\n\n\t\t// Keep a reference to the original handler so removeHook() can remove the\n\t\t// once wrapper when called with the original handler reference.\n\t\t// biome-ignore lint/suspicious/noExplicitAny: attaching metadata to the wrapper\n\t\t(wrappedHandler as any)._originalHandler = hook.handler;\n\n\t\tthis.onHook({ id: hook.id, event: hook.event, handler: wrappedHandler });\n\t}\n\n\t/**\n\t * Removes a handler function for a specific event\n\t * @param {IHook} hook - the hook containing event name and handler to remove\n\t * @returns {IHook | undefined} the removed hook, or undefined if not found\n\t */\n\tpublic removeHook(hook: IHook): IHook | undefined {\n\t\tthis.validateHookName(hook.event);\n\t\tconst eventHandlers = this._hooks.get(hook.event);\n\t\tif (eventHandlers) {\n\t\t\t// Prefer an exact handler match before falling back to once-wrapper\n\t\t\t// matching, so a normal hook is never left behind when an identical\n\t\t\t// once-wrapper happens to precede it in the array.\n\t\t\tlet index = eventHandlers.findIndex((h) => h.handler === hook.handler);\n\t\t\tif (index === -1) {\n\t\t\t\tindex = eventHandlers.findIndex((h) => {\n\t\t\t\t\t// Match once-wrappers by their original handler reference. The\n\t\t\t\t\t// undefined guard prevents a normal hook (whose _originalHandler\n\t\t\t\t\t// is also undefined) from matching when hook.handler is undefined.\n\t\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: wrapper metadata lookup\n\t\t\t\t\tconst original = (h.handler as any)._originalHandler;\n\t\t\t\t\treturn original !== undefined && original === hook.handler;\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (index !== -1) {\n\t\t\t\teventHandlers.splice(index, 1);\n\t\t\t\tif (eventHandlers.length === 0) {\n\t\t\t\t\tthis._hooks.delete(hook.event);\n\t\t\t\t}\n\n\t\t\t\treturn { event: hook.event, handler: hook.handler };\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Removes multiple hook handlers\n\t * @param {Array<IHook>} hooks\n\t * @returns {IHook[]} the hooks that were successfully removed\n\t */\n\tpublic removeHooks(hooks: IHook[]): IHook[] {\n\t\tconst removed: IHook[] = [];\n\t\tfor (const hook of hooks) {\n\t\t\tconst result = this.removeHook(hook);\n\t\t\tif (result) {\n\t\t\t\tremoved.push(result);\n\t\t\t}\n\t\t}\n\n\t\treturn removed;\n\t}\n\n\t/**\n\t * Calls all handlers for a specific event\n\t * @param {string} event\n\t * @param {T[]} arguments_\n\t * @returns {Promise<void>}\n\t */\n\tpublic async hook<T>(event: string, ...arguments_: T[]) {\n\t\tthis.validateHookName(event);\n\t\tif (!this.checkDeprecatedHook(event)) {\n\t\t\treturn; // Skip execution if deprecated hooks are not allowed\n\t\t}\n\t\tconst eventHandlers = this._hooks.get(event);\n\t\tif (eventHandlers) {\n\t\t\tfor (const hook of [...eventHandlers]) {\n\t\t\t\ttry {\n\t\t\t\t\tawait hook.handler(...arguments_);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst message = `${event}: ${(error as Error).message}`;\n\t\t\t\t\tthis.emit(\"error\", new Error(message));\n\n\t\t\t\t\tif (this._throwOnHookError) {\n\t\t\t\t\t\tthrow new Error(message);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Calls all synchronous handlers for a specific event.\n\t * Async handlers (declared with `async` keyword) are silently skipped.\n\t *\n\t * Note: The `hook` method is preferred as it executes both sync and async functions.\n\t * Use `hookSync` only when you specifically need synchronous execution.\n\t * @param {string} event\n\t * @param {T[]} arguments_\n\t * @returns {void}\n\t */\n\tpublic hookSync<T>(event: string, ...arguments_: T[]): void {\n\t\tthis.validateHookName(event);\n\t\tif (!this.checkDeprecatedHook(event)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst eventHandlers = this._hooks.get(event);\n\t\tif (eventHandlers) {\n\t\t\tfor (const hook of [...eventHandlers]) {\n\t\t\t\t// Skip async functions silently\n\t\t\t\tif (hook.handler.constructor.name === \"AsyncFunction\") {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\thook.handler(...arguments_);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst message = `${event}: ${(error as Error).message}`;\n\t\t\t\t\tthis.emit(\"error\", new Error(message));\n\n\t\t\t\t\tif (this._throwOnHookError) {\n\t\t\t\t\t\tthrow new Error(message);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Prepends the word `before` to your hook. Example is event is `test`, the before hook is `before:test`.\n\t * @param {string} event - The event name\n\t * @param {T[]} arguments_ - The arguments to pass to the hook\n\t */\n\tpublic async beforeHook<T>(event: string, ...arguments_: T[]) {\n\t\tawait this.hook(`before:${event}`, ...arguments_);\n\t}\n\n\t/**\n\t * Prepends the word `after` to your hook. Example is event is `test`, the after hook is `after:test`.\n\t * @param {string} event - The event name\n\t * @param {T[]} arguments_ - The arguments to pass to the hook\n\t */\n\tpublic async afterHook<T>(event: string, ...arguments_: T[]) {\n\t\tawait this.hook(`after:${event}`, ...arguments_);\n\t}\n\n\t/**\n\t * Calls all handlers for a specific event. This is an alias for `hook` and is provided for\n\t * compatibility with other libraries that use the `callHook` method.\n\t * @param {string} event\n\t * @param {T[]} arguments_\n\t * @returns {Promise<void>}\n\t */\n\tpublic async callHook<T>(event: string, ...arguments_: T[]) {\n\t\tawait this.hook(event, ...arguments_);\n\t}\n\n\t/**\n\t * Gets all hooks for a specific event\n\t * @param {string} event\n\t * @returns {IHook[]}\n\t */\n\tpublic getHooks(event: string) {\n\t\tthis.validateHookName(event);\n\t\treturn this._hooks.get(event);\n\t}\n\n\t/**\n\t * Gets a specific hook by id, searching across all events\n\t * @param {string} id - the hook id\n\t * @returns {IHook | undefined} the hook if found, or undefined\n\t */\n\tpublic getHook(id: string): IHook | undefined {\n\t\tfor (const eventHandlers of this._hooks.values()) {\n\t\t\tconst found = eventHandlers.find((h) => h.id === id);\n\t\t\tif (found) {\n\t\t\t\treturn found;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Removes one or more hooks by id, searching across all events\n\t * @param {string | string[]} id - the hook id or array of hook ids to remove\n\t * @returns {IHook | IHook[] | undefined} the removed hook(s), or undefined/empty array if not found\n\t */\n\tpublic removeHookById(id: string | string[]): IHook | IHook[] | undefined {\n\t\tif (Array.isArray(id)) {\n\t\t\tconst removed: IHook[] = [];\n\t\t\tfor (const singleId of id) {\n\t\t\t\tconst result = this.removeHookById(singleId);\n\t\t\t\tif (result && !Array.isArray(result)) {\n\t\t\t\t\tremoved.push(result);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn removed;\n\t\t}\n\n\t\tfor (const [event, eventHandlers] of this._hooks.entries()) {\n\t\t\tconst index = eventHandlers.findIndex((h) => h.id === id);\n\t\t\tif (index !== -1) {\n\t\t\t\tconst [removed] = eventHandlers.splice(index, 1);\n\t\t\t\tif (eventHandlers.length === 0) {\n\t\t\t\t\tthis._hooks.delete(event);\n\t\t\t\t}\n\n\t\t\t\treturn removed;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Removes all hooks\n\t * @returns {void}\n\t */\n\tpublic clearHooks() {\n\t\tthis._hooks.clear();\n\t}\n\n\t/**\n\t * Removes all hooks for a specific event and returns the removed hooks.\n\t * @param {string} event - The event name to remove hooks for.\n\t * @returns {IHook[]} the hooks that were removed\n\t */\n\tpublic removeEventHooks(event: string): IHook[] {\n\t\tthis.validateHookName(event);\n\t\tconst eventHandlers = this._hooks.get(event);\n\t\tif (eventHandlers) {\n\t\t\tconst removed = [...eventHandlers];\n\t\t\tthis._hooks.delete(event);\n\t\t\treturn removed;\n\t\t}\n\n\t\treturn [];\n\t}\n\n\t/**\n\t * Validates hook event name if enforceBeforeAfter is enabled\n\t * @param {string} event - The event name to validate\n\t * @throws {Error} If enforceBeforeAfter is true and event doesn't start with 'before' or 'after'\n\t */\n\tprivate validateHookName(event: string): void {\n\t\tif (this._enforceBeforeAfter) {\n\t\t\tconst eventValue = event.trim().toLocaleLowerCase();\n\t\t\tif (!eventValue.startsWith(\"before\") && !eventValue.startsWith(\"after\")) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Hook event \"${event}\" must start with \"before\" or \"after\" when enforceBeforeAfter is enabled`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks if a hook is deprecated and emits a warning if it is\n\t * @param {string} event - The event name to check\n\t * @returns {boolean} - Returns true if the hook should proceed, false if it should be blocked\n\t */\n\tprivate checkDeprecatedHook(event: string): boolean {\n\t\tif (this._deprecatedHooks.has(event)) {\n\t\t\tconst message = this._deprecatedHooks.get(event);\n\t\t\tconst warningMessage = `Hook \"${event}\" is deprecated${message ? `: ${message}` : \"\"}`;\n\n\t\t\t// Emit deprecation warning event\n\t\t\tthis.emit(\"warn\", { hook: event, message: warningMessage });\n\n\t\t\t// Return false if deprecated hooks are not allowed\n\t\t\treturn this._allowDeprecated;\n\t\t}\n\t\treturn true;\n\t}\n}\n\nexport { Eventified } from \"./eventified.js\";\nexport { Hook } from \"./hooks/hook.js\";\nexport { ParallelHook } from \"./hooks/parallel-hook.js\";\nexport { WaterfallHook } from \"./hooks/waterfall-hook.js\";\nexport type {\n\tEventEmitterOptions,\n\tEventListener,\n\tIEventEmitter,\n\tIParallelHook,\n\tLogger,\n\tParallelHookContext,\n\tParallelHookFinalContext,\n\tParallelHookFinalFn,\n\tParallelHookFn,\n\tParallelHookResult,\n} from \"./types.js\";\n"],"mappings":"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"}
|
package/dist/node/index.cjs
CHANGED
|
@@ -67,6 +67,7 @@ var Eventified = class {
|
|
|
67
67
|
this.off(eventName, onceListener);
|
|
68
68
|
listener(...arguments_);
|
|
69
69
|
};
|
|
70
|
+
onceListener._originalListener = listener;
|
|
70
71
|
this.on(eventName, onceListener);
|
|
71
72
|
return this;
|
|
72
73
|
}
|
|
@@ -127,6 +128,7 @@ var Eventified = class {
|
|
|
127
128
|
this.off(eventName, onceListener);
|
|
128
129
|
listener(...arguments_);
|
|
129
130
|
};
|
|
131
|
+
onceListener._originalListener = listener;
|
|
130
132
|
this.prependListener(eventName, onceListener);
|
|
131
133
|
return this;
|
|
132
134
|
}
|
|
@@ -180,6 +182,19 @@ var Eventified = class {
|
|
|
180
182
|
return this;
|
|
181
183
|
}
|
|
182
184
|
/**
|
|
185
|
+
* Determines whether a stored listener matches the listener provided to off().
|
|
186
|
+
* A match occurs when the references are identical, or when the stored listener
|
|
187
|
+
* is a once-wrapper whose original listener equals the provided reference.
|
|
188
|
+
* @param {EventListener} stored - the listener currently stored
|
|
189
|
+
* @param {EventListener} target - the listener passed to off()
|
|
190
|
+
* @returns {boolean} true if the stored listener should be removed
|
|
191
|
+
*/
|
|
192
|
+
matchesListener(stored, target) {
|
|
193
|
+
if (stored === target) return true;
|
|
194
|
+
const original = stored._originalListener;
|
|
195
|
+
return original !== void 0 && original === target;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
183
198
|
* Removes a listener for a specific event
|
|
184
199
|
* @param {string | symbol} event
|
|
185
200
|
* @param {EventListener} listener
|
|
@@ -189,10 +204,11 @@ var Eventified = class {
|
|
|
189
204
|
const entry = this._eventListeners.get(event);
|
|
190
205
|
if (entry === void 0) return this;
|
|
191
206
|
if (typeof entry === "function") {
|
|
192
|
-
if (entry
|
|
207
|
+
if (this.matchesListener(entry, listener)) this._eventListeners.delete(event);
|
|
193
208
|
return this;
|
|
194
209
|
}
|
|
195
|
-
|
|
210
|
+
let index = entry.indexOf(listener);
|
|
211
|
+
if (index === -1) index = entry.findIndex((stored) => this.matchesListener(stored, listener));
|
|
196
212
|
if (index !== -1) if (entry.length === 2) this._eventListeners.set(event, entry[1 - index]);
|
|
197
213
|
else if (entry.length === 1) this._eventListeners.delete(event);
|
|
198
214
|
else entry.splice(index, 1);
|
|
@@ -213,10 +229,11 @@ var Eventified = class {
|
|
|
213
229
|
else if (argumentLength === 2) entry(arguments_[0], arguments_[1]);
|
|
214
230
|
else entry(...arguments_);
|
|
215
231
|
else {
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
else
|
|
232
|
+
const listeners = entry.slice();
|
|
233
|
+
const len = listeners.length;
|
|
234
|
+
for (let i = 0; i < len; i++) if (argumentLength === 1) listeners[i](arguments_[0]);
|
|
235
|
+
else if (argumentLength === 2) listeners[i](arguments_[0], arguments_[1]);
|
|
236
|
+
else listeners[i](...arguments_);
|
|
220
237
|
}
|
|
221
238
|
result = true;
|
|
222
239
|
}
|
|
@@ -675,6 +692,7 @@ var Hookified = class extends Eventified {
|
|
|
675
692
|
});
|
|
676
693
|
return hook.handler(...arguments_);
|
|
677
694
|
};
|
|
695
|
+
wrappedHandler._originalHandler = hook.handler;
|
|
678
696
|
return this.onHook({
|
|
679
697
|
id: hook.id,
|
|
680
698
|
event: hook.event,
|
|
@@ -698,6 +716,7 @@ var Hookified = class extends Eventified {
|
|
|
698
716
|
});
|
|
699
717
|
return hook.handler(...arguments_);
|
|
700
718
|
};
|
|
719
|
+
wrappedHandler._originalHandler = hook.handler;
|
|
701
720
|
this.onHook({
|
|
702
721
|
id: hook.id,
|
|
703
722
|
event: hook.event,
|
|
@@ -713,7 +732,11 @@ var Hookified = class extends Eventified {
|
|
|
713
732
|
this.validateHookName(hook.event);
|
|
714
733
|
const eventHandlers = this._hooks.get(hook.event);
|
|
715
734
|
if (eventHandlers) {
|
|
716
|
-
|
|
735
|
+
let index = eventHandlers.findIndex((h) => h.handler === hook.handler);
|
|
736
|
+
if (index === -1) index = eventHandlers.findIndex((h) => {
|
|
737
|
+
const original = h.handler._originalHandler;
|
|
738
|
+
return original !== void 0 && original === hook.handler;
|
|
739
|
+
});
|
|
717
740
|
if (index !== -1) {
|
|
718
741
|
eventHandlers.splice(index, 1);
|
|
719
742
|
if (eventHandlers.length === 0) this._hooks.delete(hook.event);
|
package/dist/node/index.d.cts
CHANGED
|
@@ -420,6 +420,15 @@ declare class Eventified implements IEventEmitter {
|
|
|
420
420
|
* @returns {IEventEmitter} returns the instance of the class for chaining
|
|
421
421
|
*/
|
|
422
422
|
removeListener(event: string, listener: EventListener): IEventEmitter;
|
|
423
|
+
/**
|
|
424
|
+
* Determines whether a stored listener matches the listener provided to off().
|
|
425
|
+
* A match occurs when the references are identical, or when the stored listener
|
|
426
|
+
* is a once-wrapper whose original listener equals the provided reference.
|
|
427
|
+
* @param {EventListener} stored - the listener currently stored
|
|
428
|
+
* @param {EventListener} target - the listener passed to off()
|
|
429
|
+
* @returns {boolean} true if the stored listener should be removed
|
|
430
|
+
*/
|
|
431
|
+
private matchesListener;
|
|
423
432
|
/**
|
|
424
433
|
* Removes a listener for a specific event
|
|
425
434
|
* @param {string | symbol} event
|
package/dist/node/index.d.ts
CHANGED
|
@@ -420,6 +420,15 @@ declare class Eventified implements IEventEmitter {
|
|
|
420
420
|
* @returns {IEventEmitter} returns the instance of the class for chaining
|
|
421
421
|
*/
|
|
422
422
|
removeListener(event: string, listener: EventListener): IEventEmitter;
|
|
423
|
+
/**
|
|
424
|
+
* Determines whether a stored listener matches the listener provided to off().
|
|
425
|
+
* A match occurs when the references are identical, or when the stored listener
|
|
426
|
+
* is a once-wrapper whose original listener equals the provided reference.
|
|
427
|
+
* @param {EventListener} stored - the listener currently stored
|
|
428
|
+
* @param {EventListener} target - the listener passed to off()
|
|
429
|
+
* @returns {boolean} true if the stored listener should be removed
|
|
430
|
+
*/
|
|
431
|
+
private matchesListener;
|
|
423
432
|
/**
|
|
424
433
|
* Removes a listener for a specific event
|
|
425
434
|
* @param {string | symbol} event
|
package/dist/node/index.js
CHANGED
|
@@ -66,6 +66,7 @@ var Eventified = class {
|
|
|
66
66
|
this.off(eventName, onceListener);
|
|
67
67
|
listener(...arguments_);
|
|
68
68
|
};
|
|
69
|
+
onceListener._originalListener = listener;
|
|
69
70
|
this.on(eventName, onceListener);
|
|
70
71
|
return this;
|
|
71
72
|
}
|
|
@@ -126,6 +127,7 @@ var Eventified = class {
|
|
|
126
127
|
this.off(eventName, onceListener);
|
|
127
128
|
listener(...arguments_);
|
|
128
129
|
};
|
|
130
|
+
onceListener._originalListener = listener;
|
|
129
131
|
this.prependListener(eventName, onceListener);
|
|
130
132
|
return this;
|
|
131
133
|
}
|
|
@@ -179,6 +181,19 @@ var Eventified = class {
|
|
|
179
181
|
return this;
|
|
180
182
|
}
|
|
181
183
|
/**
|
|
184
|
+
* Determines whether a stored listener matches the listener provided to off().
|
|
185
|
+
* A match occurs when the references are identical, or when the stored listener
|
|
186
|
+
* is a once-wrapper whose original listener equals the provided reference.
|
|
187
|
+
* @param {EventListener} stored - the listener currently stored
|
|
188
|
+
* @param {EventListener} target - the listener passed to off()
|
|
189
|
+
* @returns {boolean} true if the stored listener should be removed
|
|
190
|
+
*/
|
|
191
|
+
matchesListener(stored, target) {
|
|
192
|
+
if (stored === target) return true;
|
|
193
|
+
const original = stored._originalListener;
|
|
194
|
+
return original !== void 0 && original === target;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
182
197
|
* Removes a listener for a specific event
|
|
183
198
|
* @param {string | symbol} event
|
|
184
199
|
* @param {EventListener} listener
|
|
@@ -188,10 +203,11 @@ var Eventified = class {
|
|
|
188
203
|
const entry = this._eventListeners.get(event);
|
|
189
204
|
if (entry === void 0) return this;
|
|
190
205
|
if (typeof entry === "function") {
|
|
191
|
-
if (entry
|
|
206
|
+
if (this.matchesListener(entry, listener)) this._eventListeners.delete(event);
|
|
192
207
|
return this;
|
|
193
208
|
}
|
|
194
|
-
|
|
209
|
+
let index = entry.indexOf(listener);
|
|
210
|
+
if (index === -1) index = entry.findIndex((stored) => this.matchesListener(stored, listener));
|
|
195
211
|
if (index !== -1) if (entry.length === 2) this._eventListeners.set(event, entry[1 - index]);
|
|
196
212
|
else if (entry.length === 1) this._eventListeners.delete(event);
|
|
197
213
|
else entry.splice(index, 1);
|
|
@@ -212,10 +228,11 @@ var Eventified = class {
|
|
|
212
228
|
else if (argumentLength === 2) entry(arguments_[0], arguments_[1]);
|
|
213
229
|
else entry(...arguments_);
|
|
214
230
|
else {
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
else
|
|
231
|
+
const listeners = entry.slice();
|
|
232
|
+
const len = listeners.length;
|
|
233
|
+
for (let i = 0; i < len; i++) if (argumentLength === 1) listeners[i](arguments_[0]);
|
|
234
|
+
else if (argumentLength === 2) listeners[i](arguments_[0], arguments_[1]);
|
|
235
|
+
else listeners[i](...arguments_);
|
|
219
236
|
}
|
|
220
237
|
result = true;
|
|
221
238
|
}
|
|
@@ -674,6 +691,7 @@ var Hookified = class extends Eventified {
|
|
|
674
691
|
});
|
|
675
692
|
return hook.handler(...arguments_);
|
|
676
693
|
};
|
|
694
|
+
wrappedHandler._originalHandler = hook.handler;
|
|
677
695
|
return this.onHook({
|
|
678
696
|
id: hook.id,
|
|
679
697
|
event: hook.event,
|
|
@@ -697,6 +715,7 @@ var Hookified = class extends Eventified {
|
|
|
697
715
|
});
|
|
698
716
|
return hook.handler(...arguments_);
|
|
699
717
|
};
|
|
718
|
+
wrappedHandler._originalHandler = hook.handler;
|
|
700
719
|
this.onHook({
|
|
701
720
|
id: hook.id,
|
|
702
721
|
event: hook.event,
|
|
@@ -712,7 +731,11 @@ var Hookified = class extends Eventified {
|
|
|
712
731
|
this.validateHookName(hook.event);
|
|
713
732
|
const eventHandlers = this._hooks.get(hook.event);
|
|
714
733
|
if (eventHandlers) {
|
|
715
|
-
|
|
734
|
+
let index = eventHandlers.findIndex((h) => h.handler === hook.handler);
|
|
735
|
+
if (index === -1) index = eventHandlers.findIndex((h) => {
|
|
736
|
+
const original = h.handler._originalHandler;
|
|
737
|
+
return original !== void 0 && original === hook.handler;
|
|
738
|
+
});
|
|
716
739
|
if (index !== -1) {
|
|
717
740
|
eventHandlers.splice(index, 1);
|
|
718
741
|
if (eventHandlers.length === 0) this._hooks.delete(hook.event);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hookified",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "Event Emitting and Middleware Hooks",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/node/index.js",
|
|
@@ -24,21 +24,6 @@
|
|
|
24
24
|
"default": "./dist/browser/index.global.js"
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
|
-
"scripts": {
|
|
28
|
-
"lint": "biome check --write --error-on-warnings",
|
|
29
|
-
"test": "pnpm lint && vitest run --coverage",
|
|
30
|
-
"test:ci": "biome check --error-on-warnings && vitest run --coverage",
|
|
31
|
-
"clean": "rimraf ./dist ./coverage ./site/dist",
|
|
32
|
-
"build": "tsdown",
|
|
33
|
-
"benchmark": "pnpm benchmark:hooks && pnpm benchmark:emit",
|
|
34
|
-
"benchmark:hooks": "pnpm tsx benchmark/hook.ts",
|
|
35
|
-
"benchmark:emit": "pnpm tsx benchmark/emit.ts",
|
|
36
|
-
"benchmark:readme": "pnpm tsx scripts/benchmark-readme.ts",
|
|
37
|
-
"website:build": "docula build",
|
|
38
|
-
"website:serve": "docula serve",
|
|
39
|
-
"website:dev": "docula dev",
|
|
40
|
-
"prepublishOnly": "pnpm build"
|
|
41
|
-
},
|
|
42
27
|
"keywords": [
|
|
43
28
|
"hooks",
|
|
44
29
|
"eventemitter",
|
|
@@ -70,25 +55,43 @@
|
|
|
70
55
|
"url": "https://github.com/jaredwray/hookified/issues"
|
|
71
56
|
},
|
|
72
57
|
"homepage": "https://github.com/jaredwray/hookified#readme",
|
|
58
|
+
"engines": {
|
|
59
|
+
"node": ">=22.18.0"
|
|
60
|
+
},
|
|
73
61
|
"devDependencies": {
|
|
74
|
-
"@biomejs/biome": "^2.
|
|
62
|
+
"@biomejs/biome": "^2.5.0",
|
|
75
63
|
"@monstermann/tinybench-pretty-printer": "^0.3.0",
|
|
76
64
|
"@types/node": "^24.12.2",
|
|
77
|
-
"@vitest/coverage-v8": "^4.1.
|
|
78
|
-
"docula": "^
|
|
65
|
+
"@vitest/coverage-v8": "^4.1.8",
|
|
66
|
+
"docula": "^2.0.0",
|
|
79
67
|
"emittery": "^2.0.0",
|
|
80
68
|
"eventemitter3": "^5.0.4",
|
|
81
69
|
"hookable": "^6.1.1",
|
|
82
70
|
"pino": "^10.3.1",
|
|
83
71
|
"rimraf": "^6.1.3",
|
|
84
|
-
"tinybench": "^6.0.
|
|
85
|
-
"tsdown": "^0.
|
|
86
|
-
"tsx": "^4.
|
|
72
|
+
"tinybench": "^6.0.2",
|
|
73
|
+
"tsdown": "^0.22.2",
|
|
74
|
+
"tsx": "^4.22.4",
|
|
87
75
|
"typescript": "^6.0.3",
|
|
88
|
-
"vitest": "^4.1.
|
|
76
|
+
"vitest": "^4.1.8"
|
|
89
77
|
},
|
|
90
78
|
"files": [
|
|
91
79
|
"dist",
|
|
92
80
|
"LICENSE"
|
|
93
|
-
]
|
|
94
|
-
|
|
81
|
+
],
|
|
82
|
+
"scripts": {
|
|
83
|
+
"lint": "biome check --write --error-on-warnings",
|
|
84
|
+
"test": "pnpm lint && vitest run --coverage",
|
|
85
|
+
"test:ci": "biome check --error-on-warnings && vitest run --coverage",
|
|
86
|
+
"clean": "rimraf ./dist ./coverage ./site/dist",
|
|
87
|
+
"build": "tsdown",
|
|
88
|
+
"benchmark": "pnpm benchmark:hooks && pnpm benchmark:emit && pnpm benchmark:emit-multi",
|
|
89
|
+
"benchmark:hooks": "pnpm tsx benchmark/hook.ts",
|
|
90
|
+
"benchmark:emit": "pnpm tsx benchmark/emit.ts",
|
|
91
|
+
"benchmark:emit-multi": "pnpm tsx benchmark/emit-multi.ts",
|
|
92
|
+
"benchmark:readme": "pnpm tsx scripts/benchmark-readme.ts",
|
|
93
|
+
"website:build": "docula build",
|
|
94
|
+
"website:serve": "docula serve",
|
|
95
|
+
"website:dev": "docula dev"
|
|
96
|
+
}
|
|
97
|
+
}
|