@ember-data-mirror/store 5.5.0-alpha.19 → 5.5.0-alpha.21

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.
Files changed (38) hide show
  1. package/dist/-private.js +2 -1
  2. package/dist/-private.js.map +1 -1
  3. package/dist/configure-BfLLW6GY.js +161 -0
  4. package/dist/configure-BfLLW6GY.js.map +1 -0
  5. package/dist/configure.js +1 -0
  6. package/dist/configure.js.map +1 -0
  7. package/dist/index.js +3 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/{many-array-CE2Jr4mQ.js → request-state-BrADgFy5.js} +870 -92
  10. package/dist/request-state-BrADgFy5.js.map +1 -0
  11. package/package.json +19 -11
  12. package/unstable-preview-types/-private/document.d.ts.map +1 -1
  13. package/unstable-preview-types/-private/legacy-model-support/record-reference.d.ts.map +1 -1
  14. package/unstable-preview-types/-private/managers/notification-manager.d.ts.map +1 -1
  15. package/unstable-preview-types/-private/managers/record-array-manager.d.ts.map +1 -1
  16. package/unstable-preview-types/-private/network/request-cache.d.ts +8 -8
  17. package/unstable-preview-types/-private/network/request-cache.d.ts.map +1 -1
  18. package/unstable-preview-types/-private/new-core-tmp/promise-state.d.ts +289 -0
  19. package/unstable-preview-types/-private/new-core-tmp/promise-state.d.ts.map +1 -0
  20. package/unstable-preview-types/-private/new-core-tmp/reactivity/configure.d.ts +92 -0
  21. package/unstable-preview-types/-private/new-core-tmp/reactivity/configure.d.ts.map +1 -0
  22. package/unstable-preview-types/-private/new-core-tmp/reactivity/internal.d.ts +172 -0
  23. package/unstable-preview-types/-private/new-core-tmp/reactivity/internal.d.ts.map +1 -0
  24. package/unstable-preview-types/-private/new-core-tmp/reactivity/signal.d.ts +32 -0
  25. package/unstable-preview-types/-private/new-core-tmp/reactivity/signal.d.ts.map +1 -0
  26. package/unstable-preview-types/-private/new-core-tmp/request-state.d.ts +276 -0
  27. package/unstable-preview-types/-private/new-core-tmp/request-state.d.ts.map +1 -0
  28. package/unstable-preview-types/-private/record-arrays/identifier-array.d.ts +4 -9
  29. package/unstable-preview-types/-private/record-arrays/identifier-array.d.ts.map +1 -1
  30. package/unstable-preview-types/-private/record-arrays/many-array.d.ts +2 -2
  31. package/unstable-preview-types/-private/record-arrays/many-array.d.ts.map +1 -1
  32. package/unstable-preview-types/-private.d.ts +7 -2
  33. package/unstable-preview-types/-private.d.ts.map +1 -1
  34. package/unstable-preview-types/configure.d.ts +21 -0
  35. package/unstable-preview-types/configure.d.ts.map +1 -0
  36. package/unstable-preview-types/index.d.ts +6 -0
  37. package/unstable-preview-types/index.d.ts.map +1 -1
  38. package/dist/many-array-CE2Jr4mQ.js.map +0 -1
@@ -3,11 +3,10 @@ import { macroCondition, getGlobalConfig, dependencySatisfies, importSync } from
3
3
  import { EnableHydration, SkipCache } from '@warp-drive-mirror/core-types/request';
4
4
  import { setLogging, getRuntimeConfig } from '@warp-drive-mirror/core-types/runtime';
5
5
  import { getOrSetGlobal, peekTransient, setTransient } from '@warp-drive-mirror/core-types/-private';
6
- import { _backburner } from '@ember/runloop';
7
- import { defineSubscription, notifySignal, defineSignal, createSignal, subscribe, createArrayTags, addToTransaction, addTransactionCB } from '@ember-data-mirror/tracking/-private';
6
+ import { a as createSignal, b as consumeSignal, n as notifySignal, c as createMemo, w as willSyncFlushWatchers, A as ARRAY_SIGNAL } from "./configure-BfLLW6GY.js";
8
7
  import { CACHE_OWNER, DEBUG_STALE_CACHE_OWNER, DEBUG_IDENTIFIER_BUCKET, DEBUG_CLIENT_ORIGINATED } from '@warp-drive-mirror/core-types/identifier';
9
8
  import { dasherize } from '@ember-data-mirror/request-utils/string';
10
- import { compat } from '@ember-data-mirror/tracking';
9
+ import { getPromiseResult, setPromiseResult } from '@ember-data-mirror/request';
11
10
 
