@ember-data/store 5.5.0-alpha.19 → 5.5.0-alpha.20
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/-private.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{many-array-CE2Jr4mQ.js → request-state-Bue-PTUf.js} +572 -4
- package/dist/request-state-Bue-PTUf.js.map +1 -0
- package/package.json +11 -11
- package/unstable-preview-types/-private/network/request-cache.d.ts +8 -8
- package/unstable-preview-types/-private/network/request-cache.d.ts.map +1 -1
- package/unstable-preview-types/-private/new-core-tmp/promise-state.d.ts +289 -0
- package/unstable-preview-types/-private/new-core-tmp/promise-state.d.ts.map +1 -0
- package/unstable-preview-types/-private/new-core-tmp/request-state.d.ts +276 -0
- package/unstable-preview-types/-private/new-core-tmp/request-state.d.ts.map +1 -0
- package/unstable-preview-types/-private.d.ts +3 -1
- package/unstable-preview-types/-private.d.ts.map +1 -1
- package/unstable-preview-types/index.d.ts +2 -0
- package/dist/many-array-CE2Jr4mQ.js.map +0 -1
package/dist/-private.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { A as ARRAY_SIGNAL, C as CacheHandler, k as CollectionRecordArray, I as LiveArray, M as MUTATE, R as RecordArrayManager, w as RelatedCollection, l as SOURCE, S as Store, t as StoreMap, _ as _clearCaches, v as _deprecatingNormalize, h as coerceId, g as constructResource, j as ensureStringId, m as fastPush, f as isDocumentIdentifier, i as isStableIdentifier, x as log, y as logGroup, n as notifyArray, p as peekCache, r as recordIdentifierFor, o as removeRecordDataFor, u as setCacheFor, q as setRecordIdentifier, s as storeFor } from "./
|
|
1
|
+
export { A as ARRAY_SIGNAL, C as CacheHandler, k as CollectionRecordArray, I as LiveArray, M as MUTATE, R as RecordArrayManager, w as RelatedCollection, l as SOURCE, S as Store, t as StoreMap, _ as _clearCaches, v as _deprecatingNormalize, h as coerceId, g as constructResource, j as ensureStringId, m as fastPush, z as getPromiseState, B as getRequestState, f as isDocumentIdentifier, i as isStableIdentifier, x as log, y as logGroup, n as notifyArray, p as peekCache, r as recordIdentifierFor, o as removeRecordDataFor, u as setCacheFor, q as setRecordIdentifier, s as storeFor } from "./request-state-Bue-PTUf.js";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { C as CacheHandler, S as default, r as recordIdentifierFor, c as setIdentifierForgetMethod, a as setIdentifierGenerationMethod, d as setIdentifierResetMethod, b as setIdentifierUpdateMethod, e as setKeyInfoForResource, s as storeFor } from "./
|
|
1
|
+
export { C as CacheHandler, S as default, r as recordIdentifierFor, c as setIdentifierForgetMethod, a as setIdentifierGenerationMethod, d as setIdentifierResetMethod, b as setIdentifierUpdateMethod, e as setKeyInfoForResource, s as storeFor } from "./request-state-Bue-PTUf.js";
|
|
2
2
|
import '@ember/debug';
|
|
3
3
|
import '@embroider/macros';
|
|
4
4
|
import '@ember-data/request-utils/string';
|
|
@@ -8,6 +8,7 @@ import { defineSubscription, notifySignal, defineSignal, createSignal, subscribe
|
|
|
8
8
|
import { CACHE_OWNER, DEBUG_STALE_CACHE_OWNER, DEBUG_IDENTIFIER_BUCKET, DEBUG_CLIENT_ORIGINATED } from '@warp-drive/core-types/identifier';
|
|
9
9
|
import { dasherize } from '@ember-data/request-utils/string';
|
|
10
10
|
import { compat } from '@ember-data/tracking';
|
|
11
|
+
import { getPromiseResult, setPromiseResult } from '@ember-data/request';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
@module @ember-data/store
|
|
@@ -3979,7 +3980,7 @@ class RequestStateService {
|
|
|
3979
3980
|
* @method subscribeForRecord
|
|
3980
3981
|
* @public
|
|
3981
3982
|
* @param {StableRecordIdentifier} identifier
|
|
3982
|
-
* @param {(state:
|
|
3983
|
+
* @param {(state: RequestCacheRequestState) => void} callback
|
|
3983
3984
|
*/
|
|
3984
3985
|
subscribeForRecord(identifier, callback) {
|
|
3985
3986
|
let subscriptions = this._subscriptions.get(identifier);
|
|
@@ -3996,7 +3997,7 @@ class RequestStateService {
|
|
|
3996
3997
|
* @method getPendingRequestsForRecord
|
|
3997
3998
|
* @public
|
|
3998
3999
|
* @param {StableRecordIdentifier} identifier
|
|
3999
|
-
* @return {
|
|
4000
|
+
* @return {RequestCacheRequestState[]} an array of request states for any pending requests for the given identifier
|
|
4000
4001
|
*/
|
|
4001
4002
|
getPendingRequestsForRecord(identifier) {
|
|
4002
4003
|
return this._pending.get(identifier) || EMPTY_ARR;
|
|
@@ -4008,7 +4009,7 @@ class RequestStateService {
|
|
|
4008
4009
|
* @method getLastRequestForRecord
|
|
4009
4010
|
* @public
|
|
4010
4011
|
* @param {StableRecordIdentifier} identifier
|
|
4011
|
-
* @return {
|
|
4012
|
+
* @return {RequestCacheRequestState | null} the state of the most recent request for the given identifier
|
|
4012
4013
|
*/
|
|
4013
4014
|
getLastRequestForRecord(identifier) {
|
|
4014
4015
|
const requests = this._done.get(identifier);
|
|
@@ -6918,4 +6919,571 @@ function mutate(collection, mutation, _SIGNAL) {
|
|
|
6918
6919
|
collection._manager.mutate(mutation);
|
|
6919
6920
|
addToTransaction(_SIGNAL);
|
|
6920
6921
|
}
|
|
6921
|
-
|
|
6922
|
+
const PromiseCache = new WeakMap();
|
|
6923
|
+
|
|
6924
|
+
/**
|
|
6925
|
+
* The state of a promise in the "pending"
|
|
6926
|
+
* state. This is the default initial state.
|
|
6927
|
+
*
|
|
6928
|
+
* @typedoc
|
|
6929
|
+
*/
|
|
6930
|
+
|
|
6931
|
+
/**
|
|
6932
|
+
* The state of a promise in the "fulfilled" state.
|
|
6933
|
+
* This is the state of a promise that has resolved
|
|
6934
|
+
* successfully.
|
|
6935
|
+
*
|
|
6936
|
+
* @typedoc
|
|
6937
|
+
*/
|
|
6938
|
+
|
|
6939
|
+
/**
|
|
6940
|
+
* The state of a promise in the "rejected" state.
|
|
6941
|
+
* This is the state of a promise that has rejected
|
|
6942
|
+
* with an error.
|
|
6943
|
+
*
|
|
6944
|
+
* @typedoc
|
|
6945
|
+
*/
|
|
6946
|
+
|
|
6947
|
+
/**
|
|
6948
|
+
* The state of a promise. This is the type that is returned
|
|
6949
|
+
* from `getPromiseState`.
|
|
6950
|
+
*
|
|
6951
|
+
* See also:
|
|
6952
|
+
* - {@link PendingPromise}
|
|
6953
|
+
* - {@link ResolvedPromise}
|
|
6954
|
+
* - {@link RejectedPromise}
|
|
6955
|
+
*
|
|
6956
|
+
* @typedoc
|
|
6957
|
+
*/
|
|
6958
|
+
|
|
6959
|
+
const PromiseStateProto = {};
|
|
6960
|
+
|
|
6961
|
+
// TODO introduce a new mechanism for defining multiple properties
|
|
6962
|
+
// that share a common signal
|
|
6963
|
+
defineSignal(PromiseStateProto, 'reason', null);
|
|
6964
|
+
defineSignal(PromiseStateProto, 'value', null);
|
|
6965
|
+
defineSignal(PromiseStateProto, 'result', null);
|
|
6966
|
+
defineSignal(PromiseStateProto, 'error', null);
|
|
6967
|
+
defineSignal(PromiseStateProto, 'status', 'pending');
|
|
6968
|
+
defineSignal(PromiseStateProto, 'isPending', true);
|
|
6969
|
+
defineSignal(PromiseStateProto, 'isLoading', true);
|
|
6970
|
+
defineSignal(PromiseStateProto, 'isSuccess', false);
|
|
6971
|
+
defineSignal(PromiseStateProto, 'isError', false);
|
|
6972
|
+
function createPromiseState(promise) {
|
|
6973
|
+
const state = getPromiseResult(promise);
|
|
6974
|
+
const promiseState = Object.create(PromiseStateProto);
|
|
6975
|
+
if (state) {
|
|
6976
|
+
if (state.isError) {
|
|
6977
|
+
promiseState.error = state.result;
|
|
6978
|
+
promiseState.reason = state.result;
|
|
6979
|
+
promiseState.status = 'rejected';
|
|
6980
|
+
promiseState.isError = true;
|
|
6981
|
+
promiseState.isPending = false;
|
|
6982
|
+
promiseState.isLoading = false;
|
|
6983
|
+
} else {
|
|
6984
|
+
promiseState.result = state.result;
|
|
6985
|
+
promiseState.value = state.result;
|
|
6986
|
+
promiseState.status = 'fulfilled';
|
|
6987
|
+
promiseState.isSuccess = true;
|
|
6988
|
+
promiseState.isPending = false;
|
|
6989
|
+
promiseState.isLoading = false;
|
|
6990
|
+
}
|
|
6991
|
+
} else {
|
|
6992
|
+
void promise.then(result => {
|
|
6993
|
+
setPromiseResult(promise, {
|
|
6994
|
+
isError: false,
|
|
6995
|
+
result
|
|
6996
|
+
});
|
|
6997
|
+
promiseState.result = result;
|
|
6998
|
+
promiseState.value = result;
|
|
6999
|
+
promiseState.status = 'fulfilled';
|
|
7000
|
+
promiseState.isSuccess = true;
|
|
7001
|
+
promiseState.isPending = false;
|
|
7002
|
+
promiseState.isLoading = false;
|
|
7003
|
+
}, error => {
|
|
7004
|
+
setPromiseResult(promise, {
|
|
7005
|
+
isError: true,
|
|
7006
|
+
result: error
|
|
7007
|
+
});
|
|
7008
|
+
promiseState.error = error;
|
|
7009
|
+
promiseState.reason = error;
|
|
7010
|
+
promiseState.status = 'rejected';
|
|
7011
|
+
promiseState.isError = true;
|
|
7012
|
+
promiseState.isPending = false;
|
|
7013
|
+
promiseState.isLoading = false;
|
|
7014
|
+
});
|
|
7015
|
+
}
|
|
7016
|
+
return promiseState;
|
|
7017
|
+
}
|
|
7018
|
+
const LegacyPromiseProxy = Symbol.for('LegacyPromiseProxy');
|
|
7019
|
+
function isLegacyAwaitable(promise) {
|
|
7020
|
+
return LegacyPromiseProxy in promise && 'promise' in promise && promise[LegacyPromiseProxy] === true;
|
|
7021
|
+
}
|
|
7022
|
+
function getPromise(promise) {
|
|
7023
|
+
return isLegacyAwaitable(promise) ? promise.promise : promise;
|
|
7024
|
+
}
|
|
7025
|
+
|
|
7026
|
+
/**
|
|
7027
|
+
* Returns a reactive state-machine for the provided promise or awaitable.
|
|
7028
|
+
*
|
|
7029
|
+
* Repeat calls to `getPromiseState` with the same promise will return the same state object
|
|
7030
|
+
* making is safe and easy to use in templates and JavaScript code to produce reactive
|
|
7031
|
+
* behaviors around promises.
|
|
7032
|
+
*
|
|
7033
|
+
* `getPromiseState` can be used in both JavaScript and Template contexts.
|
|
7034
|
+
*
|
|
7035
|
+
* ```ts
|
|
7036
|
+
* import { getPromiseState } from '@warp-drive/ember';
|
|
7037
|
+
*
|
|
7038
|
+
* const state = getPromiseState(promise);
|
|
7039
|
+
* ```
|
|
7040
|
+
*
|
|
7041
|
+
* For instance, we could write a getter on a component that updates whenever
|
|
7042
|
+
* the promise state advances or the promise changes, by combining the function
|
|
7043
|
+
* with the use of `@cached`
|
|
7044
|
+
*
|
|
7045
|
+
* ```ts
|
|
7046
|
+
* class Component {
|
|
7047
|
+
* @cached
|
|
7048
|
+
* get title() {
|
|
7049
|
+
* const state = getPromiseState(this.args.request);
|
|
7050
|
+
* if (state.isPending) {
|
|
7051
|
+
* return 'loading...';
|
|
7052
|
+
* }
|
|
7053
|
+
* if (state.isError) { return null; }
|
|
7054
|
+
* return state.result.title;
|
|
7055
|
+
* }
|
|
7056
|
+
* }
|
|
7057
|
+
* ```
|
|
7058
|
+
*
|
|
7059
|
+
* Or in a template as a helper:
|
|
7060
|
+
*
|
|
7061
|
+
* ```gjs
|
|
7062
|
+
* import { getPromiseState } from '@warp-drive/ember';
|
|
7063
|
+
*
|
|
7064
|
+
* <template>
|
|
7065
|
+
* {{#let (getPromiseState @request) as |state|}}
|
|
7066
|
+
* {{#if state.isPending}} <Spinner />
|
|
7067
|
+
* {{else if state.isError}} <ErrorForm @error={{state.error}} />
|
|
7068
|
+
* {{else}}
|
|
7069
|
+
* <h1>{{state.result.title}}</h1>
|
|
7070
|
+
* {{/if}}
|
|
7071
|
+
* {{/let}}
|
|
7072
|
+
* </template>
|
|
7073
|
+
* ```
|
|
7074
|
+
*
|
|
7075
|
+
* If looking to use in a template, consider also the `<Await />` component.
|
|
7076
|
+
*
|
|
7077
|
+
* @typedoc
|
|
7078
|
+
*/
|
|
7079
|
+
function getPromiseState(promise) {
|
|
7080
|
+
const _promise = getPromise(promise);
|
|
7081
|
+
let state = PromiseCache.get(_promise);
|
|
7082
|
+
if (!state) {
|
|
7083
|
+
state = createPromiseState(_promise);
|
|
7084
|
+
PromiseCache.set(_promise, state);
|
|
7085
|
+
}
|
|
7086
|
+
return state;
|
|
7087
|
+
}
|
|
7088
|
+
const RequestCache = new WeakMap();
|
|
7089
|
+
function isAbortError(error) {
|
|
7090
|
+
return error instanceof DOMException && error.name === 'AbortError';
|
|
7091
|
+
}
|
|
7092
|
+
async function watchStream(stream, state) {
|
|
7093
|
+
const reader = stream.getReader();
|
|
7094
|
+
let bytesLoaded = 0;
|
|
7095
|
+
let shouldForward = state._stream !== null && state._stream.readable.locked;
|
|
7096
|
+
let isForwarding = shouldForward;
|
|
7097
|
+
let writer = state._stream?.writable.getWriter();
|
|
7098
|
+
const buffer = [];
|
|
7099
|
+
state._isPending = false;
|
|
7100
|
+
state._isStarted = true;
|
|
7101
|
+
state._startTime = performance.now();
|
|
7102
|
+
while (true) {
|
|
7103
|
+
const {
|
|
7104
|
+
value,
|
|
7105
|
+
done
|
|
7106
|
+
} = await reader.read();
|
|
7107
|
+
if (done) {
|
|
7108
|
+
break;
|
|
7109
|
+
}
|
|
7110
|
+
bytesLoaded += value.byteLength;
|
|
7111
|
+
state._bytesLoaded = bytesLoaded;
|
|
7112
|
+
state._lastPacketTime = performance.now();
|
|
7113
|
+
shouldForward = shouldForward || state._stream !== null && state._stream.readable.locked;
|
|
7114
|
+
if (shouldForward) {
|
|
7115
|
+
if (!isForwarding) {
|
|
7116
|
+
isForwarding = true;
|
|
7117
|
+
writer = state._stream.writable.getWriter();
|
|
7118
|
+
for (const item of buffer) {
|
|
7119
|
+
await writer.ready;
|
|
7120
|
+
await writer.write(item);
|
|
7121
|
+
}
|
|
7122
|
+
buffer.length = 0;
|
|
7123
|
+
}
|
|
7124
|
+
await writer.ready;
|
|
7125
|
+
await writer.write(value);
|
|
7126
|
+
} else {
|
|
7127
|
+
buffer.push(value);
|
|
7128
|
+
}
|
|
7129
|
+
}
|
|
7130
|
+
|
|
7131
|
+
// if we are still forwarding, we need to close the writer
|
|
7132
|
+
if (isForwarding) {
|
|
7133
|
+
await writer.ready;
|
|
7134
|
+
await writer.close();
|
|
7135
|
+
} else if (state._stream) {
|
|
7136
|
+
// if we are not forwarding, we need to cancel the stream
|
|
7137
|
+
await state._stream.readable.cancel('The Stream Has Already Ended');
|
|
7138
|
+
state._stream = null;
|
|
7139
|
+
}
|
|
7140
|
+
const endTime = performance.now();
|
|
7141
|
+
state._endTime = endTime;
|
|
7142
|
+
state._isComplete = true;
|
|
7143
|
+
state._isStarted = false;
|
|
7144
|
+
}
|
|
7145
|
+
|
|
7146
|
+
/**
|
|
7147
|
+
* Lazily consumes the stream of a request, providing a number of
|
|
7148
|
+
* reactive properties that can be used to build UIs that respond
|
|
7149
|
+
* to the progress of a request.
|
|
7150
|
+
*
|
|
7151
|
+
* @typedoc
|
|
7152
|
+
*/
|
|
7153
|
+
class RequestLoadingState {
|
|
7154
|
+
_stream = null;
|
|
7155
|
+
_future;
|
|
7156
|
+
_triggered = false;
|
|
7157
|
+
_trigger() {
|
|
7158
|
+
if (this._triggered) {
|
|
7159
|
+
return;
|
|
7160
|
+
}
|
|
7161
|
+
this._triggered = true;
|
|
7162
|
+
const future = this._future;
|
|
7163
|
+
const promise = future.getStream();
|
|
7164
|
+
if (promise.sizeHint) {
|
|
7165
|
+
this._sizeHint = promise.sizeHint;
|
|
7166
|
+
}
|
|
7167
|
+
this.promise = promise.then(stream => {
|
|
7168
|
+
if (!stream) {
|
|
7169
|
+
this._isPending = false;
|
|
7170
|
+
this._isComplete = true;
|
|
7171
|
+
return;
|
|
7172
|
+
}
|
|
7173
|
+
return watchStream(stream, this);
|
|
7174
|
+
}, error => {
|
|
7175
|
+
this._isPending = false;
|
|
7176
|
+
this._isStarted = false;
|
|
7177
|
+
if (isAbortError(error)) {
|
|
7178
|
+
this._isCancelled = true;
|
|
7179
|
+
this._isComplete = true;
|
|
7180
|
+
}
|
|
7181
|
+
this._isErrored = true;
|
|
7182
|
+
this._error = error;
|
|
7183
|
+
});
|
|
7184
|
+
}
|
|
7185
|
+
promise = null;
|
|
7186
|
+
get isPending() {
|
|
7187
|
+
this._trigger();
|
|
7188
|
+
return this._isPending;
|
|
7189
|
+
}
|
|
7190
|
+
get sizeHint() {
|
|
7191
|
+
this._trigger();
|
|
7192
|
+
return this._sizeHint;
|
|
7193
|
+
}
|
|
7194
|
+
get stream() {
|
|
7195
|
+
this._trigger();
|
|
7196
|
+
if (!this._stream) {
|
|
7197
|
+
if (this._isComplete || this._isCancelled || this._isErrored) {
|
|
7198
|
+
return null;
|
|
7199
|
+
}
|
|
7200
|
+
this._stream = new TransformStream();
|
|
7201
|
+
}
|
|
7202
|
+
return this._stream.readable;
|
|
7203
|
+
}
|
|
7204
|
+
get isStarted() {
|
|
7205
|
+
this._trigger();
|
|
7206
|
+
return this._isStarted;
|
|
7207
|
+
}
|
|
7208
|
+
get bytesLoaded() {
|
|
7209
|
+
this._trigger();
|
|
7210
|
+
return this._bytesLoaded;
|
|
7211
|
+
}
|
|
7212
|
+
get startTime() {
|
|
7213
|
+
this._trigger();
|
|
7214
|
+
return this._startTime;
|
|
7215
|
+
}
|
|
7216
|
+
get endTime() {
|
|
7217
|
+
this._trigger();
|
|
7218
|
+
return this._endTime;
|
|
7219
|
+
}
|
|
7220
|
+
get lastPacketTime() {
|
|
7221
|
+
this._trigger();
|
|
7222
|
+
return this._lastPacketTime;
|
|
7223
|
+
}
|
|
7224
|
+
get isComplete() {
|
|
7225
|
+
this._trigger();
|
|
7226
|
+
return this._isComplete;
|
|
7227
|
+
}
|
|
7228
|
+
get isCancelled() {
|
|
7229
|
+
this._trigger();
|
|
7230
|
+
return this._isCancelled;
|
|
7231
|
+
}
|
|
7232
|
+
get isErrored() {
|
|
7233
|
+
this._trigger();
|
|
7234
|
+
return this._isErrored;
|
|
7235
|
+
}
|
|
7236
|
+
get error() {
|
|
7237
|
+
this._trigger();
|
|
7238
|
+
return this._error;
|
|
7239
|
+
}
|
|
7240
|
+
get elapsedTime() {
|
|
7241
|
+
return (this.endTime || this.lastPacketTime) - this.startTime;
|
|
7242
|
+
}
|
|
7243
|
+
get completedRatio() {
|
|
7244
|
+
return this.sizeHint ? this.bytesLoaded / this.sizeHint : 0;
|
|
7245
|
+
}
|
|
7246
|
+
get remainingRatio() {
|
|
7247
|
+
return 1 - this.completedRatio;
|
|
7248
|
+
}
|
|
7249
|
+
get duration() {
|
|
7250
|
+
return this.endTime - this.startTime;
|
|
7251
|
+
}
|
|
7252
|
+
get speed() {
|
|
7253
|
+
// bytes per second
|
|
7254
|
+
return this.bytesLoaded / (this.elapsedTime / 1000);
|
|
7255
|
+
}
|
|
7256
|
+
constructor(future) {
|
|
7257
|
+
this._future = future;
|
|
7258
|
+
}
|
|
7259
|
+
abort = () => {
|
|
7260
|
+
this._future.abort();
|
|
7261
|
+
};
|
|
7262
|
+
}
|
|
7263
|
+
defineSignal(RequestLoadingState.prototype, '_isPending', true);
|
|
7264
|
+
defineSignal(RequestLoadingState.prototype, '_isStarted', false);
|
|
7265
|
+
defineSignal(RequestLoadingState.prototype, '_isComplete', false);
|
|
7266
|
+
defineSignal(RequestLoadingState.prototype, '_isCancelled', false);
|
|
7267
|
+
defineSignal(RequestLoadingState.prototype, '_isErrored', false);
|
|
7268
|
+
defineSignal(RequestLoadingState.prototype, '_error', null);
|
|
7269
|
+
defineSignal(RequestLoadingState.prototype, '_sizeHint', 0);
|
|
7270
|
+
defineSignal(RequestLoadingState.prototype, '_bytesLoaded', 0);
|
|
7271
|
+
defineSignal(RequestLoadingState.prototype, '_startTime', 0);
|
|
7272
|
+
defineSignal(RequestLoadingState.prototype, '_endTime', 0);
|
|
7273
|
+
defineSignal(RequestLoadingState.prototype, '_lastPacketTime', 0);
|
|
7274
|
+
|
|
7275
|
+
/**
|
|
7276
|
+
* The state of a request in the "pending"
|
|
7277
|
+
* state. This is the default initial state.
|
|
7278
|
+
*
|
|
7279
|
+
* Extends the {@link PendingPromise} interface.
|
|
7280
|
+
*
|
|
7281
|
+
* @typedoc
|
|
7282
|
+
*/
|
|
7283
|
+
|
|
7284
|
+
/**
|
|
7285
|
+
* The state of a request in the "fulfilled" state.
|
|
7286
|
+
* This is the state of a request that has resolved
|
|
7287
|
+
* successfully.
|
|
7288
|
+
*
|
|
7289
|
+
* Extends the {@link ResolvedPromise} interface.
|
|
7290
|
+
*
|
|
7291
|
+
* @typedoc
|
|
7292
|
+
*/
|
|
7293
|
+
|
|
7294
|
+
/**
|
|
7295
|
+
* The state of a request in the "rejected" state.
|
|
7296
|
+
* This is the state of a request that has rejected
|
|
7297
|
+
* with an error.
|
|
7298
|
+
*
|
|
7299
|
+
* Extends the {@link RejectedPromise} interface.
|
|
7300
|
+
*
|
|
7301
|
+
* @typedoc
|
|
7302
|
+
*/
|
|
7303
|
+
|
|
7304
|
+
/**
|
|
7305
|
+
* The state of a request in the "cancelled" state.
|
|
7306
|
+
* This is the state of a promise that has been
|
|
7307
|
+
* cancelled.
|
|
7308
|
+
*
|
|
7309
|
+
* @typedoc
|
|
7310
|
+
*/
|
|
7311
|
+
|
|
7312
|
+
/**
|
|
7313
|
+
* RequestState extends the concept of PromiseState to provide a reactive
|
|
7314
|
+
* wrapper for a request `Future` which allows you write declarative code
|
|
7315
|
+
* around a Future's control flow.
|
|
7316
|
+
*
|
|
7317
|
+
* It is useful in both Template and JavaScript contexts, allowing you
|
|
7318
|
+
* to quickly derive behaviors and data from pending, error and success
|
|
7319
|
+
* states.
|
|
7320
|
+
*
|
|
7321
|
+
* The key difference between a Promise and a Future is that Futures provide
|
|
7322
|
+
* access to a stream of their content, the identity of the request (if any)
|
|
7323
|
+
* as well as the ability to attempt to abort the request.
|
|
7324
|
+
*
|
|
7325
|
+
* ```ts
|
|
7326
|
+
* interface Future<T> extends Promise<T>> {
|
|
7327
|
+
* getStream(): Promise<ReadableStream>;
|
|
7328
|
+
* abort(): void;
|
|
7329
|
+
* lid: StableDocumentIdentifier | null;
|
|
7330
|
+
* }
|
|
7331
|
+
* ```
|
|
7332
|
+
*
|
|
7333
|
+
* These additional APIs allow us to craft even richer state experiences.
|
|
7334
|
+
*
|
|
7335
|
+
* To get the state of a request, use `getRequestState`.
|
|
7336
|
+
*
|
|
7337
|
+
* See also:
|
|
7338
|
+
* - {@link PendingRequest}
|
|
7339
|
+
* - {@link ResolvedRequest}
|
|
7340
|
+
* - {@link RejectedRequest}
|
|
7341
|
+
* - {@link CancelledRequest}
|
|
7342
|
+
*
|
|
7343
|
+
* @typedoc
|
|
7344
|
+
*/
|
|
7345
|
+
|
|
7346
|
+
const RequestStateProto = {};
|
|
7347
|
+
|
|
7348
|
+
// TODO introduce a new mechanism for defining multiple properties
|
|
7349
|
+
// that share a common signal
|
|
7350
|
+
defineSignal(RequestStateProto, 'reason', null);
|
|
7351
|
+
defineSignal(RequestStateProto, 'value', null);
|
|
7352
|
+
defineSignal(RequestStateProto, 'result', null);
|
|
7353
|
+
defineSignal(RequestStateProto, 'error', null);
|
|
7354
|
+
defineSignal(RequestStateProto, 'status', 'pending');
|
|
7355
|
+
defineSignal(RequestStateProto, 'isPending', true);
|
|
7356
|
+
defineSignal(RequestStateProto, 'isLoading', true);
|
|
7357
|
+
defineSignal(RequestStateProto, 'isSuccess', false);
|
|
7358
|
+
defineSignal(RequestStateProto, 'isError', false);
|
|
7359
|
+
defineSignal(RequestStateProto, 'request', null);
|
|
7360
|
+
defineSignal(RequestStateProto, 'response', null);
|
|
7361
|
+
Object.defineProperty(RequestStateProto, 'isCancelled', {
|
|
7362
|
+
get() {
|
|
7363
|
+
return this.isError && isAbortError(this.reason);
|
|
7364
|
+
}
|
|
7365
|
+
});
|
|
7366
|
+
Object.defineProperty(RequestStateProto, 'loadingState', {
|
|
7367
|
+
get() {
|
|
7368
|
+
if (!this._loadingState) {
|
|
7369
|
+
this._loadingState = new RequestLoadingState(this._request);
|
|
7370
|
+
}
|
|
7371
|
+
return this._loadingState;
|
|
7372
|
+
}
|
|
7373
|
+
});
|
|
7374
|
+
function createRequestState(future) {
|
|
7375
|
+
const state = getPromiseResult(future);
|
|
7376
|
+
const promiseState = Object.create(RequestStateProto);
|
|
7377
|
+
promiseState._request = future;
|
|
7378
|
+
if (state) {
|
|
7379
|
+
if (state.isError) {
|
|
7380
|
+
promiseState.error = state.result;
|
|
7381
|
+
promiseState.reason = state.result;
|
|
7382
|
+
promiseState.status = 'rejected';
|
|
7383
|
+
promiseState.isError = true;
|
|
7384
|
+
promiseState.isPending = false;
|
|
7385
|
+
promiseState.isLoading = false;
|
|
7386
|
+
promiseState.request = state.result.request;
|
|
7387
|
+
promiseState.response = state.result.response;
|
|
7388
|
+
} else {
|
|
7389
|
+
promiseState.result = state.result.content;
|
|
7390
|
+
promiseState.value = state.result.content;
|
|
7391
|
+
promiseState.status = 'fulfilled';
|
|
7392
|
+
promiseState.isSuccess = true;
|
|
7393
|
+
promiseState.isPending = false;
|
|
7394
|
+
promiseState.isLoading = false;
|
|
7395
|
+
promiseState.request = state.result.request;
|
|
7396
|
+
promiseState.response = state.result.response;
|
|
7397
|
+
}
|
|
7398
|
+
} else {
|
|
7399
|
+
void future.then(result => {
|
|
7400
|
+
setPromiseResult(future, {
|
|
7401
|
+
isError: false,
|
|
7402
|
+
result
|
|
7403
|
+
});
|
|
7404
|
+
promiseState.result = result.content;
|
|
7405
|
+
promiseState.value = result.content;
|
|
7406
|
+
promiseState.status = 'fulfilled';
|
|
7407
|
+
promiseState.isSuccess = true;
|
|
7408
|
+
promiseState.isPending = false;
|
|
7409
|
+
promiseState.isLoading = false;
|
|
7410
|
+
promiseState.request = result.request;
|
|
7411
|
+
promiseState.response = result.response;
|
|
7412
|
+
}, error => {
|
|
7413
|
+
setPromiseResult(future, {
|
|
7414
|
+
isError: true,
|
|
7415
|
+
result: error
|
|
7416
|
+
});
|
|
7417
|
+
promiseState.error = error;
|
|
7418
|
+
promiseState.reason = error;
|
|
7419
|
+
promiseState.status = 'rejected';
|
|
7420
|
+
promiseState.isError = true;
|
|
7421
|
+
promiseState.isPending = false;
|
|
7422
|
+
promiseState.isLoading = false;
|
|
7423
|
+
promiseState.request = error.request;
|
|
7424
|
+
promiseState.response = error.response;
|
|
7425
|
+
});
|
|
7426
|
+
}
|
|
7427
|
+
return promiseState;
|
|
7428
|
+
}
|
|
7429
|
+
|
|
7430
|
+
/**
|
|
7431
|
+
* `getRequestState` can be used in both JavaScript and Template contexts.
|
|
7432
|
+
*
|
|
7433
|
+
* ```ts
|
|
7434
|
+
* import { getRequestState } from '@warp-drive/ember';
|
|
7435
|
+
*
|
|
7436
|
+
* const state = getRequestState(future);
|
|
7437
|
+
* ```
|
|
7438
|
+
*
|
|
7439
|
+
* For instance, we could write a getter on a component that updates whenever
|
|
7440
|
+
* the request state advances or the future changes, by combining the function
|
|
7441
|
+
* with the use of `@cached`
|
|
7442
|
+
*
|
|
7443
|
+
* ```ts
|
|
7444
|
+
* class Component {
|
|
7445
|
+
* @cached
|
|
7446
|
+
* get title() {
|
|
7447
|
+
* const state = getRequestState(this.args.request);
|
|
7448
|
+
* if (state.isPending) {
|
|
7449
|
+
* return 'loading...';
|
|
7450
|
+
* }
|
|
7451
|
+
* if (state.isError) { return null; }
|
|
7452
|
+
* return state.result.title;
|
|
7453
|
+
* }
|
|
7454
|
+
* }
|
|
7455
|
+
* ```
|
|
7456
|
+
*
|
|
7457
|
+
* Or in a template as a helper:
|
|
7458
|
+
*
|
|
7459
|
+
* ```gjs
|
|
7460
|
+
* import { getRequestState } from '@warp-drive/ember';
|
|
7461
|
+
*
|
|
7462
|
+
* <template>
|
|
7463
|
+
* {{#let (getRequestState @request) as |state|}}
|
|
7464
|
+
* {{#if state.isPending}}
|
|
7465
|
+
* <Spinner />
|
|
7466
|
+
* {{else if state.isError}}
|
|
7467
|
+
* <ErrorForm @error={{state.error}} />
|
|
7468
|
+
* {{else}}
|
|
7469
|
+
* <h1>{{state.result.title}}</h1>
|
|
7470
|
+
* {{/if}}
|
|
7471
|
+
* {{/let}}
|
|
7472
|
+
* </template>
|
|
7473
|
+
* ```
|
|
7474
|
+
*
|
|
7475
|
+
* If looking to use in a template, consider also the `<Request />` component
|
|
7476
|
+
* which offers a numbe of additional capabilities for requests *beyond* what
|
|
7477
|
+
* `RequestState` provides.
|
|
7478
|
+
*
|
|
7479
|
+
* @typedoc
|
|
7480
|
+
*/
|
|
7481
|
+
function getRequestState(future) {
|
|
7482
|
+
let state = RequestCache.get(future);
|
|
7483
|
+
if (!state) {
|
|
7484
|
+
state = createRequestState(future);
|
|
7485
|
+
RequestCache.set(future, state);
|
|
7486
|
+
}
|
|
7487
|
+
return state;
|
|
7488
|
+
}
|
|
7489
|
+
export { ARRAY_SIGNAL as A, getRequestState as B, CacheHandler as C, IdentifierArray as I, MUTATE as M, RecordArrayManager as R, Store as S, _clearCaches as _, setIdentifierGenerationMethod as a, setIdentifierUpdateMethod as b, setIdentifierForgetMethod as c, setIdentifierResetMethod as d, setKeyInfoForResource as e, isDocumentIdentifier as f, constructResource as g, coerceId as h, isStableIdentifier as i, ensureStringId as j, Collection as k, SOURCE as l, fastPush as m, notifyArray as n, removeRecordDataFor as o, peekCache as p, setRecordIdentifier as q, recordIdentifierFor as r, storeFor as s, StoreMap as t, setCacheFor as u, normalizeModelName as v, RelatedCollection as w, log as x, logGroup as y, getPromiseState as z };
|