@warp-drive/core 5.9.0-alpha.16 → 5.9.0-alpha.18

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 (56) hide show
  1. package/declarations/graph/-private/-state.d.ts +1 -0
  2. package/declarations/reactive/-private/default-mode.d.ts +22 -9
  3. package/declarations/reactive/-private/kind/belongs-to-field.d.ts +3 -0
  4. package/declarations/types/runtime.d.ts +16 -0
  5. package/declarations/types/schema/fields.d.ts +40 -12
  6. package/dist/graph/-private.js +56 -37
  7. package/dist/{index-CFwnjldF.js → index-BoY6aNE5.js} +88 -9
  8. package/dist/index.js +1 -1
  9. package/dist/reactive.js +1 -1
  10. package/dist/store/-private.js +1 -1
  11. package/dist/types/-private.js +1 -1
  12. package/dist/types/runtime.js +20 -1
  13. package/dist/unpkg/dev/graph/-private.js +56 -37
  14. package/dist/unpkg/dev/{index-BZRBBa34.js → index-BZ6PKU-a.js} +88 -9
  15. package/dist/unpkg/dev/index.js +1 -1
  16. package/dist/unpkg/dev/reactive.js +1 -1
  17. package/dist/unpkg/dev/store/-private.js +2 -2
  18. package/dist/unpkg/dev/types/-private.js +1 -1
  19. package/dist/unpkg/dev/types/runtime.js +20 -1
  20. package/dist/unpkg/dev-deprecated/graph/-private.js +56 -37
  21. package/dist/unpkg/dev-deprecated/{index-Bu52tQ9I.js → index-CDjd631s.js} +88 -9
  22. package/dist/unpkg/dev-deprecated/index.js +1 -1
  23. package/dist/unpkg/dev-deprecated/reactive.js +1 -1
  24. package/dist/unpkg/dev-deprecated/store/-private.js +1 -1
  25. package/dist/unpkg/dev-deprecated/types/-private.js +1 -1
  26. package/dist/unpkg/dev-deprecated/types/runtime.js +20 -1
  27. package/dist/unpkg/prod/{-leaked-BHLmJyaw.js → -leaked-DgjQ5X55.js} +2 -2
  28. package/dist/unpkg/prod/configure.js +1 -1
  29. package/dist/unpkg/prod/graph/-private.js +23 -26
  30. package/dist/unpkg/prod/{schema-BdC3DirM.js → index-BMBm3kYx.js} +2256 -91
  31. package/dist/unpkg/prod/index.js +5 -483
  32. package/dist/unpkg/prod/{promise-cache-DIT8Ypjq.js → promise-cache-DUblkX-U.js} +1 -1
  33. package/dist/unpkg/prod/reactive.js +3 -29
  34. package/dist/unpkg/prod/{request-BrJSCG6r.js → request-eb7Zm-oS.js} +1 -1
  35. package/dist/unpkg/prod/request.js +2 -2
  36. package/dist/unpkg/prod/signals/-leaked.js +1 -1
  37. package/dist/unpkg/prod/store/-private.js +2 -3
  38. package/dist/unpkg/prod/types/-private.js +1 -1
  39. package/dist/unpkg/prod/types/runtime.js +20 -1
  40. package/dist/unpkg/prod-deprecated/{-leaked-D_5Yrs5c.js → -leaked-BNVttukY.js} +1 -1
  41. package/dist/unpkg/prod-deprecated/configure.js +1 -1
  42. package/dist/unpkg/prod-deprecated/graph/-private.js +23 -26
  43. package/dist/unpkg/prod-deprecated/{schema-h0nuUTCj.js → index-CZkDXZog.js} +890 -7
  44. package/dist/unpkg/prod-deprecated/index.js +5 -483
  45. package/dist/unpkg/prod-deprecated/{promise-cache-DIT8Ypjq.js → promise-cache-DUblkX-U.js} +1 -1
  46. package/dist/unpkg/prod-deprecated/reactive.js +2 -3
  47. package/dist/unpkg/prod-deprecated/{request-BrJSCG6r.js → request-eb7Zm-oS.js} +1 -1
  48. package/dist/unpkg/prod-deprecated/request.js +2 -2
  49. package/dist/unpkg/prod-deprecated/signals/-leaked.js +1 -1
  50. package/dist/unpkg/prod-deprecated/store/-private.js +1 -2
  51. package/dist/unpkg/prod-deprecated/types/-private.js +1 -1
  52. package/dist/unpkg/prod-deprecated/types/runtime.js +20 -1
  53. package/package.json +3 -3
  54. package/dist/unpkg/prod/handler-BJogFbfS.js +0 -1619
  55. package/dist/unpkg/prod-deprecated/handler-kGR8zguj.js +0 -334
  56. package/dist/unpkg/prod-deprecated/hooks-wJdveHPi.js +0 -26