12
11
  /**
13
12
  @module @ember-data-mirror/store
@@ -902,9 +901,245 @@ function _log(scope, prefix, subScop1, subScop2, subScop3, subScop4) {
902
901
  return [];
903
902
  }
904
903
 
904
+ /**
905
+ * A WarpDriveSignal is a wrapper around a framework specific or TC39 signal
906
+ * that enables us to store and manage the signal in a universal way.
907
+ *
908
+ * WarpDrive uses signals to manage three separate concepts:
909
+ *
910
+ * - as a `storage` for a value local to the object that we want to be reactive
911
+ * (see `@local` schema field for an example)
912
+ * - as a `gate` for a memoized getter that we want to act as a reactive property
913
+ * but whose value is computed/pulled from a non-reactive source elsewhere
914
+ * and whose latest value is stored in the signal
915
+ * (see `field` schema field for an example)
916
+ * - as a `gate` with a manually managed value updated on pull when `isStale` is true
917
+ *
918
+ *
919
+ * It offers
920
+ *
921
+ * - a non-reactive way to access/update the current value
922
+ * - a non-reactive way to mark the signal as dirtied
923
+ * - a non-reactive way to store content for why the signal was dirtied
924
+ * - access to the underlying Signal(s) in-use
925
+ *
926
+ * For debugging:
927
+ * - the "key" or "name" of the signal
928
+ * - the "object identity" or "context" to which the signal is attached
929
+ *
930
+ * @internal
931
+ */
932
+
933
+ /**
934
+ * We attach signals to their context object via
935
+ * a Map attached to the object via this symbol.
936
+ *
937
+ * This allows us to store multiple signals
938
+ * on the same object with smaller memory
939
+ * overhead and no WeakMap lookups.
940
+ *
941
+ * Performance sensitive objects should
942
+ * pre-warm their shape by assigning this
943
+ * during initialization.
944
+ *
945
+ * ```ts
946
+ * initializeSignalStore(obj);
947
+ * ```
948
+ *
949
+ * @internal
950
+ */
951
+ const Signals = getOrSetGlobal('Signals', Symbol('Signals'));
952
+
953
+ /**
954
+ * A util that will create a signal store on the object
955
+ * if it does not already exist and returns the associated
956
+ * signal store.
957
+ *
958
+ * @internal
959
+ */
960
+ function withSignalStore(obj) {
961
+ if (obj[Signals] === undefined) {
962
+ initializeSignalStore(obj);
963
+ }
964
+ return obj[Signals];
965
+ }
966
+
967
+ /**
968
+ * A util that will create a signal store on the object
969
+ * if it does not already exist.
970
+ *
971
+ * Useful for pre-warming the shape of an object to ensure
972
+ * a key-transition to add it is not required later.
973
+ *
974
+ * @internal
975
+ */
976
+ function initializeSignalStore(obj) {
977
+ macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
978
+ if (!test) {
979
+ throw new Error(`Signal store already exists on object`);
980
+ }
981
+ })(obj[Signals] === undefined) : {};
982
+ obj[Signals] = new Map();
983
+ }
984
+ function createInternalSignal(signals, obj, key, initialValue) {
985
+ const warpDriveSignal = {
986
+ key,
987
+ context: obj,
988
+ signal: createSignal(obj, key),
989
+ value: initialValue,
990
+ isStale: false
991
+ };
992
+ signals.set(key, warpDriveSignal);
993
+ return warpDriveSignal;
994
+ }
995
+ function getOrCreateInternalSignal(signals, obj, key, initialValue) {
996
+ let signal = peekInternalSignal(signals, key);
997
+ if (!signal) {
998
+ signal = createInternalSignal(signals, obj, key, initialValue);
999
+ }
1000
+ return signal;
1001
+ }
1002
+ function peekInternalSignal(signals, key) {
1003
+ return signals?.get(key);
1004
+ }
1005
+ function consumeInternalSignal(signal) {
1006
+ consumeSignal(signal.signal);
1007
+ }
1008
+ function notifyInternalSignal(signal) {
1009
+ if (signal) {
1010
+ signal.isStale = true;
1011
+ notifySignal(signal.signal);
1012
+ }
1013
+ }
1014
+ function entangleSignal(signals, obj, key, initialValue) {
1015
+ let signal = peekInternalSignal(signals, key);
1016
+ if (!signal) {
1017
+ signal = createInternalSignal(signals, obj, key, initialValue);
1018
+ }
1019
+ consumeInternalSignal(signal);
1020
+ return signal;
1021
+ }
1022
+ function createSignalDescriptor(key, intialValue) {
1023
+ return {
1024
+ enumerable: true,
1025
+ configurable: false,
1026
+ get() {
1027
+ const signals = withSignalStore(this);
1028
+ return entangleSignal(signals, this, key, intialValue).value;
1029
+ },
1030
+ set(value) {
1031
+ const signals = withSignalStore(this);
1032
+ const signal = getOrCreateInternalSignal(signals, this, key, intialValue);
1033
+ if (signal.value !== value) {
1034
+ signal.value = value;
1035
+ notifyInternalSignal(signal);
1036
+ }
1037
+ }
1038
+ };
1039
+ }
1040
+
1041
+ /**
1042
+ * define an enumerable signal property.
1043
+ *
1044
+ * Akin to Object.defineProperty.
1045
+ *
1046
+ * The signal will be lazily created when accessed and scoped to the
1047
+ * instance of the object.
1048
+ *
1049
+ * @internal
1050
+ */
1051
+ function defineSignal(obj, key, v) {
1052
+ Object.defineProperty(obj, key, createSignalDescriptor(key, v));
1053
+ }
1054
+
1055
+ /**
1056
+ * Define a non-enumerable signal property.
1057
+ *
1058
+ * @internal
1059
+ */
1060
+ function defineNonEnumerableSignal(obj, key, v) {
1061
+ const desc = createSignalDescriptor(key, v);
1062
+ desc.enumerable = false;
1063
+ Object.defineProperty(obj, key, desc);
1064
+ }
1065
+ function memoized(target, key, descriptor) {
1066
+ // Error on `@memoized()`, `@memoized(...args)`, and `@memoized propName = value;`
1067
+ macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
1068
+ if (!test) {
1069
+ throw new Error('You attempted to use @memoized(), which is not necessary nor supported. Remove the parentheses and you will be good to go!');
1070
+ }
1071
+ })(target !== undefined) : {};
1072
+ macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
1073
+ if (!test) {
1074
+ throw new Error(`You attempted to use @memoized on with ${arguments.length > 1 ? 'arguments' : 'an argument'} ( @memoized(${Array.from(arguments).map(d => `'${d}'`).join(', ')}), which is not supported. Dependencies are automatically tracked, so you can just use ${'`@memoized`'}`);
1075
+ }
1076
+ })(typeof target === 'object' && typeof key === 'string' && typeof descriptor === 'object' && arguments.length === 3) : {};
1077
+ macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
1078
+ if (!test) {
1079
+ throw new Error(`The @memoized decorator must be applied to getters. '${key}' is not a getter.`);
1080
+ }
1081
+ })(typeof descriptor.get === 'function') : {};
1082
+
1083
+ // eslint-disable-next-line @typescript-eslint/unbound-method
1084
+ const getter = descriptor.get;
1085
+ descriptor.get = function () {
1086
+ const signals = withSignalStore(this);
1087
+ let memoSignal = signals.get(key);
1088
+ if (!memoSignal) {
1089
+ memoSignal = createMemo(this, key, getter.bind(this));
1090
+ signals.set(key, memoSignal);
1091
+ }
1092
+ return memoSignal();
1093
+ };
1094
+ return descriptor;
1095
+ }
1096
+ function gate(_target, key, desc) {
1097
+ // eslint-disable-next-line @typescript-eslint/unbound-method
1098
+ const getter = desc.get;
1099
+ // eslint-disable-next-line @typescript-eslint/unbound-method
1100
+ const setter = desc.set;
1101
+ desc.get = function () {
1102
+ const signals = withSignalStore(this);
1103
+ let signal = peekInternalSignal(signals, key);
1104
+ if (!signal) {
1105
+ signal = createInternalSignal(signals, this, key, getter.call(this));
1106
+ } else if (signal.isStale) {
1107
+ signal.isStale = false;
1108
+ signal.value = getter.call(this);
1109
+ }
1110
+ consumeInternalSignal(signal);
1111
+ return signal.value;
1112
+ };
1113
+ if (setter) {
1114
+ desc.set = function (v) {
1115
+ const signals = withSignalStore(this);
1116
+ let signal = peekInternalSignal(signals, key);
1117
+ if (!signal) {
1118
+ // we can't use `v` as initialValue here because setters don't
1119
+ // return the value and the final value may be different
1120
+ // than what the setter was called with.
1121
+ signal = createInternalSignal(signals, this, key, undefined);
1122
+ signal.isStale = true;
1123
+ }
1124
+ setter.call(this, v);
1125
+ // when a gate is set, we do not notify the signal
1126
+ // as its update is controlled externally.
1127
+ };
1128
+ }
1129
+ return desc;
1130
+ }
1131
+ function defineGate(obj, key, desc) {
1132
+ const options = Object.assign({
1133
+ enumerable: true,
1134
+ configurable: false
1135
+ }, gate(obj, key, desc));
1136
+ Object.defineProperty(obj, key, options);
1137
+ }
1138
+
905
1139
  /**
906
1140
  * @module @ember-data-mirror/store
907
1141
  */
