hookified 1.15.0 → 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.
@@ -7,13 +7,13 @@ var Eventified = class {
7
7
  constructor(options) {
8
8
  __publicField(this, "_eventListeners");
9
9
  __publicField(this, "_maxListeners");
10
- __publicField(this, "_logger");
10
+ __publicField(this, "_eventLogger");
11
11
  __publicField(this, "_throwOnEmitError", false);
12
- __publicField(this, "_throwOnEmptyListeners", false);
12
+ __publicField(this, "_throwOnEmptyListeners", true);
13
13
  __publicField(this, "_errorEvent", "error");
14
14
  this._eventListeners = /* @__PURE__ */ new Map();
15
- this._maxListeners = 100;
16
- this._logger = options?.logger;
15
+ this._maxListeners = 0;
16
+ this._eventLogger = options?.eventLogger;
17
17
  if (options?.throwOnEmitError !== void 0) {
18
18
  this._throwOnEmitError = options.throwOnEmitError;
19
19
  }
@@ -22,18 +22,18 @@ var Eventified = class {
22
22
  }
23
23
  }
24
24
  /**
25
- * Gets the logger
25
+ * Gets the event logger
26
26
  * @returns {Logger}
27
27
  */
28
- get logger() {
29
- return this._logger;
28
+ get eventLogger() {
29
+ return this._eventLogger;
30
30
  }
31
31
  /**
32
- * Sets the logger
33
- * @param {Logger} logger
32
+ * Sets the event logger
33
+ * @param {Logger} eventLogger
34
34
  */
35
- set logger(logger) {
36
- this._logger = logger;
35
+ set eventLogger(eventLogger) {
36
+ this._eventLogger = eventLogger;
37
37
  }
38
38
  /**
39
39
  * Gets whether an error should be thrown when an emit throws an error. Default is false and only emits an error event.
@@ -162,7 +162,7 @@ var Eventified = class {
162
162
  }
163
163
  const listeners = this._eventListeners.get(event);
164
164
  if (listeners) {
165
- if (listeners.length >= this._maxListeners) {
165
+ if (this._maxListeners > 0 && listeners.length >= this._maxListeners) {
166
166
  console.warn(
167
167
  `MaxListenersExceededWarning: Possible event memory leak detected. ${listeners.length + 1} ${event} listeners added. Use setMaxListeners() to increase limit.`
168
168
  );
@@ -213,6 +213,7 @@ var Eventified = class {
213
213
  result = true;
214
214
  }
215
215
  }
216
+ this.sendToEventLogger(event, arguments_);
216
217
  if (event === this._errorEvent) {
217
218
  const error = arguments_[0] instanceof Error ? arguments_[0] : new Error(`${arguments_[0]}`);
218
219
  if (this._throwOnEmitError && !result) {
@@ -223,7 +224,6 @@ var Eventified = class {
223
224
  }
224
225
  }
225
226
  }
226
- this.sendLog(event, arguments_);
227
227
  return result;
228
228
  }
229
229
  /**
@@ -253,12 +253,7 @@ var Eventified = class {
253
253
  * @returns {void}
254
254
  */
255
255
  setMaxListeners(n) {
256
- this._maxListeners = n;
257
- for (const listeners of this._eventListeners.values()) {
258
- if (listeners.length > n) {
259
- listeners.splice(n);
260
- }
261
- }
256
+ this._maxListeners = n < 0 ? 0 : n;
262
257
  }
263
258
  /**
264
259
  * Gets all listeners
@@ -276,8 +271,8 @@ var Eventified = class {
276
271
  * @param {string | symbol} eventName - The event name that determines the log level
277
272
  * @param {unknown} data - The data to log
278
273
  */
279
- sendLog(eventName, data) {
280
- if (!this._logger) {
274
+ sendToEventLogger(eventName, data) {
275
+ if (!this._eventLogger) {
281
276
  return;
282
277
  }
283
278
  let message;
@@ -294,38 +289,106 @@ var Eventified = class {
294
289
  }
295
290
  switch (eventName) {
296
291
  case "error": {
297
- this._logger.error?.(message, { event: eventName, data });
292
+ this._eventLogger.error?.(message, { event: eventName, data });
298
293
  break;
299
294
  }
300
295
  case "warn": {
301
- this._logger.warn?.(message, { event: eventName, data });
296
+ this._eventLogger.warn?.(message, { event: eventName, data });
302
297
  break;
303
298
  }
304
299
  case "trace": {
305
- this._logger.trace?.(message, { event: eventName, data });
300
+ this._eventLogger.trace?.(message, { event: eventName, data });
306
301
  break;
307
302
  }
308
303
  case "debug": {
309
- this._logger.debug?.(message, { event: eventName, data });
304
+ this._eventLogger.debug?.(message, { event: eventName, data });
310
305
  break;
311
306
  }
312
307
  case "fatal": {
313
- this._logger.fatal?.(message, { event: eventName, data });
308
+ this._eventLogger.fatal?.(message, { event: eventName, data });
314
309
  break;
315
310
  }
316
311
  default: {
317
- this._logger.info?.(message, { event: eventName, data });
312
+ this._eventLogger.info?.(message, { event: eventName, data });
318
313
  break;
319
314
  }
320
315
  }
321
316
  }
322
317
  };
323
318
 
319
+ // src/hooks/hook.ts
320
+ var Hook = class {
321
+ /**
322
+ * Creates a new Hook instance
323
+ * @param {string} event - The event name for the hook
324
+ * @param {HookFn} handler - The handler function for the hook
325
+ * @param {string} [id] - Optional unique identifier for the hook
326
+ */
327
+ constructor(event, handler, id) {
328
+ __publicField(this, "id");
329
+ __publicField(this, "event");
330
+ __publicField(this, "handler");
331
+ this.id = id;
332
+ this.event = event;
333
+ this.handler = handler;
334
+ }
335
+ };
336
+
337
+ // src/hooks/waterfall-hook.ts
338
+ var WaterfallHook = class {
339
+ /**
340
+ * Creates a new WaterfallHook instance
341
+ * @param {string} event - The event name for the hook
342
+ * @param {WaterfallHookFn} finalHandler - The final handler function that receives the transformed result
343
+ * @param {string} [id] - Optional unique identifier for the hook
344
+ */
345
+ constructor(event, finalHandler, id) {
346
+ __publicField(this, "id");
347
+ __publicField(this, "event");
348
+ __publicField(this, "handler");
349
+ __publicField(this, "hooks");
350
+ __publicField(this, "_finalHandler");
351
+ this.id = id;
352
+ this.event = event;
353
+ this.hooks = [];
354
+ this._finalHandler = finalHandler;
355
+ this.handler = async (...arguments_) => {
356
+ const initialArgs = arguments_.length === 1 ? arguments_[0] : arguments_;
357
+ const results = [];
358
+ for (const hook of this.hooks) {
359
+ const result = await hook({ initialArgs, results: [...results] });
360
+ results.push({ hook, result });
361
+ }
362
+ await this._finalHandler({ initialArgs, results: [...results] });
363
+ };
364
+ }
365
+ /**
366
+ * Adds a hook function to the end of the waterfall chain
367
+ * @param {WaterfallHookFn} hook - The hook function to add
368
+ */
369
+ addHook(hook) {
370
+ this.hooks.push(hook);
371
+ }
372
+ /**
373
+ * Removes a specific hook function from the waterfall chain
374
+ * @param {WaterfallHookFn} hook - The hook function to remove
375
+ * @returns {boolean} true if the hook was found and removed
376
+ */
377
+ removeHook(hook) {
378
+ const index = this.hooks.indexOf(hook);
379
+ if (index !== -1) {
380
+ this.hooks.splice(index, 1);
381
+ return true;
382
+ }
383
+ return false;
384
+ }
385
+ };
386
+
324
387
  // src/index.ts
325
388
  var Hookified = class extends Eventified {
326
389
  constructor(options) {
327
390
  super({
328
- logger: options?.logger,
391
+ eventLogger: options?.eventLogger,
329
392
  throwOnEmitError: options?.throwOnEmitError,
330
393
  throwOnEmptyListeners: options?.throwOnEmptyListeners
331
394
  });
@@ -334,12 +397,11 @@ var Hookified = class extends Eventified {
334
397
  __publicField(this, "_enforceBeforeAfter", false);
335
398
  __publicField(this, "_deprecatedHooks");
336
399
  __publicField(this, "_allowDeprecated", true);
400
+ __publicField(this, "_useHookClone", true);
337
401
  this._hooks = /* @__PURE__ */ new Map();
338
402
  this._deprecatedHooks = options?.deprecatedHooks ? new Map(options.deprecatedHooks) : /* @__PURE__ */ new Map();
339
403
  if (options?.throwOnHookError !== void 0) {
340
404
  this._throwOnHookError = options.throwOnHookError;
341
- } else if (options?.throwHookErrors !== void 0) {
342
- this._throwOnHookError = options.throwHookErrors;
343
405
  }
344
406
  if (options?.enforceBeforeAfter !== void 0) {
345
407
  this._enforceBeforeAfter = options.enforceBeforeAfter;
@@ -347,30 +409,17 @@ var Hookified = class extends Eventified {
347
409
  if (options?.allowDeprecated !== void 0) {
348
410
  this._allowDeprecated = options.allowDeprecated;
349
411
  }
412
+ if (options?.useHookClone !== void 0) {
413
+ this._useHookClone = options.useHookClone;
414
+ }
350
415
  }
351
416
  /**
352
417
  * Gets all hooks
353
- * @returns {Map<string, Hook[]>}
418
+ * @returns {Map<string, IHook[]>}
354
419
  */
355
420
  get hooks() {
356
421
  return this._hooks;
357
422
  }
358
- /**
359
- * Gets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
360
- * @returns {boolean}
361
- * @deprecated - this will be deprecated in version 2. Please use throwOnHookError.
362
- */
363
- get throwHookErrors() {
364
- return this._throwOnHookError;
365
- }
366
- /**
367
- * Sets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
368
- * @param {boolean} value
369
- * @deprecated - this will be deprecated in version 2. Please use throwOnHookError.
370
- */
371
- set throwHookErrors(value) {
372
- this._throwOnHookError = value;
373
- }
374
423
  /**
375
424
  * Gets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
376
425
  * @returns {boolean}
@@ -429,157 +478,153 @@ var Hookified = class extends Eventified {
429
478
  this._allowDeprecated = value;
430
479
  }
431
480
  /**
432
- * Validates hook event name if enforceBeforeAfter is enabled
433
- * @param {string} event - The event name to validate
434
- * @throws {Error} If enforceBeforeAfter is true and event doesn't start with 'before' or 'after'
435
- */
436
- validateHookName(event) {
437
- if (this._enforceBeforeAfter) {
438
- const eventValue = event.trim().toLocaleLowerCase();
439
- if (!eventValue.startsWith("before") && !eventValue.startsWith("after")) {
440
- throw new Error(
441
- `Hook event "${event}" must start with "before" or "after" when enforceBeforeAfter is enabled`
442
- );
443
- }
444
- }
445
- }
446
- /**
447
- * Checks if a hook is deprecated and emits a warning if it is
448
- * @param {string} event - The event name to check
449
- * @returns {boolean} - Returns true if the hook should proceed, false if it should be blocked
481
+ * Gets whether hook objects are cloned before storing. Default is true.
482
+ * @returns {boolean}
450
483
  */
451
- checkDeprecatedHook(event) {
452
- if (this._deprecatedHooks.has(event)) {
453
- const message = this._deprecatedHooks.get(event);
454
- const warningMessage = `Hook "${event}" is deprecated${message ? `: ${message}` : ""}`;
455
- this.emit("warn", { hook: event, message: warningMessage });
456
- return this._allowDeprecated;
457
- }
458
- return true;
484
+ get useHookClone() {
485
+ return this._useHookClone;
459
486
  }
460
487
  /**
461
- * Adds a handler function for a specific event
462
- * @param {string} event
463
- * @param {Hook} handler - this can be async or sync
464
- * @returns {void}
488
+ * Sets whether hook objects are cloned before storing. Default is true.
489
+ * When false, the original IHook reference is stored directly.
490
+ * @param {boolean} value
465
491
  */
466
- onHook(event, handler) {
467
- this.onHookEntry({ event, handler });
492
+ set useHookClone(value) {
493
+ this._useHookClone = value;
468
494
  }
469
495
  /**
470
- * Adds a handler function for a specific event
471
- * @param {HookEntry} hookEntry
472
- * @returns {void}
496
+ * Adds a handler function for a specific event.
497
+ * If you prefer the legacy `(event, handler)` signature, use {@link addHook} instead.
498
+ * To register multiple hooks at once, use {@link onHooks}.
499
+ * @param {IHook} hook - the hook containing event name and handler
500
+ * @param {OnHookOptions} [options] - optional per-call options (e.g., useHookClone override, position)
501
+ * @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation
473
502
  */
474
- onHookEntry(hookEntry) {
475
- this.validateHookName(hookEntry.event);
476
- if (!this.checkDeprecatedHook(hookEntry.event)) {
477
- return;
503
+ onHook(hook, options) {
504
+ this.validateHookName(hook.event);
505
+ if (!this.checkDeprecatedHook(hook.event)) {
506
+ return void 0;
478
507
  }
479
- const eventHandlers = this._hooks.get(hookEntry.event);
508
+ const shouldClone = options?.useHookClone ?? this._useHookClone;
509
+ const entry = shouldClone ? { id: hook.id, event: hook.event, handler: hook.handler } : hook;
510
+ entry.id = entry.id ?? crypto.randomUUID();
511
+ const eventHandlers = this._hooks.get(hook.event);
480
512
  if (eventHandlers) {
481
- eventHandlers.push(hookEntry.handler);
513
+ const existingIndex = eventHandlers.findIndex((h) => h.id === entry.id);
514
+ if (existingIndex !== -1) {
515
+ eventHandlers[existingIndex] = entry;
516
+ } else {
517
+ const position = options?.position ?? "Bottom";
518
+ if (position === "Top") {
519
+ eventHandlers.unshift(entry);
520
+ } else if (position === "Bottom") {
521
+ eventHandlers.push(entry);
522
+ } else {
523
+ const index = Math.max(0, Math.min(position, eventHandlers.length));
524
+ eventHandlers.splice(index, 0, entry);
525
+ }
526
+ }
482
527
  } else {
483
- this._hooks.set(hookEntry.event, [hookEntry.handler]);
528
+ this._hooks.set(hook.event, [entry]);
484
529
  }
530
+ return entry;
485
531
  }
486
532
  /**
487
533
  * Alias for onHook. This is provided for compatibility with other libraries that use the `addHook` method.
488
- * @param {string} event
489
- * @param {Hook} handler - this can be async or sync
534
+ * @param {string} event - the event name
535
+ * @param {HookFn} handler - the handler function
490
536
  * @returns {void}
491
537
  */
492
538
  addHook(event, handler) {
493
- this.onHookEntry({ event, handler });
539
+ this.onHook({ event, handler });
494
540
  }
495
541
  /**
496
- * Adds a handler function for a specific event
497
- * @param {Array<HookEntry>} hooks
542
+ * Adds handler functions for specific events
543
+ * @param {Array<IHook>} hooks
544
+ * @param {OnHookOptions} [options] - optional per-call options (e.g., useHookClone override, position)
498
545
  * @returns {void}
499
546
  */
500
- onHooks(hooks) {
547
+ onHooks(hooks, options) {
501
548
  for (const hook of hooks) {
502
- this.onHook(hook.event, hook.handler);
549
+ this.onHook(hook, options);
503
550
  }
504
551
  }
505
552
  /**
506
- * Adds a handler function for a specific event that runs before all other handlers
507
- * @param {string} event
508
- * @param {Hook} handler - this can be async or sync
509
- * @returns {void}
553
+ * Adds a handler function for a specific event that runs before all other handlers.
554
+ * Equivalent to calling `onHook(hook, { position: "Top" })`.
555
+ * @param {IHook} hook - the hook containing event name and handler
556
+ * @param {PrependHookOptions} [options] - optional per-call options (e.g., useHookClone override)
557
+ * @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation
510
558
  */
511
- prependHook(event, handler) {
512
- this.validateHookName(event);
513
- if (!this.checkDeprecatedHook(event)) {
514
- return;
515
- }
516
- const eventHandlers = this._hooks.get(event);
517
- if (eventHandlers) {
518
- eventHandlers.unshift(handler);
519
- } else {
520
- this._hooks.set(event, [handler]);
521
- }
559
+ prependHook(hook, options) {
560
+ return this.onHook(hook, { ...options, position: "Top" });
522
561
  }
523
562
  /**
524
- * Adds a handler that only executes once for a specific event before all other handlers
525
- * @param event
526
- * @param handler
563
+ * Adds a handler that only executes once for a specific event before all other handlers.
564
+ * Equivalent to calling `onHook` with a self-removing wrapper and `{ position: "Top" }`.
565
+ * @param {IHook} hook - the hook containing event name and handler
566
+ * @param {PrependHookOptions} [options] - optional per-call options (e.g., useHookClone override)
567
+ * @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation
527
568
  */
528
- prependOnceHook(event, handler) {
529
- this.validateHookName(event);
530
- if (!this.checkDeprecatedHook(event)) {
531
- return;
532
- }
533
- const hook = async (...arguments_) => {
534
- this.removeHook(event, hook);
535
- return handler(...arguments_);
569
+ prependOnceHook(hook, options) {
570
+ const wrappedHandler = async (...arguments_) => {
571
+ this.removeHook({ event: hook.event, handler: wrappedHandler });
572
+ return hook.handler(...arguments_);
536
573
  };
537
- this.prependHook(event, hook);
574
+ return this.onHook(
575
+ { id: hook.id, event: hook.event, handler: wrappedHandler },
576
+ { ...options, position: "Top" }
577
+ );
538
578
  }
539
579
  /**
540
580
  * Adds a handler that only executes once for a specific event
541
- * @param event
542
- * @param handler
581
+ * @param {IHook} hook - the hook containing event name and handler
543
582
  */
544
- onceHook(event, handler) {
545
- this.validateHookName(event);
546
- if (!this.checkDeprecatedHook(event)) {
583
+ onceHook(hook) {
584
+ this.validateHookName(hook.event);
585
+ if (!this.checkDeprecatedHook(hook.event)) {
547
586
  return;
548
587
  }
549
- const hook = async (...arguments_) => {
550
- this.removeHook(event, hook);
551
- return handler(...arguments_);
588
+ const wrappedHandler = async (...arguments_) => {
589
+ this.removeHook({ event: hook.event, handler: wrappedHandler });
590
+ return hook.handler(...arguments_);
552
591
  };
553
- this.onHook(event, hook);
592
+ this.onHook({ id: hook.id, event: hook.event, handler: wrappedHandler });
554
593
  }
555
594
  /**
556
595
  * Removes a handler function for a specific event
557
- * @param {string} event
558
- * @param {Hook} handler
559
- * @returns {void}
596
+ * @param {IHook} hook - the hook containing event name and handler to remove
597
+ * @returns {IHook | undefined} the removed hook, or undefined if not found
560
598
  */
561
- removeHook(event, handler) {
562
- this.validateHookName(event);
563
- if (!this.checkDeprecatedHook(event)) {
564
- return;
565
- }
566
- const eventHandlers = this._hooks.get(event);
599
+ removeHook(hook) {
600
+ this.validateHookName(hook.event);
601
+ const eventHandlers = this._hooks.get(hook.event);
567
602
  if (eventHandlers) {
568
- const index = eventHandlers.indexOf(handler);
603
+ const index = eventHandlers.findIndex((h) => h.handler === hook.handler);
569
604
  if (index !== -1) {
570
605
  eventHandlers.splice(index, 1);
606
+ if (eventHandlers.length === 0) {
607
+ this._hooks.delete(hook.event);
608
+ }
609
+ return { event: hook.event, handler: hook.handler };
571
610
  }
572
611
  }
612
+ return void 0;
573
613
  }
574
614
  /**
575
- * Removes all handlers for a specific event
576
- * @param {Array<HookEntry>} hooks
577
- * @returns {void}
615
+ * Removes multiple hook handlers
616
+ * @param {Array<IHook>} hooks
617
+ * @returns {IHook[]} the hooks that were successfully removed
578
618
  */
579
619
  removeHooks(hooks) {
620
+ const removed = [];
580
621
  for (const hook of hooks) {
581
- this.removeHook(hook.event, hook.handler);
622
+ const result = this.removeHook(hook);
623
+ if (result) {
624
+ removed.push(result);
625
+ }
582
626
  }
627
+ return removed;
583
628
  }
584
629
  /**
585
630
  * Calls all handlers for a specific event
@@ -594,9 +639,9 @@ var Hookified = class extends Eventified {
594
639
  }
595
640
  const eventHandlers = this._hooks.get(event);
596
641
  if (eventHandlers) {
597
- for (const handler of eventHandlers) {
642
+ for (const hook of [...eventHandlers]) {
598
643
  try {
599
- await handler(...arguments_);
644
+ await hook.handler(...arguments_);
600
645
  } catch (error) {
601
646
  const message = `${event}: ${error.message}`;
602
647
  this.emit("error", new Error(message));
@@ -624,12 +669,12 @@ var Hookified = class extends Eventified {
624
669
  }
625
670
  const eventHandlers = this._hooks.get(event);
626
671
  if (eventHandlers) {
627
- for (const handler of eventHandlers) {
628
- if (handler.constructor.name === "AsyncFunction") {
672
+ for (const hook of [...eventHandlers]) {
673
+ if (hook.handler.constructor.name === "AsyncFunction") {
629
674
  continue;
630
675
  }
631
676
  try {
632
- handler(...arguments_);
677
+ hook.handler(...arguments_);
633
678
  } catch (error) {
634
679
  const message = `${event}: ${error.message}`;
635
680
  this.emit("error", new Error(message));
@@ -669,15 +714,54 @@ var Hookified = class extends Eventified {
669
714
  /**
670
715
  * Gets all hooks for a specific event
671
716
  * @param {string} event
672
- * @returns {Hook[]}
717
+ * @returns {IHook[]}
673
718
  */
674
719
  getHooks(event) {
675
720
  this.validateHookName(event);
676
- if (!this.checkDeprecatedHook(event)) {
677
- return void 0;
678
- }
679
721
  return this._hooks.get(event);
680
722
  }
723
+ /**
724
+ * Gets a specific hook by id, searching across all events
725
+ * @param {string} id - the hook id
726
+ * @returns {IHook | undefined} the hook if found, or undefined
727
+ */
728
+ getHook(id) {
729
+ for (const eventHandlers of this._hooks.values()) {
730
+ const found = eventHandlers.find((h) => h.id === id);
731
+ if (found) {
732
+ return found;
733
+ }
734
+ }
735
+ return void 0;
736
+ }
737
+ /**
738
+ * Removes one or more hooks by id, searching across all events
739
+ * @param {string | string[]} id - the hook id or array of hook ids to remove
740
+ * @returns {IHook | IHook[] | undefined} the removed hook(s), or undefined/empty array if not found
741
+ */
742
+ removeHookById(id) {
743
+ if (Array.isArray(id)) {
744
+ const removed = [];
745
+ for (const singleId of id) {
746
+ const result = this.removeHookById(singleId);
747
+ if (result && !Array.isArray(result)) {
748
+ removed.push(result);
749
+ }
750
+ }
751
+ return removed;
752
+ }
753
+ for (const [event, eventHandlers] of this._hooks.entries()) {
754
+ const index = eventHandlers.findIndex((h) => h.id === id);
755
+ if (index !== -1) {
756
+ const [removed] = eventHandlers.splice(index, 1);
757
+ if (eventHandlers.length === 0) {
758
+ this._hooks.delete(event);
759
+ }
760
+ return removed;
761
+ }
762
+ }
763
+ return void 0;
764
+ }
681
765
  /**
682
766
  * Removes all hooks
683
767
  * @returns {void}
@@ -685,10 +769,56 @@ var Hookified = class extends Eventified {
685
769
  clearHooks() {
686
770
  this._hooks.clear();
687
771
  }
772
+ /**
773
+ * Removes all hooks for a specific event and returns the removed hooks.
774
+ * @param {string} event - The event name to remove hooks for.
775
+ * @returns {IHook[]} the hooks that were removed
776
+ */
777
+ removeEventHooks(event) {
778
+ this.validateHookName(event);
779
+ const eventHandlers = this._hooks.get(event);
780
+ if (eventHandlers) {
781
+ const removed = [...eventHandlers];
782
+ this._hooks.delete(event);
783
+ return removed;
784
+ }
785
+ return [];
786
+ }
787
+ /**
788
+ * Validates hook event name if enforceBeforeAfter is enabled
789
+ * @param {string} event - The event name to validate
790
+ * @throws {Error} If enforceBeforeAfter is true and event doesn't start with 'before' or 'after'
791
+ */
792
+ validateHookName(event) {
793
+ if (this._enforceBeforeAfter) {
794
+ const eventValue = event.trim().toLocaleLowerCase();
795
+ if (!eventValue.startsWith("before") && !eventValue.startsWith("after")) {
796
+ throw new Error(
797
+ `Hook event "${event}" must start with "before" or "after" when enforceBeforeAfter is enabled`
798
+ );
799
+ }
800
+ }
801
+ }
802
+ /**
803
+ * Checks if a hook is deprecated and emits a warning if it is
804
+ * @param {string} event - The event name to check
805
+ * @returns {boolean} - Returns true if the hook should proceed, false if it should be blocked
806
+ */
807
+ checkDeprecatedHook(event) {
808
+ if (this._deprecatedHooks.has(event)) {
809
+ const message = this._deprecatedHooks.get(event);
810
+ const warningMessage = `Hook "${event}" is deprecated${message ? `: ${message}` : ""}`;
811
+ this.emit("warn", { hook: event, message: warningMessage });
812
+ return this._allowDeprecated;
813
+ }
814
+ return true;
815
+ }
688
816
  };
689
817
  export {
690
818
  Eventified,
691
- Hookified
819
+ Hook,
820
+ Hookified,
821
+ WaterfallHook
692
822
  };
693
823
  /* v8 ignore next -- @preserve */
694
824
  //# sourceMappingURL=index.js.map