@warp-drive/ember 0.0.0-beta.1 → 0.0.0-beta.11

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.
package/dist/index.js CHANGED
@@ -6,26 +6,7 @@ import { macroCondition, moduleExists, importSync, getGlobalConfig } from '@embr
6
6
  import { EnableHydration } from '@warp-drive/core-types/request';
7
7
  import { precompileTemplate } from '@ember/template-compilation';
8
8
  import { setComponentTemplate } from '@ember/component';
9
- var __defProp = Object.defineProperty;
10
- var __export = (target, all) => {
11
- for (var name in all) __defProp(target, name, {
12
- get: all[name],
13
- enumerable: true
14
- });
15
- };
16
-
17
- // src/runtime.ts
18
- var runtime_exports = {};
19
- __export(runtime_exports, {
20
- c: () => decorateClass,
21
- f: () => decorateFieldV1,
22
- g: () => decorateFieldV2,
23
- i: () => initializeDeferredDecorator,
24
- m: () => decorateMethodV1,
25
- n: () => decorateMethodV2,
26
- p: () => decoratePOJO
27
- });
28
- var deferred = /* @__PURE__ */new WeakMap();
9
+ const deferred = /* @__PURE__ */new WeakMap();
29
10
  function deferDecorator(proto, prop, desc) {
30
11
  let map = deferred.get(proto);
31
12
  if (!map) {
@@ -35,18 +16,16 @@ function deferDecorator(proto, prop, desc) {
35
16
  map.set(prop, desc);
36
17
  }
37
18
  function findDeferredDecorator(target, prop) {
19
+ var _a;
38
20
  let cursor = target.prototype;
39
21
  while (cursor) {
40
- let desc = deferred.get(cursor)?.get(prop);
22
+ let desc = (_a = deferred.get(cursor)) == null ? void 0 : _a.get(prop);
41
23
  if (desc) {
42
24
  return desc;
43
25
  }
44
26
  cursor = cursor.prototype;
45
27
  }
46
28
  }
47
- function decorateFieldV1(target, prop, decorators, initializer) {
48
- return decorateFieldV2(target.prototype, prop, decorators, initializer);
49
- }
50
29
  function decorateFieldV2(prototype, prop, decorators, initializer) {
51
30
  let desc = {
52
31
  configurable: true,
@@ -66,11 +45,6 @@ function decorateFieldV2(prototype, prop, decorators, initializer) {
66
45
  deferDecorator(prototype, prop, desc);
67
46
  }
68
47
  }
69
- function decorateMethodV1({
70
- prototype
71
- }, prop, decorators) {
72
- return decorateMethodV2(prototype, prop, decorators);
73
- }
74
48
  function decorateMethodV2(prototype, prop, decorators) {
75
49
  const origDesc = Object.getOwnPropertyDescriptor(prototype, prop);
76
50
  let desc = {
@@ -96,35 +70,6 @@ function initializeDeferredDecorator(target, prop) {
96
70
  });
97
71
  }
98
72
  }
99
- function decorateClass(target, decorators) {
100
- return decorators.reduce((accum, decorator) => decorator(accum) || accum, target);
101
- }
102
- function decoratePOJO(pojo, decorated) {
103
- for (let [type, prop, decorators] of decorated) {
104
- if (type === "field") {
105
- decoratePojoField(pojo, prop, decorators);
106
- } else {
107
- decorateMethodV2(pojo, prop, decorators);
108
- }
109
- }
110
- return pojo;
111
- }
112
- function decoratePojoField(pojo, prop, decorators) {
113
- let desc = {
114
- configurable: true,
115
- enumerable: true,
116
- writable: true,
117
- initializer: () => Object.getOwnPropertyDescriptor(pojo, prop)?.value
118
- };
119
- for (let decorator of decorators) {
120
- desc = decorator(pojo, prop, desc) || desc;
121
- }
122
- if (desc.initializer) {
123
- desc.value = desc.initializer.call(pojo);
124
- delete desc.initializer;
125
- }
126
- Object.defineProperty(pojo, prop, desc);
127
- }
128
73
  const RequestCache = new WeakMap();
129
74
  function isAbortError(error) {
130
75
  return error instanceof DOMException && error.name === 'AbortError';
@@ -542,10 +487,10 @@ function getPromiseState(promise) {
542
487
  }
543
488
  return state;
544
489
  }
545
- const and = (x1, y1) => Boolean(x1 && y1);
490
+ const and = (x, y) => Boolean(x && y);
546
491
  class Throw extends Component {
547
- constructor(owner1, args1) {
548
- super(owner1, args1);
492
+ constructor(owner, args) {
493
+ super(owner, args);
549
494
  // this error is opaque (user supplied) so we don't validate it
550
495
  // as an Error instance.
551
496
  // eslint-disable-next-line @typescript-eslint/no-throw-literal
@@ -577,33 +522,44 @@ class Await extends Component {
577
522
  }), this);
578
523
  }
579
524
  }
580
- function notNull(x1) {
525
+ function notNull(x) {
581
526
  macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
582
527
  if (!test) {
583
528
  throw new Error('Expected a non-null value, but got null');
584
529
  }
585
- })(x1 !== null) : {};
586
- return x1;
530
+ })(x !== null) : {};
531
+ return x;
587
532
  }