1142
+
908
1143
  function urlFromLink(link) {
909
1144
  if (typeof link === 'string') return link;
910
1145
  return link.href;
@@ -981,6 +1216,7 @@ class ReactiveDocument {
981
1216
  this._store = store;
982
1217
  this._localCache = localCache;
983
1218
  this.identifier = identifier;
1219
+ const signals = withSignalStore(this);
984
1220
 
985
1221
  // TODO if we ever enable auto-cleanup of the cache, we will need to tear this down
986
1222
  // in a destroy method
@@ -990,10 +1226,10 @@ class ReactiveDocument {
990
1226
  case 'updated':
991
1227
  // FIXME in the case of a collection we need to notify it's length
992
1228
  // and have it recalc
993
- notifySignal(this, 'data');
994
- notifySignal(this, 'links');
995
- notifySignal(this, 'meta');
996
- notifySignal(this, 'errors');
1229
+ notifyInternalSignal(peekInternalSignal(signals, 'data'));
1230
+ notifyInternalSignal(peekInternalSignal(signals, 'links'));
1231
+ notifyInternalSignal(peekInternalSignal(signals, 'meta'));
1232
+ notifyInternalSignal(peekInternalSignal(signals, 'errors'));
997
1233
  break;
998
1234
  }
999
1235
  });
@@ -1120,7 +1356,7 @@ class ReactiveDocument {
1120
1356
  return data;
1121
1357
  }
1122
1358
  }
