hookified 1.13.0 → 1.15.0

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.
@@ -6,7 +6,21 @@ type Logger = {
6
6
  error: (message: string, ...arguments_: unknown[]) => void;
7
7
  fatal: (message: string, ...arguments_: unknown[]) => void;
8
8
  };
9
-
9
+ type EventEmitterOptions = {
10
+ /**
11
+ * Logger instance for logging errors.
12
+ */
13
+ logger?: Logger;
14
+ /**
15
+ * Whether to throw an error when emit 'error' and there are no listeners. Default is false and only emits an error event.
16
+ */
17
+ throwOnEmitError?: boolean;
18
+ /**
19
+ * Whether to throw on 'error' when there are no listeners. This is the standard functionality in EventEmitter
20
+ * @default false - in v2 this will be set to true by default
21
+ */
22
+ throwOnEmptyListeners?: boolean;
23
+ };
10
24
  type IEventEmitter = {
11
25
  /**
12
26
  * Registers a listener for the specified event.
@@ -152,21 +166,47 @@ type IEventEmitter = {
152
166
  prependOnceListener(eventName: string | symbol, listener: (...arguments_: any[]) => void): IEventEmitter;
153
167
  };
154
168
  type EventListener = (...arguments_: any[]) => void;
155
- type EventEmitterOptions = {
169
+ type Hook = (...arguments_: any[]) => Promise<void> | void;
170
+ type HookEntry = {
156
171
  /**
157
- * Logger instance for logging errors.
172
+ * The event name for the hook
158
173
  */
159
- logger?: Logger;
174
+ event: string;
160
175
  /**
161
- * Whether to throw an error when emit 'error' and there are no listeners. Default is false and only emits an error event.
176
+ * The handler function for the hook
162
177
  */
163
- throwOnEmitError?: boolean;
178
+ handler: Hook;
179
+ };
180
+ type HookifiedOptions = {
164
181
  /**
165
- * Whether to throw on 'error' when there are no listeners. This is the standard functionality in EventEmitter
166
- * @default false - in v2 this will be set to true by default
182
+ * Whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
183
+ * @deprecated - this will be deprecated in version 2. Please use throwOnHookError.
167
184
  */
168
- throwOnEmptyListeners?: boolean;
169
- };
185
+ throwHookErrors?: boolean;
186
+ /**
187
+ * Whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
188
+ */
189
+ throwOnHookError?: boolean;
190
+ /**
191
+ * Whether to enforce that all hook names start with 'before' or 'after'. Default is false.
192
+ * @type {boolean}
193
+ * @default false
194
+ */
195
+ enforceBeforeAfter?: boolean;
196
+ /**
197
+ * Map of deprecated hook names to deprecation messages. When a deprecated hook is used, a warning will be emitted.
198
+ * @type {Map<string, string>}
199
+ * @default new Map()
200
+ */
201
+ deprecatedHooks?: Map<string, string>;
202
+ /**
203
+ * Whether to allow deprecated hooks to be registered and executed. Default is true.
204
+ * @type {boolean}
205
+ * @default true
206
+ */
207
+ allowDeprecated?: boolean;
208
+ } & EventEmitterOptions;
209
+
170
210
  declare class Eventified implements IEventEmitter {
171
211
  private readonly _eventListeners;
172
212
  private _maxListeners;
@@ -306,48 +346,14 @@ declare class Eventified implements IEventEmitter {
306
346
  * @returns {EventListener[]} An array of listeners
307
347
  */
308
348
  getAllListeners(): EventListener[];
309
- }
310
-
311
- type Hook = (...arguments_: any[]) => Promise<void> | void;
312
- type HookEntry = {
313
- /**
314
- * The event name for the hook
315
- */
316
- event: string;
317
- /**
318
- * The handler function for the hook
319
- */
320
- handler: Hook;
321
- };
322
- type HookifiedOptions = {
323
- /**
324
- * Whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
325
- * @deprecated - this will be deprecated in version 2. Please use throwOnHookError.
326
- */
327
- throwHookErrors?: boolean;
328
349
  /**
329
- * Whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
350
+ * Sends a log message using the configured logger based on the event name
351
+ * @param {string | symbol} eventName - The event name that determines the log level
352
+ * @param {unknown} data - The data to log
330
353
  */
331
- throwOnHookError?: boolean;
332
- /**
333
- * Whether to enforce that all hook names start with 'before' or 'after'. Default is false.
334
- * @type {boolean}
335
- * @default false
336
- */
337
- enforceBeforeAfter?: boolean;
338
- /**
339
- * Map of deprecated hook names to deprecation messages. When a deprecated hook is used, a warning will be emitted.
340
- * @type {Map<string, string>}
341
- * @default new Map()
342
- */
343
- deprecatedHooks?: Map<string, string>;
344
- /**
345
- * Whether to allow deprecated hooks to be registered and executed. Default is true.
346
- * @type {boolean}
347
- * @default true
348
- */
349
- allowDeprecated?: boolean;
350
- } & EventEmitterOptions;
354
+ private sendLog;
355
+ }
356
+
351
357
  declare class Hookified extends Eventified {
352
358
  private readonly _hooks;
353
359
  private _throwOnHookError;
@@ -433,7 +439,7 @@ declare class Hookified extends Eventified {
433
439
  */
434
440
  onHook(event: string, handler: Hook): void;
435
441
  /**
436
- * Adds a handler function for a specific event that runs before all other handlers
442
+ * Adds a handler function for a specific event
437
443
  * @param {HookEntry} hookEntry
438
444
  * @returns {void}
439
445
  */
@@ -490,6 +496,17 @@ declare class Hookified extends Eventified {
490
496
  * @returns {Promise<void>}
491
497
  */
492
498
  hook<T>(event: string, ...arguments_: T[]): Promise<void>;
499
+ /**
500
+ * Calls all synchronous handlers for a specific event.
501
+ * Async handlers (declared with `async` keyword) are silently skipped.
502
+ *
503
+ * Note: The `hook` method is preferred as it executes both sync and async functions.
504
+ * Use `hookSync` only when you specifically need synchronous execution.
505
+ * @param {string} event
506
+ * @param {T[]} arguments_
507
+ * @returns {void}
508
+ */
509
+ hookSync<T>(event: string, ...arguments_: T[]): void;
493
510
  /**
494
511
  * Prepends the word `before` to your hook. Example is event is `test`, the before hook is `before:test`.
495
512
  * @param {string} event - The event name
@@ -523,4 +540,4 @@ declare class Hookified extends Eventified {
523
540
  clearHooks(): void;
524
541
  }
525
542
 
526
- export { type EventListener, Eventified, type Hook, type HookEntry, Hookified, type HookifiedOptions, type Logger };
543
+ export { type EventEmitterOptions, type EventListener, Eventified, type Hook, type HookEntry, Hookified, type HookifiedOptions, type IEventEmitter, type Logger };
@@ -6,7 +6,21 @@ type Logger = {
6
6
  error: (message: string, ...arguments_: unknown[]) => void;
7
7
  fatal: (message: string, ...arguments_: unknown[]) => void;
8
8
  };
9
-
9
+ type EventEmitterOptions = {
10
+ /**
11
+ * Logger instance for logging errors.
12
+ */
13
+ logger?: Logger;
14
+ /**
15
+ * Whether to throw an error when emit 'error' and there are no listeners. Default is false and only emits an error event.
16
+ */
17
+ throwOnEmitError?: boolean;
18
+ /**
19
+ * Whether to throw on 'error' when there are no listeners. This is the standard functionality in EventEmitter
20
+ * @default false - in v2 this will be set to true by default
21
+ */
22
+ throwOnEmptyListeners?: boolean;
23
+ };
10
24
  type IEventEmitter = {
11
25
  /**
12
26
  * Registers a listener for the specified event.
@@ -152,21 +166,47 @@ type IEventEmitter = {
152
166
  prependOnceListener(eventName: string | symbol, listener: (...arguments_: any[]) => void): IEventEmitter;
153
167
  };
154
168
  type EventListener = (...arguments_: any[]) => void;
155
- type EventEmitterOptions = {
169
+ type Hook = (...arguments_: any[]) => Promise<void> | void;
170
+ type HookEntry = {
156
171
  /**
157
- * Logger instance for logging errors.
172
+ * The event name for the hook
158
173
  */
159
- logger?: Logger;
174
+ event: string;
160
175
  /**
161
- * Whether to throw an error when emit 'error' and there are no listeners. Default is false and only emits an error event.
176
+ * The handler function for the hook
162
177
  */
163
- throwOnEmitError?: boolean;
178
+ handler: Hook;
179
+ };
180
+ type HookifiedOptions = {
164
181
  /**
165
- * Whether to throw on 'error' when there are no listeners. This is the standard functionality in EventEmitter
166
- * @default false - in v2 this will be set to true by default
182
+ * Whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
183
+ * @deprecated - this will be deprecated in version 2. Please use throwOnHookError.
167
184
  */
168
- throwOnEmptyListeners?: boolean;
169
- };
185
+ throwHookErrors?: boolean;
186
+ /**
187
+ * Whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
188
+ */
189
+ throwOnHookError?: boolean;
190
+ /**
191
+ * Whether to enforce that all hook names start with 'before' or 'after'. Default is false.
192
+ * @type {boolean}
193
+ * @default false
194
+ */
195
+ enforceBeforeAfter?: boolean;
196
+ /**
197
+ * Map of deprecated hook names to deprecation messages. When a deprecated hook is used, a warning will be emitted.
198
+ * @type {Map<string, string>}
199
+ * @default new Map()
200
+ */
201
+ deprecatedHooks?: Map<string, string>;
202
+ /**
203
+ * Whether to allow deprecated hooks to be registered and executed. Default is true.
204
+ * @type {boolean}
205
+ * @default true
206
+ */
207
+ allowDeprecated?: boolean;
208
+ } & EventEmitterOptions;
209
+
170
210
  declare class Eventified implements IEventEmitter {
171
211
  private readonly _eventListeners;
172
212
  private _maxListeners;
@@ -306,48 +346,14 @@ declare class Eventified implements IEventEmitter {
306
346
  * @returns {EventListener[]} An array of listeners
307
347
  */
308
348
  getAllListeners(): EventListener[];
309
- }
310
-
311
- type Hook = (...arguments_: any[]) => Promise<void> | void;
312
- type HookEntry = {
313
- /**
314
- * The event name for the hook
315
- */
316
- event: string;
317
- /**
318
- * The handler function for the hook
319
- */
320
- handler: Hook;
321
- };
322
- type HookifiedOptions = {
323
- /**
324
- * Whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
325
- * @deprecated - this will be deprecated in version 2. Please use throwOnHookError.
326
- */
327
- throwHookErrors?: boolean;
328
349
  /**
329
- * Whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
350
+ * Sends a log message using the configured logger based on the event name
351
+ * @param {string | symbol} eventName - The event name that determines the log level
352
+ * @param {unknown} data - The data to log
330
353
  */
331
- throwOnHookError?: boolean;
332
- /**
333
- * Whether to enforce that all hook names start with 'before' or 'after'. Default is false.
334
- * @type {boolean}
335
- * @default false
336
- */
337
- enforceBeforeAfter?: boolean;
338
- /**
339
- * Map of deprecated hook names to deprecation messages. When a deprecated hook is used, a warning will be emitted.
340
- * @type {Map<string, string>}
341
- * @default new Map()
342
- */
343
- deprecatedHooks?: Map<string, string>;
344
- /**
345
- * Whether to allow deprecated hooks to be registered and executed. Default is true.
346
- * @type {boolean}
347
- * @default true
348
- */
349
- allowDeprecated?: boolean;
350
- } & EventEmitterOptions;
354
+ private sendLog;
355
+ }
356
+
351
357
  declare class Hookified extends Eventified {
352
358
  private readonly _hooks;
353
359
  private _throwOnHookError;
@@ -433,7 +439,7 @@ declare class Hookified extends Eventified {
433
439
  */
434
440
  onHook(event: string, handler: Hook): void;
435
441
  /**
436
- * Adds a handler function for a specific event that runs before all other handlers
442
+ * Adds a handler function for a specific event
437
443
  * @param {HookEntry} hookEntry
438
444
  * @returns {void}
439
445
  */
@@ -490,6 +496,17 @@ declare class Hookified extends Eventified {
490
496
  * @returns {Promise<void>}
491
497
  */
492
498
  hook<T>(event: string, ...arguments_: T[]): Promise<void>;
499
+ /**
500
+ * Calls all synchronous handlers for a specific event.
501
+ * Async handlers (declared with `async` keyword) are silently skipped.
502
+ *
503
+ * Note: The `hook` method is preferred as it executes both sync and async functions.
504
+ * Use `hookSync` only when you specifically need synchronous execution.
505
+ * @param {string} event
506
+ * @param {T[]} arguments_
507
+ * @returns {void}
508
+ */
509
+ hookSync<T>(event: string, ...arguments_: T[]): void;
493
510
  /**
494
511
  * Prepends the word `before` to your hook. Example is event is `test`, the before hook is `before:test`.
495
512
  * @param {string} event - The event name
@@ -523,4 +540,4 @@ declare class Hookified extends Eventified {
523
540
  clearHooks(): void;
524
541
  }
525
542
 
526
- export { type EventListener, Eventified, type Hook, type HookEntry, Hookified, type HookifiedOptions, type Logger };
543
+ export { type EventEmitterOptions, type EventListener, Eventified, type Hook, type HookEntry, Hookified, type HookifiedOptions, type IEventEmitter, type Logger };
@@ -219,6 +219,7 @@ var Eventified = class {
219
219
  }
220
220
  }
221
221
  }
222
+ this.sendLog(event, arguments_);
222
223
  return result;
223
224
  }
224
225
  /**
@@ -266,6 +267,54 @@ var Eventified = class {
266
267
  }
267
268
  return result;
268
269
  }
270
+ /**
271
+ * Sends a log message using the configured logger based on the event name
272
+ * @param {string | symbol} eventName - The event name that determines the log level
273
+ * @param {unknown} data - The data to log
274
+ */
275
+ sendLog(eventName, data) {
276
+ if (!this._logger) {
277
+ return;
278
+ }
279
+ let message;
280
+ if (typeof data === "string") {
281
+ message = data;
282
+ } else if (Array.isArray(data) && data.length > 0 && data[0] instanceof Error) {
283
+ message = data[0].message;
284
+ } else if (data instanceof Error) {
285
+ message = data.message;
286
+ } else if (Array.isArray(data) && data.length > 0 && typeof data[0]?.message === "string") {
287
+ message = data[0].message;
288
+ } else {
289
+ message = JSON.stringify(data);
290
+ }
291
+ switch (eventName) {
292
+ case "error": {
293
+ this._logger.error?.(message, { event: eventName, data });
294
+ break;
295
+ }
296
+ case "warn": {
297
+ this._logger.warn?.(message, { event: eventName, data });
298
+ break;
299
+ }
300
+ case "trace": {
301
+ this._logger.trace?.(message, { event: eventName, data });
302
+ break;
303
+ }
304
+ case "debug": {
305
+ this._logger.debug?.(message, { event: eventName, data });
306
+ break;
307
+ }
308
+ case "fatal": {
309
+ this._logger.fatal?.(message, { event: eventName, data });
310
+ break;
311
+ }
312
+ default: {
313
+ this._logger.info?.(message, { event: eventName, data });
314
+ break;
315
+ }
316
+ }
317
+ }
269
318
  };
270
319
 
271
320
  // src/index.ts
@@ -400,9 +449,6 @@ var Hookified = class extends Eventified {
400
449
  const message = this._deprecatedHooks.get(event);
401
450
  const warningMessage = `Hook "${event}" is deprecated${message ? `: ${message}` : ""}`;
402
451
  this.emit("warn", { hook: event, message: warningMessage });
403
- if (this.logger?.warn) {
404
- this.logger.warn(warningMessage);
405
- }
406
452
  return this._allowDeprecated;
407
453
  }
408
454
  return true;
@@ -414,24 +460,24 @@ var Hookified = class extends Eventified {
414
460
  * @returns {void}
415
461
  */
416
462
  onHook(event, handler) {
417
- this.validateHookName(event);
418
- if (!this.checkDeprecatedHook(event)) {
419
- return;
420
- }
421
- const eventHandlers = this._hooks.get(event);
422
- if (eventHandlers) {
423
- eventHandlers.push(handler);
424
- } else {
425
- this._hooks.set(event, [handler]);
426
- }
463
+ this.onHookEntry({ event, handler });
427
464
  }
428
465
  /**
429
- * Adds a handler function for a specific event that runs before all other handlers
466
+ * Adds a handler function for a specific event
430
467
  * @param {HookEntry} hookEntry
431
468
  * @returns {void}
432
469
  */
433
470
  onHookEntry(hookEntry) {
434
- this.onHook(hookEntry.event, hookEntry.handler);
471
+ this.validateHookName(hookEntry.event);
472
+ if (!this.checkDeprecatedHook(hookEntry.event)) {
473
+ return;
474
+ }
475
+ const eventHandlers = this._hooks.get(hookEntry.event);
476
+ if (eventHandlers) {
477
+ eventHandlers.push(hookEntry.handler);
478
+ } else {
479
+ this._hooks.set(hookEntry.event, [hookEntry.handler]);
480
+ }
435
481
  }
436
482
  /**
437
483
  * Alias for onHook. This is provided for compatibility with other libraries that use the `addHook` method.
@@ -440,7 +486,7 @@ var Hookified = class extends Eventified {
440
486
  * @returns {void}
441
487
  */
442
488
  addHook(event, handler) {
443
- this.onHook(event, handler);
489
+ this.onHookEntry({ event, handler });
444
490
  }
445
491
  /**
446
492
  * Adds a handler function for a specific event
@@ -550,9 +596,39 @@ var Hookified = class extends Eventified {
550
596
  } catch (error) {
551
597
  const message = `${event}: ${error.message}`;
552
598
  this.emit("error", new Error(message));
553
- if (this.logger) {
554
- this.logger.error(message);
599
+ if (this._throwOnHookError) {
600
+ throw new Error(message);
555
601
  }
602
+ }
603
+ }
604
+ }
605
+ }
606
+ /**
607
+ * Calls all synchronous handlers for a specific event.
608
+ * Async handlers (declared with `async` keyword) are silently skipped.
609
+ *
610
+ * Note: The `hook` method is preferred as it executes both sync and async functions.
611
+ * Use `hookSync` only when you specifically need synchronous execution.
612
+ * @param {string} event
613
+ * @param {T[]} arguments_
614
+ * @returns {void}
615
+ */
616
+ hookSync(event, ...arguments_) {
617
+ this.validateHookName(event);
618
+ if (!this.checkDeprecatedHook(event)) {
619
+ return;
620
+ }
621
+ const eventHandlers = this._hooks.get(event);
622
+ if (eventHandlers) {
623
+ for (const handler of eventHandlers) {
624
+ if (handler.constructor.name === "AsyncFunction") {
625
+ continue;
626
+ }
627
+ try {
628
+ handler(...arguments_);
629
+ } catch (error) {
630
+ const message = `${event}: ${error.message}`;
631
+ this.emit("error", new Error(message));
556
632
  if (this._throwOnHookError) {
557
633
  throw new Error(message);
558
634
  }
@@ -610,3 +686,4 @@ export {
610
686
  Eventified,
611
687
  Hookified
612
688
  };
689
+ /* v8 ignore next -- @preserve */
package/package.json CHANGED
@@ -1,21 +1,28 @@
1
1
  {
2
2
  "name": "hookified",
3
- "version": "1.13.0",
3
+ "version": "1.15.0",
4
4
  "description": "Event Emitting and Middleware Hooks",
5
5
  "type": "module",
6
- "main": "dist/node/index.cjs",
7
- "module": "dist/node/index.js",
6
+ "main": "./dist/node/index.js",
7
+ "module": "./dist/node/index.js",
8
+ "types": "./dist/node/index.d.ts",
8
9
  "exports": {
9
10
  ".": {
10
- "import": "./dist/node/index.js",
11
- "require": "./dist/node/index.cjs"
11
+ "import": {
12
+ "types": "./dist/node/index.d.ts",
13
+ "default": "./dist/node/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/node/index.d.cts",
17
+ "default": "./dist/node/index.cjs"
18
+ },
19
+ "default": "./dist/node/index.js"
12
20
  },
13
21
  "./browser": {
14
22
  "import": "./dist/browser/index.js",
15
23
  "default": "./dist/browser/index.global.js"
16
24
  }
17
25
  },
18
- "types": "dist/node/index.d.ts",
19
26
  "scripts": {
20
27
  "lint": "biome check --write --error-on-warnings",
21
28
  "test": "pnpm lint && vitest run --coverage",
@@ -61,29 +68,24 @@
61
68
  },
62
69
  "homepage": "https://github.com/jaredwray/hookified#readme",
63
70
  "devDependencies": {
64
- "@biomejs/biome": "^2.3.5",
65
- "@monstermann/tinybench-pretty-printer": "^0.2.0",
66
- "@types/node": "^24.10.0",
67
- "@vitest/coverage-v8": "^4.0.8",
68
- "docula": "^0.31.0",
71
+ "@biomejs/biome": "^2.3.8",
72
+ "@monstermann/tinybench-pretty-printer": "^0.3.0",
73
+ "@types/node": "^25.0.3",
74
+ "@vitest/coverage-v8": "^4.0.15",
75
+ "docula": "^0.31.1",
69
76
  "emittery": "^1.2.0",
70
77
  "eventemitter3": "^5.0.1",
71
- "hookable": "^5.5.3",
78
+ "hookable": "^6.0.1",
72
79
  "pino": "^10.1.0",
73
- "rimraf": "^6.1.0",
74
- "tinybench": "^5.1.0",
75
- "tsup": "^8.5.0",
76
- "tsx": "^4.20.6",
80
+ "rimraf": "^6.1.2",
81
+ "tinybench": "^6.0.0",
82
+ "tsup": "^8.5.1",
83
+ "tsx": "^4.21.0",
77
84
  "typescript": "^5.9.3",
78
- "vitest": "^4.0.8"
85
+ "vitest": "^4.0.15"
79
86
  },
80
87
  "files": [
81
88
  "dist",
82
89
  "LICENSE"
83
- ],
84
- "pnpm": {
85
- "onlyBuiltDependencies": [
86
- "unrs-resolver"
87
- ]
88
- }
90
+ ]
89
91
  }