@@ -2,6 +2,7 @@ import { d as defineGate, w as withSignalStore, n as notifyInternalSignal, p as
2
2
  import { EnableHydration, SkipCache, STRUCTURED } from './types/request.js';
3
3
  import { D as Destroy, a as Context, S as SOURCE, C as Checkout, b as Commit } from "./-private-3C1OkYtZ.js";
4
4
  import { isResourceSchema } from './types/schema/fields.js';
5
+ import { setLogging, getRuntimeConfig, setIsMaybeMirage } from './types/runtime.js';
5
6
  import { a as cloneResponseProperties, I as IS_CACHE_HANDLER, b as assertValidRequest, e as executeNextHandler, d as getRequestResult, u as upgradePromise, s as setPromiseResult, f as clearRequestResult } from "./future-DUuPqyLj.js";
6
7
  import { getOrSetGlobal, peekTransient, setTransient, peekUniversalTransient, setUniversalTransient } from './types/-private.js';
7
8
  import { DefaultCachePolicy } from './store.js';
@@ -9,7 +10,6 @@ import { withBrand } from './request.js';
9
10
  import { CACHE_OWNER, DEBUG_STALE_CACHE_OWNER, DEBUG_KEY_TYPE, DEBUG_CLIENT_ORIGINATED } from './types/identifier.js';
10
11
  import { dasherize } from './utils/string.js';
11
12
  import { g as getGlobalConfig } from "./runtime-DfhJzpZH.js";
12
- import { setLogging, getRuntimeConfig } from './types/runtime.js';
13
13
  import { RecordStore, Type } from './types/symbols.js';
14
14
  import * as _importSync20 from '@ember/object';
15
15
  function urlFromLink(link) {
@@ -7248,11 +7248,32 @@ function getBelongsToField(context) {
7248
7248
  }
7249
7249
  function setBelongsToField(context) {
7250
7250
  const {
7251
+ field,
7252
+ resourceKey,
7251
7253
  store
7252
7254
  } = context;
7253
7255
  const {
7254
- schema
7256
+ schema,
7257
+ cache
7255
7258
  } = store;
7259
+
7260
+ /**
7261
+ * We currently only allow editing sync belongsTo relationships
7262
+ * in PolarisMode
7263
+ */
7264
+ const isValidPolarisConfig = field.options.linksMode && !field.options.async;
7265
+ if (!context.legacy && isValidPolarisConfig) {
7266
+ const name = context.path.at(-1);
7267
+ cache.mutate({
7268
+ op: 'replaceRelatedRecord',
7269
+ record: resourceKey,
7270
+ field: name,
7271
+ value: getResourceKey(context.value)
7272
+ },
7273
+ // @ts-expect-error
7274
+ true);
7275
+ return true;
7276
+ }
7256
7277
  (test => {
7257
7278
  if (!test) {
7258
7279
  throw new Error(`Can only mutate belongsTo fields when the resource is in legacy mode`);
@@ -7261,6 +7282,12 @@ function setBelongsToField(context) {
7261
7282
  schema._kind('@legacy', 'belongsTo').set(store, context.record, context.resourceKey, context.field, context.value);
7262
7283
  return true;
7263
7284
  }
7285
+ function getResourceKey(record) {
7286
+ if (!record) {
7287
+ return null;
7288
+ }
7289
+ return recordIdentifierFor(record);
7290
+ }
7264
7291
  function getCollectionField(context) {
7265
7292
  entangleSignal(context.signals, context.record, context.path.at(-1), null);
7266
7293
  (test => {
@@ -7993,6 +8020,17 @@ function setSchemaObjectField(context) {
7993
8020
  // }
7994
8021
  return true;
7995
8022
  }
8023
+
8024
+ /**
8025
+ * A ReactiveResource context object passed to
8026
+ * the get/set functions of a field kind implementation.
8027
+ *
8028
+ * This provides all the necessary information for
8029
+ * the field kind to perform its operations.
8030
+ *
8031
+ * @internal
8032
+ */
8033
+
7996
8034
  const DefaultMode = {
7997
8035
  '@hash': {
7998
8036
  get: getHashField,
@@ -8786,6 +8824,14 @@ const TypeField = {
8786
8824
  key: 'type'
8787
8825
  }
8788
8826
  };
8827
+ const IdentifierField = {
8828
+ type: '@identity',
8829
+ name: '$key',
8830
+ kind: 'derived',
8831
+ options: {
8832
+ key: '^'
8833
+ }
8834
+ };
8789
8835
  const DefaultIdentityField = {
8790
8836
  name: 'id',
8791
8837
  kind: '@id'
@@ -8974,6 +9020,7 @@ function withDefaults(schema) {
8974
9020
  // we add TypeField to the beginning so that it will
8975
9021
  // appear right next to the identity field
8976
9022
  schema.fields.unshift(TypeField);
9023
+ schema.fields.unshift(IdentifierField);
8977
9024
  schema.fields.push(ConstructorField);
8978
9025
  return schema;
8979
9026
  }
@@ -9490,9 +9537,33 @@ function cloneResponse(response, overrides) {
9490
9537
  const props = cloneResponseProperties(response);
9491
9538
  return new Response(response.body, Object.assign(props, overrides));
9492
9539
  }
9540
+ function withDateHeader(response) {
9541
+ const headers = new Headers(response.headers);
9542
+ headers.set('date', new Date().toUTCString());
9543
+ return cloneResponse(response, {
9544
+ headers
9545
+ });
9546
+ }
9547
+
9548
+ // Detects Mirage (or another Pretender-based fetch mock), whose `Response`
9549
+ // may (unlike a spec-compliant `fetch()`, whose Response headers are always
9550
+ // immutable) allow header mutation and may not support streaming reads.
9551
+ //
9552
+ // This is inherently a heuristic - many legitimate tools (APM/monitoring
9553
+ // agents, browser extensions, polyfills) also patch `window.fetch`, and can
9554
+ // produce false positives. `setWarpDriveIsMaybeMirage(value)` lets an app
9555
+ // declare the answer explicitly (`true` or `false`), overriding the
9556
+ // heuristic in either direction; leave it unset to keep the default
9557
+ // detection. See https://github.com/warp-drive-data/warp-drive/issues/10535
9493
9558
  let IS_MAYBE_MIRAGE = () => false;
9494
9559
  {
9495
- IS_MAYBE_MIRAGE = () => Boolean(typeof window !== 'undefined' && (window.server?.pretender || window.fetch.toString().replace(/\s+/g, '') !== 'function fetch() { [native code] }'.replace(/\s+/g, '')));
9560
+ IS_MAYBE_MIRAGE = () => {
9561
+ const override = getRuntimeConfig().mirage;
9562
+ if (override !== undefined) {
9563
+ return override;
9564
+ }
9565
+ return Boolean(typeof window !== 'undefined' && (window.server?.pretender || window.fetch.toString().replace(/\s+/g, '') !== 'function fetch() { [native code] }'.replace(/\s+/g, '')));
9566
+ };
9496
9567
  }
9497
9568
  const MUTATION_OPS = new Set(['updateRecord', 'createRecord', 'deleteRecord']);
9498
9569
  const ERROR_STATUS_CODE_FOR = new Map([[400, 'Bad Request'], [401, 'Unauthorized'], [402, 'Payment Required'], [403, 'Forbidden'], [404, 'Not Found'], [405, 'Method Not Allowed'], [406, 'Not Acceptable'], [407, 'Proxy Authentication Required'], [408, 'Request Timeout'], [409, 'Conflict'], [410, 'Gone'], [411, 'Length Required'], [412, 'Precondition Failed'], [413, 'Payload Too Large'], [414, 'URI Too Long'], [415, 'Unsupported Media Type'], [416, 'Range Not Satisfiable'], [417, 'Expectation Failed'], [419, 'Page Expired'], [420, 'Enhance Your Calm'], [421, 'Misdirected Request'], [422, 'Unprocessable Entity'], [423, 'Locked'], [424, 'Failed Dependency'], [425, 'Too Early'], [426, 'Upgrade Required'], [428, 'Precondition Required'], [429, 'Too Many Requests'], [430, 'Request Header Fields Too Large'], [431, 'Request Header Fields Too Large'], [450, 'Blocked By Windows Parental Controls'], [451, 'Unavailable For Legal Reasons'], [500, 'Internal Server Error'], [501, 'Not Implemented'], [502, 'Bad Gateway'], [503, 'Service Unavailable'], [504, 'Gateway Timeout'], [505, 'HTTP Version Not Supported'], [506, 'Variant Also Negotiates'], [507, 'Insufficient Storage'], [508, 'Loop Detected'], [509, 'Bandwidth Limit Exceeded'], [510, 'Not Extended'], [511, 'Network Authentication Required']]);
@@ -9544,13 +9615,15 @@ const Fetch = {
9544
9615
  const isMutationOp = Boolean(op && MUTATION_OPS.has(op));
9545
9616
  if (!isError && !isMutationOp && response.status !== 204 && !response.headers.has('date')) {
9546
9617
  if (IS_MAYBE_MIRAGE()) {
9547
- response.headers.set('date', new Date().toUTCString());
9618
+ try {
9619
+ response.headers.set('date', new Date().toUTCString());
9620
+ } catch {
9621
+ // IS_MAYBE_MIRAGE() was a false positive, or the mock's headers
9622
+ // are (correctly) immutable - fall back to cloning.
9623
+ response = withDateHeader(response);
9624
+ }
9548
9625
  } else {
9549
- const headers = new Headers(response.headers);
9550
- headers.set('date', new Date().toUTCString());
9551
- response = cloneResponse(response, {
9552
- headers
9553
- });
9626
+ response = withDateHeader(response);
9554
9627
  }
9555
9628
  }
9556
9629
  context.setResponse(response);
@@ -9945,6 +10018,12 @@ class RequestManager {
9945
10018
  globalThis.getWarpDriveRuntimeConfig = getRuntimeConfig;
9946
10019
  }
9947
10020
 
10021
+ // Mirage (or another Pretender-based fetch mock) may be used outside of a
10022
+ // `TESTING` build (e.g. `ember serve` in dev mode), so this override is
10023
+ // exposed unconditionally rather than gated to the `TESTING` env.
10024
+ // @ts-expect-error adding to globalThis
10025
+ globalThis.setWarpDriveIsMaybeMirage = setIsMaybeMirage;
10026
+
9948
10027
  /**
9949
10028
  * Options for setting up a Store instance with `useRecommendedStore`.
9950
10029
  */
@@ -1,4 +1,4 @@
1
- export { C as CacheHandler, F as Fetch, z as RequestManager, S as Store, r as cacheKeyFor, r as recordIdentifierFor, E as setIdentifierForgetMethod, B as setIdentifierGenerationMethod, G as setIdentifierResetMethod, D as setIdentifierUpdateMethod, H as setKeyInfoForResource, s as storeFor, A as useRecommendedStore } from "./index-Bu52tQ9I.js";
1
+ export { C as CacheHandler, F as Fetch, z as RequestManager, S as Store, r as cacheKeyFor, r as recordIdentifierFor, E as setIdentifierForgetMethod, B as setIdentifierGenerationMethod, G as setIdentifierResetMethod, D as setIdentifierUpdateMethod, H as setKeyInfoForResource, s as storeFor, A as useRecommendedStore } from "./index-CDjd631s.js";
2
2
  import "./-private-3C1OkYtZ.js";
3
3
  import "./-leaked-C40gfiH-.js";
4
4
  import './store.js';
@@ -1,3 +1,3 @@
1
- export { u as SchemaService, p as checkout, y as commit, v as fromIdentity, q as instantiateRecord, x as registerDerivations, t as teardownRecord, w as withDefaults } from "./index-Bu52tQ9I.js";
1
+ export { u as SchemaService, p as checkout, y as commit, v as fromIdentity, q as instantiateRecord, x as registerDerivations, t as teardownRecord, w as withDefaults } from "./index-CDjd631s.js";
2
2
  export { C as Checkout } from "./-private-3C1OkYtZ.js";
3
3
  export { c as createRequestSubscription, a as getPromiseState, g as getRequestState } from "./-leaked-C40gfiH-.js";
@@ -1 +1 @@
1
- export { C as CacheHandler, R as RecordArrayManager, S as Store, k as StoreMap, _ as _clearCaches, n as _deprecatingNormalize, h as assertPrivateCapabilities, d as assertPrivateStore, b as coerceId, c as constructResource, l as createLegacyManyArray, e as ensureStringId, f as fastPush, g as isPrivateStore, a as isRequestKey, i as isResourceKey, m as log, o as logGroup, r as recordIdentifierFor, j as setRecordIdentifier, s as storeFor } from "../index-Bu52tQ9I.js";
1
+ export { C as CacheHandler, R as RecordArrayManager, S as Store, k as StoreMap, _ as _clearCaches, n as _deprecatingNormalize, h as assertPrivateCapabilities, d as assertPrivateStore, b as coerceId, c as constructResource, l as createLegacyManyArray, e as ensureStringId, f as fastPush, g as isPrivateStore, a as isRequestKey, i as isResourceKey, m as log, o as logGroup, r as recordIdentifierFor, j as setRecordIdentifier, s as storeFor } from "../index-CDjd631s.js";
@@ -1,5 +1,5 @@
1
1
  const name = "@warp-drive/core";
2
- const version = "5.9.0-alpha.16";
2
+ const version = "5.9.0-alpha.18";
3
3
 
4
4
  // in testing mode, we utilize globals to ensure only one copy exists of
5
5
  // these maps, due to bugs in ember-auto-import
@@ -31,4 +31,23 @@ function setLogging(config) {
31
31
  Object.assign(RuntimeConfig.debug, config);
32
32
  storage?.setItem('WarpDriveRuntimeConfig', JSON.stringify(RuntimeConfig));
33
33
  }
34
- export { getRuntimeConfig, setLogging };
34
+
35
+ /**
36
+ * Explicitly declares whether requests may be served by Mirage (or another
37
+ * Pretender-based fetch mock) instead of a native `fetch` implementation.
38
+ *
39
+ * The `Fetch` request handler otherwise infers this via a heuristic (the
40
+ * presence of `window.server.pretender`, or `window.fetch` appearing to be
41
+ * patched), which can be wrong in either direction: some Mirage setups don't
42
+ * expose `window.server`, while some unrelated tools (APM agents, browser
43
+ * extensions) also patch `fetch`. Call this to override that heuristic:
44
+ * `true` to force Mirage-compatible behavior on, `false` to force it off.
45
+ *
46
+ * globalThis.setWarpDriveIsMaybeMirage(true);
47
+ *
48
+ */
49
+ function setIsMaybeMirage(value) {
50
+ RuntimeConfig.mirage = value;
51
+ storage?.setItem('WarpDriveRuntimeConfig', JSON.stringify(RuntimeConfig));
52
+ }
53
+ export { getRuntimeConfig, setIsMaybeMirage, setLogging };
@@ -1,5 +1,5 @@
1
1
  import { peekTransient, getOrSetGlobal, setTransient } from './types/-private.js';
2
- import { b as getPromiseResult, s as setPromiseResult } from "./promise-cache-DIT8Ypjq.js";
2
+ import { g as getPromiseResult, a as setPromiseResult } from "./promise-cache-DUblkX-U.js";
3
3
 
4
4
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
5
5
 
@@ -1673,4 +1673,4 @@ function getPromiseState(promise) {
1673
1673
  }
1674
1674
  return state;
1675
1675
  }
1676
- export { ARRAY_SIGNAL as A, DISPOSE as D, OBJECT_SIGNAL as O, Signals as S, withSignalStore as a, createInternalSignal as b, consumeInternalSignal as c, defineGate as d, createSignalDescriptor as e, defineSignal as f, getOrCreateInternalSignal as g, entangleSignal as h, entangleInitiallyStaleSignal as i, createInternalMemo as j, createRequestSubscription as k, getRequestState as l, getPromiseState as m, notifyInternalSignal as n, defineNonEnumerableSignal as o, peekInternalSignal as p, makeInitializer as q, signal as r, setupSignals as s, waitFor as t, gate as u, memoized as v, willSyncFlushWatchers as w };
1676
+ export { ARRAY_SIGNAL as A, DISPOSE as D, OBJECT_SIGNAL as O, Signals as S, willSyncFlushWatchers as a, createInternalSignal as b, consumeInternalSignal as c, defineGate as d, createSignalDescriptor as e, defineSignal as f, getOrCreateInternalSignal as g, entangleSignal as h, entangleInitiallyStaleSignal as i, createInternalMemo as j, createRequestSubscription as k, getRequestState as l, getPromiseState as m, notifyInternalSignal as n, defineNonEnumerableSignal as o, peekInternalSignal as p, makeInitializer as q, signal as r, setupSignals as s, waitFor as t, gate as u, memoized as v, withSignalStore as w };
@@ -1,2 +1,2 @@
1
- export { s as setupSignals } from "./-leaked-BHLmJyaw.js";
1
+ export { s as setupSignals } from "./-leaked-DgjQ5X55.js";
2
2
  import './types/-private.js';
@@ -789,8 +789,10 @@ function replaceRelatedRecord(graph, op, isRemote = false) {
789
789
  if (op.value === existingState) {
790
790
  // if we were empty before but now know we are empty this needs to be true
791
791
  state.hasReceivedData = true;
792
+
792
793
  // if this is a remote update we still sync
793
794
  if (isRemote) {
795
+ state.hasReceivedRemoteData = true;
794
796
  const {
795
797
  localState
796
798
  } = relationship;
@@ -813,6 +815,15 @@ function replaceRelatedRecord(graph, op, isRemote = false) {
813
815
  // update value to the new value
814
816
  relationship[prop] = op.value;
815
817
  state.hasReceivedData = true;
818
+ /**
819
+ * Local mutations never give us additional information about
820
+ * whether the relationship has received *remote* data. This is
821
+ * what `getRemoteRelationship` relies on to avoid reflecting
822
+ * local-only edits.
823
+ */
824
+ if (isRemote) {
825
+ state.hasReceivedRemoteData = true;
826
+ }
816
827
  state.isEmpty = op.value === null;
817
828
  state.isStale = false;
818
829
  state.hasFailedLoadAttempt = false;
@@ -979,7 +990,12 @@ function diffCollection(finalState, relationship, onAdd, onDel) {
979
990
  return _compare(priorLocalState, finalState, finalSet, remoteState, remoteMembers, onAdd, onDel, relationship.definition.resetOnRemoteUpdate);
980
991
  }
981
992
  function computeLocalState(storage) {
982
- if (!storage.isDirty) {
993
+ // When the edge is clean and we already have a materialized localState we can
994
+ // return it directly. A clean edge can still have a `null` localState though:
995
+ // dematerializing an inverse member (e.g. when a route reloads its model)
996
+ // nulls out localState without dirtying the edge. In that case we fall through
997
+ // and recompute from remoteState rather than asserting.
998
+ if (!storage.isDirty && storage.localState) {
983
999
  return storage.localState;
984
1000
  }
985
1001
  const state = storage.remoteState.slice();
@@ -1201,6 +1217,7 @@ function rollbackRelationship(graph, key, field, relationship) {
1201
1217
  function createState() {
1202
1218
  return {
1203
1219
  hasReceivedData: false,
1220
+ hasReceivedRemoteData: false,
1204
1221
  isEmpty: true,
1205
1222
  isStale: false,
1206
1223
  hasFailedLoadAttempt: false,
@@ -1305,13 +1322,10 @@ function legacyGetResourceRelationshipData(source, getRemoteState) {
1305
1322
  source.accessed = true;
1306
1323
  let data;
1307
1324
  const payload = {};
1308
- if (getRemoteState && source.remoteState) {
1309
- data = source.remoteState;
1310
- } else if (!getRemoteState && source.localState) {
1311
- data = source.localState;
1312
- }
1313
- if ((getRemoteState && source.remoteState === null || source.localState === null) && source.state.hasReceivedData) {
1314
- data = null;
1325
+ if (getRemoteState && (source.remoteState || source.state.hasReceivedRemoteData)) {
1326
+ data = source.remoteState ?? null;
1327
+ } else if (!getRemoteState && (source.localState || source.state.hasReceivedData)) {
1328
+ data = source.localState ?? null;
1315
1329
  }
1316
1330
  if (source.links) {
1317
1331
  payload.links = source.links;
@@ -1488,7 +1502,6 @@ function updateRelationshipOperation(graph, op) {
1488
1502
  const relationship = graph.get(op.record, op.field);
1489
1503
  const {
1490
1504
  definition,
1491
- state,
1492
1505
  identifier
1493
1506
  } = relationship;
1494
1507
  const {
@@ -1523,23 +1536,6 @@ function updateRelationshipOperation(graph, op) {
1523
1536
  value: payload.data ? graph.store.cacheKeyManager.upgradeIdentifier(payload.data) : null
1524
1537
  }, true);
1525
1538
  }
1526
- } else if (definition.isAsync === false && !state.hasReceivedData) {
1527
- hasRelationshipDataProperty = true;
1528
- if (isCollection) {
1529
- graph.update({
1530
- op: 'replaceRelatedRecords',
1531
- record: identifier,
1532
- field: op.field,
1533
- value: []
1534
- }, true);
1535
- } else {
1536
- graph.update({
1537
- op: 'replaceRelatedRecord',
1538
- record: identifier,
1539
- field: op.field,
1540
- value: null
1541
- }, true);
1542
- }
1543
1539
  }
1544
1540
  if (payload.links) {
1545
1541
  const originalLinks = relationship.links;
@@ -1574,6 +1570,7 @@ function updateRelationshipOperation(graph, op) {
1574
1570
  // we don't need to notify here as the update op we pushed in above will notify once
1575
1571
  // membership is in the correct state.
1576
1572
  relationship.state.hasReceivedData = true;
1573
+ relationship.state.hasReceivedRemoteData = true;
1577
1574
  relationship.state.isStale = false;
1578
1575
  relationship.state.hasDematerializedInverse = false;
1579
1576
  relationship.state.isEmpty = relationshipIsEmpty;