1123
- defineSubscription(ReactiveDocument.prototype, 'errors', {
1359
+ defineGate(ReactiveDocument.prototype, 'errors', {
1124
1360
  get() {
1125
1361
  const {
1126
1362
  identifier
@@ -1143,7 +1379,7 @@ defineSubscription(ReactiveDocument.prototype, 'errors', {
1143
1379
  return 'errors' in doc ? doc.errors : undefined;
1144
1380
  }
1145
1381
  });
1146
- defineSubscription(ReactiveDocument.prototype, 'data', {
1382
+ defineGate(ReactiveDocument.prototype, 'data', {
1147
1383
  get() {
1148
1384
  const {
1149
1385
  identifier,
@@ -1170,7 +1406,7 @@ defineSubscription(ReactiveDocument.prototype, 'data', {
1170
1406
  }
1171
1407
  }
1172
1408
  });
1173
- defineSubscription(ReactiveDocument.prototype, 'links', {
1409
+ defineGate(ReactiveDocument.prototype, 'links', {
1174
1410
  get() {
1175
1411
  const {
1176
1412
  identifier
@@ -1187,7 +1423,7 @@ defineSubscription(ReactiveDocument.prototype, 'links', {
1187
1423
  return data.links;
1188
1424
  }
1189
1425
  });
1190
- defineSubscription(ReactiveDocument.prototype, 'meta', {
1426
+ defineGate(ReactiveDocument.prototype, 'meta', {
1191
1427
  get() {
1192
1428
  const {
1193
1429
  identifier
@@ -1209,6 +1445,10 @@ defineSubscription(ReactiveDocument.prototype, 'meta', {
1209
1445
  @module @ember-data-mirror/store
1210
1446
  */
1211
1447
 
1448
+ /**
1449
+ @module @ember-data-mirror/store
1450
+ */
1451
+
1212
1452
  /**
1213
1453
  A `RecordReference` is a low-level API that allows users and
1214
1454
  addon authors to perform meta-operations on a record.
@@ -2624,10 +2864,6 @@ class CacheManager {
2624
2864
  function isCacheOperationValue(value) {
2625
2865
  return value === 'added' || value === 'state' || value === 'updated' || value === 'removed' || value === 'invalidated';
2626
2866
  }
2627
- function runLoopIsFlushing() {
2628
- //@ts-expect-error
2629
- return !!_backburner.currentInstance && _backburner._autorun !== true;
2630
- }
2631
2867
  function count(label) {
2632
2868
  // @ts-expect-error
2633
2869
  // eslint-disable-next-line
@@ -2823,11 +3059,11 @@ class NotificationManager {
2823
3059
  _scheduleNotify() {
2824
3060
  const asyncFlush = this.store._enableAsyncFlush;
2825
3061
  if (this._hasFlush) {
2826
- if (asyncFlush !== false && !runLoopIsFlushing()) {
3062
+ if (asyncFlush !== false && !willSyncFlushWatchers()) {
2827
3063
  return false;
2828
3064
  }
2829
3065
  }
2830
- if (asyncFlush && !runLoopIsFlushing()) {
3066
+ if (asyncFlush && !willSyncFlushWatchers()) {
2831
3067
  this._hasFlush = true;
2832
3068
  return false;
2833
3069
  }
@@ -2890,24 +3126,11 @@ class NotificationManager {
2890
3126
  */
2891
3127
 
2892
3128
  const NativeProxy = Proxy;
2893
- function decorateMethodV2(prototype, prop, decorators) {
2894
- const origDesc = Object.getOwnPropertyDescriptor(prototype, prop);
2895
- let desc = {
2896
- ...origDesc
2897
- };
2898
- for (let decorator of decorators) {
2899
- desc = decorator(prototype, prop, desc) || desc;
2900
- }
2901
- if (desc.initializer !== void 0) {
2902
- desc.value = desc.initializer ? desc.initializer.call(prototype) : void 0;
2903
- desc.initializer = void 0;
2904
- }
2905
- Object.defineProperty(prototype, prop, desc);
2906
- }
2907
3129
 
2908
3130
  /**
2909
3131
  @module @ember-data-mirror/store
2910
3132
  */
3133
+
2911
3134
  const ARRAY_GETTER_METHODS = new Set([Symbol.iterator, 'concat', 'entries', 'every', 'fill', 'filter', 'find', 'findIndex', 'flat', 'flatMap', 'forEach', 'includes', 'indexOf', 'join', 'keys', 'lastIndexOf', 'map', 'reduce', 'reduceRight', 'slice', 'some', 'values']);
2912
3135
  const ARRAY_SETTER_METHODS = new Set(['push', 'pop', 'unshift', 'shift', 'splice', 'sort']);
2913
3136
  const SYNC_PROPS = new Set(['[]', 'length', 'links', 'meta']);
@@ -2920,14 +3143,9 @@ function isArraySetter(prop) {
2920
3143
  function isSelfProp(self, prop) {
2921
3144
  return prop in self;
2922
3145
  }
2923
- const ARRAY_SIGNAL = getOrSetGlobal('#signal', Symbol('#signal'));
2924
3146
  const SOURCE = getOrSetGlobal('#source', Symbol('#source'));
2925
3147
  const MUTATE = getOrSetGlobal('#update', Symbol('#update'));
2926
- const NOTIFY = getOrSetGlobal('#notify', Symbol('#notify'));
2927
3148
  const IS_COLLECTION = getOrSetGlobal('IS_COLLECTION', Symbol.for('Collection'));
2928
- function notifyArray(arr) {
2929
- addToTransaction(arr[ARRAY_SIGNAL]);
2930
- }
2931
3149
  function convertToInt(prop) {
2932
3150
  if (typeof prop === 'symbol') return null;
2933
3151
  const num = Number(prop);
@@ -2991,11 +3209,6 @@ class IdentifierArray {
2991
3209
  isDestroyed = false;
2992
3210
  _updatingPromise = null;
2993
3211
  identifier;
2994
- [IS_COLLECTION] = true;
2995
- [SOURCE];
2996
- [NOTIFY]() {
2997
- notifyArray(this);
2998
- }
2999
3212
 
3000
3213
  /**
3001
3214
  The store that created this record array.
@@ -3009,20 +3222,9 @@ class IdentifierArray {
3009
3222
  // changing the reference breaks the Proxy
3010
3223
  // this[SOURCE] = [];
3011
3224
  this[SOURCE].length = 0;
3012
- this[NOTIFY]();
3225
+ notifyInternalSignal(this[ARRAY_SIGNAL]);
3013
3226
  this.isDestroyed = !clear;
3014
3227
  }
3015
-
3016
- // length must be on self for proxied methods to work properly
3017
- get length() {
3018
- return this[SOURCE].length;
3019
- }
3020
- static {
3021
- decorateMethodV2(this.prototype, "length", [compat]);
3022
- }
3023
- set length(value) {
3024
- this[SOURCE].length = value;
3025
- }
3026
3228
  constructor(options) {
3027
3229
  // eslint-disable-next-line @typescript-eslint/no-this-alias
3028
3230
  const self = this;
@@ -3031,10 +3233,13 @@ class IdentifierArray {
3031
3233
  this._manager = options.manager;
3032
3234
  this.identifier = options.identifier || null;
3033
3235
  this[SOURCE] = options.identifiers;
3034
- this[ARRAY_SIGNAL] = createSignal(this, 'length');
3236
+ this[IS_COLLECTION] = true;
3237
+
3238
+ // we attach the signal storage to the class
3239
+ // so that its easier to find debugging.
3240
+ const signals = withSignalStore(this);
3035
3241
  const store = options.store;
3036
3242
  const boundFns = new Map();
3037
- const _SIGNAL = this[ARRAY_SIGNAL];
3038
3243
  const PrivateState = {
3039
3244
  links: options.links || null,
3040
3245
  meta: options.meta || null
@@ -3044,31 +3249,36 @@ class IdentifierArray {
3044
3249
  // when a mutation occurs
3045
3250
  // we track all mutations within the call
3046
3251
  // and forward them as one
3047
-
3252
+ let _SIGNAL = null;
3048
3253
  const proxy = new NativeProxy(this[SOURCE], {
3049
3254
  get(target, prop, receiver) {
3050
3255
  const index = convertToInt(prop);
3051
- if (_SIGNAL.shouldReset && (index !== null || SYNC_PROPS.has(prop) || isArrayGetter(prop))) {
3256
+ if (_SIGNAL.isStale && (index !== null || SYNC_PROPS.has(prop) || isArrayGetter(prop))) {
3052
3257
  options.manager._syncArray(receiver);
3053
- _SIGNAL.t = false;
3054
- _SIGNAL.shouldReset = false;
3258
+ _SIGNAL.isStale = false;
3055
3259
  }
3056
3260
  if (index !== null) {
3057
3261
  const identifier = target[index];
3058
3262
  if (!transaction) {
3059
- subscribe(_SIGNAL);
3263
+ consumeInternalSignal(_SIGNAL);
3060
3264
  }
3061
3265
  return identifier && store._instanceCache.getRecord(identifier);
3062
3266
  }
3063
- if (prop === 'meta') return subscribe(_SIGNAL), PrivateState.meta;
3064
- if (prop === 'links') return subscribe(_SIGNAL), PrivateState.links;
3065
- if (prop === '[]') return subscribe(_SIGNAL), receiver;
3267
+ if (prop === ARRAY_SIGNAL) {
3268
+ return _SIGNAL;
3269
+ }
3270
+ if (prop === 'length') {
3271
+ return consumeInternalSignal(_SIGNAL), target.length;
3272
+ }
3273
+ if (prop === 'meta') return consumeInternalSignal(_SIGNAL), PrivateState.meta;
3274
+ if (prop === 'links') return consumeInternalSignal(_SIGNAL), PrivateState.links;
3275
+ if (prop === '[]') return consumeInternalSignal(_SIGNAL), receiver;
3066
3276
  if (isArrayGetter(prop)) {
3067
3277
  let fn = boundFns.get(prop);
3068
3278
  if (fn === undefined) {
3069
3279
  if (prop === 'forEach') {
3070
3280
  fn = function () {
3071
- subscribe(_SIGNAL);
3281
+ consumeInternalSignal(_SIGNAL);
3072
3282
  transaction = true;
3073
3283
  const result = safeForEach(receiver, target, store, arguments[0], arguments[1]);
3074
3284
  transaction = false;
@@ -3076,7 +3286,7 @@ class IdentifierArray {
3076
3286
  };
3077
3287
  } else {
3078
3288
  fn = function () {
3079
- subscribe(_SIGNAL);
3289
+ consumeInternalSignal(_SIGNAL);
3080
3290
  // array functions must run through Reflect to work properly
3081
3291
  // binding via other means will not work.
3082
3292
  transaction = true;
@@ -3119,7 +3329,7 @@ class IdentifierArray {
3119
3329
  return fn;
3120
3330
  }
3121
3331
  if (isSelfProp(self, prop)) {
3122
- if (prop === NOTIFY || prop === ARRAY_SIGNAL || prop === SOURCE) {
3332
+ if (prop === SOURCE) {
3123
3333
  return self[prop];
3124
3334
  }
3125
3335
  let fn = boundFns.get(prop);
@@ -3127,7 +3337,7 @@ class IdentifierArray {
3127
3337
  const outcome = self[prop];
3128
3338
  if (typeof outcome === 'function') {
3129
3339
  fn = function () {
3130
- subscribe(_SIGNAL);
3340
+ consumeInternalSignal(_SIGNAL);
3131
3341
  // array functions must run through Reflect to work properly
3132
3342
  // binding via other means will not work.
3133
3343
  return Reflect.apply(outcome, receiver, arguments);
@@ -3135,7 +3345,7 @@ class IdentifierArray {
3135
3345
  boundFns.set(prop, fn);
3136
3346
  return fn;
3137
3347
  }
3138
- return subscribe(_SIGNAL), outcome;
3348
+ return consumeInternalSignal(_SIGNAL), outcome;
3139
3349
  }
3140
3350
  return target[prop];
3141
3351
  },
@@ -3253,8 +3463,10 @@ class IdentifierArray {
3253
3463
  }
3254
3464
  });
3255
3465
  }
3256
- createArrayTags(proxy, _SIGNAL);
3257
- this[NOTIFY] = this[NOTIFY].bind(proxy);
3466
+
3467
+ // we entangle the signal on the returned proxy since that is
3468
+ // the object that other code will be interfacing with.
3469
+ _SIGNAL = entangleSignal(signals, proxy, ARRAY_SIGNAL, undefined);
3258
3470
  return proxy;
3259
3471
  }
3260
3472
 
@@ -3345,7 +3557,7 @@ const desc = {
3345
3557
  }
3346
3558
  }
3347
3559
  };
3348
- compat(desc);
3560
+ // compat(desc);
3349
3561
  Object.defineProperty(IdentifierArray.prototype, '[]', desc);
3350
3562
  defineSignal(IdentifierArray.prototype, 'isUpdating', false);
3351
3563
  class Collection extends IdentifierArray {
@@ -3418,6 +3630,7 @@ function extractIdentifierFromRecord$2(record) {
3418
3630
  /**
3419
3631
  @module @ember-data-mirror/store
3420
3632
  */
3633
+
3421
3634
  const FAKE_ARR = getOrSetGlobal('FAKE_ARR', {});
3422
3635
  const SLICE_BATCH_SIZE = 1200;
3423
3636
  /**
@@ -3519,9 +3732,11 @@ class RecordArrayManager {
3519
3732
 
3520
3733
  // then pull new state if required
3521
3734
  if (isRequestArray) {
3522
- const tag = array[ARRAY_SIGNAL];
3523
- if (tag.reason === 'cache-sync') {
3524
- tag.reason = null;
3735
+ const signal = array[ARRAY_SIGNAL];
3736
+
3737
+ // we only need to rebuild the array from cache if a full sync is required
3738
+ // due to notification that the cache has changed
3739
+ if (signal.value === 'cache-sync') {
3525
3740
  const doc = this.store.cache.peek(array.identifier);
3526
3741
  macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
3527
3742
  if (!test) {
@@ -3604,15 +3819,13 @@ class RecordArrayManager {
3604
3819
  if (array === FAKE_ARR) {
3605
3820
  return;
3606
3821
  }
3607
- const tag = array[ARRAY_SIGNAL];
3608
- if (shouldSyncFromCache) {
3609
- tag.reason = 'cache-sync';
3610
- }
3611
- if (!tag.shouldReset) {
3612
- tag.shouldReset = true;
3613
- addTransactionCB(array[NOTIFY]);
3614
- } else if (delta > 0 && !tag.t) {
3615
- addTransactionCB(array[NOTIFY]);
3822
+ const signal = array[ARRAY_SIGNAL];
3823
+ if (!signal.isStale || delta > 0) {
3824
+ notifyInternalSignal(signal);
3825
+
3826
+ // when the cache has updated for our array, we need to
3827
+ // do a full rebuild of the array
3828
+ signal.value = shouldSyncFromCache ? 'cache-sync' : 'patch';
3616
3829
  }
3617
3830
  }
3618
3831
  _getPendingFor(identifier, includeManaged, isRemove) {
@@ -3676,7 +3889,7 @@ class RecordArrayManager {
3676
3889
  fastPush(source, identifiers);
3677
3890
  this._set.set(array, new Set(identifiers));
3678
3891
  if (!isCollection(array)) {
3679
- notifyArray(array);
3892
+ notifyInternalSignal(array[ARRAY_SIGNAL]);
3680
3893
  array.meta = payload?.meta || null;
3681
3894
  array.links = payload?.links || null;
3682
3895
  }
@@ -3979,7 +4192,7 @@ class RequestStateService {
3979
4192
  * @method subscribeForRecord
3980
4193
  * @public
3981
4194
  * @param {StableRecordIdentifier} identifier
3982
- * @param {(state: RequestState) => void} callback
4195
+ * @param {(state: RequestCacheRequestState) => void} callback
3983
4196
  */
3984
4197
  subscribeForRecord(identifier, callback) {
3985
4198
  let subscriptions = this._subscriptions.get(identifier);
@@ -3996,7 +4209,7 @@ class RequestStateService {
3996
4209
  * @method getPendingRequestsForRecord
3997
4210
  * @public
3998
4211
  * @param {StableRecordIdentifier} identifier
3999
- * @return {RequestState[]} an array of request states for any pending requests for the given identifier
4212
+ * @return {RequestCacheRequestState[]} an array of request states for any pending requests for the given identifier
4000
4213
  */
4001
4214
  getPendingRequestsForRecord(identifier) {
4002
4215
  return this._pending.get(identifier) || EMPTY_ARR;
@@ -4008,7 +4221,7 @@ class RequestStateService {
4008
4221
  * @method getLastRequestForRecord
4009
4222
  * @public
4010
4223
  * @param {StableRecordIdentifier} identifier
4011
- * @return {RequestState | null} the state of the most recent request for the given identifier
4224
+ * @return {RequestCacheRequestState | null} the state of the most recent request for the given identifier
4012
4225
  */
4013
4226
  getLastRequestForRecord(identifier) {
4014
4227
  const requests = this._done.get(identifier);
@@ -6748,9 +6961,7 @@ class RelatedCollection extends IdentifierArray {
6748
6961
  }
6749
6962
  }
6750
6963
  notify() {
6751
- const signal = this[ARRAY_SIGNAL];
6752
- signal.shouldReset = true;
6753
- notifyArray(this);
6964
+ notifyInternalSignal(this[ARRAY_SIGNAL]);
6754
6965
  }
6755
6966
 
6756
6967
  /**
@@ -6916,6 +7127,573 @@ function mutate(collection, mutation, _SIGNAL) {
6916
7127
  }
6917
7128
  })(typeof collection._manager.mutate === 'function') : {};
6918
7129
  collection._manager.mutate(mutation);
6919
- addToTransaction(_SIGNAL);
7130
+ notifyInternalSignal(_SIGNAL);
7131
+ }
7132
+ const PromiseCache = new WeakMap();
7133
+
7134
+ /**
7135
+ * The state of a promise in the "pending"
7136
+ * state. This is the default initial state.
7137
+ *
7138
+ * @typedoc
7139
+ */
7140
+
7141
+ /**
7142
+ * The state of a promise in the "fulfilled" state.
7143
+ * This is the state of a promise that has resolved
7144
+ * successfully.
7145
+ *
7146
+ * @typedoc
7147
+ */
7148
+
7149
+ /**
7150
+ * The state of a promise in the "rejected" state.
7151
+ * This is the state of a promise that has rejected
7152
+ * with an error.
7153
+ *
7154
+ * @typedoc
7155
+ */
7156
+
7157
+ /**
7158
+ * The state of a promise. This is the type that is returned
7159
+ * from `getPromiseState`.
7160
+ *
7161
+ * See also:
7162
+ * - {@link PendingPromise}
7163
+ * - {@link ResolvedPromise}
7164
+ * - {@link RejectedPromise}
7165
+ *
7166
+ * @typedoc
7167
+ */
7168
+
7169
+ const PromiseStateProto = {};
7170
+
7171
+ // TODO introduce a new mechanism for defining multiple properties
7172
+ // that share a common signal
7173
+ defineSignal(PromiseStateProto, 'reason', null);
7174
+ defineSignal(PromiseStateProto, 'value', null);
7175
+ defineSignal(PromiseStateProto, 'result', null);
7176
+ defineSignal(PromiseStateProto, 'error', null);
7177
+ defineSignal(PromiseStateProto, 'status', 'pending');
7178
+ defineSignal(PromiseStateProto, 'isPending', true);
7179
+ defineSignal(PromiseStateProto, 'isLoading', true);
7180
+ defineSignal(PromiseStateProto, 'isSuccess', false);
7181
+ defineSignal(PromiseStateProto, 'isError', false);
7182
+ function createPromiseState(promise) {
7183
+ const state = getPromiseResult(promise);
7184
+ const promiseState = Object.create(PromiseStateProto);
7185
+ if (state) {
7186
+ if (state.isError) {
7187
+ promiseState.error = state.result;
7188
+ promiseState.reason = state.result;
7189
+ promiseState.status = 'rejected';
7190
+ promiseState.isError = true;
7191
+ promiseState.isPending = false;
7192
+ promiseState.isLoading = false;
7193
+ } else {
7194
+ promiseState.result = state.result;
7195
+ promiseState.value = state.result;
7196
+ promiseState.status = 'fulfilled';
7197
+ promiseState.isSuccess = true;
7198
+ promiseState.isPending = false;
7199
+ promiseState.isLoading = false;
7200
+ }
7201
+ } else {
7202
+ void promise.then(result => {
7203
+ setPromiseResult(promise, {
7204
+ isError: false,
7205
+ result
7206
+ });
7207
+ promiseState.result = result;
7208
+ promiseState.value = result;
7209
+ promiseState.status = 'fulfilled';
7210
+ promiseState.isSuccess = true;
7211
+ promiseState.isPending = false;
7212
+ promiseState.isLoading = false;
7213
+ }, error => {
7214
+ setPromiseResult(promise, {
7215
+ isError: true,
7216
+ result: error
7217
+ });
7218
+ promiseState.error = error;
7219
+ promiseState.reason = error;
7220
+ promiseState.status = 'rejected';
7221
+ promiseState.isError = true;
7222
+ promiseState.isPending = false;
7223
+ promiseState.isLoading = false;
7224
+ });
7225
+ }
7226
+ return promiseState;
7227
+ }
7228
+ const LegacyPromiseProxy = Symbol.for('LegacyPromiseProxy');
7229
+ function isLegacyAwaitable(promise) {
7230
+ return LegacyPromiseProxy in promise && 'promise' in promise && promise[LegacyPromiseProxy] === true;
7231
+ }
7232
+ function getPromise(promise) {
7233
+ return isLegacyAwaitable(promise) ? promise.promise : promise;
7234
+ }
7235
+
7236
+ /**
7237
+ * Returns a reactive state-machine for the provided promise or awaitable.
7238
+ *
7239
+ * Repeat calls to `getPromiseState` with the same promise will return the same state object
7240
+ * making is safe and easy to use in templates and JavaScript code to produce reactive
7241
+ * behaviors around promises.
7242
+ *
7243
+ * `getPromiseState` can be used in both JavaScript and Template contexts.
7244
+ *
7245
+ * ```ts
7246
+ * import { getPromiseState } from '@warp-drive-mirror/ember';
7247
+ *
7248
+ * const state = getPromiseState(promise);
7249
+ * ```
7250
+ *
7251
+ * For instance, we could write a getter on a component that updates whenever
7252
+ * the promise state advances or the promise changes, by combining the function
7253
+ * with the use of `@cached`
7254
+ *
7255
+ * ```ts
7256
+ * class Component {
7257
+ * @cached
7258
+ * get title() {
7259
+ * const state = getPromiseState(this.args.request);
7260
+ * if (state.isPending) {
7261
+ * return 'loading...';
7262
+ * }
7263
+ * if (state.isError) { return null; }
7264
+ * return state.result.title;
7265
+ * }
7266
+ * }
7267
+ * ```
7268
+ *
7269
+ * Or in a template as a helper:
7270
+ *
7271
+ * ```gjs
7272
+ * import { getPromiseState } from '@warp-drive-mirror/ember';
7273
+ *
7274
+ * <template>
7275
+ * {{#let (getPromiseState @request) as |state|}}
7276
+ * {{#if state.isPending}} <Spinner />
7277
+ * {{else if state.isError}} <ErrorForm @error={{state.error}} />
7278
+ * {{else}}
7279
+ * <h1>{{state.result.title}}</h1>
7280
+ * {{/if}}
7281
+ * {{/let}}
7282
+ * </template>
7283
+ * ```
7284
+ *
7285
+ * If looking to use in a template, consider also the `<Await />` component.
7286
+ *
7287
+ * @typedoc
7288
+ */
7289
+ function getPromiseState(promise) {
7290
+ const _promise = getPromise(promise);
7291
+ let state = PromiseCache.get(_promise);
7292
+ if (!state) {
7293
+ state = createPromiseState(_promise);
7294
+ PromiseCache.set(_promise, state);
7295
+ }
7296
+ return state;
7297
+ }
7298
+ const RequestCache = new WeakMap();
7299
+ function isAbortError(error) {
7300
+ return error instanceof DOMException && error.name === 'AbortError';
7301
+ }
7302
+ async function watchStream(stream, state) {
7303
+ const reader = stream.getReader();
7304
+ let bytesLoaded = 0;
7305
+ let shouldForward = state._stream !== null && state._stream.readable.locked;
7306
+ let isForwarding = shouldForward;
7307
+ let writer = state._stream?.writable.getWriter();
7308
+ const buffer = [];
7309
+ state._isPending = false;
7310
+ state._isStarted = true;
7311
+ state._startTime = performance.now();
7312
+ while (true) {
7313
+ const {
7314
+ value,
7315
+ done
7316
+ } = await reader.read();
7317
+ if (done) {
7318
+ break;
7319
+ }
7320
+ bytesLoaded += value.byteLength;
7321
+ state._bytesLoaded = bytesLoaded;
7322
+ state._lastPacketTime = performance.now();
7323
+ shouldForward = shouldForward || state._stream !== null && state._stream.readable.locked;
7324
+ if (shouldForward) {
7325
+ if (!isForwarding) {
7326
+ isForwarding = true;
7327
+ writer = state._stream.writable.getWriter();
7328
+ for (const item of buffer) {
7329
+ await writer.ready;
7330
+ await writer.write(item);
7331
+ }
7332
+ buffer.length = 0;
7333
+ }
7334
+ await writer.ready;
7335
+ await writer.write(value);
7336
+ } else {
7337
+ buffer.push(value);
7338
+ }
7339
+ }
7340
+
7341
+ // if we are still forwarding, we need to close the writer
7342
+ if (isForwarding) {
7343
+ await writer.ready;
7344
+ await writer.close();
7345
+ } else if (state._stream) {
7346
+ // if we are not forwarding, we need to cancel the stream
7347
+ await state._stream.readable.cancel('The Stream Has Already Ended');
7348
+ state._stream = null;
7349
+ }
7350
+ const endTime = performance.now();
7351
+ state._endTime = endTime;
7352
+ state._isComplete = true;
7353
+ state._isStarted = false;
7354
+ }
7355
+
7356
+ /**
7357
+ * Lazily consumes the stream of a request, providing a number of
7358
+ * reactive properties that can be used to build UIs that respond
7359
+ * to the progress of a request.
7360
+ *
7361
+ * @typedoc
7362
+ */
7363
+ class RequestLoadingState {
7364
+ _stream = null;
7365
+ _future;
7366
+ _triggered = false;
7367
+ _trigger() {
7368
+ if (this._triggered) {
7369
+ return;
7370
+ }
7371
+ this._triggered = true;
7372
+ const future = this._future;
7373
+ const promise = future.getStream();
7374
+ if (promise.sizeHint) {
7375
+ this._sizeHint = promise.sizeHint;
7376
+ }
7377
+ this.promise = promise.then(stream => {
7378
+ if (!stream) {
7379
+ this._isPending = false;
7380
+ this._isComplete = true;
7381
+ return;
7382
+ }
7383
+ return watchStream(stream, this);
7384
+ }, error => {
7385
+ this._isPending = false;
7386
+ this._isStarted = false;
7387
+ if (isAbortError(error)) {
7388
+ this._isCancelled = true;
7389
+ this._isComplete = true;
7390
+ }
7391
+ this._isErrored = true;
7392
+ this._error = error;
7393
+ });
7394
+ }
7395
+ promise = null;
7396
+ get isPending() {
7397
+ this._trigger();
7398
+ return this._isPending;
7399
+ }
7400
+ get sizeHint() {
7401
+ this._trigger();
7402
+ return this._sizeHint;
7403
+ }
7404
+ get stream() {
7405
+ this._trigger();
7406
+ if (!this._stream) {
7407
+ if (this._isComplete || this._isCancelled || this._isErrored) {
7408
+ return null;
7409
+ }
7410
+ this._stream = new TransformStream();
7411
+ }
7412
+ return this._stream.readable;
7413
+ }
7414
+ get isStarted() {
7415
+ this._trigger();
7416
+ return this._isStarted;
7417
+ }
7418
+ get bytesLoaded() {
7419
+ this._trigger();
7420
+ return this._bytesLoaded;
7421
+ }
7422
+ get startTime() {
7423
+ this._trigger();
7424
+ return this._startTime;
7425
+ }
7426
+ get endTime() {
7427
+ this._trigger();
7428
+ return this._endTime;
7429
+ }
7430
+ get lastPacketTime() {
7431
+ this._trigger();
7432
+ return this._lastPacketTime;
7433
+ }
7434
+ get isComplete() {
7435
+ this._trigger();
7436
+ return this._isComplete;
7437
+ }
7438
+ get isCancelled() {
7439
+ this._trigger();
7440
+ return this._isCancelled;
7441
+ }
7442
+ get isErrored() {
7443
+ this._trigger();
7444
+ return this._isErrored;
7445
+ }
7446
+ get error() {
7447
+ this._trigger();
7448
+ return this._error;
7449
+ }
7450
+ get elapsedTime() {
7451
+ return (this.endTime || this.lastPacketTime) - this.startTime;
7452
+ }
7453
+ get completedRatio() {
7454
+ return this.sizeHint ? this.bytesLoaded / this.sizeHint : 0;
7455
+ }
7456
+ get remainingRatio() {
7457
+ return 1 - this.completedRatio;
7458
+ }
7459
+ get duration() {
7460
+ return this.endTime - this.startTime;
7461
+ }
7462
+ get speed() {
7463
+ // bytes per second
7464
+ return this.bytesLoaded / (this.elapsedTime / 1000);
7465
+ }
7466
+ constructor(future) {
7467
+ this._future = future;
7468
+ }
7469
+ abort = () => {
7470
+ this._future.abort();
7471
+ };
7472
+ }
7473
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_isPending', true);
7474
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_isStarted', false);
7475
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_isComplete', false);
7476
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_isCancelled', false);
7477
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_isErrored', false);
7478
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_error', null);
7479
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_sizeHint', 0);
7480
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_bytesLoaded', 0);
7481
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_startTime', 0);
7482
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_endTime', 0);
7483
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_lastPacketTime', 0);
7484
+
7485
+ /**
7486
+ * The state of a request in the "pending"
7487
+ * state. This is the default initial state.
7488
+ *
7489
+ * Extends the {@link PendingPromise} interface.
7490
+ *
7491
+ * @typedoc
7492
+ */
7493
+
7494
+ /**
7495
+ * The state of a request in the "fulfilled" state.
7496
+ * This is the state of a request that has resolved
7497
+ * successfully.
7498
+ *
7499
+ * Extends the {@link ResolvedPromise} interface.
7500
+ *
7501
+ * @typedoc
7502
+ */
7503
+
7504
+ /**
7505
+ * The state of a request in the "rejected" state.
7506
+ * This is the state of a request that has rejected
7507
+ * with an error.
7508
+ *
7509
+ * Extends the {@link RejectedPromise} interface.
7510
+ *
7511
+ * @typedoc
7512
+ */
7513
+
7514
+ /**
7515
+ * The state of a request in the "cancelled" state.
7516
+ * This is the state of a promise that has been
7517
+ * cancelled.
7518
+ *
7519
+ * @typedoc
7520
+ */
7521
+
7522
+ /**
7523
+ * RequestState extends the concept of PromiseState to provide a reactive
7524
+ * wrapper for a request `Future` which allows you write declarative code
7525
+ * around a Future's control flow.
7526
+ *
7527
+ * It is useful in both Template and JavaScript contexts, allowing you
7528
+ * to quickly derive behaviors and data from pending, error and success
7529
+ * states.
7530
+ *
7531
+ * The key difference between a Promise and a Future is that Futures provide
7532
+ * access to a stream of their content, the identity of the request (if any)
7533
+ * as well as the ability to attempt to abort the request.
7534
+ *
7535
+ * ```ts
7536
+ * interface Future<T> extends Promise<T>> {
7537
+ * getStream(): Promise<ReadableStream>;
7538
+ * abort(): void;
7539
+ * lid: StableDocumentIdentifier | null;
7540
+ * }
7541
+ * ```
7542
+ *
7543
+ * These additional APIs allow us to craft even richer state experiences.
7544
+ *
7545
+ * To get the state of a request, use `getRequestState`.
7546
+ *
7547
+ * See also:
7548
+ * - {@link PendingRequest}
7549
+ * - {@link ResolvedRequest}
7550
+ * - {@link RejectedRequest}
7551
+ * - {@link CancelledRequest}
7552
+ *
7553
+ * @typedoc
7554
+ */
7555
+
7556
+ const RequestStateProto = {};
7557
+
7558
+ // TODO introduce a new mechanism for defining multiple properties
7559
+ // that share a common signal
7560
+ defineSignal(RequestStateProto, 'reason', null);
7561
+ defineSignal(RequestStateProto, 'value', null);
7562
+ defineSignal(RequestStateProto, 'result', null);
7563
+ defineSignal(RequestStateProto, 'error', null);
7564
+ defineSignal(RequestStateProto, 'status', 'pending');
7565
+ defineSignal(RequestStateProto, 'isPending', true);
7566
+ defineSignal(RequestStateProto, 'isLoading', true);
7567
+ defineSignal(RequestStateProto, 'isSuccess', false);
7568
+ defineSignal(RequestStateProto, 'isError', false);
7569
+ defineSignal(RequestStateProto, 'request', null);
7570
+ defineSignal(RequestStateProto, 'response', null);
7571
+ Object.defineProperty(RequestStateProto, 'isCancelled', {
7572
+ get() {
7573
+ return this.isError && isAbortError(this.reason);
7574
+ }
7575
+ });
7576
+ Object.defineProperty(RequestStateProto, 'loadingState', {
7577
+ get() {
7578
+ if (!this._loadingState) {
7579
+ this._loadingState = new RequestLoadingState(this._request);
7580
+ }
7581
+ return this._loadingState;
7582
+ }
7583
+ });
7584
+ function createRequestState(future) {
7585
+ const state = getPromiseResult(future);
7586
+ const promiseState = Object.create(RequestStateProto);
7587
+ promiseState._request = future;
7588
+ if (state) {
7589
+ if (state.isError) {
7590
+ promiseState.error = state.result;
7591
+ promiseState.reason = state.result;
7592
+ promiseState.status = 'rejected';
7593
+ promiseState.isError = true;
7594
+ promiseState.isPending = false;
7595
+ promiseState.isLoading = false;
7596
+ promiseState.request = state.result.request;
7597
+ promiseState.response = state.result.response;
7598
+ } else {
7599
+ promiseState.result = state.result.content;
7600
+ promiseState.value = state.result.content;
7601
+ promiseState.status = 'fulfilled';
7602
+ promiseState.isSuccess = true;
7603
+ promiseState.isPending = false;
7604
+ promiseState.isLoading = false;
7605
+ promiseState.request = state.result.request;
7606
+ promiseState.response = state.result.response;
7607
+ }
7608
+ } else {
7609
+ void future.then(result => {
7610
+ setPromiseResult(future, {
7611
+ isError: false,
7612
+ result
7613
+ });
7614
+ promiseState.result = result.content;
7615
+ promiseState.value = result.content;
7616
+ promiseState.status = 'fulfilled';
7617
+ promiseState.isSuccess = true;
7618
+ promiseState.isPending = false;
7619
+ promiseState.isLoading = false;
7620
+ promiseState.request = result.request;
7621
+ promiseState.response = result.response;
7622
+ }, error => {
7623
+ setPromiseResult(future, {
7624
+ isError: true,
7625
+ result: error
7626
+ });
7627
+ promiseState.error = error;
7628
+ promiseState.reason = error;
7629
+ promiseState.status = 'rejected';
7630
+ promiseState.isError = true;
7631
+ promiseState.isPending = false;
7632
+ promiseState.isLoading = false;
7633
+ promiseState.request = error.request;
7634
+ promiseState.response = error.response;
7635
+ });
7636
+ }
7637
+ return promiseState;
7638
+ }
7639
+
7640
+ /**
7641
+ * `getRequestState` can be used in both JavaScript and Template contexts.
7642
+ *
7643
+ * ```ts
7644
+ * import { getRequestState } from '@warp-drive-mirror/ember';
7645
+ *
7646
+ * const state = getRequestState(future);
7647
+ * ```
7648
+ *
7649
+ * For instance, we could write a getter on a component that updates whenever
7650
+ * the request state advances or the future changes, by combining the function
7651
+ * with the use of `@cached`
7652
+ *
7653
+ * ```ts
7654
+ * class Component {
7655
+ * @cached
7656
+ * get title() {
7657
+ * const state = getRequestState(this.args.request);
7658
+ * if (state.isPending) {
7659
+ * return 'loading...';
7660
+ * }
7661
+ * if (state.isError) { return null; }
7662
+ * return state.result.title;
7663
+ * }
7664
+ * }
7665
+ * ```
7666
+ *
7667
+ * Or in a template as a helper:
7668
+ *
7669
+ * ```gjs
7670
+ * import { getRequestState } from '@warp-drive-mirror/ember';
7671
+ *
7672
+ * <template>
7673
+ * {{#let (getRequestState @request) as |state|}}
7674
+ * {{#if state.isPending}}
7675
+ * <Spinner />
7676
+ * {{else if state.isError}}
7677
+ * <ErrorForm @error={{state.error}} />
7678
+ * {{else}}
7679
+ * <h1>{{state.result.title}}</h1>
7680
+ * {{/if}}
7681
+ * {{/let}}
7682
+ * </template>
7683
+ * ```
7684
+ *
7685
+ * If looking to use in a template, consider also the `<Request />` component
7686
+ * which offers a numbe of additional capabilities for requests *beyond* what
7687
+ * `RequestState` provides.
7688
+ *
7689
+ * @typedoc
7690
+ */
7691
+ function getRequestState(future) {
7692
+ let state = RequestCache.get(future);
7693
+ if (!state) {
7694
+ state = createRequestState(future);
7695
+ RequestCache.set(future, state);
7696
+ }
7697
+ return state;
6920
7698
  }
6921
- export { ARRAY_SIGNAL as A, 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 };
7699
+ export { memoized as A, gate as B, CacheHandler as C, entangleSignal as D, defineSignal as E, defineNonEnumerableSignal as F, Signals as G, peekInternalSignal as H, IdentifierArray as I, withSignalStore as J, notifyInternalSignal as K, consumeInternalSignal as L, MUTATE as M, getOrCreateInternalSignal as N, 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, removeRecordDataFor as n, setRecordIdentifier as o, peekCache as p, StoreMap as q, recordIdentifierFor as r, storeFor as s, setCacheFor as t, normalizeModelName as u, RelatedCollection as v, log as w, logGroup as x, getPromiseState as y, getRequestState as z };