hookified 1.15.1 → 2.0.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.
@@ -21,7 +21,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  Eventified: () => Eventified,
24
- Hookified: () => Hookified
24
+ Hook: () => Hook,
25
+ Hookified: () => Hookified,
26
+ WaterfallHook: () => WaterfallHook
25
27
  });
26
28
  module.exports = __toCommonJS(index_exports);
27
29
 
@@ -29,14 +31,14 @@ module.exports = __toCommonJS(index_exports);
29
31
  var Eventified = class {
30
32
  _eventListeners;
31
33
  _maxListeners;
32
- _logger;
34
+ _eventLogger;
33
35
  _throwOnEmitError = false;
34
- _throwOnEmptyListeners = false;
36
+ _throwOnEmptyListeners = true;
35
37
  _errorEvent = "error";
36
38
  constructor(options) {
37
39
  this._eventListeners = /* @__PURE__ */ new Map();
38
- this._maxListeners = 100;
39
- this._logger = options?.logger;
40
+ this._maxListeners = 0;
41
+ this._eventLogger = options?.eventLogger;
40
42
  if (options?.throwOnEmitError !== void 0) {
41
43
  this._throwOnEmitError = options.throwOnEmitError;
42
44
  }
@@ -45,18 +47,18 @@ var Eventified = class {
45
47
  }
46
48
  }
47
49
  /**
48
- * Gets the logger
50
+ * Gets the event logger
49
51
  * @returns {Logger}
50
52
  */
51
- get logger() {
52
- return this._logger;
53
+ get eventLogger() {
54
+ return this._eventLogger;
53
55
  }
54
56
  /**
55
- * Sets the logger
56
- * @param {Logger} logger
57
+ * Sets the event logger
58
+ * @param {Logger} eventLogger
57
59
  */
58
- set logger(logger) {
59
- this._logger = logger;
60
+ set eventLogger(eventLogger) {
61
+ this._eventLogger = eventLogger;
60
62
  }
61
63
  /**
62
64
  * Gets whether an error should be thrown when an emit throws an error. Default is false and only emits an error event.
@@ -185,7 +187,7 @@ var Eventified = class {
185
187
  }
186
188
  const listeners = this._eventListeners.get(event);
187
189
  if (listeners) {
188
- if (listeners.length >= this._maxListeners) {
190
+ if (this._maxListeners > 0 && listeners.length >= this._maxListeners) {
189
191
  console.warn(
190
192
  `MaxListenersExceededWarning: Possible event memory leak detected. ${listeners.length + 1} ${event} listeners added. Use setMaxListeners() to increase limit.`
191
193
  );
@@ -236,6 +238,7 @@ var Eventified = class {
236
238
  result = true;
237
239
  }
238
240
  }
241
+ this.sendToEventLogger(event, arguments_);
239
242
  if (event === this._errorEvent) {
240
243
  const error = arguments_[0] instanceof Error ? arguments_[0] : new Error(`${arguments_[0]}`);
241
244
  if (this._throwOnEmitError && !result) {
@@ -246,7 +249,6 @@ var Eventified = class {
246
249
  }
247
250
  }
248
251
  }
249
- this.sendLog(event, arguments_);
250
252
  return result;
251
253
  }
252
254
  /**
@@ -276,12 +278,7 @@ var Eventified = class {
276
278
  * @returns {void}
277
279
  */
278
280
  setMaxListeners(n) {
279
- this._maxListeners = n;
280
- for (const listeners of this._eventListeners.values()) {
281
- if (listeners.length > n) {
282
- listeners.splice(n);
283
- }
284
- }
281
+ this._maxListeners = n < 0 ? 0 : n;
285
282
  }
286
283
  /**
287
284
  * Gets all listeners
@@ -299,8 +296,8 @@ var Eventified = class {
299
296
  * @param {string | symbol} eventName - The event name that determines the log level
300
297
  * @param {unknown} data - The data to log
301
298
  */
302
- sendLog(eventName, data) {
303
- if (!this._logger) {
299
+ sendToEventLogger(eventName, data) {
300
+ if (!this._eventLogger) {
304
301
  return;
305
302
  }
306
303
  let message;
@@ -317,33 +314,101 @@ var Eventified = class {
317
314
  }
318
315
  switch (eventName) {
319
316
  case "error": {
320
- this._logger.error?.(message, { event: eventName, data });
317
+ this._eventLogger.error?.(message, { event: eventName, data });
321
318
  break;
322
319
  }
323
320
  case "warn": {
324
- this._logger.warn?.(message, { event: eventName, data });
321
+ this._eventLogger.warn?.(message, { event: eventName, data });
325
322
  break;
326
323
  }
327
324
  case "trace": {
328
- this._logger.trace?.(message, { event: eventName, data });
325
+ this._eventLogger.trace?.(message, { event: eventName, data });
329
326
  break;
330
327
  }
331
328
  case "debug": {
332
- this._logger.debug?.(message, { event: eventName, data });
329
+ this._eventLogger.debug?.(message, { event: eventName, data });
333
330
  break;
334
331
  }
335
332
  case "fatal": {
336
- this._logger.fatal?.(message, { event: eventName, data });
333
+ this._eventLogger.fatal?.(message, { event: eventName, data });
337
334
  break;
338
335
  }
339
336
  default: {
340
- this._logger.info?.(message, { event: eventName, data });
337
+ this._eventLogger.info?.(message, { event: eventName, data });
341
338
  break;
342
339
  }
343
340
  }
344
341
  }
345
342
  };
346
343
 
344
+ // src/hooks/hook.ts
345
+ var Hook = class {
346
+ id;
347
+ event;
348
+ handler;
349
+ /**
350
+ * Creates a new Hook instance
351
+ * @param {string} event - The event name for the hook
352
+ * @param {HookFn} handler - The handler function for the hook
353
+ * @param {string} [id] - Optional unique identifier for the hook
354
+ */
355
+ constructor(event, handler, id) {
356
+ this.id = id;
357
+ this.event = event;
358
+ this.handler = handler;
359
+ }
360
+ };
361
+
362
+ // src/hooks/waterfall-hook.ts
363
+ var WaterfallHook = class {
364
+ id;
365
+ event;
366
+ handler;
367
+ hooks;
368
+ _finalHandler;
369
+ /**
370
+ * Creates a new WaterfallHook instance
371
+ * @param {string} event - The event name for the hook
372
+ * @param {WaterfallHookFn} finalHandler - The final handler function that receives the transformed result
373
+ * @param {string} [id] - Optional unique identifier for the hook
374
+ */
375
+ constructor(event, finalHandler, id) {
376
+ this.id = id;
377
+ this.event = event;
378
+ this.hooks = [];
379
+ this._finalHandler = finalHandler;
380
+ this.handler = async (...arguments_) => {
381
+ const initialArgs = arguments_.length === 1 ? arguments_[0] : arguments_;
382
+ const results = [];
383
+ for (const hook of this.hooks) {
384
+ const result = await hook({ initialArgs, results: [...results] });
385
+ results.push({ hook, result });
386
+ }
387
+ await this._finalHandler({ initialArgs, results: [...results] });
388
+ };
389
+ }
390
+ /**
391
+ * Adds a hook function to the end of the waterfall chain
392
+ * @param {WaterfallHookFn} hook - The hook function to add
393
+ */
394
+ addHook(hook) {
395
+ this.hooks.push(hook);
396
+ }
397
+ /**
398
+ * Removes a specific hook function from the waterfall chain
399
+ * @param {WaterfallHookFn} hook - The hook function to remove
400
+ * @returns {boolean} true if the hook was found and removed
401
+ */
402
+ removeHook(hook) {
403
+ const index = this.hooks.indexOf(hook);
404
+ if (index !== -1) {
405
+ this.hooks.splice(index, 1);
406
+ return true;
407
+ }
408
+ return false;
409
+ }
410
+ };
411
+
347
412
  // src/index.ts
348
413
  var Hookified = class extends Eventified {
349
414
  _hooks;
@@ -351,9 +416,10 @@ var Hookified = class extends Eventified {
351
416
  _enforceBeforeAfter = false;
352
417
  _deprecatedHooks;
353
418
  _allowDeprecated = true;
419
+ _useHookClone = true;
354
420
  constructor(options) {
355
421
  super({
356
- logger: options?.logger,
422
+ eventLogger: options?.eventLogger,
357
423
  throwOnEmitError: options?.throwOnEmitError,
358
424
  throwOnEmptyListeners: options?.throwOnEmptyListeners
359
425
  });
@@ -361,8 +427,6 @@ var Hookified = class extends Eventified {
361
427
  this._deprecatedHooks = options?.deprecatedHooks ? new Map(options.deprecatedHooks) : /* @__PURE__ */ new Map();
362
428
  if (options?.throwOnHookError !== void 0) {
363
429
  this._throwOnHookError = options.throwOnHookError;
364
- } else if (options?.throwHookErrors !== void 0) {
365
- this._throwOnHookError = options.throwHookErrors;
366
430
  }
367
431
  if (options?.enforceBeforeAfter !== void 0) {
368
432
  this._enforceBeforeAfter = options.enforceBeforeAfter;
@@ -370,30 +434,17 @@ var Hookified = class extends Eventified {
370
434
  if (options?.allowDeprecated !== void 0) {
371
435
  this._allowDeprecated = options.allowDeprecated;
372
436
  }
437
+ if (options?.useHookClone !== void 0) {
438
+ this._useHookClone = options.useHookClone;
439
+ }
373
440
  }
374
441
  /**
375
442
  * Gets all hooks
376
- * @returns {Map<string, Hook[]>}
443
+ * @returns {Map<string, IHook[]>}
377
444
  */
378
445
  get hooks() {
379
446
  return this._hooks;
380
447
  }
381
- /**
382
- * Gets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
383
- * @returns {boolean}
384
- * @deprecated - this will be deprecated in version 2. Please use throwOnHookError.
385
- */
386
- get throwHookErrors() {
387
- return this._throwOnHookError;
388
- }
389
- /**
390
- * Sets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
391
- * @param {boolean} value
392
- * @deprecated - this will be deprecated in version 2. Please use throwOnHookError.
393
- */
394
- set throwHookErrors(value) {
395
- this._throwOnHookError = value;
396
- }
397
448
  /**
398
449
  * Gets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
399
450
  * @returns {boolean}
@@ -452,157 +503,153 @@ var Hookified = class extends Eventified {
452
503
  this._allowDeprecated = value;
453
504
  }
454
505
  /**
455
- * Validates hook event name if enforceBeforeAfter is enabled
456
- * @param {string} event - The event name to validate
457
- * @throws {Error} If enforceBeforeAfter is true and event doesn't start with 'before' or 'after'
458
- */
459
- validateHookName(event) {
460
- if (this._enforceBeforeAfter) {
461
- const eventValue = event.trim().toLocaleLowerCase();
462
- if (!eventValue.startsWith("before") && !eventValue.startsWith("after")) {
463
- throw new Error(
464
- `Hook event "${event}" must start with "before" or "after" when enforceBeforeAfter is enabled`
465
- );
466
- }
467
- }
468
- }
469
- /**
470
- * Checks if a hook is deprecated and emits a warning if it is
471
- * @param {string} event - The event name to check
472
- * @returns {boolean} - Returns true if the hook should proceed, false if it should be blocked
506
+ * Gets whether hook objects are cloned before storing. Default is true.
507
+ * @returns {boolean}
473
508
  */
474
- checkDeprecatedHook(event) {
475
- if (this._deprecatedHooks.has(event)) {
476
- const message = this._deprecatedHooks.get(event);
477
- const warningMessage = `Hook "${event}" is deprecated${message ? `: ${message}` : ""}`;
478
- this.emit("warn", { hook: event, message: warningMessage });
479
- return this._allowDeprecated;
480
- }
481
- return true;
509
+ get useHookClone() {
510
+ return this._useHookClone;
482
511
  }
483
512
  /**
484
- * Adds a handler function for a specific event
485
- * @param {string} event
486
- * @param {Hook} handler - this can be async or sync
487
- * @returns {void}
513
+ * Sets whether hook objects are cloned before storing. Default is true.
514
+ * When false, the original IHook reference is stored directly.
515
+ * @param {boolean} value
488
516
  */
489
- onHook(event, handler) {
490
- this.onHookEntry({ event, handler });
517
+ set useHookClone(value) {
518
+ this._useHookClone = value;
491
519
  }
492
520
  /**
493
- * Adds a handler function for a specific event
494
- * @param {HookEntry} hookEntry
495
- * @returns {void}
521
+ * Adds a handler function for a specific event.
522
+ * If you prefer the legacy `(event, handler)` signature, use {@link addHook} instead.
523
+ * To register multiple hooks at once, use {@link onHooks}.
524
+ * @param {IHook} hook - the hook containing event name and handler
525
+ * @param {OnHookOptions} [options] - optional per-call options (e.g., useHookClone override, position)
526
+ * @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation
496
527
  */
497
- onHookEntry(hookEntry) {
498
- this.validateHookName(hookEntry.event);
499
- if (!this.checkDeprecatedHook(hookEntry.event)) {
500
- return;
528
+ onHook(hook, options) {
529
+ this.validateHookName(hook.event);
530
+ if (!this.checkDeprecatedHook(hook.event)) {
531
+ return void 0;
501
532
  }
502
- const eventHandlers = this._hooks.get(hookEntry.event);
533
+ const shouldClone = options?.useHookClone ?? this._useHookClone;
534
+ const entry = shouldClone ? { id: hook.id, event: hook.event, handler: hook.handler } : hook;
535
+ entry.id = entry.id ?? crypto.randomUUID();
536
+ const eventHandlers = this._hooks.get(hook.event);
503
537
  if (eventHandlers) {
504
- eventHandlers.push(hookEntry.handler);
538
+ const existingIndex = eventHandlers.findIndex((h) => h.id === entry.id);
539
+ if (existingIndex !== -1) {
540
+ eventHandlers[existingIndex] = entry;
541
+ } else {
542
+ const position = options?.position ?? "Bottom";
543
+ if (position === "Top") {
544
+ eventHandlers.unshift(entry);
545
+ } else if (position === "Bottom") {
546
+ eventHandlers.push(entry);
547
+ } else {
548
+ const index = Math.max(0, Math.min(position, eventHandlers.length));
549
+ eventHandlers.splice(index, 0, entry);
550
+ }
551
+ }
505
552
  } else {
506
- this._hooks.set(hookEntry.event, [hookEntry.handler]);
553
+ this._hooks.set(hook.event, [entry]);
507
554
  }
555
+ return entry;
508
556
  }
509
557
  /**
510
558
  * Alias for onHook. This is provided for compatibility with other libraries that use the `addHook` method.
511
- * @param {string} event
512
- * @param {Hook} handler - this can be async or sync
559
+ * @param {string} event - the event name
560
+ * @param {HookFn} handler - the handler function
513
561
  * @returns {void}
514
562
  */
515
563
  addHook(event, handler) {
516
- this.onHookEntry({ event, handler });
564
+ this.onHook({ event, handler });
517
565
  }
518
566
  /**
519
- * Adds a handler function for a specific event
520
- * @param {Array<HookEntry>} hooks
567
+ * Adds handler functions for specific events
568
+ * @param {Array<IHook>} hooks
569
+ * @param {OnHookOptions} [options] - optional per-call options (e.g., useHookClone override, position)
521
570
  * @returns {void}
522
571
  */
523
- onHooks(hooks) {
572
+ onHooks(hooks, options) {
524
573
  for (const hook of hooks) {
525
- this.onHook(hook.event, hook.handler);
574
+ this.onHook(hook, options);
526
575
  }
527
576
  }
528
577
  /**
529
- * Adds a handler function for a specific event that runs before all other handlers
530
- * @param {string} event
531
- * @param {Hook} handler - this can be async or sync
532
- * @returns {void}
578
+ * Adds a handler function for a specific event that runs before all other handlers.
579
+ * Equivalent to calling `onHook(hook, { position: "Top" })`.
580
+ * @param {IHook} hook - the hook containing event name and handler
581
+ * @param {PrependHookOptions} [options] - optional per-call options (e.g., useHookClone override)
582
+ * @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation
533
583
  */
534
- prependHook(event, handler) {
535
- this.validateHookName(event);
536
- if (!this.checkDeprecatedHook(event)) {
537
- return;
538
- }
539
- const eventHandlers = this._hooks.get(event);
540
- if (eventHandlers) {
541
- eventHandlers.unshift(handler);
542
- } else {
543
- this._hooks.set(event, [handler]);
544
- }
584
+ prependHook(hook, options) {
585
+ return this.onHook(hook, { ...options, position: "Top" });
545
586
  }
546
587
  /**
547
- * Adds a handler that only executes once for a specific event before all other handlers
548
- * @param event
549
- * @param handler
588
+ * Adds a handler that only executes once for a specific event before all other handlers.
589
+ * Equivalent to calling `onHook` with a self-removing wrapper and `{ position: "Top" }`.
590
+ * @param {IHook} hook - the hook containing event name and handler
591
+ * @param {PrependHookOptions} [options] - optional per-call options (e.g., useHookClone override)
592
+ * @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation
550
593
  */
551
- prependOnceHook(event, handler) {
552
- this.validateHookName(event);
553
- if (!this.checkDeprecatedHook(event)) {
554
- return;
555
- }
556
- const hook = async (...arguments_) => {
557
- this.removeHook(event, hook);
558
- return handler(...arguments_);
594
+ prependOnceHook(hook, options) {
595
+ const wrappedHandler = async (...arguments_) => {
596
+ this.removeHook({ event: hook.event, handler: wrappedHandler });
597
+ return hook.handler(...arguments_);
559
598
  };
560
- this.prependHook(event, hook);
599
+ return this.onHook(
600
+ { id: hook.id, event: hook.event, handler: wrappedHandler },
601
+ { ...options, position: "Top" }
602
+ );
561
603
  }
562
604
  /**
563
605
  * Adds a handler that only executes once for a specific event
564
- * @param event
565
- * @param handler
606
+ * @param {IHook} hook - the hook containing event name and handler
566
607
  */
567
- onceHook(event, handler) {
568
- this.validateHookName(event);
569
- if (!this.checkDeprecatedHook(event)) {
608
+ onceHook(hook) {
609
+ this.validateHookName(hook.event);
610
+ if (!this.checkDeprecatedHook(hook.event)) {
570
611
  return;
571
612
  }
572
- const hook = async (...arguments_) => {
573
- this.removeHook(event, hook);
574
- return handler(...arguments_);
613
+ const wrappedHandler = async (...arguments_) => {
614
+ this.removeHook({ event: hook.event, handler: wrappedHandler });
615
+ return hook.handler(...arguments_);
575
616
  };
576
- this.onHook(event, hook);
617
+ this.onHook({ id: hook.id, event: hook.event, handler: wrappedHandler });
577
618
  }
578
619
  /**
579
620
  * Removes a handler function for a specific event
580
- * @param {string} event
581
- * @param {Hook} handler
582
- * @returns {void}
621
+ * @param {IHook} hook - the hook containing event name and handler to remove
622
+ * @returns {IHook | undefined} the removed hook, or undefined if not found
583
623
  */
584
- removeHook(event, handler) {
585
- this.validateHookName(event);
586
- if (!this.checkDeprecatedHook(event)) {
587
- return;
588
- }
589
- const eventHandlers = this._hooks.get(event);
624
+ removeHook(hook) {
625
+ this.validateHookName(hook.event);
626
+ const eventHandlers = this._hooks.get(hook.event);
590
627
  if (eventHandlers) {
591
- const index = eventHandlers.indexOf(handler);
628
+ const index = eventHandlers.findIndex((h) => h.handler === hook.handler);
592
629
  if (index !== -1) {
593
630
  eventHandlers.splice(index, 1);
631
+ if (eventHandlers.length === 0) {
632
+ this._hooks.delete(hook.event);
633
+ }
634
+ return { event: hook.event, handler: hook.handler };
594
635
  }
595
636
  }
637
+ return void 0;
596
638
  }
597
639
  /**
598
- * Removes all handlers for a specific event
599
- * @param {Array<HookEntry>} hooks
600
- * @returns {void}
640
+ * Removes multiple hook handlers
641
+ * @param {Array<IHook>} hooks
642
+ * @returns {IHook[]} the hooks that were successfully removed
601
643
  */
602
644
  removeHooks(hooks) {
645
+ const removed = [];
603
646
  for (const hook of hooks) {
604
- this.removeHook(hook.event, hook.handler);
647
+ const result = this.removeHook(hook);
648
+ if (result) {
649
+ removed.push(result);
650
+ }
605
651
  }
652
+ return removed;
606
653
  }
607
654
  /**
608
655
  * Calls all handlers for a specific event
@@ -617,9 +664,9 @@ var Hookified = class extends Eventified {
617
664
  }
618
665
  const eventHandlers = this._hooks.get(event);
619
666
  if (eventHandlers) {
620
- for (const handler of eventHandlers) {
667
+ for (const hook of [...eventHandlers]) {
621
668
  try {
622
- await handler(...arguments_);
669
+ await hook.handler(...arguments_);
623
670
  } catch (error) {
624
671
  const message = `${event}: ${error.message}`;
625
672
  this.emit("error", new Error(message));
@@ -647,12 +694,12 @@ var Hookified = class extends Eventified {
647
694
  }
648
695
  const eventHandlers = this._hooks.get(event);
649
696
  if (eventHandlers) {
650
- for (const handler of eventHandlers) {
651
- if (handler.constructor.name === "AsyncFunction") {
697
+ for (const hook of [...eventHandlers]) {
698
+ if (hook.handler.constructor.name === "AsyncFunction") {
652
699
  continue;
653
700
  }
654
701
  try {
655
- handler(...arguments_);
702
+ hook.handler(...arguments_);
656
703
  } catch (error) {
657
704
  const message = `${event}: ${error.message}`;
658
705
  this.emit("error", new Error(message));
@@ -692,15 +739,54 @@ var Hookified = class extends Eventified {
692
739
  /**
693
740
  * Gets all hooks for a specific event
694
741
  * @param {string} event
695
- * @returns {Hook[]}
742
+ * @returns {IHook[]}
696
743
  */
697
744
  getHooks(event) {
698
745
  this.validateHookName(event);
699
- if (!this.checkDeprecatedHook(event)) {
700
- return void 0;
701
- }
702
746
  return this._hooks.get(event);
703
747
  }
748
+ /**
749
+ * Gets a specific hook by id, searching across all events
750
+ * @param {string} id - the hook id
751
+ * @returns {IHook | undefined} the hook if found, or undefined
752
+ */
753
+ getHook(id) {
754
+ for (const eventHandlers of this._hooks.values()) {
755
+ const found = eventHandlers.find((h) => h.id === id);
756
+ if (found) {
757
+ return found;
758
+ }
759
+ }
760
+ return void 0;
761
+ }
762
+ /**
763
+ * Removes one or more hooks by id, searching across all events
764
+ * @param {string | string[]} id - the hook id or array of hook ids to remove
765
+ * @returns {IHook | IHook[] | undefined} the removed hook(s), or undefined/empty array if not found
766
+ */
767
+ removeHookById(id) {
768
+ if (Array.isArray(id)) {
769
+ const removed = [];
770
+ for (const singleId of id) {
771
+ const result = this.removeHookById(singleId);
772
+ if (result && !Array.isArray(result)) {
773
+ removed.push(result);
774
+ }
775
+ }
776
+ return removed;
777
+ }
778
+ for (const [event, eventHandlers] of this._hooks.entries()) {
779
+ const index = eventHandlers.findIndex((h) => h.id === id);
780
+ if (index !== -1) {
781
+ const [removed] = eventHandlers.splice(index, 1);
782
+ if (eventHandlers.length === 0) {
783
+ this._hooks.delete(event);
784
+ }
785
+ return removed;
786
+ }
787
+ }
788
+ return void 0;
789
+ }
704
790
  /**
705
791
  * Removes all hooks
706
792
  * @returns {void}
@@ -708,10 +794,56 @@ var Hookified = class extends Eventified {
708
794
  clearHooks() {
709
795
  this._hooks.clear();
710
796
  }
797
+ /**
798
+ * Removes all hooks for a specific event and returns the removed hooks.
799
+ * @param {string} event - The event name to remove hooks for.
800
+ * @returns {IHook[]} the hooks that were removed
801
+ */
802
+ removeEventHooks(event) {
803
+ this.validateHookName(event);
804
+ const eventHandlers = this._hooks.get(event);
805
+ if (eventHandlers) {
806
+ const removed = [...eventHandlers];
807
+ this._hooks.delete(event);
808
+ return removed;
809
+ }
810
+ return [];
811
+ }
812
+ /**
813
+ * Validates hook event name if enforceBeforeAfter is enabled
814
+ * @param {string} event - The event name to validate
815
+ * @throws {Error} If enforceBeforeAfter is true and event doesn't start with 'before' or 'after'
816
+ */
817
+ validateHookName(event) {
818
+ if (this._enforceBeforeAfter) {
819
+ const eventValue = event.trim().toLocaleLowerCase();
820
+ if (!eventValue.startsWith("before") && !eventValue.startsWith("after")) {
821
+ throw new Error(
822
+ `Hook event "${event}" must start with "before" or "after" when enforceBeforeAfter is enabled`
823
+ );
824
+ }
825
+ }
826
+ }
827
+ /**
828
+ * Checks if a hook is deprecated and emits a warning if it is
829
+ * @param {string} event - The event name to check
830
+ * @returns {boolean} - Returns true if the hook should proceed, false if it should be blocked
831
+ */
832
+ checkDeprecatedHook(event) {
833
+ if (this._deprecatedHooks.has(event)) {
834
+ const message = this._deprecatedHooks.get(event);
835
+ const warningMessage = `Hook "${event}" is deprecated${message ? `: ${message}` : ""}`;
836
+ this.emit("warn", { hook: event, message: warningMessage });
837
+ return this._allowDeprecated;
838
+ }
839
+ return true;
840
+ }
711
841
  };
712
842
  // Annotate the CommonJS export names for ESM import in node:
713
843
  0 && (module.exports = {
714
844
  Eventified,
715
- Hookified
845
+ Hook,
846
+ Hookified,
847
+ WaterfallHook
716
848
  });
717
849
  /* v8 ignore next -- @preserve */