588
- const not = x1 => !x1;
533
+ const not = x => !x;
589
534
  // default to 30 seconds unavailable before we refresh
590
535
  const DEFAULT_DEADLINE = 30_000;
591
- let provide = service;
536
+ const IdleBlockMissingError = new Error('No idle block provided for <Request> component, and no query or request was provided.');
537
+ let consume = service;
592
538
  if (macroCondition(moduleExists('ember-provide-consume-context'))) {
593
539
  const {
594
- consume
540
+ consume: contextConsume
595
541
  } = importSync('ember-provide-consume-context');
596
- provide = consume;
542
+ consume = contextConsume;
597
543
  }
598
- function isNeverString(val1) {
599
- return val1;
544
+ function isNeverString(val) {
545
+ return val;
600
546
  }
547
+ /**
548
+ * The `<Request>` component is a powerful tool for managing data fetching and
549
+ * state in your Ember application. It provides declarative reactive control-flow
550
+ * for managing requests and state in your application.
551
+ *
552
+ * @typedoc
553
+ */
601
554
  class Request extends Component {
602
555
  static {
603
- decorateFieldV2(this.prototype, "_store", [provide('store')]);
556
+ decorateFieldV2(this.prototype, "_store", [consume('store')]);
604
557
  }
605
558
  #_store = (initializeDeferredDecorator(this, "_store"), void 0);
606
559
  /**
560
+ * The store instance to use for making requests. If contexts are available, this
561
+ * will be the `store` on the context, else it will be the store service.
562
+ *
607
563
  * @internal
608
564
  */
609
565
  static {
@@ -612,35 +568,286 @@ class Request extends Component {
612
568
  });
613
569
  }
614
570
  #isOnline = (initializeDeferredDecorator(this, "isOnline"), void 0);
571
+ /**
572
+ * Whether the browser reports that the network is online.
573
+ *
574
+ * @internal
575
+ */
615
576
  static {
616
577
  decorateFieldV2(this.prototype, "isHidden", [tracked], function () {
617
578
  return true;
618
579
  });
619
580
  }
620
581
  #isHidden = (initializeDeferredDecorator(this, "isHidden"), void 0);
582
+ /**
583
+ * Whether the browser reports that the tab is hidden.
584
+ *
585
+ * @internal
586
+ */
621
587
  static {
622
588
  decorateFieldV2(this.prototype, "isRefreshing", [tracked], function () {
623
589
  return false;
624
590
  });
625
591
  }
626
592
  #isRefreshing = (initializeDeferredDecorator(this, "isRefreshing"), void 0);
593
+ /**
594
+ * Whether the component is currently refreshing the request.
595
+ *
596
+ * @internal
597
+ */
627
598
  static {
628
599
  decorateFieldV2(this.prototype, "_localRequest", [tracked]);
629
600
  }
630
601
  #_localRequest = (initializeDeferredDecorator(this, "_localRequest"), void 0);
602
+ /**
603
+ * The most recent blocking request that was made, typically
604
+ * the result of a reload.
605
+ *
606
+ * This will never be the original request passed as an arg to
607
+ * the component.
608
+ *
609
+ * @internal
610
+ */
631
611
  static {
632
612
  decorateFieldV2(this.prototype, "_latestRequest", [tracked]);
633
613
  }
634
614
  #_latestRequest = (initializeDeferredDecorator(this, "_latestRequest"), void 0);
615
+ /**
616
+ * The most recent request that was made, typically due to either a
617
+ * reload or a refresh.
618
+ *
619
+ * This will never be the original request passed as an arg to
620
+ * the component.
621
+ *
622
+ * @internal
623
+ */
624
+ /**
625
+ * The time at which the network was reported as offline.
626
+ *
627
+ * @internal
628
+ */
635
629
  unavailableStart;
630
+ intervalStart;
631
+ nextInterval;
632
+ invalidated;
633
+ isUpdating;
634
+ /**
635
+ * The event listener for network status changes,
636
+ * cached to use the reference for removal.
637
+ *
638
+ * @internal
639
+ */
636
640
  onlineChanged;
641
+ /**
642
+ * The event listener for visibility status changes,
643
+ * cached to use the reference for removal.
644
+ *
645
+ * @internal
646
+ */
637
647
  backgroundChanged;
648
+ /**
649
+ * The last request passed as an arg to the component,
650
+ * cached for comparison.
651
+ *
652
+ * @internal
653
+ */
638
654
  _originalRequest;
655
+ /**
656
+ * The last query passed as an arg to the component,
657
+ * cached for comparison.
658
+ *
659
+ * @internal
660
+ */
639
661
  _originalQuery;
640
- constructor(owner1, args1) {
641
- super(owner1, args1);
662
+ _subscription;
663
+ _subscribedTo;
664
+ constructor(owner, args) {
665
+ super(owner, args);
666
+ this._subscribedTo = null;
667
+ this._subscription = null;
668
+ this.intervalStart = null;
669
+ this.invalidated = false;
670
+ this.nextInterval = null;
642
671
  this.installListeners();
672
+ void this.beginPolling();
673
+ }
674
+ async beginPolling() {
675
+ // await the initial request
676
+ try {
677
+ await this.request;
678
+ } catch {
679
+ // ignore errors here, we just want to wait for the request to finish
680
+ } finally {
681
+ if (!this.isDestroyed) {
682
+ void this.scheduleInterval();
683
+ }
684
+ }
685
+ }
686
+ get isIdle() {
687
+ const {
688
+ request,
689
+ query
690
+ } = this.args;
691
+ return Boolean(!request && !query);
692
+ }
693
+ static {
694
+ decorateMethodV2(this.prototype, "isIdle", [cached]);
695
+ }
696
+ get autorefreshTypes() {
697
+ const {
698
+ autorefresh
699
+ } = this.args;
700
+ let types;
701
+ if (autorefresh === true) {
702
+ types = ['online', 'invalid'];
703
+ } else if (typeof autorefresh === 'string') {
704
+ types = autorefresh.split(',');
705
+ } else {
706
+ types = [];
707
+ }
708
+ return new Set(types);
709
+ }
710
+ // we only run this function on component creation
711
+ // and when an update is triggered, so it does not
712
+ // react to changes in the autorefreshThreshold
713
+ // or autorefresh args.
714
+ //
715
+ // if we need to react to those changes, we can
716
+ // use a modifier or internal component or some
717
+ // such to trigger a re-run of this function.
718
+ static {
719
+ decorateMethodV2(this.prototype, "autorefreshTypes", [cached]);
720
+ }
721
+ async scheduleInterval() {
722
+ const {
723
+ autorefreshThreshold
724
+ } = this.args;
725
+ const hasValidThreshold = typeof autorefreshThreshold === 'number' && autorefreshThreshold > 0;
726
+ if (typeof window === 'undefined' ||
727
+ // dont schedule without a threshold
728
+ !hasValidThreshold ||
729
+ // dont schedule if we weren't told to
730
+ !this.autorefreshTypes.has('interval') ||
731
+ // dont schedule if we're already scheduled
732
+ this.intervalStart !== null) {
733
+ return;
734
+ }
735
+ // if we have a current request, wait for it to finish
736
+ // before scheduling the next one
737
+ if (this._latestRequest) {
738
+ try {
739
+ await this._latestRequest;
740
+ } catch {
741
+ // ignore errors here, we just want to wait for the request to finish
742
+ }
743
+ if (this.isDestroyed) {
744
+ return;
745
+ }
746
+ }
747
+ // setup the next interval
748
+ this.intervalStart = Date.now();
749
+ this.nextInterval = setTimeout(() => {
750
+ this.maybeUpdate();
751
+ }, autorefreshThreshold);
643
752
  }
753
+ clearInterval() {
754
+ if (this.nextInterval) {
755
+ clearTimeout(this.nextInterval);
756
+ this.intervalStart = null;
757
+ }
758
+ }
759
+ updateSubscriptions() {
760
+ if (this.isIdle) {
761
+ return;
762
+ }
763
+ const requestId = this._request.lid;
764
+ // if we're already subscribed to this request, we don't need to do anything
765
+ if (this._subscribedTo === requestId) {
766
+ return;
767
+ }
768
+ // if we're subscribed to a different request, we need to unsubscribe
769
+ this.removeSubscriptions();
770
+ // if we have a request, we need to subscribe to it
771
+ if (requestId) {
772
+ this._subscribedTo = requestId;
773
+ this._subscription = this.store.notifications.subscribe(requestId, (_id, op) => {
774
+ // ignore subscription events that occur while our own component's request
775
+ // is ocurring
776
+ if (this.isUpdating) {
777
+ return;
778
+ }
779
+ switch (op) {
780
+ case 'invalidated':
781
+ {
782
+ // if we're subscribed to invalidations, we need to update
783
+ if (this.autorefreshTypes.has('invalid')) {
784
+ this.invalidated = true;
785
+ this.maybeUpdate();
786
+ }
787
+ break;
788
+ }
789
+ case 'state':
790
+ {
791
+ const latest = this.store.requestManager._deduped.get(requestId);
792
+ const priority = latest?.priority;
793
+ const state = this.reqState;
794
+ if (!priority) {
795
+ // if there is no priority, we have completed whatever request
796
+ // was occurring and so we are no longer refreshing (if we were)
797
+ this.isRefreshing = false;
798
+ } else if (priority.blocking && !state.isLoading) {
799
+ // if we are blocking, there is an active request for this identity
800
+ // that MUST be fulfilled from network (not cache).
801
+ // Thus this is not "refreshing" because we should clear out and
802
+ // block on this request.
803
+ //
804
+ // we receive state notifications when either a request initiates
805
+ // or completes.
806
+ //
807
+ // In the completes case: we may receive the state notification
808
+ // slightly before the request is finalized because the NotificationManager
809
+ // may sync flush it (and thus deliver it before the microtask completes)
810
+ //
811
+ // In the initiates case: we aren't supposed to receive one unless there
812
+ // is no other request in flight for this identity.
813
+ //
814
+ // However, there is a race condition here where the completed
815
+ // notification can trigger an update that generates a new request
816
+ // thus giving us an initiated notification before the older request
817
+ // finalizes.
818
+ //
819
+ // When this occurs, if the triggered update happens to have caused
820
+ // a new request to be made for the same identity AND that request
821
+ // is the one passed into this component as the @request arg, then
822
+ // getRequestState will return the state of the new request.
823
+ // We can detect this by checking if the request state is "loading"
824
+ // as outside of this case we would have a completed request.
825
+ //
826
+ // That is the reason for the `&& !state.isLoading` check above.
827
+ // TODO should we just treat this as refreshing?
828
+ this.isRefreshing = false;
829
+ this.maybeUpdate('policy', true);
830
+ } else {
831
+ this.isRefreshing = true;
832
+ }
833
+ }
834
+ }
835
+ });
836
+ }
837
+ }
838
+ removeSubscriptions() {
839
+ if (this._subscription) {
840
+ this.store.notifications.unsubscribe(this._subscription);
841
+ this._subscribedTo = null;
842
+ this._subscription = null;
843
+ }
844
+ }
845
+ /**
846
+ * Install the event listeners for network and visibility changes.
847
+ * This is only done in browser environments with a global `window`.
848
+ *
849
+ * @internal
850
+ */
644
851
  installListeners() {
645
852
  if (typeof window === 'undefined') {
646
853
  return;
@@ -648,17 +855,17 @@ class Request extends Component {
648
855
  this.isOnline = window.navigator.onLine;
649
856
  this.unavailableStart = this.isOnline ? null : Date.now();
650
857
  this.isHidden = document.visibilityState === 'hidden';
651
- this.onlineChanged = event1 => {
652
- this.isOnline = event1.type === 'online';
653
- if (event1.type === 'offline' && this.unavailableStart === null) {
858
+ this.onlineChanged = event => {
859
+ this.isOnline = event.type === 'online';
860
+ if (event.type === 'offline' && this.unavailableStart === null) {
654
861
  this.unavailableStart = Date.now();
655
862
  }
656
863
  this.maybeUpdate();
657
864
  };
658
865
  this.backgroundChanged = () => {
659
- const isHidden1 = document.visibilityState === 'hidden';
660
- this.isHidden = isHidden1;
661
- if (isHidden1 && this.unavailableStart === null) {
866
+ const isHidden = document.visibilityState === 'hidden';
867
+ this.isHidden = isHidden;
868
+ if (isHidden && this.unavailableStart === null) {
662
869
  this.unavailableStart = Date.now();
663
870
  }
664
871
  this.maybeUpdate();
@@ -676,59 +883,112 @@ class Request extends Component {
676
883
  capture: true
677
884
  });
678
885
  }
679
- maybeUpdate(mode1) {
680
- if (this.isOnline && !this.isHidden && (mode1 || this.args.autorefresh)) {
681
- const deadline1 = typeof this.args.autorefreshThreshold === 'number' ? this.args.autorefreshThreshold : DEFAULT_DEADLINE;
682
- const shouldAttempt1 = mode1 || this.unavailableStart && Date.now() - this.unavailableStart > deadline1;
683
- this.unavailableStart = null;
684
- if (shouldAttempt1) {
685
- const request1 = Object.assign({}, this.reqState.request);
686
- const val1 = mode1 ?? this.args.autorefreshBehavior ?? 'policy';
687
- switch (val1) {
688
- case 'reload':
689
- request1.cacheOptions = Object.assign({}, request1.cacheOptions, {
690
- reload: true
691
- });
692
- break;
693
- case 'refresh':
694
- request1.cacheOptions = Object.assign({}, request1.cacheOptions, {
695
- backgroundReload: true
696
- });
697
- break;
698
- case 'policy':
699
- break;
700
- default:
701
- throw new Error(`Invalid ${mode1 ? 'update mode' : '@autorefreshBehavior'} for <Request />: ${isNeverString(val1)}`);
702
- }
703
- const wasStoreRequest1 = request1[EnableHydration] === true;
704
- macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
705
- if (!test) {
706
- throw new Error(`Cannot supply a different store via context than was used to create the request`);
707
- }
708
- })(!request1.store || request1.store === this.store) : {};
709
- this._latestRequest = wasStoreRequest1 ? this.store.request(request1) : this.store.requestManager.request(request1);
710
- if (val1 !== 'refresh') {
711
- this._localRequest = this._latestRequest;
712
- }
713
- return;
886
+ /**
887
+ * If the network is online and the tab is visible, either reload or refresh the request
888
+ * based on the component's configuration and the requested update mode.
889
+ *
890
+ * Valid modes are:
891
+ *
892
+ * - `'reload'`: Force a reload of the request.
893
+ * - `'refresh'`: Refresh the request in the background.
894
+ * - `'policy'`: Make the request, letting the store's configured CachePolicy decide whether to reload, refresh, or do nothing.
895
+ * - `undefined`: Make the request using the component's autorefreshBehavior setting if the autorefreshThreshold has passed.
896
+ *
897
+ * @internal
898
+ */
899
+ maybeUpdate(mode, silent) {
900
+ if (this.isIdle) {
901
+ return;
902
+ }
903
+ const canAttempt = Boolean(this.isOnline && !this.isHidden && (mode || this.autorefreshTypes.size));
904
+ if (!canAttempt) {
905
+ if (!silent && mode && mode !== 'invalidated') {
906
+ throw new Error(`Reload not available: the network is not online or the tab is hidden`);
714
907
  }
908
+ return;
715
909
  }
716
- if (mode1) {
717
- throw new Error(`Reload not available: the network is not online or the tab is hidden`);
910
+ const {
911
+ autorefreshTypes
912
+ } = this;
913
+ let shouldAttempt = this.invalidated || Boolean(mode);
914
+ if (!shouldAttempt && autorefreshTypes.has('online')) {
915
+ const {
916
+ unavailableStart
917
+ } = this;
918
+ const {
919
+ autorefreshThreshold
920
+ } = this.args;
921
+ const deadline = typeof autorefreshThreshold === 'number' ? autorefreshThreshold : DEFAULT_DEADLINE;
922
+ shouldAttempt = Boolean(unavailableStart && Date.now() - unavailableStart > deadline);
923
+ }
924
+ if (!shouldAttempt && autorefreshTypes.has('interval')) {
925
+ const {
926
+ intervalStart
927
+ } = this;
928
+ const {
929
+ autorefreshThreshold
930
+ } = this.args;
931
+ if (intervalStart && typeof autorefreshThreshold === 'number' && autorefreshThreshold > 0) {
932
+ shouldAttempt = Boolean(Date.now() - intervalStart >= autorefreshThreshold);
933
+ }
934
+ }
935
+ this.unavailableStart = null;
936
+ this.invalidated = false;
937
+ if (shouldAttempt) {
938
+ this.clearInterval();
939
+ const request = Object.assign({}, this.reqState.request);
940
+ const realMode = mode === 'invalidated' ? null : mode;
941
+ const val = realMode ?? this.args.autorefreshBehavior ?? 'policy';
942
+ switch (val) {
943
+ case 'reload':
944
+ request.cacheOptions = Object.assign({}, request.cacheOptions, {
945
+ reload: true
946
+ });
947
+ break;
948
+ case 'refresh':
949
+ request.cacheOptions = Object.assign({}, request.cacheOptions, {
950
+ backgroundReload: true
951
+ });
952
+ break;
953
+ case 'policy':
954
+ break;
955
+ default:
956
+ throw new Error(`Invalid ${mode ? 'update mode' : '@autorefreshBehavior'} for <Request />: ${isNeverString(val)}`);
957
+ }
958
+ const wasStoreRequest = request[EnableHydration] === true;
959
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
960
+ if (!test) {
961
+ throw new Error(`Cannot supply a different store via context than was used to create the request`);
962
+ }
963
+ })(!request.store || request.store === this.store) : {};
964
+ this.isUpdating = true;
965
+ this._latestRequest = wasStoreRequest ? this.store.request(request) : this.store.requestManager.request(request);
966
+ if (val !== 'refresh') {
967
+ this._localRequest = this._latestRequest;
968
+ }
969
+ void this.scheduleInterval();
970
+ void this._latestRequest.finally(() => {
971
+ this.isUpdating = false;
972
+ });
718
973
  }
719
974
  }
975
+ /**
976
+ * Retry the request, reloading it from the server.
977
+ *
978
+ * @internal
979
+ */
720
980
  retry = async () => {
721
981
  this.maybeUpdate('reload');
722
982
  await this._localRequest;
723
983
  };
984
+ /**
985
+ * Refresh the request, updating it in the background.
986
+ *
987
+ * @internal
988
+ */
724
989
  refresh = async () => {
725
- this.isRefreshing = true;
726
990
  this.maybeUpdate('refresh');
727
- try {
728
- await this._latestRequest;
729
- } finally {
730
- this.isRefreshing = false;
731
- }
991
+ await this._latestRequest;
732
992
  };
733
993
  get errorFeatures() {
734
994
  return {
@@ -741,7 +1001,7 @@ class Request extends Component {
741
1001
  decorateMethodV2(this.prototype, "errorFeatures", [cached]);
742
1002
  }
743
1003
  get contentFeatures() {
744
- const feat1 = {
1004
+ const feat = {
745
1005
  isHidden: this.isHidden,
746
1006
  isOnline: this.isOnline,
747
1007
  reload: this.retry,
@@ -749,20 +1009,22 @@ class Request extends Component {
749
1009
  isRefreshing: this.isRefreshing,
750
1010
  latestRequest: this._latestRequest
751
1011
  };
752
- if (feat1.isRefreshing) {
753
- feat1.abort = () => {
1012
+ if (feat.isRefreshing) {
1013
+ feat.abort = () => {
754
1014
  this._latestRequest?.abort();
755
1015
  };
756
1016
  }
757
- return feat1;
1017
+ return feat;
758
1018
  }
759
1019
  static {
760
1020
  decorateMethodV2(this.prototype, "contentFeatures", [cached]);
761
1021
  }
762
1022
  willDestroy() {
1023
+ this.removeSubscriptions();
763
1024
  if (typeof window === 'undefined') {
764
1025
  return;
765
1026
  }
1027
+ this.clearInterval();
766
1028
  window.removeEventListener('online', this.onlineChanged, {
767
1029
  passive: true,
768
1030
  capture: true
@@ -776,49 +1038,57 @@ class Request extends Component {
776
1038
  capture: true
777
1039
  });
778
1040
  }
779
- get request() {
1041
+ get _request() {
780
1042
  const {
781
- request: request1,
782
- query: query1
1043
+ request,
1044
+ query
783
1045
  } = this.args;
784
1046
  macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
785
1047
  if (!test) {
786
1048
  throw new Error(`Cannot use both @request and @query args with the <Request> component`);
787
1049
  }
788
- })(!request1 || !query1) : {};
1050
+ })(!request || !query) : {};
789
1051
  const {
790
- _localRequest: _localRequest1,
791
- _originalRequest: _originalRequest1,
792
- _originalQuery: _originalQuery1
1052
+ _localRequest,
1053
+ _originalRequest,
1054
+ _originalQuery
793
1055
  } = this;
794
- const isOriginalRequest1 = request1 === _originalRequest1 && query1 === _originalQuery1;
795
- if (_localRequest1 && isOriginalRequest1) {
796
- return _localRequest1;
1056
+ const isOriginalRequest = request === _originalRequest && query === _originalQuery;
1057
+ if (_localRequest && isOriginalRequest) {
1058
+ return _localRequest;
797
1059
  }
798
1060
  // update state checks for the next time
799
- this._originalQuery = query1;
800
- this._originalRequest = request1;
801
- if (request1) {
802
- return request1;
1061
+ this._originalQuery = query;
1062
+ this._originalRequest = request;
1063
+ if (request) {
1064
+ return request;
803
1065
  }
804
1066
  macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
805
1067
  if (!test) {
806
1068
  throw new Error(`You must provide either @request or an @query arg with the <Request> component`);
807
1069
  }
808
- })(query1) : {};
809
- return this.store.request(query1);
1070
+ })(query) : {};
1071
+ return this.store.request(query);
1072
+ }
1073
+ static {
1074
+ decorateMethodV2(this.prototype, "_request", [cached]);
1075
+ }
1076
+ get request() {
1077
+ const request = this._request;
1078
+ this.updateSubscriptions();
1079
+ return request;
810
1080
  }
811
1081
  static {
812
1082
  decorateMethodV2(this.prototype, "request", [cached]);
813
1083
  }
814
1084
  get store() {
815
- const store1 = this.args.store || this._store;
1085
+ const store = this.args.store || this._store;
816
1086
  macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
817
1087
  if (!test) {
818
1088
  throw new Error(moduleExists('ember-provide-consume-context') ? `No store was provided to the <Request> component. Either provide a store via the @store arg or via the context API provided by ember-provide-consume-context.` : `No store was provided to the <Request> component. Either provide a store via the @store arg or by registering a store service.`);
819
1089
  }
820
- })(store1) : {};
821
- return store1;
1090
+ })(store) : {};
1091
+ return store;
822
1092
  }
823
1093
  get reqState() {
824
1094
  return getRequestState(this.request);
@@ -827,13 +1097,14 @@ class Request extends Component {
827
1097
  return this.reqState.result;
828
1098
  }
829
1099
  static {
830
- setComponentTemplate(precompileTemplate("\n {{#if this.reqState.isLoading}}\n {{yield this.reqState.loadingState to=\"loading\"}}\n {{else if (and this.reqState.isCancelled (has-block \"cancelled\"))}}\n {{yield (notNull this.reqState.error) this.errorFeatures to=\"cancelled\"}}\n {{else if (and this.reqState.isError (has-block \"error\"))}}\n {{yield (notNull this.reqState.error) this.errorFeatures to=\"error\"}}\n {{else if this.reqState.isSuccess}}\n {{yield this.result this.contentFeatures to=\"content\"}}\n {{else if (not this.reqState.isCancelled)}}\n <Throw @error={{(notNull this.reqState.error)}} />\n {{/if}}\n {{yield this.reqState to=\"always\"}}\n ", {
1100
+ setComponentTemplate(precompileTemplate("\n {{#if (and this.isIdle (has-block \"idle\"))}}\n {{yield to=\"idle\"}}\n {{else if this.isIdle}}\n <Throw @error={{IdleBlockMissingError}} />\n {{else if this.reqState.isLoading}}\n {{yield this.reqState.loadingState to=\"loading\"}}\n {{else if (and this.reqState.isCancelled (has-block \"cancelled\"))}}\n {{yield (notNull this.reqState.error) this.errorFeatures to=\"cancelled\"}}\n {{else if (and this.reqState.isError (has-block \"error\"))}}\n {{yield (notNull this.reqState.error) this.errorFeatures to=\"error\"}}\n {{else if this.reqState.isSuccess}}\n {{yield this.result this.contentFeatures to=\"content\"}}\n {{else if (not this.reqState.isCancelled)}}\n <Throw @error={{(notNull this.reqState.error)}} />\n {{/if}}\n {{yield this.reqState to=\"always\"}}\n ", {
831
1101
  strictMode: true,
832
1102
  scope: () => ({
833
1103
  and,
1104
+ Throw,
1105
+ IdleBlockMissingError,
834
1106
  notNull,
835
- not,
836
- Throw
1107
+ not
837
1108
  })
838
1109
  }), this);
839
1110
  }