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