@logosdx/hooks 1.0.0-beta.2 → 1.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.
@@ -209,21 +209,6 @@ function _non_iterable_rest() {
209
209
  function _non_iterable_spread() {
210
210
  throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
211
211
  }
212
- function _object_spread(target) {
213
- for(var i = 1; i < arguments.length; i++){
214
- var source = arguments[i] != null ? arguments[i] : {};
215
- var ownKeys = Object.keys(source);
216
- if (typeof Object.getOwnPropertySymbols === "function") {
217
- ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
218
- return Object.getOwnPropertyDescriptor(source, sym).enumerable;
219
- }));
220
- }
221
- ownKeys.forEach(function(key) {
222
- _define_property(target, key, source[key]);
223
- });
224
- }
225
- return target;
226
- }
227
212
  function _possible_constructor_return(self, call) {
228
213
  if (call && (_type_of(call) === "object" || typeof call === "function")) {
229
214
  return call;
@@ -398,17 +383,15 @@ import { assert, attempt, attemptSync, isFunction, isObject } from '@logosdx/uti
398
383
  /**
399
384
  * Error thrown when a hook calls `ctx.fail()`.
400
385
  *
401
- * This error is only created when using the default `handleFail` behavior.
386
+ * Only created when using the default `handleFail` behavior.
402
387
  * If a custom `handleFail` is provided, that error type is thrown instead.
403
388
  *
404
389
  * @example
405
- * hooks.on('validate', async (ctx) => {
406
- * if (!ctx.args[0].isValid) {
407
- * ctx.fail('Validation failed');
408
- * }
390
+ * hooks.add('validate', (data, ctx) => {
391
+ * if (!data.isValid) ctx.fail('Validation failed');
409
392
  * });
410
393
  *
411
- * const [, err] = await attempt(() => engine.emit('validate', data));
394
+ * const [, err] = await attempt(() => engine.run('validate', data));
412
395
  * if (isHookError(err)) {
413
396
  * console.log(err.hookName); // 'validate'
414
397
  * }
@@ -429,32 +412,408 @@ import { assert, attempt, attemptSync, isFunction, isObject } from '@logosdx/uti
429
412
  * Type guard to check if an error is a HookError.
430
413
  *
431
414
  * @example
432
- * const { error } = await engine.emit('validate', data);
433
- * if (isHookError(error)) {
434
- * console.log(`Hook "${error.hookName}" failed`);
415
+ * const [, err] = await attempt(() => engine.run('validate', data));
416
+ * if (isHookError(err)) {
417
+ * console.log(`Hook "${err.hookName}" failed`);
435
418
  * }
436
419
  */ export var isHookError = function(error) {
437
420
  var _error_constructor;
438
421
  return (error === null || error === void 0 ? void 0 : (_error_constructor = error.constructor) === null || _error_constructor === void 0 ? void 0 : _error_constructor.name) === HookError.name;
439
422
  };
440
- var _hooks = /*#__PURE__*/ new WeakMap(), _hookOpts = /*#__PURE__*/ new WeakMap(), _handleFail = /*#__PURE__*/ new WeakMap(), _registered = /*#__PURE__*/ new WeakMap(), /**
441
- * Validate that a hook is registered (if registration is enabled).
442
- */ _assertRegistered = /*#__PURE__*/ new WeakSet();
443
- export var HookEngine = /*#__PURE__*/ function() {
423
+ var _data = /*#__PURE__*/ new WeakMap();
424
+ /**
425
+ * Request-scoped state bag that flows across hook runs and engine instances.
426
+ *
427
+ * Use symbols for private plugin state and strings for shared cross-plugin contracts.
428
+ *
429
+ * @example
430
+ * // Private plugin state (symbol key)
431
+ * const CACHE_STATE = Symbol('cache');
432
+ * ctx.scope.set(CACHE_STATE, { key, rule });
433
+ *
434
+ * // Shared cross-plugin contract (string key)
435
+ * ctx.scope.set('serializedKey', key);
436
+ */ export var HookScope = /*#__PURE__*/ function() {
437
+ "use strict";
438
+ function HookScope() {
439
+ _class_call_check(this, HookScope);
440
+ _class_private_field_init(this, _data, {
441
+ writable: true,
442
+ value: new Map()
443
+ });
444
+ }
445
+ _create_class(HookScope, [
446
+ {
447
+ /**
448
+ * Get a value from the scope.
449
+ *
450
+ * @example
451
+ * const state = ctx.scope.get<CacheState>(CACHE_STATE);
452
+ */ key: "get",
453
+ value: function get(key) {
454
+ return _class_private_field_get(this, _data).get(key);
455
+ }
456
+ },
457
+ {
458
+ /**
459
+ * Set a value in the scope.
460
+ *
461
+ * @example
462
+ * ctx.scope.set(CACHE_STATE, { key: 'abc', rule });
463
+ */ key: "set",
464
+ value: function set(key, value) {
465
+ _class_private_field_get(this, _data).set(key, value);
466
+ }
467
+ },
468
+ {
469
+ /**
470
+ * Check if a key exists in the scope.
471
+ */ key: "has",
472
+ value: function has(key) {
473
+ return _class_private_field_get(this, _data).has(key);
474
+ }
475
+ },
476
+ {
477
+ /**
478
+ * Delete a key from the scope.
479
+ */ key: "delete",
480
+ value: function _delete(key) {
481
+ return _class_private_field_get(this, _data).delete(key);
482
+ }
483
+ }
484
+ ]);
485
+ return HookScope;
486
+ }();
487
+ var EARLY_RETURN = Symbol('early-return');
488
+ var _args = /*#__PURE__*/ new WeakMap(), _argsChanged = /*#__PURE__*/ new WeakMap(), _result = /*#__PURE__*/ new WeakMap(), _earlyReturn = /*#__PURE__*/ new WeakMap(), _handleFail = /*#__PURE__*/ new WeakMap(), _hookName = /*#__PURE__*/ new WeakMap(), _removeFn = /*#__PURE__*/ new WeakMap();
489
+ /**
490
+ * Context object passed as the last argument to hook callbacks.
491
+ * Provides methods to modify args, short-circuit, fail, or self-remove.
492
+ *
493
+ * @example
494
+ * // Replace args for downstream callbacks
495
+ * hooks.add('beforeRequest', (url, opts, ctx) => {
496
+ * ctx.args(url, { ...opts, cache: 'no-store' });
497
+ * });
498
+ *
499
+ * // Short-circuit: replace args AND stop the chain
500
+ * hooks.add('beforeRequest', (url, opts, ctx) => {
501
+ * return ctx.args(normalizedUrl, opts);
502
+ * });
503
+ *
504
+ * // Short-circuit with a result value
505
+ * hooks.add('beforeRequest', (url, opts, ctx) => {
506
+ * const cached = cache.get(url);
507
+ * if (cached) return ctx.returns(cached);
508
+ * });
509
+ */ export var HookContext = /*#__PURE__*/ function() {
510
+ "use strict";
511
+ function HookContext(handleFail, hookName, removeFn, scope) {
512
+ _class_call_check(this, HookContext);
513
+ _class_private_field_init(this, _args, {
514
+ writable: true,
515
+ value: void 0
516
+ });
517
+ _class_private_field_init(this, _argsChanged, {
518
+ writable: true,
519
+ value: false
520
+ });
521
+ _class_private_field_init(this, _result, {
522
+ writable: true,
523
+ value: void 0
524
+ });
525
+ _class_private_field_init(this, _earlyReturn, {
526
+ writable: true,
527
+ value: false
528
+ });
529
+ _class_private_field_init(this, _handleFail, {
530
+ writable: true,
531
+ value: void 0
532
+ });
533
+ _class_private_field_init(this, _hookName, {
534
+ writable: true,
535
+ value: void 0
536
+ });
537
+ _class_private_field_init(this, _removeFn, {
538
+ writable: true,
539
+ value: void 0
540
+ });
541
+ /**
542
+ * Request-scoped state bag shared across hook runs and engine instances.
543
+ *
544
+ * @example
545
+ * // In beforeRequest hook
546
+ * ctx.scope.set(CACHE_KEY, serializedKey);
547
+ *
548
+ * // In afterRequest hook (same scope)
549
+ * const key = ctx.scope.get<string>(CACHE_KEY);
550
+ */ _define_property(this, "scope", void 0);
551
+ _class_private_field_set(this, _handleFail, handleFail);
552
+ _class_private_field_set(this, _hookName, hookName);
553
+ _class_private_field_set(this, _removeFn, removeFn);
554
+ this.scope = scope;
555
+ }
556
+ _create_class(HookContext, [
557
+ {
558
+ /**
559
+ * Replace args for downstream callbacks.
560
+ * When used with `return`, also stops the chain.
561
+ *
562
+ * @example
563
+ * // Just replace args, continue chain
564
+ * ctx.args(newUrl, newOpts);
565
+ *
566
+ * // Replace args AND stop the chain
567
+ * return ctx.args(newUrl, newOpts);
568
+ */ key: "args",
569
+ value: function args() {
570
+ for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
571
+ args[_key] = arguments[_key];
572
+ }
573
+ _class_private_field_set(this, _args, args);
574
+ _class_private_field_set(this, _argsChanged, true);
575
+ return EARLY_RETURN;
576
+ }
577
+ },
578
+ {
579
+ /**
580
+ * Set a result value and stop the chain.
581
+ * Always used with `return`.
582
+ *
583
+ * @example
584
+ * return ctx.returns(cachedResponse);
585
+ */ key: "returns",
586
+ value: function returns(value) {
587
+ _class_private_field_set(this, _result, value);
588
+ _class_private_field_set(this, _earlyReturn, true);
589
+ return EARLY_RETURN;
590
+ }
591
+ },
592
+ {
593
+ /**
594
+ * Abort hook execution with an error.
595
+ * Uses the engine's `handleFail` to create the error.
596
+ *
597
+ * @example
598
+ * ctx.fail('Validation failed');
599
+ */ key: "fail",
600
+ value: function fail() {
601
+ for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
602
+ args[_key] = arguments[_key];
603
+ }
604
+ var _handler_prototype;
605
+ var handler = _class_private_field_get(this, _handleFail);
606
+ var isConstructor = typeof handler === 'function' && ((_handler_prototype = handler.prototype) === null || _handler_prototype === void 0 ? void 0 : _handler_prototype.constructor) === handler;
607
+ var _attemptSync = _sliced_to_array(attemptSync(function() {
608
+ if (isConstructor) {
609
+ throw _construct(handler, _to_consumable_array(args));
610
+ }
611
+ handler.apply(void 0, _to_consumable_array(args));
612
+ }), 2), error = _attemptSync[1];
613
+ if (error) {
614
+ if (_instanceof(error, HookError)) {
615
+ error.hookName = _class_private_field_get(this, _hookName);
616
+ }
617
+ throw error;
618
+ }
619
+ throw new HookError('ctx.fail() handler did not throw');
620
+ }
621
+ },
622
+ {
623
+ /**
624
+ * Remove this callback from future runs.
625
+ *
626
+ * @example
627
+ * hooks.add('init', (config, ctx) => {
628
+ * bootstrap(config);
629
+ * ctx.removeHook();
630
+ * });
631
+ */ key: "removeHook",
632
+ value: function removeHook() {
633
+ _class_private_field_get(this, _removeFn).call(this);
634
+ }
635
+ },
636
+ {
637
+ key: "_argsChanged",
638
+ get: /** @internal */ function get() {
639
+ return _class_private_field_get(this, _argsChanged);
640
+ }
641
+ },
642
+ {
643
+ key: "_newArgs",
644
+ get: /** @internal */ function get() {
645
+ return _class_private_field_get(this, _args);
646
+ }
647
+ },
648
+ {
649
+ key: "_result",
650
+ get: /** @internal */ function get() {
651
+ return _class_private_field_get(this, _result);
652
+ }
653
+ },
654
+ {
655
+ key: "_earlyReturn",
656
+ get: /** @internal */ function get() {
657
+ return _class_private_field_get(this, _earlyReturn);
658
+ }
659
+ }
660
+ ]);
661
+ return HookContext;
662
+ }();
663
+ var _handleFail1 = /*#__PURE__*/ new WeakMap(), _hookName1 = /*#__PURE__*/ new WeakMap(), _removeFn1 = /*#__PURE__*/ new WeakMap(), _setArgs = /*#__PURE__*/ new WeakMap();
664
+ /**
665
+ * Context object passed as the last argument to pipe middleware callbacks.
666
+ * Simpler than HookContext — no `returns()` needed since you control
667
+ * flow by calling or not calling `next()`.
668
+ *
669
+ * @example
670
+ * hooks.add('execute', async (next, opts, ctx) => {
671
+ * // Modify opts for inner layers
672
+ * ctx.args({ ...opts, headers: { ...opts.headers, Auth: token } });
673
+ *
674
+ * // Call next to continue the chain, or don't to short-circuit
675
+ * return next();
676
+ * });
677
+ */ export var PipeContext = /*#__PURE__*/ function() {
678
+ "use strict";
679
+ function PipeContext(handleFail, hookName, removeFn, scope, setArgs) {
680
+ _class_call_check(this, PipeContext);
681
+ _class_private_field_init(this, _handleFail1, {
682
+ writable: true,
683
+ value: void 0
684
+ });
685
+ _class_private_field_init(this, _hookName1, {
686
+ writable: true,
687
+ value: void 0
688
+ });
689
+ _class_private_field_init(this, _removeFn1, {
690
+ writable: true,
691
+ value: void 0
692
+ });
693
+ _class_private_field_init(this, _setArgs, {
694
+ writable: true,
695
+ value: void 0
696
+ });
697
+ /**
698
+ * Request-scoped state bag shared across hook runs and engine instances.
699
+ */ _define_property(this, "scope", void 0);
700
+ _class_private_field_set(this, _handleFail1, handleFail);
701
+ _class_private_field_set(this, _hookName1, hookName);
702
+ _class_private_field_set(this, _removeFn1, removeFn);
703
+ this.scope = scope;
704
+ _class_private_field_set(this, _setArgs, setArgs);
705
+ }
706
+ _create_class(PipeContext, [
707
+ {
708
+ /**
709
+ * Replace args for `next()` and downstream middleware.
710
+ *
711
+ * @example
712
+ * ctx.args({ ...opts, timeout: 5000 });
713
+ * return next(); // next receives modified opts
714
+ */ key: "args",
715
+ value: function args() {
716
+ for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
717
+ args[_key] = arguments[_key];
718
+ }
719
+ _class_private_field_get(this, _setArgs).call(this, args);
720
+ }
721
+ },
722
+ {
723
+ /**
724
+ * Abort execution with an error.
725
+ *
726
+ * @example
727
+ * ctx.fail('Rate limit exceeded');
728
+ */ key: "fail",
729
+ value: function fail() {
730
+ for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
731
+ args[_key] = arguments[_key];
732
+ }
733
+ var _handler_prototype;
734
+ var handler = _class_private_field_get(this, _handleFail1);
735
+ var isConstructor = typeof handler === 'function' && ((_handler_prototype = handler.prototype) === null || _handler_prototype === void 0 ? void 0 : _handler_prototype.constructor) === handler;
736
+ var _attemptSync = _sliced_to_array(attemptSync(function() {
737
+ if (isConstructor) {
738
+ throw _construct(handler, _to_consumable_array(args));
739
+ }
740
+ handler.apply(void 0, _to_consumable_array(args));
741
+ }), 2), error = _attemptSync[1];
742
+ if (error) {
743
+ if (_instanceof(error, HookError)) {
744
+ error.hookName = _class_private_field_get(this, _hookName1);
745
+ }
746
+ throw error;
747
+ }
748
+ throw new HookError('ctx.fail() handler did not throw');
749
+ }
750
+ },
751
+ {
752
+ /**
753
+ * Remove this middleware from future runs.
754
+ */ key: "removeHook",
755
+ value: function removeHook() {
756
+ _class_private_field_get(this, _removeFn1).call(this);
757
+ }
758
+ }
759
+ ]);
760
+ return PipeContext;
761
+ }();
762
+ var _hooks = /*#__PURE__*/ new WeakMap(), _handleFail2 = /*#__PURE__*/ new WeakMap(), _registered = /*#__PURE__*/ new WeakMap(), _callCounts = /*#__PURE__*/ new WeakMap(), /**
763
+ * Validate that a hook name is registered (when strict mode is active).
764
+ */ _assertRegistered = /*#__PURE__*/ new WeakSet(), /**
765
+ * Process a HookContext after a callback has run.
766
+ */ _processCtx = /*#__PURE__*/ new WeakSet(), /**
767
+ * Check times limit and increment counter. Returns true if exceeded.
768
+ */ _checkTimes = /*#__PURE__*/ new WeakSet(), /**
769
+ * Remove an entry from the hooks array.
770
+ */ _removeEntry = /*#__PURE__*/ new WeakSet(), /**
771
+ * Extract RunOptions from the args array if present.
772
+ */ _extractRunOptions = /*#__PURE__*/ new WeakSet();
773
+ /**
774
+ * A lightweight, type-safe lifecycle hook system.
775
+ *
776
+ * HookEngine allows you to define lifecycle events and subscribe to them.
777
+ * Callbacks receive spread arguments with a context object as the last param.
778
+ *
779
+ * @example
780
+ * interface FetchLifecycle {
781
+ * beforeRequest(url: string, options: RequestInit): Promise<Response>;
782
+ * afterRequest(response: Response, url: string): Promise<Response>;
783
+ * }
784
+ *
785
+ * const hooks = new HookEngine<FetchLifecycle>();
786
+ *
787
+ * hooks.add('beforeRequest', (url, opts, ctx) => {
788
+ * ctx.args(url, { ...opts, headers: { ...opts.headers, 'X-Token': token } });
789
+ * });
790
+ *
791
+ * hooks.add('beforeRequest', (url, opts, ctx) => {
792
+ * const cached = cache.get(url);
793
+ * if (cached) return ctx.returns(cached);
794
+ * });
795
+ *
796
+ * const pre = await hooks.run('beforeRequest', url, options);
797
+ * if (pre.returned) return pre.result;
798
+ * const response = await fetch(...pre.args);
799
+ *
800
+ * @typeParam Lifecycle - Interface defining the lifecycle hooks
801
+ * @typeParam FailArgs - Arguments type for ctx.fail() (default: [string])
802
+ */ export var HookEngine = /*#__PURE__*/ function() {
444
803
  "use strict";
445
804
  function HookEngine() {
446
805
  var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
447
806
  _class_call_check(this, HookEngine);
448
807
  _class_private_method_init(this, _assertRegistered);
808
+ _class_private_method_init(this, _processCtx);
809
+ _class_private_method_init(this, _checkTimes);
810
+ _class_private_method_init(this, _removeEntry);
811
+ _class_private_method_init(this, _extractRunOptions);
449
812
  _class_private_field_init(this, _hooks, {
450
813
  writable: true,
451
814
  value: new Map()
452
815
  });
453
- _class_private_field_init(this, _hookOpts, {
454
- writable: true,
455
- value: new WeakMap()
456
- });
457
- _class_private_field_init(this, _handleFail, {
816
+ _class_private_field_init(this, _handleFail2, {
458
817
  writable: true,
459
818
  value: void 0
460
819
  });
@@ -462,8 +821,12 @@ export var HookEngine = /*#__PURE__*/ function() {
462
821
  writable: true,
463
822
  value: null
464
823
  });
824
+ _class_private_field_init(this, _callCounts, {
825
+ writable: true,
826
+ value: new WeakMap()
827
+ });
465
828
  var _options_handleFail;
466
- _class_private_field_set(this, _handleFail, (_options_handleFail = options.handleFail) !== null && _options_handleFail !== void 0 ? _options_handleFail : function(message) {
829
+ _class_private_field_set(this, _handleFail2, (_options_handleFail = options.handleFail) !== null && _options_handleFail !== void 0 ? _options_handleFail : function(message) {
467
830
  throw new HookError(message);
468
831
  });
469
832
  }
@@ -478,10 +841,10 @@ export var HookEngine = /*#__PURE__*/ function() {
478
841
  *
479
842
  * @example
480
843
  * const hooks = new HookEngine<FetchLifecycle>()
481
- * .register('preRequest', 'postRequest', 'rateLimit');
844
+ * .register('beforeRequest', 'afterRequest');
482
845
  *
483
- * hooks.on('preRequest', cb); // OK
484
- * hooks.on('preRequset', cb); // Error: not registered (typo caught!)
846
+ * hooks.add('beforeRequest', cb); // OK
847
+ * hooks.add('beforeRequset', cb); // Error: not registered (typo caught!)
485
848
  */ key: "register",
486
849
  value: function register() {
487
850
  for(var _len = arguments.length, names = new Array(_len), _key = 0; _key < _len; _key++){
@@ -520,142 +883,102 @@ export var HookEngine = /*#__PURE__*/ function() {
520
883
  * Subscribe to a lifecycle hook.
521
884
  *
522
885
  * @param name - Name of the lifecycle hook
523
- * @param cbOrOpts - Callback function or options object
886
+ * @param callback - Callback function receiving spread args + ctx
887
+ * @param options - Options for this subscription
524
888
  * @returns Cleanup function to remove the subscription
525
889
  *
526
890
  * @example
527
891
  * // Simple callback
528
- * const cleanup = hooks.on('preRequest', async (ctx) => {
529
- * console.log('Request:', ctx.args[0]);
892
+ * const cleanup = hooks.add('beforeRequest', (url, opts, ctx) => {
893
+ * console.log('Request:', url);
530
894
  * });
531
895
  *
532
896
  * // With options
533
- * hooks.on('analytics', {
534
- * callback: async (ctx) => { track(ctx.args); },
535
- * once: true, // Remove after first run
536
- * ignoreOnFail: true // Don't throw if callback fails
537
- * });
897
+ * hooks.add('analytics', (event, ctx) => {
898
+ * track(event);
899
+ * }, { once: true, ignoreOnFail: true });
900
+ *
901
+ * // With priority (lower runs first)
902
+ * hooks.add('beforeRequest', cb, { priority: -10 });
538
903
  *
539
904
  * // Remove subscription
540
905
  * cleanup();
541
- */ key: "on",
542
- value: function on(name, cbOrOpts) {
543
- var callback = typeof cbOrOpts === 'function' ? cbOrOpts : cbOrOpts === null || cbOrOpts === void 0 ? void 0 : cbOrOpts.callback;
544
- var opts = typeof cbOrOpts === 'function' ? {} : cbOrOpts;
906
+ */ key: "add",
907
+ value: function add(name, callback) {
908
+ var _this = this;
909
+ var options = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : {};
545
910
  assert(typeof name === 'string', '"name" must be a string');
546
- assert(isFunction(callback) || isObject(cbOrOpts), '"cbOrOpts" must be a callback or options');
547
- assert(isFunction(callback), 'callback must be a function');
548
- _class_private_method_get(this, _assertRegistered, assertRegistered).call(this, name, 'on');
911
+ assert(isFunction(callback), '"callback" must be a function');
912
+ _class_private_method_get(this, _assertRegistered, assertRegistered).call(this, name, 'add');
913
+ var _options_priority;
914
+ var priority = (_options_priority = options.priority) !== null && _options_priority !== void 0 ? _options_priority : 0;
915
+ var entry = {
916
+ callback: callback,
917
+ options: options,
918
+ priority: priority
919
+ };
549
920
  var _class_private_field_get_get;
550
- var hooks = (_class_private_field_get_get = _class_private_field_get(this, _hooks).get(name)) !== null && _class_private_field_get_get !== void 0 ? _class_private_field_get_get : new Set();
551
- hooks.add(callback);
921
+ var hooks = (_class_private_field_get_get = _class_private_field_get(this, _hooks).get(name)) !== null && _class_private_field_get_get !== void 0 ? _class_private_field_get_get : [];
922
+ var inserted = false;
923
+ for(var i = 0; i < hooks.length; i++){
924
+ if (hooks[i].priority > priority) {
925
+ hooks.splice(i, 0, entry);
926
+ inserted = true;
927
+ break;
928
+ }
929
+ }
930
+ if (!inserted) {
931
+ hooks.push(entry);
932
+ }
552
933
  _class_private_field_get(this, _hooks).set(name, hooks);
553
- _class_private_field_get(this, _hookOpts).set(callback, opts);
554
934
  return function() {
555
- hooks.delete(callback);
935
+ var arr = _class_private_field_get(_this, _hooks).get(name);
936
+ if (arr) {
937
+ var idx = arr.indexOf(entry);
938
+ if (idx !== -1) {
939
+ arr.splice(idx, 1);
940
+ }
941
+ }
556
942
  };
557
943
  }
558
944
  },
559
945
  {
560
- /**
561
- * Subscribe to a lifecycle hook that fires only once.
562
- * Sugar for `on(name, { callback, once: true })`.
563
- *
564
- * @param name - Name of the lifecycle hook
565
- * @param callback - Callback function
566
- * @returns Cleanup function to remove the subscription
567
- *
568
- * @example
569
- * // Log only the first request
570
- * hooks.once('preRequest', async (ctx) => {
571
- * console.log('First request:', ctx.args[0]);
572
- * });
573
- */ key: "once",
574
- value: function once(name, callback) {
575
- return this.on(name, {
576
- callback: callback,
577
- once: true
578
- });
579
- }
580
- },
581
- {
582
- key: "emit",
946
+ key: "run",
583
947
  value: /**
584
- * Emit a lifecycle hook, running all subscribed callbacks.
948
+ * Run all callbacks for a hook asynchronously.
585
949
  *
586
- * @param name - Name of the lifecycle hook to emit
587
- * @param args - Arguments to pass to callbacks
588
- * @returns EmitResult with final args, result, and earlyReturn flag
950
+ * @param name - Name of the lifecycle hook to run
951
+ * @param args - Arguments to pass to callbacks (spread + ctx)
952
+ * @returns RunResult with final args, result, and returned flag
589
953
  *
590
954
  * @example
591
- * const result = await hooks.emit('cacheCheck', url);
592
- *
593
- * if (result.earlyReturn && result.result) {
594
- * return result.result; // Use cached value
595
- * }
596
- *
597
- * // Continue with modified args
598
- * const [modifiedUrl] = result.args;
599
- */ function emit(name) {
955
+ * const pre = await hooks.run('beforeRequest', url, options);
956
+ * if (pre.returned) return pre.result;
957
+ * const response = await fetch(...pre.args);
958
+ */ function run(name) {
600
959
  for(var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++){
601
960
  args[_key - 1] = arguments[_key];
602
961
  }
603
962
  return _async_to_generator(function() {
604
- var _this, earlyReturn, hooks, context, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _this1, _loop, _iterator, _step, _ret, err;
963
+ var _this, _class_private_method_get_call, realArgs, runOptions, currentArgs, _runOptions_scope, scope, hooks, entries, result, returned, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _this1, _loop, _iterator, _step, _ret, err;
605
964
  return _ts_generator(this, function(_state) {
606
965
  switch(_state.label){
607
966
  case 0:
608
967
  _this = this;
609
- _class_private_method_get(this, _assertRegistered, assertRegistered).call(this, name, 'emit');
610
- earlyReturn = false;
968
+ _class_private_method_get(this, _assertRegistered, assertRegistered).call(this, name, 'run');
969
+ _class_private_method_get_call = _class_private_method_get(this, _extractRunOptions, extractRunOptions).call(this, args), realArgs = _class_private_method_get_call.realArgs, runOptions = _class_private_method_get_call.runOptions;
970
+ currentArgs = realArgs;
971
+ scope = (_runOptions_scope = runOptions === null || runOptions === void 0 ? void 0 : runOptions.scope) !== null && _runOptions_scope !== void 0 ? _runOptions_scope : new HookScope();
611
972
  hooks = _class_private_field_get(this, _hooks).get(name);
612
- context = {
613
- args: args,
614
- removeHook: function removeHook() {},
615
- returnEarly: function returnEarly() {
616
- earlyReturn = true;
617
- },
618
- setArgs: function(next) {
619
- assert(Array.isArray(next), "setArgs: args for '".concat(String(name), "' must be an array"));
620
- context.args = next;
621
- },
622
- setResult: function(next) {
623
- context.result = next;
624
- },
625
- fail: function() {
626
- for(var _len = arguments.length, failArgs = new Array(_len), _key = 0; _key < _len; _key++){
627
- failArgs[_key] = arguments[_key];
628
- }
629
- var _handler_prototype;
630
- var handler = _class_private_field_get(_this, _handleFail);
631
- // Check if handler is a constructor (class or function with prototype)
632
- var isConstructor = typeof handler === 'function' && ((_handler_prototype = handler.prototype) === null || _handler_prototype === void 0 ? void 0 : _handler_prototype.constructor) === handler;
633
- var _attemptSync = _sliced_to_array(attemptSync(function() {
634
- if (isConstructor) {
635
- throw _construct(handler, _to_consumable_array(failArgs));
636
- }
637
- handler.apply(void 0, _to_consumable_array(failArgs));
638
- }), 2), error = _attemptSync[1];
639
- if (error) {
640
- if (_instanceof(error, HookError)) {
641
- error.hookName = String(name);
642
- }
643
- throw error;
644
- }
645
- // If handler didn't throw, we need to throw something
646
- throw new HookError('ctx.fail() handler did not throw');
647
- }
648
- };
649
- if (!hooks || hooks.size === 0) {
650
- return [
651
- 2,
652
- {
653
- args: context.args,
654
- result: context.result,
655
- earlyReturn: false
656
- }
657
- ];
973
+ entries = hooks ? _to_consumable_array(hooks) : [];
974
+ if (runOptions === null || runOptions === void 0 ? void 0 : runOptions.append) {
975
+ entries.push({
976
+ callback: runOptions.append,
977
+ options: {},
978
+ priority: Infinity
979
+ });
658
980
  }
981
+ returned = false;
659
982
  _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
660
983
  _state.label = 1;
661
984
  case 1:
@@ -666,21 +989,57 @@ export var HookEngine = /*#__PURE__*/ function() {
666
989
  8
667
990
  ]);
668
991
  _loop = function() {
669
- var fn, _class_private_field_get_get, opts, _ref, _$err;
992
+ var entry, callback, opts, timesExceeded, removeFn, ctx, _ref, _$err, signal;
670
993
  return _ts_generator(this, function(_state) {
671
994
  switch(_state.label){
672
995
  case 0:
673
- fn = _step.value;
674
- context.removeHook = function() {
675
- return hooks.delete(fn);
676
- };
677
- opts = (_class_private_field_get_get = _class_private_field_get(_this1, _hookOpts).get(fn)) !== null && _class_private_field_get_get !== void 0 ? _class_private_field_get_get : {
678
- callback: fn
996
+ entry = _step.value;
997
+ callback = entry.callback, opts = entry.options;
998
+ timesExceeded = _class_private_method_get(_this1, _checkTimes, checkTimes).call(_this1, callback, opts);
999
+ if (timesExceeded) {
1000
+ _class_private_method_get(_this1, _removeEntry, removeEntry).call(_this1, name, entry);
1001
+ return [
1002
+ 2,
1003
+ "continue"
1004
+ ];
1005
+ }
1006
+ removeFn = function() {
1007
+ return _class_private_method_get(_this, _removeEntry, removeEntry).call(_this, name, entry);
679
1008
  };
1009
+ ctx = new HookContext(_class_private_field_get(_this1, _handleFail2), String(name), removeFn, scope);
1010
+ if (!opts.ignoreOnFail) return [
1011
+ 3,
1012
+ 2
1013
+ ];
680
1014
  return [
681
1015
  4,
682
1016
  attempt(function() {
683
- return fn(_object_spread({}, context));
1017
+ return _async_to_generator(function() {
1018
+ var signal;
1019
+ return _ts_generator(this, function(_state) {
1020
+ switch(_state.label){
1021
+ case 0:
1022
+ return [
1023
+ 4,
1024
+ callback.apply(void 0, _to_consumable_array(currentArgs).concat([
1025
+ ctx
1026
+ ]))
1027
+ ];
1028
+ case 1:
1029
+ signal = _state.sent();
1030
+ _class_private_method_get(this, _processCtx, processCtx).call(this, ctx, signal, function(a) {
1031
+ currentArgs = a;
1032
+ }, function(r) {
1033
+ result = r;
1034
+ }, function() {
1035
+ returned = true;
1036
+ });
1037
+ return [
1038
+ 2
1039
+ ];
1040
+ }
1041
+ });
1042
+ }).call(_this);
684
1043
  })
685
1044
  ];
686
1045
  case 1:
@@ -688,11 +1047,33 @@ export var HookEngine = /*#__PURE__*/ function() {
688
1047
  _state.sent(),
689
1048
  2
690
1049
  ]), _$err = _ref[1];
691
- if (opts.once) context.removeHook();
692
- if (_$err && opts.ignoreOnFail !== true) {
693
- throw _$err;
694
- }
695
- if (earlyReturn) return [
1050
+ if (!_$err && opts.once) removeFn();
1051
+ if (returned) return [
1052
+ 2,
1053
+ "break"
1054
+ ];
1055
+ return [
1056
+ 2,
1057
+ "continue"
1058
+ ];
1059
+ case 2:
1060
+ return [
1061
+ 4,
1062
+ callback.apply(void 0, _to_consumable_array(currentArgs).concat([
1063
+ ctx
1064
+ ]))
1065
+ ];
1066
+ case 3:
1067
+ signal = _state.sent();
1068
+ _class_private_method_get(_this1, _processCtx, processCtx).call(_this1, ctx, signal, function(a) {
1069
+ currentArgs = a;
1070
+ }, function(r) {
1071
+ result = r;
1072
+ }, function() {
1073
+ returned = true;
1074
+ });
1075
+ if (opts.once) removeFn();
1076
+ if (returned) return [
696
1077
  2,
697
1078
  "break"
698
1079
  ];
@@ -702,7 +1083,7 @@ export var HookEngine = /*#__PURE__*/ function() {
702
1083
  }
703
1084
  });
704
1085
  };
705
- _iterator = hooks[Symbol.iterator]();
1086
+ _iterator = entries[Symbol.iterator]();
706
1087
  _state.label = 2;
707
1088
  case 2:
708
1089
  if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
@@ -757,9 +1138,10 @@ export var HookEngine = /*#__PURE__*/ function() {
757
1138
  return [
758
1139
  2,
759
1140
  {
760
- args: context.args,
761
- result: context.result,
762
- earlyReturn: earlyReturn
1141
+ args: currentArgs,
1142
+ result: result,
1143
+ returned: returned,
1144
+ scope: scope
763
1145
  }
764
1146
  ];
765
1147
  }
@@ -769,59 +1151,122 @@ export var HookEngine = /*#__PURE__*/ function() {
769
1151
  },
770
1152
  {
771
1153
  /**
772
- * Clear all registered hooks.
1154
+ * Run all callbacks for a hook synchronously.
773
1155
  *
774
- * @example
775
- * hooks.on('preRequest', validator);
776
- * hooks.on('postRequest', logger);
1156
+ * @param name - Name of the lifecycle hook to run
1157
+ * @param args - Arguments to pass to callbacks (spread + ctx)
1158
+ * @returns RunResult with final args, result, and returned flag
777
1159
  *
778
- * // Reset for testing
779
- * hooks.clear();
780
- */ key: "clear",
781
- value: function clear() {
782
- _class_private_field_get(this, _hooks).clear();
783
- _class_private_field_set(this, _hookOpts, new WeakMap());
784
- _class_private_field_set(this, _registered, null);
1160
+ * @example
1161
+ * const pre = hooks.runSync('beforeValidation', data);
1162
+ * if (pre.returned) return pre.result;
1163
+ */ key: "runSync",
1164
+ value: function runSync(name) {
1165
+ var _this = this;
1166
+ for(var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++){
1167
+ args[_key - 1] = arguments[_key];
1168
+ }
1169
+ _class_private_method_get(this, _assertRegistered, assertRegistered).call(this, name, 'runSync');
1170
+ var _class_private_method_get_call = _class_private_method_get(this, _extractRunOptions, extractRunOptions).call(this, args), realArgs = _class_private_method_get_call.realArgs, runOptions = _class_private_method_get_call.runOptions;
1171
+ var currentArgs = realArgs;
1172
+ var _runOptions_scope;
1173
+ var scope = (_runOptions_scope = runOptions === null || runOptions === void 0 ? void 0 : runOptions.scope) !== null && _runOptions_scope !== void 0 ? _runOptions_scope : new HookScope();
1174
+ var hooks = _class_private_field_get(this, _hooks).get(name);
1175
+ var entries = hooks ? _to_consumable_array(hooks) : [];
1176
+ if (runOptions === null || runOptions === void 0 ? void 0 : runOptions.append) {
1177
+ entries.push({
1178
+ callback: runOptions.append,
1179
+ options: {},
1180
+ priority: Infinity
1181
+ });
1182
+ }
1183
+ var result;
1184
+ var returned = false;
1185
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1186
+ try {
1187
+ var _this1, _loop = function() {
1188
+ var entry = _step.value;
1189
+ var callback = entry.callback, opts = entry.options;
1190
+ var timesExceeded = _class_private_method_get(_this1, _checkTimes, checkTimes).call(_this1, callback, opts);
1191
+ if (timesExceeded) {
1192
+ _class_private_method_get(_this1, _removeEntry, removeEntry).call(_this1, name, entry);
1193
+ return "continue";
1194
+ }
1195
+ var removeFn = function() {
1196
+ return _class_private_method_get(_this, _removeEntry, removeEntry).call(_this, name, entry);
1197
+ };
1198
+ var ctx = new HookContext(_class_private_field_get(_this1, _handleFail2), String(name), removeFn, scope);
1199
+ if (opts.ignoreOnFail) {
1200
+ var _attemptSync = _sliced_to_array(attemptSync(function() {
1201
+ var signal = callback.apply(void 0, _to_consumable_array(currentArgs).concat([
1202
+ ctx
1203
+ ]));
1204
+ _class_private_method_get(_this, _processCtx, processCtx).call(_this, ctx, signal, function(a) {
1205
+ currentArgs = a;
1206
+ }, function(r) {
1207
+ result = r;
1208
+ }, function() {
1209
+ returned = true;
1210
+ });
1211
+ }), 2), _$err = _attemptSync[1];
1212
+ if (!_$err && opts.once) removeFn();
1213
+ if (returned) return "break";
1214
+ return "continue";
1215
+ }
1216
+ var signal = callback.apply(void 0, _to_consumable_array(currentArgs).concat([
1217
+ ctx
1218
+ ]));
1219
+ _class_private_method_get(_this1, _processCtx, processCtx).call(_this1, ctx, signal, function(a) {
1220
+ currentArgs = a;
1221
+ }, function(r) {
1222
+ result = r;
1223
+ }, function() {
1224
+ returned = true;
1225
+ });
1226
+ if (opts.once) removeFn();
1227
+ if (returned) return "break";
1228
+ };
1229
+ for(var _iterator = entries[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1230
+ var _ret = (_this1 = this, _loop());
1231
+ if (_ret === "break") break;
1232
+ }
1233
+ } catch (err) {
1234
+ _didIteratorError = true;
1235
+ _iteratorError = err;
1236
+ } finally{
1237
+ try {
1238
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1239
+ _iterator.return();
1240
+ }
1241
+ } finally{
1242
+ if (_didIteratorError) {
1243
+ throw _iteratorError;
1244
+ }
1245
+ }
1246
+ }
1247
+ return {
1248
+ args: currentArgs,
1249
+ result: result,
1250
+ returned: returned,
1251
+ scope: scope
1252
+ };
785
1253
  }
786
1254
  },
787
1255
  {
788
1256
  /**
789
- * Wrap a function with pre/post lifecycle hooks.
1257
+ * Wrap an async function with pre/post lifecycle hooks.
790
1258
  *
791
- * - Pre hook: emitted with function args, can modify args or returnEarly with result
792
- * - Post hook: emitted with [result, ...args], can modify result
1259
+ * - Pre hook: called with function args, can modify args or return early
1260
+ * - Post hook: called with `(result, ...originalArgs)`, can transform result
793
1261
  *
794
1262
  * @param fn - The async function to wrap
795
1263
  * @param hooks - Object with optional pre and post hook names
796
1264
  * @returns Wrapped function with same signature
797
1265
  *
798
1266
  * @example
799
- * interface Lifecycle {
800
- * preRequest(url: string, opts: RequestInit): Promise<Response>;
801
- * postRequest(result: Response, url: string, opts: RequestInit): Promise<Response>;
802
- * }
803
- *
804
- * const hooks = new HookEngine<Lifecycle>();
805
- *
806
- * // Add cache check in pre hook
807
- * hooks.on('preRequest', async (ctx) => {
808
- * const cached = cache.get(ctx.args[0]);
809
- * if (cached) {
810
- * ctx.setResult(cached);
811
- * ctx.returnEarly();
812
- * }
813
- * });
814
- *
815
- * // Log result in post hook
816
- * hooks.on('postRequest', async (ctx) => {
817
- * const [result, url] = ctx.args;
818
- * console.log(`Fetched ${url}:`, result.status);
819
- * });
820
- *
821
- * // Wrap the fetch function
822
1267
  * const wrappedFetch = hooks.wrap(
823
1268
  * async (url: string, opts: RequestInit) => fetch(url, opts),
824
- * { pre: 'preRequest', post: 'postRequest' }
1269
+ * { pre: 'beforeRequest', post: 'afterRequest' }
825
1270
  * );
826
1271
  */ key: "wrap",
827
1272
  value: function wrap(fn, hooks) {
@@ -834,7 +1279,7 @@ export var HookEngine = /*#__PURE__*/ function() {
834
1279
  args[_key] = arguments[_key];
835
1280
  }
836
1281
  return _async_to_generator(function() {
837
- var currentArgs, result, preResult, postResult;
1282
+ var currentArgs, preResult, result, postResult;
838
1283
  return _ts_generator(this, function(_state) {
839
1284
  switch(_state.label){
840
1285
  case 0:
@@ -845,14 +1290,14 @@ export var HookEngine = /*#__PURE__*/ function() {
845
1290
  ];
846
1291
  return [
847
1292
  4,
848
- this.emit.apply(this, [
1293
+ this.run.apply(this, [
849
1294
  hooks.pre
850
1295
  ].concat(_to_consumable_array(currentArgs)))
851
1296
  ];
852
1297
  case 1:
853
1298
  preResult = _state.sent();
854
1299
  currentArgs = preResult.args;
855
- if (preResult.earlyReturn && preResult.result !== undefined) {
1300
+ if (preResult.returned && preResult.result !== undefined) {
856
1301
  return [
857
1302
  2,
858
1303
  preResult.result
@@ -865,7 +1310,6 @@ export var HookEngine = /*#__PURE__*/ function() {
865
1310
  fn.apply(void 0, _to_consumable_array(currentArgs))
866
1311
  ];
867
1312
  case 3:
868
- // Execute function
869
1313
  result = _state.sent();
870
1314
  if (!hooks.post) return [
871
1315
  3,
@@ -873,7 +1317,7 @@ export var HookEngine = /*#__PURE__*/ function() {
873
1317
  ];
874
1318
  return [
875
1319
  4,
876
- this.emit.apply(this, [
1320
+ this.run.apply(this, [
877
1321
  hooks.post
878
1322
  ].concat(_to_consumable_array([
879
1323
  result
@@ -881,7 +1325,7 @@ export var HookEngine = /*#__PURE__*/ function() {
881
1325
  ];
882
1326
  case 4:
883
1327
  postResult = _state.sent();
884
- if (postResult.result !== undefined) {
1328
+ if (postResult.returned) {
885
1329
  return [
886
1330
  2,
887
1331
  postResult.result
@@ -898,6 +1342,294 @@ export var HookEngine = /*#__PURE__*/ function() {
898
1342
  }).call(_this);
899
1343
  };
900
1344
  }
1345
+ },
1346
+ {
1347
+ /**
1348
+ * Wrap a synchronous function with pre/post lifecycle hooks.
1349
+ *
1350
+ * @param fn - The sync function to wrap
1351
+ * @param hooks - Object with optional pre and post hook names
1352
+ * @returns Wrapped function with same signature
1353
+ *
1354
+ * @example
1355
+ * const wrappedValidate = hooks.wrapSync(
1356
+ * (data: UserData) => validate(data),
1357
+ * { pre: 'beforeValidate' }
1358
+ * );
1359
+ */ key: "wrapSync",
1360
+ value: function wrapSync(fn, hooks) {
1361
+ var _this = this;
1362
+ assert(hooks.pre || hooks.post, 'wrapSync() requires at least one of "pre" or "post" hooks');
1363
+ if (hooks.pre) _class_private_method_get(this, _assertRegistered, assertRegistered).call(this, hooks.pre, 'wrapSync');
1364
+ if (hooks.post) _class_private_method_get(this, _assertRegistered, assertRegistered).call(this, hooks.post, 'wrapSync');
1365
+ return function() {
1366
+ for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
1367
+ args[_key] = arguments[_key];
1368
+ }
1369
+ var currentArgs = args;
1370
+ if (hooks.pre) {
1371
+ var preResult = _this.runSync.apply(_this, [
1372
+ hooks.pre
1373
+ ].concat(_to_consumable_array(currentArgs)));
1374
+ currentArgs = preResult.args;
1375
+ if (preResult.returned && preResult.result !== undefined) {
1376
+ return preResult.result;
1377
+ }
1378
+ }
1379
+ var result = fn.apply(void 0, _to_consumable_array(currentArgs));
1380
+ if (hooks.post) {
1381
+ var postResult = _this.runSync.apply(_this, [
1382
+ hooks.post
1383
+ ].concat(_to_consumable_array([
1384
+ result
1385
+ ].concat(_to_consumable_array(currentArgs)))));
1386
+ if (postResult.returned) {
1387
+ return postResult.result;
1388
+ }
1389
+ }
1390
+ return result;
1391
+ };
1392
+ }
1393
+ },
1394
+ {
1395
+ key: "pipe",
1396
+ value: /**
1397
+ * Execute middleware hooks as an onion (nested) composition.
1398
+ *
1399
+ * Unlike `run()` which executes hooks linearly, `pipe()` composes hooks
1400
+ * as nested middleware. Each hook receives a `next` function that calls
1401
+ * the next layer. The innermost layer is `coreFn`. Control flow is
1402
+ * managed by calling or not calling `next()` — no `ctx.returns()` needed.
1403
+ *
1404
+ * Hooks execute in priority order (lower first = outermost layer).
1405
+ *
1406
+ * @param name - Name of the lifecycle hook
1407
+ * @param coreFn - The innermost function to wrap
1408
+ * @param args - Arguments passed to each middleware
1409
+ * @returns The result from the middleware chain
1410
+ *
1411
+ * @example
1412
+ * // Retry plugin wraps the fetch call
1413
+ * hooks.add('execute', async (next, opts, ctx) => {
1414
+ * for (let i = 0; i < 3; i++) {
1415
+ * const [result, err] = await attempt(next);
1416
+ * if (!err) return result;
1417
+ * await wait(1000 * i);
1418
+ * }
1419
+ * throw lastError;
1420
+ * }, { priority: -20 });
1421
+ *
1422
+ * // Dedupe plugin wraps retry
1423
+ * hooks.add('execute', async (next, opts, ctx) => {
1424
+ * const inflight = getInflight(key);
1425
+ * if (inflight) return inflight;
1426
+ * const result = await next();
1427
+ * share(result);
1428
+ * return result;
1429
+ * }, { priority: -30 });
1430
+ *
1431
+ * // Execute: dedupe( retry( makeCall() ) )
1432
+ * const response = await hooks.pipe(
1433
+ * 'execute',
1434
+ * () => makeCall(opts),
1435
+ * opts
1436
+ * );
1437
+ */ function pipe(name, coreFn) {
1438
+ for(var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++){
1439
+ args[_key - 2] = arguments[_key];
1440
+ }
1441
+ return _async_to_generator(function() {
1442
+ var _this, _class_private_method_get_call, realArgs, runOptions, _runOptions_scope, scope, hooks, entries, currentArgs, buildChain;
1443
+ return _ts_generator(this, function(_state) {
1444
+ _this = this;
1445
+ _class_private_method_get(this, _assertRegistered, assertRegistered).call(this, name, 'pipe');
1446
+ _class_private_method_get_call = _class_private_method_get(this, _extractRunOptions, extractRunOptions).call(this, args), realArgs = _class_private_method_get_call.realArgs, runOptions = _class_private_method_get_call.runOptions;
1447
+ scope = (_runOptions_scope = runOptions === null || runOptions === void 0 ? void 0 : runOptions.scope) !== null && _runOptions_scope !== void 0 ? _runOptions_scope : new HookScope();
1448
+ hooks = _class_private_field_get(this, _hooks).get(name);
1449
+ entries = hooks ? _to_consumable_array(hooks) : [];
1450
+ if (runOptions === null || runOptions === void 0 ? void 0 : runOptions.append) {
1451
+ entries.push({
1452
+ callback: runOptions.append,
1453
+ options: {},
1454
+ priority: Infinity
1455
+ });
1456
+ }
1457
+ currentArgs = realArgs;
1458
+ buildChain = function(index) {
1459
+ if (index >= entries.length) return coreFn;
1460
+ return function() {
1461
+ return _async_to_generator(function() {
1462
+ var _this, entry, callback, opts, timesExceeded, removeFn, ctx, next, cb, _ref, result, err, result1;
1463
+ return _ts_generator(this, function(_state) {
1464
+ switch(_state.label){
1465
+ case 0:
1466
+ _this = this;
1467
+ entry = entries[index];
1468
+ callback = entry.callback, opts = entry.options;
1469
+ timesExceeded = _class_private_method_get(this, _checkTimes, checkTimes).call(this, callback, opts);
1470
+ if (timesExceeded) {
1471
+ _class_private_method_get(this, _removeEntry, removeEntry).call(this, name, entry);
1472
+ return [
1473
+ 2,
1474
+ buildChain(index + 1)()
1475
+ ];
1476
+ }
1477
+ removeFn = function() {
1478
+ return _class_private_method_get(_this, _removeEntry, removeEntry).call(_this, name, entry);
1479
+ };
1480
+ ctx = new PipeContext(_class_private_field_get(this, _handleFail2), String(name), removeFn, scope, function(newArgs) {
1481
+ currentArgs = newArgs;
1482
+ });
1483
+ next = buildChain(index + 1);
1484
+ cb = callback;
1485
+ if (!opts.ignoreOnFail) return [
1486
+ 3,
1487
+ 2
1488
+ ];
1489
+ return [
1490
+ 4,
1491
+ attempt(function() {
1492
+ return _async_to_generator(function() {
1493
+ return _ts_generator(this, function(_state) {
1494
+ return [
1495
+ 2,
1496
+ cb.apply(void 0, [
1497
+ next
1498
+ ].concat(_to_consumable_array(currentArgs), [
1499
+ ctx
1500
+ ]))
1501
+ ];
1502
+ });
1503
+ })();
1504
+ })
1505
+ ];
1506
+ case 1:
1507
+ _ref = _sliced_to_array.apply(void 0, [
1508
+ _state.sent(),
1509
+ 2
1510
+ ]), result = _ref[0], err = _ref[1];
1511
+ if (opts.once) removeFn();
1512
+ if (err) return [
1513
+ 2,
1514
+ next()
1515
+ ];
1516
+ return [
1517
+ 2,
1518
+ result
1519
+ ];
1520
+ case 2:
1521
+ return [
1522
+ 4,
1523
+ cb.apply(void 0, [
1524
+ next
1525
+ ].concat(_to_consumable_array(currentArgs), [
1526
+ ctx
1527
+ ]))
1528
+ ];
1529
+ case 3:
1530
+ result1 = _state.sent();
1531
+ if (opts.once) removeFn();
1532
+ return [
1533
+ 2,
1534
+ result1
1535
+ ];
1536
+ }
1537
+ });
1538
+ }).call(_this);
1539
+ };
1540
+ };
1541
+ return [
1542
+ 2,
1543
+ buildChain(0)()
1544
+ ];
1545
+ });
1546
+ }).call(this);
1547
+ }
1548
+ },
1549
+ {
1550
+ /**
1551
+ * Synchronous version of `pipe()`.
1552
+ *
1553
+ * @param name - Name of the lifecycle hook
1554
+ * @param coreFn - The innermost function to wrap
1555
+ * @param args - Arguments passed to each middleware
1556
+ * @returns The result from the middleware chain
1557
+ */ key: "pipeSync",
1558
+ value: function pipeSync(name, coreFn) {
1559
+ var _this = this;
1560
+ for(var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++){
1561
+ args[_key - 2] = arguments[_key];
1562
+ }
1563
+ _class_private_method_get(this, _assertRegistered, assertRegistered).call(this, name, 'pipeSync');
1564
+ var _class_private_method_get_call = _class_private_method_get(this, _extractRunOptions, extractRunOptions).call(this, args), realArgs = _class_private_method_get_call.realArgs, runOptions = _class_private_method_get_call.runOptions;
1565
+ var _runOptions_scope;
1566
+ var scope = (_runOptions_scope = runOptions === null || runOptions === void 0 ? void 0 : runOptions.scope) !== null && _runOptions_scope !== void 0 ? _runOptions_scope : new HookScope();
1567
+ var hooks = _class_private_field_get(this, _hooks).get(name);
1568
+ var entries = hooks ? _to_consumable_array(hooks) : [];
1569
+ if (runOptions === null || runOptions === void 0 ? void 0 : runOptions.append) {
1570
+ entries.push({
1571
+ callback: runOptions.append,
1572
+ options: {},
1573
+ priority: Infinity
1574
+ });
1575
+ }
1576
+ var currentArgs = realArgs;
1577
+ var buildChain = function(index) {
1578
+ if (index >= entries.length) return coreFn;
1579
+ return function() {
1580
+ var entry = entries[index];
1581
+ var callback = entry.callback, opts = entry.options;
1582
+ var timesExceeded = _class_private_method_get(_this, _checkTimes, checkTimes).call(_this, callback, opts);
1583
+ if (timesExceeded) {
1584
+ _class_private_method_get(_this, _removeEntry, removeEntry).call(_this, name, entry);
1585
+ return buildChain(index + 1)();
1586
+ }
1587
+ var removeFn = function() {
1588
+ return _class_private_method_get(_this, _removeEntry, removeEntry).call(_this, name, entry);
1589
+ };
1590
+ var ctx = new PipeContext(_class_private_field_get(_this, _handleFail2), String(name), removeFn, scope, function(newArgs) {
1591
+ currentArgs = newArgs;
1592
+ });
1593
+ var next = buildChain(index + 1);
1594
+ var cb = callback;
1595
+ if (opts.ignoreOnFail) {
1596
+ var _attemptSync = _sliced_to_array(attemptSync(function() {
1597
+ return cb.apply(void 0, [
1598
+ next
1599
+ ].concat(_to_consumable_array(currentArgs), [
1600
+ ctx
1601
+ ]));
1602
+ }), 2), result = _attemptSync[0], err = _attemptSync[1];
1603
+ if (opts.once) removeFn();
1604
+ if (err) return next();
1605
+ return result;
1606
+ }
1607
+ var result1 = cb.apply(void 0, [
1608
+ next
1609
+ ].concat(_to_consumable_array(currentArgs), [
1610
+ ctx
1611
+ ]));
1612
+ if (opts.once) removeFn();
1613
+ return result1;
1614
+ };
1615
+ };
1616
+ return buildChain(0)();
1617
+ }
1618
+ },
1619
+ {
1620
+ /**
1621
+ * Clear all hooks and reset registration state.
1622
+ *
1623
+ * @example
1624
+ * hooks.add('beforeRequest', validator);
1625
+ * hooks.clear();
1626
+ * // All hooks removed, back to permissive mode
1627
+ */ key: "clear",
1628
+ value: function clear() {
1629
+ _class_private_field_get(this, _hooks).clear();
1630
+ _class_private_field_set(this, _registered, null);
1631
+ _class_private_field_set(this, _callCounts, new WeakMap());
1632
+ }
901
1633
  }
902
1634
  ]);
903
1635
  return HookEngine;
@@ -908,3 +1640,46 @@ function assertRegistered(name, method) {
908
1640
  throw new Error('Hook "'.concat(String(name), '" is not registered. ') + 'Call register("'.concat(String(name), '") before using ').concat(method, "(). ") + "Registered hooks: ".concat(registered || '(none)'));
909
1641
  }
910
1642
  }
1643
+ function processCtx(ctx, signal, setArgs, setResult, setReturned) {
1644
+ if (ctx._earlyReturn) {
1645
+ setResult(ctx._result);
1646
+ setReturned();
1647
+ return;
1648
+ }
1649
+ if (ctx._argsChanged) {
1650
+ setArgs(ctx._newArgs);
1651
+ if (signal === EARLY_RETURN) {
1652
+ setReturned();
1653
+ }
1654
+ }
1655
+ }
1656
+ function checkTimes(callback, opts) {
1657
+ if (opts.times === undefined) return false;
1658
+ var _class_private_field_get_get;
1659
+ var count = (_class_private_field_get_get = _class_private_field_get(this, _callCounts).get(callback)) !== null && _class_private_field_get_get !== void 0 ? _class_private_field_get_get : 0;
1660
+ if (count >= opts.times) return true;
1661
+ _class_private_field_get(this, _callCounts).set(callback, count + 1);
1662
+ return false;
1663
+ }
1664
+ function removeEntry(name, entry) {
1665
+ var arr = _class_private_field_get(this, _hooks).get(name);
1666
+ if (arr) {
1667
+ var idx = arr.indexOf(entry);
1668
+ if (idx !== -1) {
1669
+ arr.splice(idx, 1);
1670
+ }
1671
+ }
1672
+ }
1673
+ function extractRunOptions(args) {
1674
+ var last = args[args.length - 1];
1675
+ if (isObject(last) && ('append' in last && isFunction(last.append) || 'scope' in last && _instanceof(last.scope, HookScope))) {
1676
+ return {
1677
+ realArgs: args.slice(0, -1),
1678
+ runOptions: last
1679
+ };
1680
+ }
1681
+ return {
1682
+ realArgs: args,
1683
+ runOptions: undefined
1684
+ };
1685
+ }