@warp-drive/core 5.7.0-alpha.36 → 5.7.0-alpha.38
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.
|
@@ -3,10 +3,10 @@ import { macroCondition, getGlobalConfig, dependencySatisfies, importSync } from
|
|
|
3
3
|
import { deprecate, warn } from '@ember/debug';
|
|
4
4
|
import { setLogging, getRuntimeConfig } from './types/runtime.js';
|
|
5
5
|
import { getOrSetGlobal, peekTransient, setTransient } from './types/-private.js';
|
|
6
|
-
import { c as createSignal, a as consumeSignal, n as notifySignal, b as createMemo, A as ARRAY_SIGNAL, O as OBJECT_SIGNAL, d as willSyncFlushWatchers } from "./configure-C3x8YXzL.js";
|
|
7
6
|
import { CACHE_OWNER, DEBUG_STALE_CACHE_OWNER, DEBUG_KEY_TYPE, DEBUG_CLIENT_ORIGINATED } from './types/identifier.js';
|
|
8
7
|
import { dasherize } from './utils/string.js';
|
|
9
8
|
import { S as SOURCE, C as Context, D as Destroy, a as Checkout, b as Commit } from "./symbols-sql1_mdx.js";
|
|
9
|
+
import { c as createSignal, a as consumeSignal, n as notifySignal, b as createMemo, A as ARRAY_SIGNAL, O as OBJECT_SIGNAL, d as willSyncFlushWatchers } from "./configure-C3x8YXzL.js";
|
|
10
10
|
import { g as getPromiseResult, s as setPromiseResult } from "./context-C_7OLieY.js";
|
|
11
11
|
import { RecordStore } from './types/symbols.js';
|
|
12
12
|
const INITIALIZER_PROTO = {
|
|
@@ -9451,87 +9451,85 @@ function getPromiseState(promise) {
|
|
|
9451
9451
|
}
|
|
9452
9452
|
return state;
|
|
9453
9453
|
}
|
|
9454
|
-
|
|
9455
|
-
|
|
9456
|
-
|
|
9457
|
-
|
|
9458
|
-
|
|
9459
|
-
|
|
9460
|
-
|
|
9461
|
-
async function watchStream(stream, loadingState) {
|
|
9462
|
-
const state = upgradeLoadingState(loadingState);
|
|
9463
|
-
const reader = stream.getReader();
|
|
9464
|
-
let bytesLoaded = 0;
|
|
9465
|
-
let shouldForward = state._stream !== null && state._stream.readable.locked;
|
|
9466
|
-
let isForwarding = shouldForward;
|
|
9467
|
-
let writer = state._stream?.writable.getWriter();
|
|
9468
|
-
const buffer = [];
|
|
9469
|
-
state._isPending = false;
|
|
9470
|
-
state._isStarted = true;
|
|
9471
|
-
state._startTime = performance.now();
|
|
9472
|
-
while (true) {
|
|
9473
|
-
const {
|
|
9474
|
-
value,
|
|
9475
|
-
done
|
|
9476
|
-
} = await reader.read();
|
|
9477
|
-
if (done) {
|
|
9478
|
-
break;
|
|
9479
|
-
}
|
|
9480
|
-
bytesLoaded += value.byteLength;
|
|
9481
|
-
state._bytesLoaded = bytesLoaded;
|
|
9482
|
-
state._lastPacketTime = performance.now();
|
|
9483
|
-
shouldForward = shouldForward || state._stream !== null && state._stream.readable.locked;
|
|
9484
|
-
if (shouldForward) {
|
|
9485
|
-
if (!isForwarding) {
|
|
9486
|
-
isForwarding = true;
|
|
9487
|
-
writer = state._stream.writable.getWriter();
|
|
9488
|
-
for (const item of buffer) {
|
|
9489
|
-
await writer.ready;
|
|
9490
|
-
await writer.write(item);
|
|
9491
|
-
}
|
|
9492
|
-
buffer.length = 0;
|
|
9493
|
-
}
|
|
9494
|
-
await writer.ready;
|
|
9495
|
-
await writer.write(value);
|
|
9496
|
-
} else {
|
|
9497
|
-
buffer.push(value);
|
|
9498
|
-
}
|
|
9454
|
+
function decorateMethodV2(prototype, prop, decorators) {
|
|
9455
|
+
const origDesc = Object.getOwnPropertyDescriptor(prototype, prop);
|
|
9456
|
+
let desc = {
|
|
9457
|
+
...origDesc
|
|
9458
|
+
};
|
|
9459
|
+
for (let decorator of decorators) {
|
|
9460
|
+
desc = decorator(prototype, prop, desc) || desc;
|
|
9499
9461
|
}
|
|
9500
|
-
|
|
9501
|
-
|
|
9502
|
-
|
|
9503
|
-
await writer.ready;
|
|
9504
|
-
await writer.close();
|
|
9505
|
-
} else if (state._stream) {
|
|
9506
|
-
// if we are not forwarding, we need to cancel the stream
|
|
9507
|
-
await state._stream.readable.cancel('The Stream Has Already Ended');
|
|
9508
|
-
state._stream = null;
|
|
9462
|
+
if (desc.initializer !== void 0) {
|
|
9463
|
+
desc.value = desc.initializer ? desc.initializer.call(prototype) : void 0;
|
|
9464
|
+
desc.initializer = void 0;
|
|
9509
9465
|
}
|
|
9510
|
-
|
|
9511
|
-
|
|
9512
|
-
|
|
9513
|
-
|
|
9466
|
+
Object.defineProperty(prototype, prop, desc);
|
|
9467
|
+
}
|
|
9468
|
+
|
|
9469
|
+
// default to 30 seconds unavailable before we refresh
|
|
9470
|
+
const DEFAULT_DEADLINE = 30_000;
|
|
9471
|
+
const DISPOSE = Symbol.dispose || Symbol.for('dispose');
|
|
9472
|
+
function isNeverString(val) {
|
|
9473
|
+
return val;
|
|
9514
9474
|
}
|
|
9515
9475
|
|
|
9516
9476
|
/**
|
|
9517
|
-
*
|
|
9518
|
-
|
|
9519
|
-
|
|
9477
|
+
* Utilities to assist in recovering from the error.
|
|
9478
|
+
*/
|
|
9479
|
+
|
|
9480
|
+
/** @deprecated use {@link RecoveryFeatures} */
|
|
9481
|
+
|
|
9482
|
+
/**
|
|
9483
|
+
* Utilities for keeping the request fresh
|
|
9484
|
+
*/
|
|
9485
|
+
|
|
9486
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
9487
|
+
|
|
9488
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
9489
|
+
|
|
9490
|
+
/**
|
|
9491
|
+
* A reactive class
|
|
9520
9492
|
*
|
|
9521
9493
|
* @hideconstructor
|
|
9522
9494
|
*/
|
|
9523
|
-
class
|
|
9524
|
-
/**
|
|
9495
|
+
class RequestSubscription {
|
|
9496
|
+
/**
|
|
9497
|
+
* Whether the browser reports that the network is online.
|
|
9498
|
+
*/
|
|
9525
9499
|
|
|
9526
|
-
/**
|
|
9500
|
+
/**
|
|
9501
|
+
* Whether the browser reports that the tab is hidden.
|
|
9502
|
+
*/
|
|
9527
9503
|
|
|
9528
|
-
/**
|
|
9504
|
+
/**
|
|
9505
|
+
* Whether the component is currently refreshing the request.
|
|
9506
|
+
*/
|
|
9529
9507
|
|
|
9530
|
-
/**
|
|
9508
|
+
/**
|
|
9509
|
+
* The most recent blocking request that was made, typically
|
|
9510
|
+
* the result of a reload.
|
|
9511
|
+
*
|
|
9512
|
+
* This will never be the original request passed as an arg to
|
|
9513
|
+
* the component.
|
|
9514
|
+
*
|
|
9515
|
+
* @internal
|
|
9516
|
+
*/
|
|
9531
9517
|
|
|
9532
|
-
/**
|
|
9518
|
+
/**
|
|
9519
|
+
* The most recent request that was made, typically due to either a
|
|
9520
|
+
* reload or a refresh.
|
|
9521
|
+
*
|
|
9522
|
+
* This will never be the original request passed as an arg to
|
|
9523
|
+
* the component.
|
|
9524
|
+
*
|
|
9525
|
+
* @internal
|
|
9526
|
+
*/
|
|
9533
9527
|
|
|
9534
|
-
/**
|
|
9528
|
+
/**
|
|
9529
|
+
* The time at which the network was reported as offline.
|
|
9530
|
+
*
|
|
9531
|
+
* @internal
|
|
9532
|
+
*/
|
|
9535
9533
|
|
|
9536
9534
|
/** @internal */
|
|
9537
9535
|
|
|
@@ -9543,1035 +9541,1039 @@ class RequestLoadingState {
|
|
|
9543
9541
|
|
|
9544
9542
|
/** @internal */
|
|
9545
9543
|
|
|
9544
|
+
/**
|
|
9545
|
+
* The event listener for network status changes,
|
|
9546
|
+
* cached to use the reference for removal.
|
|
9547
|
+
*
|
|
9548
|
+
* @internal
|
|
9549
|
+
*/
|
|
9550
|
+
|
|
9551
|
+
/**
|
|
9552
|
+
* The event listener for visibility status changes,
|
|
9553
|
+
* cached to use the reference for removal.
|
|
9554
|
+
*
|
|
9555
|
+
* @internal
|
|
9556
|
+
*/
|
|
9557
|
+
|
|
9558
|
+
/**
|
|
9559
|
+
* The last request passed as an arg to the component,
|
|
9560
|
+
* cached for comparison.
|
|
9561
|
+
*
|
|
9562
|
+
* @internal
|
|
9563
|
+
*/
|
|
9564
|
+
|
|
9565
|
+
/**
|
|
9566
|
+
* The last query passed as an arg to the component,
|
|
9567
|
+
* cached for comparison.
|
|
9568
|
+
*
|
|
9569
|
+
* @internal
|
|
9570
|
+
*/
|
|
9571
|
+
|
|
9546
9572
|
/** @internal */
|
|
9547
|
-
|
|
9548
|
-
/** @internal */
|
|
9549
|
-
_future;
|
|
9573
|
+
|
|
9550
9574
|
/** @internal */
|
|
9551
|
-
|
|
9575
|
+
|
|
9552
9576
|
/** @internal */
|
|
9553
|
-
|
|
9554
|
-
|
|
9555
|
-
|
|
9556
|
-
|
|
9557
|
-
|
|
9558
|
-
|
|
9559
|
-
|
|
9560
|
-
|
|
9561
|
-
|
|
9562
|
-
|
|
9563
|
-
|
|
9564
|
-
|
|
9565
|
-
|
|
9566
|
-
|
|
9567
|
-
|
|
9577
|
+
|
|
9578
|
+
/**
|
|
9579
|
+
* The Store this subscription subscribes to or the RequestManager
|
|
9580
|
+
* which issues this request.
|
|
9581
|
+
*/
|
|
9582
|
+
|
|
9583
|
+
/**
|
|
9584
|
+
* The Store or RequestManager that the last subscription is attached to.
|
|
9585
|
+
*
|
|
9586
|
+
* This differs from 'store' because a <Request /> may be passed a
|
|
9587
|
+
* request originating from a different store than the <Request />
|
|
9588
|
+
* component would use if it were to issue the request itself.
|
|
9589
|
+
*
|
|
9590
|
+
* @internal
|
|
9591
|
+
*/
|
|
9592
|
+
_requester;
|
|
9593
|
+
constructor(store, args) {
|
|
9594
|
+
this._args = args;
|
|
9595
|
+
this.store = store;
|
|
9596
|
+
this._subscribedTo = null;
|
|
9597
|
+
this._subscription = null;
|
|
9598
|
+
this._intervalStart = null;
|
|
9599
|
+
this._invalidated = false;
|
|
9600
|
+
this._nextInterval = null;
|
|
9601
|
+
this._requester = null;
|
|
9602
|
+
this.isDestroyed = false;
|
|
9603
|
+
this[DISPOSE] = _DISPOSE;
|
|
9604
|
+
this._installListeners();
|
|
9605
|
+
void this._beginPolling();
|
|
9606
|
+
}
|
|
9607
|
+
|
|
9608
|
+
/**
|
|
9609
|
+
* @internal
|
|
9610
|
+
*/
|
|
9611
|
+
async _beginPolling() {
|
|
9612
|
+
// await the initial request
|
|
9613
|
+
try {
|
|
9614
|
+
if (!this.isIdle) {
|
|
9615
|
+
await this.request;
|
|
9568
9616
|
}
|
|
9569
|
-
|
|
9570
|
-
|
|
9571
|
-
|
|
9572
|
-
this.
|
|
9573
|
-
|
|
9574
|
-
this._isCancelled = true;
|
|
9575
|
-
this._isComplete = true;
|
|
9617
|
+
} catch {
|
|
9618
|
+
// ignore errors here, we just want to wait for the request to finish
|
|
9619
|
+
} finally {
|
|
9620
|
+
if (!this.isDestroyed) {
|
|
9621
|
+
void this._scheduleInterval();
|
|
9576
9622
|
}
|
|
9577
|
-
|
|
9578
|
-
this._error = error;
|
|
9579
|
-
});
|
|
9623
|
+
}
|
|
9580
9624
|
}
|
|
9581
|
-
|
|
9582
|
-
|
|
9583
|
-
|
|
9584
|
-
|
|
9625
|
+
get isIdle() {
|
|
9626
|
+
const {
|
|
9627
|
+
request,
|
|
9628
|
+
query
|
|
9629
|
+
} = this._args;
|
|
9630
|
+
return Boolean(!request && !query);
|
|
9585
9631
|
}
|
|
9586
|
-
|
|
9587
|
-
this.
|
|
9588
|
-
return this._sizeHint;
|
|
9632
|
+
static {
|
|
9633
|
+
decorateMethodV2(this.prototype, "isIdle", [memoized]);
|
|
9589
9634
|
}
|
|
9590
|
-
get
|
|
9591
|
-
|
|
9592
|
-
|
|
9593
|
-
|
|
9594
|
-
|
|
9595
|
-
|
|
9596
|
-
|
|
9635
|
+
get autorefreshTypes() {
|
|
9636
|
+
const {
|
|
9637
|
+
autorefresh
|
|
9638
|
+
} = this._args;
|
|
9639
|
+
let types;
|
|
9640
|
+
if (autorefresh === true) {
|
|
9641
|
+
types = ['online', 'invalid'];
|
|
9642
|
+
} else if (typeof autorefresh === 'string') {
|
|
9643
|
+
types = autorefresh.split(',');
|
|
9644
|
+
} else {
|
|
9645
|
+
types = [];
|
|
9597
9646
|
}
|
|
9598
|
-
return
|
|
9599
|
-
}
|
|
9600
|
-
get isStarted() {
|
|
9601
|
-
this._trigger();
|
|
9602
|
-
return this._isStarted;
|
|
9603
|
-
}
|
|
9604
|
-
get bytesLoaded() {
|
|
9605
|
-
this._trigger();
|
|
9606
|
-
return this._bytesLoaded;
|
|
9607
|
-
}
|
|
9608
|
-
get startTime() {
|
|
9609
|
-
this._trigger();
|
|
9610
|
-
return this._startTime;
|
|
9611
|
-
}
|
|
9612
|
-
get endTime() {
|
|
9613
|
-
this._trigger();
|
|
9614
|
-
return this._endTime;
|
|
9615
|
-
}
|
|
9616
|
-
get lastPacketTime() {
|
|
9617
|
-
this._trigger();
|
|
9618
|
-
return this._lastPacketTime;
|
|
9619
|
-
}
|
|
9620
|
-
get isComplete() {
|
|
9621
|
-
this._trigger();
|
|
9622
|
-
return this._isComplete;
|
|
9623
|
-
}
|
|
9624
|
-
get isCancelled() {
|
|
9625
|
-
this._trigger();
|
|
9626
|
-
return this._isCancelled;
|
|
9627
|
-
}
|
|
9628
|
-
get isErrored() {
|
|
9629
|
-
this._trigger();
|
|
9630
|
-
return this._isErrored;
|
|
9631
|
-
}
|
|
9632
|
-
get error() {
|
|
9633
|
-
this._trigger();
|
|
9634
|
-
return this._error;
|
|
9635
|
-
}
|
|
9636
|
-
get elapsedTime() {
|
|
9637
|
-
return (this.endTime || this.lastPacketTime) - this.startTime;
|
|
9638
|
-
}
|
|
9639
|
-
get completedRatio() {
|
|
9640
|
-
return this.sizeHint ? this.bytesLoaded / this.sizeHint : 0;
|
|
9641
|
-
}
|
|
9642
|
-
get remainingRatio() {
|
|
9643
|
-
return 1 - this.completedRatio;
|
|
9644
|
-
}
|
|
9645
|
-
get duration() {
|
|
9646
|
-
return this.endTime - this.startTime;
|
|
9647
|
-
}
|
|
9648
|
-
get speed() {
|
|
9649
|
-
// bytes per second
|
|
9650
|
-
return this.bytesLoaded / (this.elapsedTime / 1000);
|
|
9651
|
-
}
|
|
9652
|
-
constructor(future) {
|
|
9653
|
-
this._future = future;
|
|
9654
|
-
}
|
|
9655
|
-
abort = () => {
|
|
9656
|
-
this._future.abort();
|
|
9657
|
-
};
|
|
9658
|
-
}
|
|
9659
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_isPending', true);
|
|
9660
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_isStarted', false);
|
|
9661
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_isComplete', false);
|
|
9662
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_isCancelled', false);
|
|
9663
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_isErrored', false);
|
|
9664
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_error', null);
|
|
9665
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_sizeHint', 0);
|
|
9666
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_bytesLoaded', 0);
|
|
9667
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_startTime', 0);
|
|
9668
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_endTime', 0);
|
|
9669
|
-
defineNonEnumerableSignal(RequestLoadingState.prototype, '_lastPacketTime', 0);
|
|
9670
|
-
|
|
9671
|
-
/**
|
|
9672
|
-
* The state of a request in the "pending"
|
|
9673
|
-
* state. This is the default initial state.
|
|
9674
|
-
*
|
|
9675
|
-
* Extends the {@link PendingPromise} interface.
|
|
9676
|
-
*
|
|
9677
|
-
*/
|
|
9678
|
-
|
|
9679
|
-
/**
|
|
9680
|
-
* The state of a request in the "fulfilled" state.
|
|
9681
|
-
* This is the state of a request that has resolved
|
|
9682
|
-
* successfully.
|
|
9683
|
-
*
|
|
9684
|
-
* Extends the {@link ResolvedPromise} interface.
|
|
9685
|
-
*
|
|
9686
|
-
*/
|
|
9687
|
-
|
|
9688
|
-
/**
|
|
9689
|
-
* The state of a request in the "rejected" state.
|
|
9690
|
-
* This is the state of a request that has rejected
|
|
9691
|
-
* with an error.
|
|
9692
|
-
*
|
|
9693
|
-
* Extends the {@link RejectedPromise} interface.
|
|
9694
|
-
*
|
|
9695
|
-
*/
|
|
9696
|
-
|
|
9697
|
-
/**
|
|
9698
|
-
* The state of a request in the "cancelled" state.
|
|
9699
|
-
* This is the state of a promise that has been
|
|
9700
|
-
* cancelled.
|
|
9701
|
-
*
|
|
9702
|
-
*/
|
|
9703
|
-
|
|
9704
|
-
/**
|
|
9705
|
-
* RequestState extends the concept of {@link PromiseState} to provide a reactive
|
|
9706
|
-
* wrapper for a request {@link Future} which allows you write declarative code
|
|
9707
|
-
* around a Future's control flow.
|
|
9708
|
-
*
|
|
9709
|
-
* It is useful in both Template and JavaScript contexts, allowing you
|
|
9710
|
-
* to quickly derive behaviors and data from pending, error and success
|
|
9711
|
-
* states.
|
|
9712
|
-
*
|
|
9713
|
-
* The key difference between a {@link Promise} and a Future is that Futures provide
|
|
9714
|
-
* access to a {@link ReadableStream | stream} of their content, the {@link RequestKey} of the request (if any)
|
|
9715
|
-
* as well as the ability to attempt to {@link Future.abort | abort} the request.
|
|
9716
|
-
*
|
|
9717
|
-
* ```ts
|
|
9718
|
-
* interface Future<T> extends Promise<T>> {
|
|
9719
|
-
* getStream(): Promise<ReadableStream>;
|
|
9720
|
-
* abort(): void;
|
|
9721
|
-
* lid: RequestKey | null;
|
|
9722
|
-
* }
|
|
9723
|
-
* ```
|
|
9724
|
-
*
|
|
9725
|
-
* These additional APIs allow us to craft even richer state experiences.
|
|
9726
|
-
*
|
|
9727
|
-
* To get the state of a request, use {@link getRequestState}.
|
|
9728
|
-
*
|
|
9729
|
-
* See also:
|
|
9730
|
-
* - {@link PendingRequest}
|
|
9731
|
-
* - {@link ResolvedRequest}
|
|
9732
|
-
* - {@link RejectedRequest}
|
|
9733
|
-
* - {@link CancelledRequest}
|
|
9734
|
-
*
|
|
9735
|
-
*/
|
|
9736
|
-
|
|
9737
|
-
const RequestStateProto = {};
|
|
9738
|
-
function performRefresh(requester, request, isReload) {
|
|
9739
|
-
const req = Object.assign({}, request);
|
|
9740
|
-
const cacheOptions = Object.assign({}, req.cacheOptions);
|
|
9741
|
-
if (isReload) {
|
|
9742
|
-
// force direct to network
|
|
9743
|
-
cacheOptions.reload = true;
|
|
9744
|
-
} else if (isReload === false) {
|
|
9745
|
-
// delete reload to ensure we use backgroundReload / policy
|
|
9746
|
-
delete cacheOptions.reload;
|
|
9747
|
-
cacheOptions.backgroundReload = true;
|
|
9748
|
-
} else {
|
|
9749
|
-
// delete props to ensure we use the policy
|
|
9750
|
-
delete cacheOptions.backgroundReload;
|
|
9751
|
-
delete cacheOptions.reload;
|
|
9647
|
+
return new Set(types);
|
|
9752
9648
|
}
|
|
9753
|
-
req.cacheOptions = cacheOptions;
|
|
9754
|
-
return requester.request(req);
|
|
9755
|
-
}
|
|
9756
9649
|
|
|
9757
|
-
//
|
|
9758
|
-
//
|
|
9759
|
-
|
|
9760
|
-
|
|
9761
|
-
|
|
9762
|
-
|
|
9763
|
-
|
|
9764
|
-
|
|
9765
|
-
|
|
9766
|
-
|
|
9767
|
-
|
|
9768
|
-
defineSignal(RequestStateProto, 'request', null);
|
|
9769
|
-
defineSignal(RequestStateProto, 'response', null);
|
|
9770
|
-
Object.defineProperty(RequestStateProto, 'isCancelled', {
|
|
9771
|
-
get() {
|
|
9772
|
-
return this.isError && isAbortError(this.reason);
|
|
9650
|
+
// we only run this function on component creation
|
|
9651
|
+
// and when an update is triggered, so it does not
|
|
9652
|
+
// react to changes in the autorefreshThreshold
|
|
9653
|
+
// or autorefresh args.
|
|
9654
|
+
//
|
|
9655
|
+
// if we need to react to those changes, we can
|
|
9656
|
+
// use a modifier or internal component or some
|
|
9657
|
+
// such to trigger a re-run of this function.
|
|
9658
|
+
/** @internal */
|
|
9659
|
+
static {
|
|
9660
|
+
decorateMethodV2(this.prototype, "autorefreshTypes", [memoized]);
|
|
9773
9661
|
}
|
|
9774
|
-
|
|
9775
|
-
|
|
9776
|
-
|
|
9777
|
-
|
|
9778
|
-
|
|
9662
|
+
async _scheduleInterval() {
|
|
9663
|
+
const {
|
|
9664
|
+
autorefreshThreshold
|
|
9665
|
+
} = this._args;
|
|
9666
|
+
const hasValidThreshold = typeof autorefreshThreshold === 'number' && autorefreshThreshold > 0;
|
|
9667
|
+
if (
|
|
9668
|
+
// dont schedule in SSR
|
|
9669
|
+
typeof window === 'undefined' ||
|
|
9670
|
+
// dont schedule without a threshold
|
|
9671
|
+
!hasValidThreshold ||
|
|
9672
|
+
// dont schedule if we weren't told to
|
|
9673
|
+
!this.autorefreshTypes.has('interval') ||
|
|
9674
|
+
// dont schedule if we're already scheduled
|
|
9675
|
+
this._intervalStart !== null) {
|
|
9676
|
+
return;
|
|
9779
9677
|
}
|
|
9780
|
-
return this._loadingState;
|
|
9781
|
-
}
|
|
9782
|
-
});
|
|
9783
|
-
function createRequestState(future) {
|
|
9784
|
-
const state = getPromiseResult(future);
|
|
9785
|
-
const promiseState = Object.create(RequestStateProto);
|
|
9786
|
-
promiseState._request = future;
|
|
9787
|
-
// @ts-expect-error - we still attach it for PendingState
|
|
9788
|
-
promiseState.reload = () => {
|
|
9789
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
9790
|
-
if (!test) {
|
|
9791
|
-
throw new Error(`Cannot reload a request that is still pending. Await or abort the original request first.`);
|
|
9792
|
-
}
|
|
9793
|
-
})(!promiseState.isPending) : {};
|
|
9794
|
-
return performRefresh(future.requester, promiseState.request, true);
|
|
9795
|
-
};
|
|
9796
9678
|
|
|
9797
|
-
|
|
9798
|
-
|
|
9799
|
-
|
|
9800
|
-
|
|
9801
|
-
|
|
9679
|
+
// if we have a current request, wait for it to finish
|
|
9680
|
+
// before scheduling the next one
|
|
9681
|
+
if (this._latestRequest) {
|
|
9682
|
+
try {
|
|
9683
|
+
await this._latestRequest;
|
|
9684
|
+
} catch {
|
|
9685
|
+
// ignore errors here, we just want to wait for the request to finish
|
|
9686
|
+
}
|
|
9687
|
+
if (this.isDestroyed) {
|
|
9688
|
+
return;
|
|
9802
9689
|
}
|
|
9803
|
-
})(!promiseState.isPending) : {};
|
|
9804
|
-
return performRefresh(future.requester, promiseState.request, usePolicy === true ? null : false);
|
|
9805
|
-
};
|
|
9806
|
-
if (state) {
|
|
9807
|
-
if (state.isError) {
|
|
9808
|
-
promiseState.error = state.result;
|
|
9809
|
-
promiseState.reason = state.result;
|
|
9810
|
-
promiseState.status = 'rejected';
|
|
9811
|
-
promiseState.isError = true;
|
|
9812
|
-
promiseState.isPending = false;
|
|
9813
|
-
promiseState.isLoading = false;
|
|
9814
|
-
promiseState.request = state.result.request;
|
|
9815
|
-
promiseState.response = state.result.response;
|
|
9816
|
-
} else {
|
|
9817
|
-
promiseState.result = state.result.content;
|
|
9818
|
-
promiseState.value = state.result.content;
|
|
9819
|
-
promiseState.status = 'fulfilled';
|
|
9820
|
-
promiseState.isSuccess = true;
|
|
9821
|
-
promiseState.isPending = false;
|
|
9822
|
-
promiseState.isLoading = false;
|
|
9823
|
-
promiseState.request = state.result.request;
|
|
9824
|
-
promiseState.response = state.result.response;
|
|
9825
9690
|
}
|
|
9826
|
-
} else {
|
|
9827
|
-
void future.then(result => {
|
|
9828
|
-
setPromiseResult(future, {
|
|
9829
|
-
isError: false,
|
|
9830
|
-
result
|
|
9831
|
-
});
|
|
9832
|
-
promiseState.result = result.content;
|
|
9833
|
-
promiseState.value = result.content;
|
|
9834
|
-
promiseState.status = 'fulfilled';
|
|
9835
|
-
promiseState.isSuccess = true;
|
|
9836
|
-
promiseState.isPending = false;
|
|
9837
|
-
promiseState.isLoading = false;
|
|
9838
|
-
promiseState.request = result.request;
|
|
9839
|
-
promiseState.response = result.response;
|
|
9840
|
-
}, error => {
|
|
9841
|
-
setPromiseResult(future, {
|
|
9842
|
-
isError: true,
|
|
9843
|
-
result: error
|
|
9844
|
-
});
|
|
9845
|
-
promiseState.error = error;
|
|
9846
|
-
promiseState.reason = error;
|
|
9847
|
-
promiseState.status = 'rejected';
|
|
9848
|
-
promiseState.isError = true;
|
|
9849
|
-
promiseState.isPending = false;
|
|
9850
|
-
promiseState.isLoading = false;
|
|
9851
|
-
promiseState.request = error.request;
|
|
9852
|
-
promiseState.response = error.response;
|
|
9853
|
-
});
|
|
9854
|
-
}
|
|
9855
|
-
return promiseState;
|
|
9856
|
-
}
|
|
9857
9691
|
|
|
9858
|
-
|
|
9859
|
-
|
|
9860
|
-
|
|
9861
|
-
|
|
9862
|
-
|
|
9863
|
-
*
|
|
9864
|
-
* const state = getRequestState(future);
|
|
9865
|
-
* ```
|
|
9866
|
-
*
|
|
9867
|
-
* For instance, we could write a getter on a component that updates whenever
|
|
9868
|
-
* the request state advances or the future changes, by combining the function
|
|
9869
|
-
* with the use of `@cached`
|
|
9870
|
-
*
|
|
9871
|
-
* ```ts
|
|
9872
|
-
* class Component {
|
|
9873
|
-
* @cached
|
|
9874
|
-
* get title() {
|
|
9875
|
-
* const state = getRequestState(this.args.request);
|
|
9876
|
-
* if (state.isPending) {
|
|
9877
|
-
* return 'loading...';
|
|
9878
|
-
* }
|
|
9879
|
-
* if (state.isError) { return null; }
|
|
9880
|
-
* return state.result.title;
|
|
9881
|
-
* }
|
|
9882
|
-
* }
|
|
9883
|
-
* ```
|
|
9884
|
-
*
|
|
9885
|
-
* Or in a template as a helper:
|
|
9886
|
-
*
|
|
9887
|
-
* ```gjs
|
|
9888
|
-
* import { getRequestState } from '@warp-drive/ember';
|
|
9889
|
-
*
|
|
9890
|
-
* <template>
|
|
9891
|
-
* {{#let (getRequestState @request) as |state|}}
|
|
9892
|
-
* {{#if state.isPending}}
|
|
9893
|
-
* <Spinner />
|
|
9894
|
-
* {{else if state.isError}}
|
|
9895
|
-
* <ErrorForm @error={{state.error}} />
|
|
9896
|
-
* {{else}}
|
|
9897
|
-
* <h1>{{state.result.title}}</h1>
|
|
9898
|
-
* {{/if}}
|
|
9899
|
-
* {{/let}}
|
|
9900
|
-
* </template>
|
|
9901
|
-
* ```
|
|
9902
|
-
*
|
|
9903
|
-
* If looking to use in a template, consider also the `<Request />` component
|
|
9904
|
-
* which offers a numbe of additional capabilities for requests *beyond* what
|
|
9905
|
-
* `RequestState` provides.
|
|
9906
|
-
*
|
|
9907
|
-
*/
|
|
9908
|
-
function getRequestState(future) {
|
|
9909
|
-
let state = RequestCache.get(future);
|
|
9910
|
-
if (!state) {
|
|
9911
|
-
state = createRequestState(future);
|
|
9912
|
-
RequestCache.set(future, state);
|
|
9913
|
-
}
|
|
9914
|
-
return state;
|
|
9915
|
-
}
|
|
9916
|
-
function decorateMethodV2(prototype, prop, decorators) {
|
|
9917
|
-
const origDesc = Object.getOwnPropertyDescriptor(prototype, prop);
|
|
9918
|
-
let desc = {
|
|
9919
|
-
...origDesc
|
|
9920
|
-
};
|
|
9921
|
-
for (let decorator of decorators) {
|
|
9922
|
-
desc = decorator(prototype, prop, desc) || desc;
|
|
9923
|
-
}
|
|
9924
|
-
if (desc.initializer !== void 0) {
|
|
9925
|
-
desc.value = desc.initializer ? desc.initializer.call(prototype) : void 0;
|
|
9926
|
-
desc.initializer = void 0;
|
|
9692
|
+
// setup the next interval
|
|
9693
|
+
this._intervalStart = Date.now();
|
|
9694
|
+
this._nextInterval = setTimeout(() => {
|
|
9695
|
+
this._maybeUpdate();
|
|
9696
|
+
}, autorefreshThreshold);
|
|
9927
9697
|
}
|
|
9928
|
-
Object.defineProperty(prototype, prop, desc);
|
|
9929
|
-
}
|
|
9930
|
-
const DEFAULT_DEADLINE = 30_000;
|
|
9931
|
-
const DISPOSE = Symbol.dispose || Symbol.for('dispose');
|
|
9932
|
-
function isNeverString(val) {
|
|
9933
|
-
return val;
|
|
9934
|
-
}
|
|
9935
|
-
|
|
9936
|
-
/**
|
|
9937
|
-
* Utilities to assist in recovering from the error.
|
|
9938
|
-
*/
|
|
9939
9698
|
|
|
9940
|
-
/** @
|
|
9941
|
-
|
|
9942
|
-
|
|
9943
|
-
|
|
9944
|
-
|
|
9699
|
+
/** @internal */
|
|
9700
|
+
_clearInterval() {
|
|
9701
|
+
if (this._nextInterval) {
|
|
9702
|
+
clearTimeout(this._nextInterval);
|
|
9703
|
+
this._intervalStart = null;
|
|
9704
|
+
}
|
|
9705
|
+
}
|
|
9706
|
+
/**
|
|
9707
|
+
* @internal
|
|
9708
|
+
*/
|
|
9709
|
+
_updateSubscriptions() {
|
|
9710
|
+
if (this.isIdle) {
|
|
9711
|
+
return;
|
|
9712
|
+
}
|
|
9713
|
+
const requestId = this._request.lid;
|
|
9945
9714
|
|
|
9946
|
-
//
|
|
9715
|
+
// if we're already subscribed to this request, we don't need to do anything
|
|
9716
|
+
if (this._subscribedTo === requestId) {
|
|
9717
|
+
return;
|
|
9718
|
+
}
|
|
9947
9719
|
|
|
9948
|
-
//
|
|
9720
|
+
// if we're subscribed to a different request, we need to unsubscribe
|
|
9721
|
+
this._removeSubscriptions();
|
|
9949
9722
|
|
|
9950
|
-
|
|
9951
|
-
|
|
9952
|
-
|
|
9953
|
-
|
|
9954
|
-
|
|
9955
|
-
|
|
9956
|
-
|
|
9957
|
-
|
|
9958
|
-
|
|
9723
|
+
// if we have a request, we need to subscribe to it
|
|
9724
|
+
const store = this._getRequester();
|
|
9725
|
+
this._requester = store;
|
|
9726
|
+
if (requestId && isStore(store)) {
|
|
9727
|
+
this._subscribedTo = requestId;
|
|
9728
|
+
this._subscription = store.notifications.subscribe(requestId, (_id, op) => {
|
|
9729
|
+
// ignore subscription events that occur while our own component's request
|
|
9730
|
+
// is occurring
|
|
9731
|
+
if (this._isUpdating) {
|
|
9732
|
+
return;
|
|
9733
|
+
}
|
|
9734
|
+
switch (op) {
|
|
9735
|
+
case 'invalidated':
|
|
9736
|
+
{
|
|
9737
|
+
// if we're subscribed to invalidations, we need to update
|
|
9738
|
+
if (this.autorefreshTypes.has('invalid')) {
|
|
9739
|
+
this._invalidated = true;
|
|
9740
|
+
this._maybeUpdate();
|
|
9741
|
+
}
|
|
9742
|
+
break;
|
|
9743
|
+
}
|
|
9744
|
+
case 'state':
|
|
9745
|
+
{
|
|
9746
|
+
const latest = store.requestManager._deduped.get(requestId);
|
|
9747
|
+
const priority = latest?.priority;
|
|
9748
|
+
const state = this.reqState;
|
|
9749
|
+
if (!priority) {
|
|
9750
|
+
// if there is no priority, we have completed whatever request
|
|
9751
|
+
// was occurring and so we are no longer refreshing (if we were)
|
|
9752
|
+
this.isRefreshing = false;
|
|
9753
|
+
} else if (priority.blocking && !state.isLoading) {
|
|
9754
|
+
// if we are blocking, there is an active request for this identity
|
|
9755
|
+
// that MUST be fulfilled from network (not cache).
|
|
9756
|
+
// Thus this is not "refreshing" because we should clear out and
|
|
9757
|
+
// block on this request.
|
|
9758
|
+
//
|
|
9759
|
+
// we receive state notifications when either a request initiates
|
|
9760
|
+
// or completes.
|
|
9761
|
+
//
|
|
9762
|
+
// In the completes case: we may receive the state notification
|
|
9763
|
+
// slightly before the request is finalized because the NotificationManager
|
|
9764
|
+
// may sync flush it (and thus deliver it before the microtask completes)
|
|
9765
|
+
//
|
|
9766
|
+
// In the initiates case: we aren't supposed to receive one unless there
|
|
9767
|
+
// is no other request in flight for this identity.
|
|
9768
|
+
//
|
|
9769
|
+
// However, there is a race condition here where the completed
|
|
9770
|
+
// notification can trigger an update that generates a new request
|
|
9771
|
+
// thus giving us an initiated notification before the older request
|
|
9772
|
+
// finalizes.
|
|
9773
|
+
//
|
|
9774
|
+
// When this occurs, if the triggered update happens to have caused
|
|
9775
|
+
// a new request to be made for the same identity AND that request
|
|
9776
|
+
// is the one passed into this component as the @request arg, then
|
|
9777
|
+
// getRequestState will return the state of the new request.
|
|
9778
|
+
// We can detect this by checking if the request state is "loading"
|
|
9779
|
+
// as outside of this case we would have a completed request.
|
|
9780
|
+
//
|
|
9781
|
+
// That is the reason for the `&& !state.isLoading` check above.
|
|
9959
9782
|
|
|
9960
|
-
|
|
9961
|
-
|
|
9962
|
-
|
|
9783
|
+
// TODO should we just treat this as refreshing?
|
|
9784
|
+
this.isRefreshing = false;
|
|
9785
|
+
this._maybeUpdate('policy', true);
|
|
9786
|
+
} else {
|
|
9787
|
+
this.isRefreshing = true;
|
|
9788
|
+
}
|
|
9789
|
+
}
|
|
9790
|
+
}
|
|
9791
|
+
});
|
|
9792
|
+
}
|
|
9793
|
+
}
|
|
9963
9794
|
|
|
9964
9795
|
/**
|
|
9965
|
-
*
|
|
9796
|
+
* @internal
|
|
9966
9797
|
*/
|
|
9798
|
+
_removeSubscriptions() {
|
|
9799
|
+
const store = this._requester;
|
|
9800
|
+
if (this._subscription && store && isStore(store)) {
|
|
9801
|
+
store.notifications.unsubscribe(this._subscription);
|
|
9802
|
+
this._subscribedTo = null;
|
|
9803
|
+
this._subscription = null;
|
|
9804
|
+
this._requester = null;
|
|
9805
|
+
}
|
|
9806
|
+
}
|
|
9967
9807
|
|
|
9968
9808
|
/**
|
|
9969
|
-
*
|
|
9970
|
-
*
|
|
9971
|
-
*
|
|
9972
|
-
* This will never be the original request passed as an arg to
|
|
9973
|
-
* the component.
|
|
9809
|
+
* Install the event listeners for network and visibility changes.
|
|
9810
|
+
* This is only done in browser environments with a global `window`.
|
|
9974
9811
|
*
|
|
9975
9812
|
* @internal
|
|
9976
9813
|
*/
|
|
9814
|
+
_installListeners() {
|
|
9815
|
+
if (typeof window === 'undefined') {
|
|
9816
|
+
return;
|
|
9817
|
+
}
|
|
9818
|
+
this.isOnline = window.navigator.onLine;
|
|
9819
|
+
this._unavailableStart = this.isOnline ? null : Date.now();
|
|
9820
|
+
this.isHidden = document.visibilityState === 'hidden';
|
|
9821
|
+
this._onlineChanged = event => {
|
|
9822
|
+
this.isOnline = event.type === 'online';
|
|
9823
|
+
if (event.type === 'offline' && this._unavailableStart === null) {
|
|
9824
|
+
this._unavailableStart = Date.now();
|
|
9825
|
+
}
|
|
9826
|
+
this._maybeUpdate();
|
|
9827
|
+
};
|
|
9828
|
+
this._backgroundChanged = () => {
|
|
9829
|
+
const isHidden = document.visibilityState === 'hidden';
|
|
9830
|
+
this.isHidden = isHidden;
|
|
9831
|
+
if (isHidden && this._unavailableStart === null) {
|
|
9832
|
+
this._unavailableStart = Date.now();
|
|
9833
|
+
}
|
|
9834
|
+
this._maybeUpdate();
|
|
9835
|
+
};
|
|
9836
|
+
window.addEventListener('online', this._onlineChanged, {
|
|
9837
|
+
passive: true,
|
|
9838
|
+
capture: true
|
|
9839
|
+
});
|
|
9840
|
+
window.addEventListener('offline', this._onlineChanged, {
|
|
9841
|
+
passive: true,
|
|
9842
|
+
capture: true
|
|
9843
|
+
});
|
|
9844
|
+
document.addEventListener('visibilitychange', this._backgroundChanged, {
|
|
9845
|
+
passive: true,
|
|
9846
|
+
capture: true
|
|
9847
|
+
});
|
|
9848
|
+
}
|
|
9977
9849
|
|
|
9978
9850
|
/**
|
|
9979
|
-
*
|
|
9980
|
-
*
|
|
9851
|
+
* If the network is online and the tab is visible, either reload or refresh the request
|
|
9852
|
+
* based on the component's configuration and the requested update mode.
|
|
9981
9853
|
*
|
|
9982
|
-
*
|
|
9983
|
-
* the component.
|
|
9854
|
+
* Valid modes are:
|
|
9984
9855
|
*
|
|
9985
|
-
*
|
|
9986
|
-
|
|
9987
|
-
|
|
9988
|
-
|
|
9989
|
-
* The time at which the network was reported as offline.
|
|
9856
|
+
* - `'reload'`: Force a reload of the request.
|
|
9857
|
+
* - `'refresh'`: Refresh the request in the background.
|
|
9858
|
+
* - `'policy'`: Make the request, letting the store's configured CachePolicy decide whether to reload, refresh, or do nothing.
|
|
9859
|
+
* - `undefined`: Make the request using the component's autorefreshBehavior setting if the autorefreshThreshold has passed.
|
|
9990
9860
|
*
|
|
9991
9861
|
* @internal
|
|
9992
9862
|
*/
|
|
9863
|
+
_maybeUpdate(mode, silent) {
|
|
9864
|
+
if (this.isIdle) {
|
|
9865
|
+
return;
|
|
9866
|
+
}
|
|
9867
|
+
const {
|
|
9868
|
+
reqState
|
|
9869
|
+
} = this;
|
|
9870
|
+
if (reqState.isPending) {
|
|
9871
|
+
return;
|
|
9872
|
+
}
|
|
9873
|
+
const canAttempt = Boolean(this.isOnline && !this.isHidden && (mode || this.autorefreshTypes.size));
|
|
9874
|
+
if (!canAttempt) {
|
|
9875
|
+
if (!silent && mode && mode !== '_invalidated') {
|
|
9876
|
+
throw new Error(`Reload not available: the network is not online or the tab is hidden`);
|
|
9877
|
+
}
|
|
9878
|
+
return;
|
|
9879
|
+
}
|
|
9880
|
+
const {
|
|
9881
|
+
autorefreshTypes
|
|
9882
|
+
} = this;
|
|
9883
|
+
let shouldAttempt = this._invalidated || Boolean(mode);
|
|
9884
|
+
if (!shouldAttempt && autorefreshTypes.has('online')) {
|
|
9885
|
+
const {
|
|
9886
|
+
_unavailableStart
|
|
9887
|
+
} = this;
|
|
9888
|
+
const {
|
|
9889
|
+
autorefreshThreshold
|
|
9890
|
+
} = this._args;
|
|
9891
|
+
const deadline = typeof autorefreshThreshold === 'number' ? autorefreshThreshold : DEFAULT_DEADLINE;
|
|
9892
|
+
shouldAttempt = Boolean(_unavailableStart && Date.now() - _unavailableStart > deadline);
|
|
9893
|
+
}
|
|
9894
|
+
if (!shouldAttempt && autorefreshTypes.has('interval')) {
|
|
9895
|
+
const {
|
|
9896
|
+
_intervalStart
|
|
9897
|
+
} = this;
|
|
9898
|
+
const {
|
|
9899
|
+
autorefreshThreshold
|
|
9900
|
+
} = this._args;
|
|
9901
|
+
if (_intervalStart && typeof autorefreshThreshold === 'number' && autorefreshThreshold > 0) {
|
|
9902
|
+
shouldAttempt = Boolean(Date.now() - _intervalStart >= autorefreshThreshold);
|
|
9903
|
+
}
|
|
9904
|
+
}
|
|
9905
|
+
this._unavailableStart = null;
|
|
9906
|
+
this._invalidated = false;
|
|
9907
|
+
if (shouldAttempt) {
|
|
9908
|
+
this._clearInterval();
|
|
9909
|
+
this._isUpdating = true;
|
|
9910
|
+
const realMode = mode === '_invalidated' ? null : mode;
|
|
9911
|
+
const val = realMode ?? this._args.autorefreshBehavior ?? 'policy';
|
|
9993
9912
|
|
|
9994
|
-
|
|
9995
|
-
|
|
9996
|
-
|
|
9997
|
-
|
|
9998
|
-
|
|
9999
|
-
|
|
10000
|
-
|
|
10001
|
-
|
|
10002
|
-
|
|
10003
|
-
|
|
10004
|
-
|
|
10005
|
-
|
|
10006
|
-
|
|
10007
|
-
|
|
10008
|
-
|
|
10009
|
-
|
|
9913
|
+
// if the future was generated by an older store version, it may not have
|
|
9914
|
+
// a requester set. In this case we append it to ensure that reload and
|
|
9915
|
+
// refresh will work appropriately.
|
|
9916
|
+
const requester = this._getRequester();
|
|
9917
|
+
if (!reqState._request.requester) {
|
|
9918
|
+
reqState._request.requester = requester;
|
|
9919
|
+
}
|
|
9920
|
+
switch (val) {
|
|
9921
|
+
case 'reload':
|
|
9922
|
+
this._latestRequest = reqState.reload();
|
|
9923
|
+
break;
|
|
9924
|
+
case 'refresh':
|
|
9925
|
+
this._latestRequest = reqState.refresh();
|
|
9926
|
+
break;
|
|
9927
|
+
case 'policy':
|
|
9928
|
+
this._latestRequest = reqState.refresh(true);
|
|
9929
|
+
break;
|
|
9930
|
+
default:
|
|
9931
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
9932
|
+
{
|
|
9933
|
+
throw new Error(`Invalid ${mode ? 'update mode' : '@autorefreshBehavior'} for <Request />: ${isNeverString(val)}`);
|
|
9934
|
+
}
|
|
9935
|
+
})() : {};
|
|
9936
|
+
}
|
|
9937
|
+
if (val !== 'refresh') {
|
|
9938
|
+
this._localRequest = this._latestRequest;
|
|
9939
|
+
}
|
|
9940
|
+
void this._scheduleInterval();
|
|
9941
|
+
void this._latestRequest.finally(() => {
|
|
9942
|
+
this._isUpdating = false;
|
|
9943
|
+
});
|
|
9944
|
+
}
|
|
9945
|
+
}
|
|
10010
9946
|
|
|
10011
9947
|
/**
|
|
10012
|
-
* The event listener for visibility status changes,
|
|
10013
|
-
* cached to use the reference for removal.
|
|
10014
|
-
*
|
|
10015
9948
|
* @internal
|
|
10016
9949
|
*/
|
|
9950
|
+
_getRequester() {
|
|
9951
|
+
// Note: we check for the requester's presence
|
|
9952
|
+
// as well as the request's presence because we may
|
|
9953
|
+
// be subscribed to a request issued by a store from an older
|
|
9954
|
+
// version of the library that didn't yet set requester.
|
|
9955
|
+
if (this._args.request?.requester) {
|
|
9956
|
+
return this._args.request.requester;
|
|
9957
|
+
}
|
|
9958
|
+
return this.store;
|
|
9959
|
+
}
|
|
10017
9960
|
|
|
10018
9961
|
/**
|
|
10019
|
-
*
|
|
10020
|
-
* cached for comparison.
|
|
10021
|
-
*
|
|
10022
|
-
* @internal
|
|
9962
|
+
* Retry the request, reloading it from the server.
|
|
10023
9963
|
*/
|
|
9964
|
+
retry = async () => {
|
|
9965
|
+
this._maybeUpdate('reload');
|
|
9966
|
+
await this._localRequest;
|
|
9967
|
+
};
|
|
10024
9968
|
|
|
10025
9969
|
/**
|
|
10026
|
-
*
|
|
10027
|
-
* cached for comparison.
|
|
10028
|
-
*
|
|
10029
|
-
* @internal
|
|
9970
|
+
* Refresh the request, updating it in the background.
|
|
10030
9971
|
*/
|
|
10031
|
-
|
|
10032
|
-
|
|
10033
|
-
|
|
10034
|
-
|
|
10035
|
-
|
|
10036
|
-
/** @internal */
|
|
9972
|
+
refresh = async () => {
|
|
9973
|
+
this._maybeUpdate('refresh');
|
|
9974
|
+
await this._latestRequest;
|
|
9975
|
+
};
|
|
10037
9976
|
|
|
10038
9977
|
/**
|
|
10039
|
-
*
|
|
10040
|
-
* which issues this request.
|
|
9978
|
+
* features to yield to the error slot of a component
|
|
10041
9979
|
*/
|
|
9980
|
+
get errorFeatures() {
|
|
9981
|
+
return {
|
|
9982
|
+
isHidden: this.isHidden,
|
|
9983
|
+
isOnline: this.isOnline,
|
|
9984
|
+
retry: this.retry
|
|
9985
|
+
};
|
|
9986
|
+
}
|
|
10042
9987
|
|
|
10043
9988
|
/**
|
|
10044
|
-
*
|
|
10045
|
-
*
|
|
10046
|
-
* This differs from 'store' because a <Request /> may be passed a
|
|
10047
|
-
* request originating from a different store than the <Request />
|
|
10048
|
-
* component would use if it were to issue the request itself.
|
|
10049
|
-
*
|
|
10050
|
-
* @internal
|
|
9989
|
+
* features to yield to the content slot of a component
|
|
10051
9990
|
*/
|
|
10052
|
-
|
|
10053
|
-
|
|
10054
|
-
|
|
10055
|
-
|
|
10056
|
-
|
|
10057
|
-
|
|
10058
|
-
|
|
10059
|
-
|
|
10060
|
-
|
|
10061
|
-
|
|
10062
|
-
|
|
10063
|
-
|
|
10064
|
-
|
|
10065
|
-
|
|
9991
|
+
static {
|
|
9992
|
+
decorateMethodV2(this.prototype, "errorFeatures", [memoized]);
|
|
9993
|
+
}
|
|
9994
|
+
get contentFeatures() {
|
|
9995
|
+
const feat = {
|
|
9996
|
+
isHidden: this.isHidden,
|
|
9997
|
+
isOnline: this.isOnline,
|
|
9998
|
+
reload: this.retry,
|
|
9999
|
+
refresh: this.refresh,
|
|
10000
|
+
isRefreshing: this.isRefreshing,
|
|
10001
|
+
latestRequest: this._latestRequest
|
|
10002
|
+
};
|
|
10003
|
+
if (feat.isRefreshing) {
|
|
10004
|
+
feat.abort = () => {
|
|
10005
|
+
this._latestRequest?.abort();
|
|
10006
|
+
};
|
|
10007
|
+
}
|
|
10008
|
+
return feat;
|
|
10066
10009
|
}
|
|
10067
10010
|
|
|
10068
10011
|
/**
|
|
10069
10012
|
* @internal
|
|
10070
10013
|
*/
|
|
10071
|
-
|
|
10072
|
-
|
|
10073
|
-
try {
|
|
10074
|
-
if (!this.isIdle) {
|
|
10075
|
-
await this.request;
|
|
10076
|
-
}
|
|
10077
|
-
} catch {
|
|
10078
|
-
// ignore errors here, we just want to wait for the request to finish
|
|
10079
|
-
} finally {
|
|
10080
|
-
if (!this.isDestroyed) {
|
|
10081
|
-
void this._scheduleInterval();
|
|
10082
|
-
}
|
|
10083
|
-
}
|
|
10014
|
+
static {
|
|
10015
|
+
decorateMethodV2(this.prototype, "contentFeatures", [memoized]);
|
|
10084
10016
|
}
|
|
10085
|
-
get
|
|
10017
|
+
get _request() {
|
|
10086
10018
|
const {
|
|
10087
10019
|
request,
|
|
10088
10020
|
query
|
|
10089
10021
|
} = this._args;
|
|
10090
|
-
|
|
10022
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
10023
|
+
if (!test) {
|
|
10024
|
+
throw new Error(`Cannot use both @request and @query args with the <Request> component`);
|
|
10025
|
+
}
|
|
10026
|
+
})(!request || !query) : {};
|
|
10027
|
+
const {
|
|
10028
|
+
_localRequest,
|
|
10029
|
+
_originalRequest,
|
|
10030
|
+
_originalQuery
|
|
10031
|
+
} = this;
|
|
10032
|
+
const isOriginalRequest = request === _originalRequest && query === _originalQuery;
|
|
10033
|
+
if (_localRequest && isOriginalRequest) {
|
|
10034
|
+
return _localRequest;
|
|
10035
|
+
}
|
|
10036
|
+
|
|
10037
|
+
// update state checks for the next time
|
|
10038
|
+
this._originalQuery = query;
|
|
10039
|
+
this._originalRequest = request;
|
|
10040
|
+
if (request) {
|
|
10041
|
+
return request;
|
|
10042
|
+
}
|
|
10043
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
10044
|
+
if (!test) {
|
|
10045
|
+
throw new Error(`You must provide either @request or an @query arg with the <Request> component`);
|
|
10046
|
+
}
|
|
10047
|
+
})(query) : {};
|
|
10048
|
+
return this.store.request(query);
|
|
10091
10049
|
}
|
|
10092
10050
|
static {
|
|
10093
|
-
decorateMethodV2(this.prototype, "
|
|
10051
|
+
decorateMethodV2(this.prototype, "_request", [memoized]);
|
|
10094
10052
|
}
|
|
10095
|
-
get
|
|
10096
|
-
|
|
10097
|
-
|
|
10098
|
-
|
|
10099
|
-
|
|
10100
|
-
|
|
10101
|
-
|
|
10102
|
-
|
|
10103
|
-
|
|
10053
|
+
get request() {
|
|
10054
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
10055
|
+
try {
|
|
10056
|
+
const request = this._request;
|
|
10057
|
+
this._updateSubscriptions();
|
|
10058
|
+
return request;
|
|
10059
|
+
} catch (e) {
|
|
10060
|
+
// eslint-disable-next-line no-console
|
|
10061
|
+
console.log(e);
|
|
10062
|
+
throw new Error(`Unable to initialize the request`, {
|
|
10063
|
+
cause: e
|
|
10064
|
+
});
|
|
10065
|
+
}
|
|
10104
10066
|
} else {
|
|
10105
|
-
|
|
10067
|
+
const request = this._request;
|
|
10068
|
+
this._updateSubscriptions();
|
|
10069
|
+
return request;
|
|
10106
10070
|
}
|
|
10107
|
-
return new Set(types);
|
|
10108
10071
|
}
|
|
10109
|
-
|
|
10110
|
-
// we only run this function on component creation
|
|
10111
|
-
// and when an update is triggered, so it does not
|
|
10112
|
-
// react to changes in the autorefreshThreshold
|
|
10113
|
-
// or autorefresh args.
|
|
10114
|
-
//
|
|
10115
|
-
// if we need to react to those changes, we can
|
|
10116
|
-
// use a modifier or internal component or some
|
|
10117
|
-
// such to trigger a re-run of this function.
|
|
10118
|
-
/** @internal */
|
|
10119
10072
|
static {
|
|
10120
|
-
decorateMethodV2(this.prototype, "
|
|
10073
|
+
decorateMethodV2(this.prototype, "request", [memoized]);
|
|
10121
10074
|
}
|
|
10122
|
-
|
|
10075
|
+
get reqState() {
|
|
10076
|
+
return getRequestState(this.request);
|
|
10077
|
+
}
|
|
10078
|
+
get result() {
|
|
10079
|
+
return this.reqState.result;
|
|
10080
|
+
}
|
|
10081
|
+
}
|
|
10082
|
+
defineSignal(RequestSubscription.prototype, 'isOnline', true);
|
|
10083
|
+
defineSignal(RequestSubscription.prototype, 'isHidden', false);
|
|
10084
|
+
defineSignal(RequestSubscription.prototype, 'isRefreshing', false);
|
|
10085
|
+
defineSignal(RequestSubscription.prototype, '_localRequest', undefined);
|
|
10086
|
+
defineSignal(RequestSubscription.prototype, '_latestRequest', undefined);
|
|
10087
|
+
function isStore(store) {
|
|
10088
|
+
return 'requestManager' in store;
|
|
10089
|
+
}
|
|
10090
|
+
function createRequestSubscription(store, args) {
|
|
10091
|
+
return new RequestSubscription(store, args);
|
|
10092
|
+
}
|
|
10093
|
+
function upgradeSubscription(sub) {
|
|
10094
|
+
return sub;
|
|
10095
|
+
}
|
|
10096
|
+
function _DISPOSE() {
|
|
10097
|
+
const self = upgradeSubscription(this);
|
|
10098
|
+
self.isDestroyed = true;
|
|
10099
|
+
self._removeSubscriptions();
|
|
10100
|
+
if (typeof window === 'undefined') {
|
|
10101
|
+
return;
|
|
10102
|
+
}
|
|
10103
|
+
self._clearInterval();
|
|
10104
|
+
window.removeEventListener('online', self._onlineChanged, {
|
|
10105
|
+
passive: true,
|
|
10106
|
+
capture: true
|
|
10107
|
+
});
|
|
10108
|
+
window.removeEventListener('offline', self._onlineChanged, {
|
|
10109
|
+
passive: true,
|
|
10110
|
+
capture: true
|
|
10111
|
+
});
|
|
10112
|
+
document.removeEventListener('visibilitychange', self._backgroundChanged, {
|
|
10113
|
+
passive: true,
|
|
10114
|
+
capture: true
|
|
10115
|
+
});
|
|
10116
|
+
}
|
|
10117
|
+
const RequestCache = new WeakMap();
|
|
10118
|
+
function isAbortError(error) {
|
|
10119
|
+
return error instanceof DOMException && error.name === 'AbortError';
|
|
10120
|
+
}
|
|
10121
|
+
function upgradeLoadingState(state) {
|
|
10122
|
+
return state;
|
|
10123
|
+
}
|
|
10124
|
+
async function watchStream(stream, loadingState) {
|
|
10125
|
+
const state = upgradeLoadingState(loadingState);
|
|
10126
|
+
const reader = stream.getReader();
|
|
10127
|
+
let bytesLoaded = 0;
|
|
10128
|
+
let shouldForward = state._stream !== null && state._stream.readable.locked;
|
|
10129
|
+
let isForwarding = shouldForward;
|
|
10130
|
+
let writer = state._stream?.writable.getWriter();
|
|
10131
|
+
const buffer = [];
|
|
10132
|
+
state._isPending = false;
|
|
10133
|
+
state._isStarted = true;
|
|
10134
|
+
state._startTime = performance.now();
|
|
10135
|
+
while (true) {
|
|
10123
10136
|
const {
|
|
10124
|
-
|
|
10125
|
-
|
|
10126
|
-
|
|
10127
|
-
if (
|
|
10128
|
-
|
|
10129
|
-
typeof window === 'undefined' ||
|
|
10130
|
-
// dont schedule without a threshold
|
|
10131
|
-
!hasValidThreshold ||
|
|
10132
|
-
// dont schedule if we weren't told to
|
|
10133
|
-
!this.autorefreshTypes.has('interval') ||
|
|
10134
|
-
// dont schedule if we're already scheduled
|
|
10135
|
-
this._intervalStart !== null) {
|
|
10136
|
-
return;
|
|
10137
|
+
value,
|
|
10138
|
+
done
|
|
10139
|
+
} = await reader.read();
|
|
10140
|
+
if (done) {
|
|
10141
|
+
break;
|
|
10137
10142
|
}
|
|
10138
|
-
|
|
10139
|
-
|
|
10140
|
-
|
|
10141
|
-
|
|
10142
|
-
|
|
10143
|
-
|
|
10144
|
-
|
|
10145
|
-
|
|
10146
|
-
|
|
10147
|
-
|
|
10148
|
-
|
|
10143
|
+
bytesLoaded += value.byteLength;
|
|
10144
|
+
state._bytesLoaded = bytesLoaded;
|
|
10145
|
+
state._lastPacketTime = performance.now();
|
|
10146
|
+
shouldForward = shouldForward || state._stream !== null && state._stream.readable.locked;
|
|
10147
|
+
if (shouldForward) {
|
|
10148
|
+
if (!isForwarding) {
|
|
10149
|
+
isForwarding = true;
|
|
10150
|
+
writer = state._stream.writable.getWriter();
|
|
10151
|
+
for (const item of buffer) {
|
|
10152
|
+
await writer.ready;
|
|
10153
|
+
await writer.write(item);
|
|
10154
|
+
}
|
|
10155
|
+
buffer.length = 0;
|
|
10149
10156
|
}
|
|
10157
|
+
await writer.ready;
|
|
10158
|
+
await writer.write(value);
|
|
10159
|
+
} else {
|
|
10160
|
+
buffer.push(value);
|
|
10150
10161
|
}
|
|
10162
|
+
}
|
|
10151
10163
|
|
|
10152
|
-
|
|
10153
|
-
|
|
10154
|
-
|
|
10155
|
-
|
|
10156
|
-
|
|
10164
|
+
// if we are still forwarding, we need to close the writer
|
|
10165
|
+
if (isForwarding) {
|
|
10166
|
+
await writer.ready;
|
|
10167
|
+
await writer.close();
|
|
10168
|
+
} else if (state._stream) {
|
|
10169
|
+
// if we are not forwarding, we need to cancel the stream
|
|
10170
|
+
await state._stream.readable.cancel('The Stream Has Already Ended');
|
|
10171
|
+
state._stream = null;
|
|
10157
10172
|
}
|
|
10173
|
+
const endTime = performance.now();
|
|
10174
|
+
state._endTime = endTime;
|
|
10175
|
+
state._isComplete = true;
|
|
10176
|
+
state._isStarted = false;
|
|
10177
|
+
}
|
|
10158
10178
|
|
|
10179
|
+
/**
|
|
10180
|
+
* Lazily consumes the stream of a request, providing a number of
|
|
10181
|
+
* reactive properties that can be used to build UIs that respond
|
|
10182
|
+
* to the progress of a request.
|
|
10183
|
+
*
|
|
10184
|
+
* @hideconstructor
|
|
10185
|
+
*/
|
|
10186
|
+
class RequestLoadingState {
|
|
10159
10187
|
/** @internal */
|
|
10160
|
-
_clearInterval() {
|
|
10161
|
-
if (this._nextInterval) {
|
|
10162
|
-
clearTimeout(this._nextInterval);
|
|
10163
|
-
this._intervalStart = null;
|
|
10164
|
-
}
|
|
10165
|
-
}
|
|
10166
|
-
/**
|
|
10167
|
-
* @internal
|
|
10168
|
-
*/
|
|
10169
|
-
_updateSubscriptions() {
|
|
10170
|
-
if (this.isIdle) {
|
|
10171
|
-
return;
|
|
10172
|
-
}
|
|
10173
|
-
const requestId = this._request.lid;
|
|
10174
10188
|
|
|
10175
|
-
|
|
10176
|
-
if (this._subscribedTo === requestId) {
|
|
10177
|
-
return;
|
|
10178
|
-
}
|
|
10189
|
+
/** @internal */
|
|
10179
10190
|
|
|
10180
|
-
|
|
10181
|
-
this._removeSubscriptions();
|
|
10191
|
+
/** @internal */
|
|
10182
10192
|
|
|
10183
|
-
|
|
10184
|
-
const store = this._getRequester();
|
|
10185
|
-
this._requester = store;
|
|
10186
|
-
if (requestId && isStore(store)) {
|
|
10187
|
-
this._subscribedTo = requestId;
|
|
10188
|
-
this._subscription = store.notifications.subscribe(requestId, (_id, op) => {
|
|
10189
|
-
// ignore subscription events that occur while our own component's request
|
|
10190
|
-
// is occurring
|
|
10191
|
-
if (this._isUpdating) {
|
|
10192
|
-
return;
|
|
10193
|
-
}
|
|
10194
|
-
switch (op) {
|
|
10195
|
-
case 'invalidated':
|
|
10196
|
-
{
|
|
10197
|
-
// if we're subscribed to invalidations, we need to update
|
|
10198
|
-
if (this.autorefreshTypes.has('invalid')) {
|
|
10199
|
-
this._invalidated = true;
|
|
10200
|
-
this._maybeUpdate();
|
|
10201
|
-
}
|
|
10202
|
-
break;
|
|
10203
|
-
}
|
|
10204
|
-
case 'state':
|
|
10205
|
-
{
|
|
10206
|
-
const latest = store.requestManager._deduped.get(requestId);
|
|
10207
|
-
const priority = latest?.priority;
|
|
10208
|
-
const state = this.reqState;
|
|
10209
|
-
if (!priority) {
|
|
10210
|
-
// if there is no priority, we have completed whatever request
|
|
10211
|
-
// was occurring and so we are no longer refreshing (if we were)
|
|
10212
|
-
this.isRefreshing = false;
|
|
10213
|
-
} else if (priority.blocking && !state.isLoading) {
|
|
10214
|
-
// if we are blocking, there is an active request for this identity
|
|
10215
|
-
// that MUST be fulfilled from network (not cache).
|
|
10216
|
-
// Thus this is not "refreshing" because we should clear out and
|
|
10217
|
-
// block on this request.
|
|
10218
|
-
//
|
|
10219
|
-
// we receive state notifications when either a request initiates
|
|
10220
|
-
// or completes.
|
|
10221
|
-
//
|
|
10222
|
-
// In the completes case: we may receive the state notification
|
|
10223
|
-
// slightly before the request is finalized because the NotificationManager
|
|
10224
|
-
// may sync flush it (and thus deliver it before the microtask completes)
|
|
10225
|
-
//
|
|
10226
|
-
// In the initiates case: we aren't supposed to receive one unless there
|
|
10227
|
-
// is no other request in flight for this identity.
|
|
10228
|
-
//
|
|
10229
|
-
// However, there is a race condition here where the completed
|
|
10230
|
-
// notification can trigger an update that generates a new request
|
|
10231
|
-
// thus giving us an initiated notification before the older request
|
|
10232
|
-
// finalizes.
|
|
10233
|
-
//
|
|
10234
|
-
// When this occurs, if the triggered update happens to have caused
|
|
10235
|
-
// a new request to be made for the same identity AND that request
|
|
10236
|
-
// is the one passed into this component as the @request arg, then
|
|
10237
|
-
// getRequestState will return the state of the new request.
|
|
10238
|
-
// We can detect this by checking if the request state is "loading"
|
|
10239
|
-
// as outside of this case we would have a completed request.
|
|
10240
|
-
//
|
|
10241
|
-
// That is the reason for the `&& !state.isLoading` check above.
|
|
10193
|
+
/** @internal */
|
|
10242
10194
|
|
|
10243
|
-
|
|
10244
|
-
this.isRefreshing = false;
|
|
10245
|
-
this._maybeUpdate('policy', true);
|
|
10246
|
-
} else {
|
|
10247
|
-
this.isRefreshing = true;
|
|
10248
|
-
}
|
|
10249
|
-
}
|
|
10250
|
-
}
|
|
10251
|
-
});
|
|
10252
|
-
}
|
|
10253
|
-
}
|
|
10195
|
+
/** @internal */
|
|
10254
10196
|
|
|
10255
|
-
/**
|
|
10256
|
-
* @internal
|
|
10257
|
-
*/
|
|
10258
|
-
_removeSubscriptions() {
|
|
10259
|
-
const store = this._requester;
|
|
10260
|
-
if (this._subscription && store && isStore(store)) {
|
|
10261
|
-
store.notifications.unsubscribe(this._subscription);
|
|
10262
|
-
this._subscribedTo = null;
|
|
10263
|
-
this._subscription = null;
|
|
10264
|
-
this._requester = null;
|
|
10265
|
-
}
|
|
10266
|
-
}
|
|
10197
|
+
/** @internal */
|
|
10267
10198
|
|
|
10268
|
-
/**
|
|
10269
|
-
* Install the event listeners for network and visibility changes.
|
|
10270
|
-
* This is only done in browser environments with a global `window`.
|
|
10271
|
-
*
|
|
10272
|
-
* @internal
|
|
10273
|
-
*/
|
|
10274
|
-
_installListeners() {
|
|
10275
|
-
if (typeof window === 'undefined') {
|
|
10276
|
-
return;
|
|
10277
|
-
}
|
|
10278
|
-
this.isOnline = window.navigator.onLine;
|
|
10279
|
-
this._unavailableStart = this.isOnline ? null : Date.now();
|
|
10280
|
-
this.isHidden = document.visibilityState === 'hidden';
|
|
10281
|
-
this._onlineChanged = event => {
|
|
10282
|
-
this.isOnline = event.type === 'online';
|
|
10283
|
-
if (event.type === 'offline' && this._unavailableStart === null) {
|
|
10284
|
-
this._unavailableStart = Date.now();
|
|
10285
|
-
}
|
|
10286
|
-
this._maybeUpdate();
|
|
10287
|
-
};
|
|
10288
|
-
this._backgroundChanged = () => {
|
|
10289
|
-
const isHidden = document.visibilityState === 'hidden';
|
|
10290
|
-
this.isHidden = isHidden;
|
|
10291
|
-
if (isHidden && this._unavailableStart === null) {
|
|
10292
|
-
this._unavailableStart = Date.now();
|
|
10293
|
-
}
|
|
10294
|
-
this._maybeUpdate();
|
|
10295
|
-
};
|
|
10296
|
-
window.addEventListener('online', this._onlineChanged, {
|
|
10297
|
-
passive: true,
|
|
10298
|
-
capture: true
|
|
10299
|
-
});
|
|
10300
|
-
window.addEventListener('offline', this._onlineChanged, {
|
|
10301
|
-
passive: true,
|
|
10302
|
-
capture: true
|
|
10303
|
-
});
|
|
10304
|
-
document.addEventListener('visibilitychange', this._backgroundChanged, {
|
|
10305
|
-
passive: true,
|
|
10306
|
-
capture: true
|
|
10307
|
-
});
|
|
10308
|
-
}
|
|
10199
|
+
/** @internal */
|
|
10309
10200
|
|
|
10310
|
-
/**
|
|
10311
|
-
|
|
10312
|
-
|
|
10313
|
-
|
|
10314
|
-
|
|
10315
|
-
|
|
10316
|
-
|
|
10317
|
-
|
|
10318
|
-
|
|
10319
|
-
|
|
10320
|
-
|
|
10321
|
-
|
|
10322
|
-
|
|
10323
|
-
|
|
10324
|
-
|
|
10325
|
-
|
|
10326
|
-
|
|
10327
|
-
const {
|
|
10328
|
-
reqState
|
|
10329
|
-
} = this;
|
|
10330
|
-
if (reqState.isPending) {
|
|
10331
|
-
return;
|
|
10332
|
-
}
|
|
10333
|
-
const canAttempt = Boolean(this.isOnline && !this.isHidden && (mode || this.autorefreshTypes.size));
|
|
10334
|
-
if (!canAttempt) {
|
|
10335
|
-
if (!silent && mode && mode !== '_invalidated') {
|
|
10336
|
-
throw new Error(`Reload not available: the network is not online or the tab is hidden`);
|
|
10337
|
-
}
|
|
10201
|
+
/** @internal */
|
|
10202
|
+
|
|
10203
|
+
/** @internal */
|
|
10204
|
+
|
|
10205
|
+
/** @internal */
|
|
10206
|
+
|
|
10207
|
+
/** @internal */
|
|
10208
|
+
|
|
10209
|
+
/** @internal */
|
|
10210
|
+
_stream = null;
|
|
10211
|
+
/** @internal */
|
|
10212
|
+
_future;
|
|
10213
|
+
/** @internal */
|
|
10214
|
+
_triggered = false;
|
|
10215
|
+
/** @internal */
|
|
10216
|
+
_trigger() {
|
|
10217
|
+
if (this._triggered) {
|
|
10338
10218
|
return;
|
|
10339
10219
|
}
|
|
10340
|
-
|
|
10341
|
-
|
|
10342
|
-
|
|
10343
|
-
|
|
10344
|
-
|
|
10345
|
-
const {
|
|
10346
|
-
_unavailableStart
|
|
10347
|
-
} = this;
|
|
10348
|
-
const {
|
|
10349
|
-
autorefreshThreshold
|
|
10350
|
-
} = this._args;
|
|
10351
|
-
const deadline = typeof autorefreshThreshold === 'number' ? autorefreshThreshold : DEFAULT_DEADLINE;
|
|
10352
|
-
shouldAttempt = Boolean(_unavailableStart && Date.now() - _unavailableStart > deadline);
|
|
10353
|
-
}
|
|
10354
|
-
if (!shouldAttempt && autorefreshTypes.has('interval')) {
|
|
10355
|
-
const {
|
|
10356
|
-
_intervalStart
|
|
10357
|
-
} = this;
|
|
10358
|
-
const {
|
|
10359
|
-
autorefreshThreshold
|
|
10360
|
-
} = this._args;
|
|
10361
|
-
if (_intervalStart && typeof autorefreshThreshold === 'number' && autorefreshThreshold > 0) {
|
|
10362
|
-
shouldAttempt = Boolean(Date.now() - _intervalStart >= autorefreshThreshold);
|
|
10363
|
-
}
|
|
10220
|
+
this._triggered = true;
|
|
10221
|
+
const future = this._future;
|
|
10222
|
+
const promise = future.getStream();
|
|
10223
|
+
if (promise.sizeHint) {
|
|
10224
|
+
this._sizeHint = promise.sizeHint;
|
|
10364
10225
|
}
|
|
10365
|
-
this.
|
|
10366
|
-
|
|
10367
|
-
|
|
10368
|
-
|
|
10369
|
-
|
|
10370
|
-
const realMode = mode === '_invalidated' ? null : mode;
|
|
10371
|
-
const val = realMode ?? this._args.autorefreshBehavior ?? 'policy';
|
|
10372
|
-
|
|
10373
|
-
// if the future was generated by an older store version, it may not have
|
|
10374
|
-
// a requester set. In this case we append it to ensure that reload and
|
|
10375
|
-
// refresh will work appropriately.
|
|
10376
|
-
const requester = this._getRequester();
|
|
10377
|
-
if (!reqState._request.requester) {
|
|
10378
|
-
reqState._request.requester = requester;
|
|
10226
|
+
this.promise = promise.then(stream => {
|
|
10227
|
+
if (!stream) {
|
|
10228
|
+
this._isPending = false;
|
|
10229
|
+
this._isComplete = true;
|
|
10230
|
+
return;
|
|
10379
10231
|
}
|
|
10380
|
-
|
|
10381
|
-
|
|
10382
|
-
|
|
10383
|
-
|
|
10384
|
-
|
|
10385
|
-
|
|
10386
|
-
|
|
10387
|
-
case 'policy':
|
|
10388
|
-
this._latestRequest = reqState.refresh(true);
|
|
10389
|
-
break;
|
|
10390
|
-
default:
|
|
10391
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
10392
|
-
{
|
|
10393
|
-
throw new Error(`Invalid ${mode ? 'update mode' : '@autorefreshBehavior'} for <Request />: ${isNeverString(val)}`);
|
|
10394
|
-
}
|
|
10395
|
-
})() : {};
|
|
10232
|
+
return watchStream(stream, this);
|
|
10233
|
+
}, error => {
|
|
10234
|
+
this._isPending = false;
|
|
10235
|
+
this._isStarted = false;
|
|
10236
|
+
if (isAbortError(error)) {
|
|
10237
|
+
this._isCancelled = true;
|
|
10238
|
+
this._isComplete = true;
|
|
10396
10239
|
}
|
|
10397
|
-
|
|
10398
|
-
|
|
10240
|
+
this._isErrored = true;
|
|
10241
|
+
this._error = error;
|
|
10242
|
+
});
|
|
10243
|
+
}
|
|
10244
|
+
promise = null;
|
|
10245
|
+
get isPending() {
|
|
10246
|
+
this._trigger();
|
|
10247
|
+
return this._isPending;
|
|
10248
|
+
}
|
|
10249
|
+
get sizeHint() {
|
|
10250
|
+
this._trigger();
|
|
10251
|
+
return this._sizeHint;
|
|
10252
|
+
}
|
|
10253
|
+
get stream() {
|
|
10254
|
+
this._trigger();
|
|
10255
|
+
if (!this._stream) {
|
|
10256
|
+
if (this._isComplete || this._isCancelled || this._isErrored) {
|
|
10257
|
+
return null;
|
|
10399
10258
|
}
|
|
10400
|
-
|
|
10401
|
-
void this._latestRequest.finally(() => {
|
|
10402
|
-
this._isUpdating = false;
|
|
10403
|
-
});
|
|
10259
|
+
this._stream = new TransformStream();
|
|
10404
10260
|
}
|
|
10261
|
+
return this._stream.readable;
|
|
10405
10262
|
}
|
|
10406
|
-
|
|
10407
|
-
|
|
10408
|
-
|
|
10409
|
-
*/
|
|
10410
|
-
_getRequester() {
|
|
10411
|
-
// Note: we check for the requester's presence
|
|
10412
|
-
// as well as the request's presence because we may
|
|
10413
|
-
// be subscribed to a request issued by a store from an older
|
|
10414
|
-
// version of the library that didn't yet set requester.
|
|
10415
|
-
if (this._args.request?.requester) {
|
|
10416
|
-
return this._args.request.requester;
|
|
10417
|
-
}
|
|
10418
|
-
return this.store;
|
|
10263
|
+
get isStarted() {
|
|
10264
|
+
this._trigger();
|
|
10265
|
+
return this._isStarted;
|
|
10419
10266
|
}
|
|
10420
|
-
|
|
10421
|
-
|
|
10422
|
-
|
|
10423
|
-
|
|
10424
|
-
|
|
10425
|
-
this.
|
|
10426
|
-
|
|
10267
|
+
get bytesLoaded() {
|
|
10268
|
+
this._trigger();
|
|
10269
|
+
return this._bytesLoaded;
|
|
10270
|
+
}
|
|
10271
|
+
get startTime() {
|
|
10272
|
+
this._trigger();
|
|
10273
|
+
return this._startTime;
|
|
10274
|
+
}
|
|
10275
|
+
get endTime() {
|
|
10276
|
+
this._trigger();
|
|
10277
|
+
return this._endTime;
|
|
10278
|
+
}
|
|
10279
|
+
get lastPacketTime() {
|
|
10280
|
+
this._trigger();
|
|
10281
|
+
return this._lastPacketTime;
|
|
10282
|
+
}
|
|
10283
|
+
get isComplete() {
|
|
10284
|
+
this._trigger();
|
|
10285
|
+
return this._isComplete;
|
|
10286
|
+
}
|
|
10287
|
+
get isCancelled() {
|
|
10288
|
+
this._trigger();
|
|
10289
|
+
return this._isCancelled;
|
|
10290
|
+
}
|
|
10291
|
+
get isErrored() {
|
|
10292
|
+
this._trigger();
|
|
10293
|
+
return this._isErrored;
|
|
10294
|
+
}
|
|
10295
|
+
get error() {
|
|
10296
|
+
this._trigger();
|
|
10297
|
+
return this._error;
|
|
10298
|
+
}
|
|
10299
|
+
get elapsedTime() {
|
|
10300
|
+
return (this.endTime || this.lastPacketTime) - this.startTime;
|
|
10301
|
+
}
|
|
10302
|
+
get completedRatio() {
|
|
10303
|
+
return this.sizeHint ? this.bytesLoaded / this.sizeHint : 0;
|
|
10304
|
+
}
|
|
10305
|
+
get remainingRatio() {
|
|
10306
|
+
return 1 - this.completedRatio;
|
|
10307
|
+
}
|
|
10308
|
+
get duration() {
|
|
10309
|
+
return this.endTime - this.startTime;
|
|
10310
|
+
}
|
|
10311
|
+
get speed() {
|
|
10312
|
+
// bytes per second
|
|
10313
|
+
return this.bytesLoaded / (this.elapsedTime / 1000);
|
|
10314
|
+
}
|
|
10315
|
+
constructor(future) {
|
|
10316
|
+
this._future = future;
|
|
10317
|
+
}
|
|
10318
|
+
abort = () => {
|
|
10319
|
+
this._future.abort();
|
|
10427
10320
|
};
|
|
10321
|
+
}
|
|
10322
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_isPending', true);
|
|
10323
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_isStarted', false);
|
|
10324
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_isComplete', false);
|
|
10325
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_isCancelled', false);
|
|
10326
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_isErrored', false);
|
|
10327
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_error', null);
|
|
10328
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_sizeHint', 0);
|
|
10329
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_bytesLoaded', 0);
|
|
10330
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_startTime', 0);
|
|
10331
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_endTime', 0);
|
|
10332
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_lastPacketTime', 0);
|
|
10428
10333
|
|
|
10429
|
-
|
|
10430
|
-
|
|
10431
|
-
|
|
10432
|
-
|
|
10433
|
-
|
|
10434
|
-
|
|
10435
|
-
|
|
10334
|
+
/**
|
|
10335
|
+
* The state of a request in the "pending"
|
|
10336
|
+
* state. This is the default initial state.
|
|
10337
|
+
*
|
|
10338
|
+
* Extends the {@link PendingPromise} interface.
|
|
10339
|
+
*
|
|
10340
|
+
*/
|
|
10436
10341
|
|
|
10437
|
-
|
|
10438
|
-
|
|
10439
|
-
|
|
10440
|
-
|
|
10441
|
-
|
|
10442
|
-
|
|
10443
|
-
|
|
10444
|
-
|
|
10445
|
-
|
|
10342
|
+
/**
|
|
10343
|
+
* The state of a request in the "fulfilled" state.
|
|
10344
|
+
* This is the state of a request that has resolved
|
|
10345
|
+
* successfully.
|
|
10346
|
+
*
|
|
10347
|
+
* Extends the {@link ResolvedPromise} interface.
|
|
10348
|
+
*
|
|
10349
|
+
*/
|
|
10350
|
+
|
|
10351
|
+
/**
|
|
10352
|
+
* The state of a request in the "rejected" state.
|
|
10353
|
+
* This is the state of a request that has rejected
|
|
10354
|
+
* with an error.
|
|
10355
|
+
*
|
|
10356
|
+
* Extends the {@link RejectedPromise} interface.
|
|
10357
|
+
*
|
|
10358
|
+
*/
|
|
10359
|
+
|
|
10360
|
+
/**
|
|
10361
|
+
* The state of a request in the "cancelled" state.
|
|
10362
|
+
* This is the state of a promise that has been
|
|
10363
|
+
* cancelled.
|
|
10364
|
+
*
|
|
10365
|
+
*/
|
|
10366
|
+
|
|
10367
|
+
/**
|
|
10368
|
+
* RequestState extends the concept of {@link PromiseState} to provide a reactive
|
|
10369
|
+
* wrapper for a request {@link Future} which allows you write declarative code
|
|
10370
|
+
* around a Future's control flow.
|
|
10371
|
+
*
|
|
10372
|
+
* It is useful in both Template and JavaScript contexts, allowing you
|
|
10373
|
+
* to quickly derive behaviors and data from pending, error and success
|
|
10374
|
+
* states.
|
|
10375
|
+
*
|
|
10376
|
+
* The key difference between a {@link Promise} and a Future is that Futures provide
|
|
10377
|
+
* access to a {@link ReadableStream | stream} of their content, the {@link RequestKey} of the request (if any)
|
|
10378
|
+
* as well as the ability to attempt to {@link Future.abort | abort} the request.
|
|
10379
|
+
*
|
|
10380
|
+
* ```ts
|
|
10381
|
+
* interface Future<T> extends Promise<T>> {
|
|
10382
|
+
* getStream(): Promise<ReadableStream>;
|
|
10383
|
+
* abort(): void;
|
|
10384
|
+
* lid: RequestKey | null;
|
|
10385
|
+
* }
|
|
10386
|
+
* ```
|
|
10387
|
+
*
|
|
10388
|
+
* These additional APIs allow us to craft even richer state experiences.
|
|
10389
|
+
*
|
|
10390
|
+
* To get the state of a request, use {@link getRequestState}.
|
|
10391
|
+
*
|
|
10392
|
+
* See also:
|
|
10393
|
+
* - {@link PendingRequest}
|
|
10394
|
+
* - {@link ResolvedRequest}
|
|
10395
|
+
* - {@link RejectedRequest}
|
|
10396
|
+
* - {@link CancelledRequest}
|
|
10397
|
+
*
|
|
10398
|
+
*/
|
|
10399
|
+
|
|
10400
|
+
const RequestStateProto = {};
|
|
10401
|
+
function performRefresh(requester, request, isReload) {
|
|
10402
|
+
const req = Object.assign({}, request);
|
|
10403
|
+
const cacheOptions = Object.assign({}, req.cacheOptions);
|
|
10404
|
+
if (isReload) {
|
|
10405
|
+
// force direct to network
|
|
10406
|
+
cacheOptions.reload = true;
|
|
10407
|
+
} else if (isReload === false) {
|
|
10408
|
+
// delete reload to ensure we use backgroundReload / policy
|
|
10409
|
+
delete cacheOptions.reload;
|
|
10410
|
+
cacheOptions.backgroundReload = true;
|
|
10411
|
+
} else {
|
|
10412
|
+
// delete props to ensure we use the policy
|
|
10413
|
+
delete cacheOptions.backgroundReload;
|
|
10414
|
+
delete cacheOptions.reload;
|
|
10446
10415
|
}
|
|
10416
|
+
req.cacheOptions = cacheOptions;
|
|
10417
|
+
return requester.request(req);
|
|
10418
|
+
}
|
|
10447
10419
|
|
|
10448
|
-
|
|
10449
|
-
|
|
10450
|
-
|
|
10451
|
-
|
|
10452
|
-
|
|
10420
|
+
// TODO introduce a new mechanism for defining multiple properties
|
|
10421
|
+
// that share a common signal
|
|
10422
|
+
defineSignal(RequestStateProto, 'reason', null);
|
|
10423
|
+
defineSignal(RequestStateProto, 'value', null);
|
|
10424
|
+
defineSignal(RequestStateProto, 'result', null);
|
|
10425
|
+
defineSignal(RequestStateProto, 'error', null);
|
|
10426
|
+
defineSignal(RequestStateProto, 'status', 'pending');
|
|
10427
|
+
defineSignal(RequestStateProto, 'isPending', true);
|
|
10428
|
+
defineSignal(RequestStateProto, 'isLoading', true);
|
|
10429
|
+
defineSignal(RequestStateProto, 'isSuccess', false);
|
|
10430
|
+
defineSignal(RequestStateProto, 'isError', false);
|
|
10431
|
+
defineSignal(RequestStateProto, 'request', null);
|
|
10432
|
+
defineSignal(RequestStateProto, 'response', null);
|
|
10433
|
+
Object.defineProperty(RequestStateProto, 'isCancelled', {
|
|
10434
|
+
get() {
|
|
10435
|
+
return this.isError && isAbortError(this.reason);
|
|
10453
10436
|
}
|
|
10454
|
-
|
|
10455
|
-
|
|
10456
|
-
|
|
10457
|
-
|
|
10458
|
-
|
|
10459
|
-
refresh: this.refresh,
|
|
10460
|
-
isRefreshing: this.isRefreshing,
|
|
10461
|
-
latestRequest: this._latestRequest
|
|
10462
|
-
};
|
|
10463
|
-
if (feat.isRefreshing) {
|
|
10464
|
-
feat.abort = () => {
|
|
10465
|
-
this._latestRequest?.abort();
|
|
10466
|
-
};
|
|
10437
|
+
});
|
|
10438
|
+
Object.defineProperty(RequestStateProto, 'loadingState', {
|
|
10439
|
+
get() {
|
|
10440
|
+
if (!this._loadingState) {
|
|
10441
|
+
this._loadingState = new RequestLoadingState(this._request);
|
|
10467
10442
|
}
|
|
10468
|
-
return
|
|
10469
|
-
}
|
|
10470
|
-
|
|
10471
|
-
/**
|
|
10472
|
-
* @internal
|
|
10473
|
-
*/
|
|
10474
|
-
static {
|
|
10475
|
-
decorateMethodV2(this.prototype, "contentFeatures", [memoized]);
|
|
10443
|
+
return this._loadingState;
|
|
10476
10444
|
}
|
|
10477
|
-
|
|
10478
|
-
|
|
10479
|
-
|
|
10480
|
-
|
|
10481
|
-
|
|
10445
|
+
});
|
|
10446
|
+
function createRequestState(future) {
|
|
10447
|
+
const state = getPromiseResult(future);
|
|
10448
|
+
const promiseState = Object.create(RequestStateProto);
|
|
10449
|
+
promiseState._request = future;
|
|
10450
|
+
// @ts-expect-error - we still attach it for PendingState
|
|
10451
|
+
promiseState.reload = () => {
|
|
10482
10452
|
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
10483
10453
|
if (!test) {
|
|
10484
|
-
throw new Error(`Cannot
|
|
10454
|
+
throw new Error(`Cannot reload a request that is still pending. Await or abort the original request first.`);
|
|
10485
10455
|
}
|
|
10486
|
-
})(!
|
|
10487
|
-
|
|
10488
|
-
|
|
10489
|
-
_originalRequest,
|
|
10490
|
-
_originalQuery
|
|
10491
|
-
} = this;
|
|
10492
|
-
const isOriginalRequest = request === _originalRequest && query === _originalQuery;
|
|
10493
|
-
if (_localRequest && isOriginalRequest) {
|
|
10494
|
-
return _localRequest;
|
|
10495
|
-
}
|
|
10456
|
+
})(!promiseState.isPending) : {};
|
|
10457
|
+
return performRefresh(future.requester, promiseState.request, true);
|
|
10458
|
+
};
|
|
10496
10459
|
|
|
10497
|
-
|
|
10498
|
-
|
|
10499
|
-
this._originalRequest = request;
|
|
10500
|
-
if (request) {
|
|
10501
|
-
return request;
|
|
10502
|
-
}
|
|
10460
|
+
// @ts-expect-error - we still attach it for PendingState
|
|
10461
|
+
promiseState.refresh = (usePolicy = false) => {
|
|
10503
10462
|
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
10504
10463
|
if (!test) {
|
|
10505
|
-
throw new Error(`
|
|
10506
|
-
}
|
|
10507
|
-
})(query) : {};
|
|
10508
|
-
return this.store.request(query);
|
|
10509
|
-
}
|
|
10510
|
-
static {
|
|
10511
|
-
decorateMethodV2(this.prototype, "_request", [memoized]);
|
|
10512
|
-
}
|
|
10513
|
-
get request() {
|
|
10514
|
-
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
10515
|
-
try {
|
|
10516
|
-
const request = this._request;
|
|
10517
|
-
this._updateSubscriptions();
|
|
10518
|
-
return request;
|
|
10519
|
-
} catch (e) {
|
|
10520
|
-
// eslint-disable-next-line no-console
|
|
10521
|
-
console.log(e);
|
|
10522
|
-
throw new Error(`Unable to initialize the request`, {
|
|
10523
|
-
cause: e
|
|
10524
|
-
});
|
|
10464
|
+
throw new Error(`Cannot refresh a request that is still pending. Await or abort the original request first.`);
|
|
10525
10465
|
}
|
|
10466
|
+
})(!promiseState.isPending) : {};
|
|
10467
|
+
return performRefresh(future.requester, promiseState.request, usePolicy === true ? null : false);
|
|
10468
|
+
};
|
|
10469
|
+
if (state) {
|
|
10470
|
+
if (state.isError) {
|
|
10471
|
+
promiseState.error = state.result;
|
|
10472
|
+
promiseState.reason = state.result;
|
|
10473
|
+
promiseState.status = 'rejected';
|
|
10474
|
+
promiseState.isError = true;
|
|
10475
|
+
promiseState.isPending = false;
|
|
10476
|
+
promiseState.isLoading = false;
|
|
10477
|
+
promiseState.request = state.result.request;
|
|
10478
|
+
promiseState.response = state.result.response;
|
|
10526
10479
|
} else {
|
|
10527
|
-
|
|
10528
|
-
|
|
10529
|
-
|
|
10480
|
+
promiseState.result = state.result.content;
|
|
10481
|
+
promiseState.value = state.result.content;
|
|
10482
|
+
promiseState.status = 'fulfilled';
|
|
10483
|
+
promiseState.isSuccess = true;
|
|
10484
|
+
promiseState.isPending = false;
|
|
10485
|
+
promiseState.isLoading = false;
|
|
10486
|
+
promiseState.request = state.result.request;
|
|
10487
|
+
promiseState.response = state.result.response;
|
|
10530
10488
|
}
|
|
10489
|
+
} else {
|
|
10490
|
+
void future.then(result => {
|
|
10491
|
+
setPromiseResult(future, {
|
|
10492
|
+
isError: false,
|
|
10493
|
+
result
|
|
10494
|
+
});
|
|
10495
|
+
promiseState.result = result.content;
|
|
10496
|
+
promiseState.value = result.content;
|
|
10497
|
+
promiseState.status = 'fulfilled';
|
|
10498
|
+
promiseState.isSuccess = true;
|
|
10499
|
+
promiseState.isPending = false;
|
|
10500
|
+
promiseState.isLoading = false;
|
|
10501
|
+
promiseState.request = result.request;
|
|
10502
|
+
promiseState.response = result.response;
|
|
10503
|
+
}, error => {
|
|
10504
|
+
setPromiseResult(future, {
|
|
10505
|
+
isError: true,
|
|
10506
|
+
result: error
|
|
10507
|
+
});
|
|
10508
|
+
promiseState.error = error;
|
|
10509
|
+
promiseState.reason = error;
|
|
10510
|
+
promiseState.status = 'rejected';
|
|
10511
|
+
promiseState.isError = true;
|
|
10512
|
+
promiseState.isPending = false;
|
|
10513
|
+
promiseState.isLoading = false;
|
|
10514
|
+
promiseState.request = error.request;
|
|
10515
|
+
promiseState.response = error.response;
|
|
10516
|
+
});
|
|
10531
10517
|
}
|
|
10532
|
-
|
|
10533
|
-
decorateMethodV2(this.prototype, "request", [memoized]);
|
|
10534
|
-
}
|
|
10535
|
-
get reqState() {
|
|
10536
|
-
return getRequestState(this.request);
|
|
10537
|
-
}
|
|
10538
|
-
get result() {
|
|
10539
|
-
return this.reqState.result;
|
|
10540
|
-
}
|
|
10541
|
-
}
|
|
10542
|
-
defineSignal(RequestSubscription.prototype, 'isOnline', true);
|
|
10543
|
-
defineSignal(RequestSubscription.prototype, 'isHidden', false);
|
|
10544
|
-
defineSignal(RequestSubscription.prototype, 'isRefreshing', false);
|
|
10545
|
-
defineSignal(RequestSubscription.prototype, '_localRequest', undefined);
|
|
10546
|
-
defineSignal(RequestSubscription.prototype, '_latestRequest', undefined);
|
|
10547
|
-
function isStore(store) {
|
|
10548
|
-
return 'requestManager' in store;
|
|
10549
|
-
}
|
|
10550
|
-
function createRequestSubscription(store, args) {
|
|
10551
|
-
return new RequestSubscription(store, args);
|
|
10552
|
-
}
|
|
10553
|
-
function upgradeSubscription(sub) {
|
|
10554
|
-
return sub;
|
|
10518
|
+
return promiseState;
|
|
10555
10519
|
}
|
|
10556
|
-
|
|
10557
|
-
|
|
10558
|
-
|
|
10559
|
-
|
|
10560
|
-
|
|
10561
|
-
|
|
10520
|
+
|
|
10521
|
+
/**
|
|
10522
|
+
* `getRequestState` can be used in both JavaScript and Template contexts.
|
|
10523
|
+
*
|
|
10524
|
+
* ```ts
|
|
10525
|
+
* import { getRequestState } from '@warp-drive/ember';
|
|
10526
|
+
*
|
|
10527
|
+
* const state = getRequestState(future);
|
|
10528
|
+
* ```
|
|
10529
|
+
*
|
|
10530
|
+
* For instance, we could write a getter on a component that updates whenever
|
|
10531
|
+
* the request state advances or the future changes, by combining the function
|
|
10532
|
+
* with the use of `@cached`
|
|
10533
|
+
*
|
|
10534
|
+
* ```ts
|
|
10535
|
+
* class Component {
|
|
10536
|
+
* @cached
|
|
10537
|
+
* get title() {
|
|
10538
|
+
* const state = getRequestState(this.args.request);
|
|
10539
|
+
* if (state.isPending) {
|
|
10540
|
+
* return 'loading...';
|
|
10541
|
+
* }
|
|
10542
|
+
* if (state.isError) { return null; }
|
|
10543
|
+
* return state.result.title;
|
|
10544
|
+
* }
|
|
10545
|
+
* }
|
|
10546
|
+
* ```
|
|
10547
|
+
*
|
|
10548
|
+
* Or in a template as a helper:
|
|
10549
|
+
*
|
|
10550
|
+
* ```gjs
|
|
10551
|
+
* import { getRequestState } from '@warp-drive/ember';
|
|
10552
|
+
*
|
|
10553
|
+
* <template>
|
|
10554
|
+
* {{#let (getRequestState @request) as |state|}}
|
|
10555
|
+
* {{#if state.isPending}}
|
|
10556
|
+
* <Spinner />
|
|
10557
|
+
* {{else if state.isError}}
|
|
10558
|
+
* <ErrorForm @error={{state.error}} />
|
|
10559
|
+
* {{else}}
|
|
10560
|
+
* <h1>{{state.result.title}}</h1>
|
|
10561
|
+
* {{/if}}
|
|
10562
|
+
* {{/let}}
|
|
10563
|
+
* </template>
|
|
10564
|
+
* ```
|
|
10565
|
+
*
|
|
10566
|
+
* If looking to use in a template, consider also the `<Request />` component
|
|
10567
|
+
* which offers a numbe of additional capabilities for requests *beyond* what
|
|
10568
|
+
* `RequestState` provides.
|
|
10569
|
+
*
|
|
10570
|
+
*/
|
|
10571
|
+
function getRequestState(future) {
|
|
10572
|
+
let state = RequestCache.get(future);
|
|
10573
|
+
if (!state) {
|
|
10574
|
+
state = createRequestState(future);
|
|
10575
|
+
RequestCache.set(future, state);
|
|
10562
10576
|
}
|
|
10563
|
-
|
|
10564
|
-
window.removeEventListener('online', self._onlineChanged, {
|
|
10565
|
-
passive: true,
|
|
10566
|
-
capture: true
|
|
10567
|
-
});
|
|
10568
|
-
window.removeEventListener('offline', self._onlineChanged, {
|
|
10569
|
-
passive: true,
|
|
10570
|
-
capture: true
|
|
10571
|
-
});
|
|
10572
|
-
document.removeEventListener('visibilitychange', self._backgroundChanged, {
|
|
10573
|
-
passive: true,
|
|
10574
|
-
capture: true
|
|
10575
|
-
});
|
|
10577
|
+
return state;
|
|
10576
10578
|
}
|
|
10577
10579
|
export { defineGate as A, defineNonEnumerableSignal as B, CacheHandler as C, DISPOSE as D, Signals as E, peekInternalSignal as F, createInternalMemo as G, withSignalStore as H, notifyInternalSignal as I, consumeInternalSignal as J, getOrCreateInternalSignal as K, ReactiveResource as L, isNonIdentityCacheableField as M, getFieldCacheKeyStrict as N, checkout as O, commit as P, setIdentifierGenerationMethod as Q, RecordArrayManager as R, Store as S, setIdentifierUpdateMethod as T, setIdentifierForgetMethod as U, setIdentifierResetMethod as V, setKeyInfoForResource as W, _clearCaches as _, isRequestKey as a, coerceId as b, constructResource as c, assertPrivateStore as d, ensureStringId as e, fastPush as f, isPrivateStore as g, assertPrivateCapabilities as h, isResourceKey as i, setRecordIdentifier as j, StoreMap as k, createLegacyManyArray as l, log as m, normalizeModelName as n, logGroup as o, getPromiseState as p, createRequestSubscription as q, recordIdentifierFor as r, storeFor as s, getRequestState as t, signal as u, memoized as v, gate as w, entangleSignal as x, entangleInitiallyStaleSignal as y, defineSignal as z };
|