@apollo/client 4.3.0-alpha.5 → 4.3.0-alpha.7

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 (52) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/__cjs/cache/core/cache.cjs +1 -1
  3. package/__cjs/cache/inmemory/entityStore.cjs +3 -3
  4. package/__cjs/cache/inmemory/key-extractor.cjs +1 -1
  5. package/__cjs/cache/inmemory/policies.cjs +28 -6
  6. package/__cjs/cache/inmemory/policies.cjs.map +1 -1
  7. package/__cjs/cache/inmemory/readFromStore.cjs +3 -3
  8. package/__cjs/cache/inmemory/readFromStore.cjs.map +1 -1
  9. package/__cjs/cache/inmemory/writeToStore.cjs +4 -4
  10. package/__cjs/core/ObservableQuery.cjs +175 -62
  11. package/__cjs/core/ObservableQuery.cjs.map +1 -1
  12. package/__cjs/core/ObservableQuery.d.cts +4 -7
  13. package/__cjs/core/QueryInfo.cjs +13 -136
  14. package/__cjs/core/QueryInfo.cjs.map +1 -1
  15. package/__cjs/core/QueryInfo.d.cts +2 -26
  16. package/__cjs/core/QueryManager.cjs +26 -25
  17. package/__cjs/core/QueryManager.cjs.map +1 -1
  18. package/__cjs/core/RefetchEventManager.cjs +3 -3
  19. package/__cjs/invariantErrorCodes.cjs +57 -32
  20. package/__cjs/utilities/internal/index.cjs +3 -1
  21. package/__cjs/utilities/internal/index.cjs.map +1 -1
  22. package/__cjs/utilities/internal/index.d.cts +1 -0
  23. package/__cjs/utilities/internal/toDiffWithDataState.cjs +20 -0
  24. package/__cjs/utilities/internal/toDiffWithDataState.cjs.map +1 -0
  25. package/__cjs/utilities/internal/toDiffWithDataState.d.cts +8 -0
  26. package/__cjs/version.cjs +1 -1
  27. package/cache/core/cache.js +1 -1
  28. package/cache/inmemory/entityStore.js +3 -3
  29. package/cache/inmemory/key-extractor.js +1 -1
  30. package/cache/inmemory/policies.js +28 -6
  31. package/cache/inmemory/policies.js.map +1 -1
  32. package/cache/inmemory/readFromStore.js +3 -3
  33. package/cache/inmemory/readFromStore.js.map +1 -1
  34. package/cache/inmemory/writeToStore.js +4 -4
  35. package/core/ObservableQuery.d.ts +4 -7
  36. package/core/ObservableQuery.js +172 -63
  37. package/core/ObservableQuery.js.map +1 -1
  38. package/core/QueryInfo.d.ts +3 -27
  39. package/core/QueryInfo.js +14 -137
  40. package/core/QueryInfo.js.map +1 -1
  41. package/core/QueryManager.js +26 -25
  42. package/core/QueryManager.js.map +1 -1
  43. package/core/RefetchEventManager.js +3 -3
  44. package/invariantErrorCodes.js +57 -32
  45. package/package.json +1 -1
  46. package/utilities/internal/index.d.ts +1 -0
  47. package/utilities/internal/index.js +1 -0
  48. package/utilities/internal/index.js.map +1 -1
  49. package/utilities/internal/toDiffWithDataState.d.ts +8 -0
  50. package/utilities/internal/toDiffWithDataState.js +17 -0
  51. package/utilities/internal/toDiffWithDataState.js.map +1 -0
  52. package/version.js +1 -1
@@ -68,7 +68,7 @@ export class StoreWriter {
68
68
  path: [],
69
69
  });
70
70
  if (!isReference(ref)) {
71
- throw newInvariantError(116, result);
71
+ throw newInvariantError(118, result);
72
72
  }
73
73
  // So far, the store has not been modified, so now it's time to process
74
74
  // context.incomingById and merge those incoming fields into context.store.
@@ -230,7 +230,7 @@ export class StoreWriter {
230
230
  // provide a default value, so its absence from the written data should
231
231
  // not be cause for alarm.
232
232
  !policies.getReadFunction(typename, field.name.value)) {
233
- invariant.error(117, resultKeyNameFromField(field), result);
233
+ invariant.error(119, resultKeyNameFromField(field), result);
234
234
  }
235
235
  });
236
236
  // Identify the result object, even if dataId was already provided,
@@ -378,7 +378,7 @@ export class StoreWriter {
378
378
  else {
379
379
  const fragment = getFragmentFromSelection(selection, context.lookupFragment);
380
380
  if (!fragment && selection.kind === Kind.FRAGMENT_SPREAD) {
381
- throw newInvariantError(118, selection.name.value);
381
+ throw newInvariantError(120, selection.name.value);
382
382
  }
383
383
  if (fragment &&
384
384
  policies.fragmentMatches(fragment, typename, result, context.variables)) {
@@ -550,7 +550,7 @@ function warnAboutDataLoss(existingRef, incomingObj, storeFieldName, store) {
550
550
  }
551
551
  });
552
552
  }
553
- __DEV__ && invariant.warn(119, fieldName, parentType, childTypenames.length ?
553
+ __DEV__ && invariant.warn(121, fieldName, parentType, childTypenames.length ?
554
554
  "either ensure all objects of type " +
555
555
  childTypenames.join(" and ") +
556
556
  " have an ID or a custom merge function, or "
@@ -278,12 +278,8 @@ export declare class ObservableQuery<TData = unknown, TVariables extends Operati
278
278
  readonly options: ObservableQuery.Options<TData, TVariables>;
279
279
  readonly queryName?: string;
280
280
  private variablesUnknown;
281
- /**
282
- * @internal will be read and written from `QueryInfo`
283
- *
284
- * @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
285
- */
286
- _lastWrite?: unknown;
281
+ private didWarnOnFeud;
282
+ private lastMissing?;
287
283
  get query(): TypedDocumentNode<TData, TVariables>;
288
284
  /**
289
285
  * An object containing the variables that were provided for the query.
@@ -349,7 +345,7 @@ export declare class ObservableQuery<TData = unknown, TVariables extends Operati
349
345
  */
350
346
  getCacheDiff({ optimistic }?: {
351
347
  optimistic?: boolean | undefined;
352
- }): Cache.DiffResult<TData>;
348
+ }): Cache.InternalDiffResultWithDataState<TData>;
353
349
  private getInitialResult;
354
350
  private resubscribeCache;
355
351
  private stableLastResult?;
@@ -469,6 +465,7 @@ export declare class ObservableQuery<TData = unknown, TVariables extends Operati
469
465
  * @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
470
466
  */
471
467
  notify(scheduled?: boolean): void;
468
+ private deliverCacheDiff;
472
469
  private activeOperations;
473
470
  private pushOperation;
474
471
  private calculateNetworkStatus;
@@ -2,7 +2,7 @@ import { equal } from "@wry/equality";
2
2
  import { BehaviorSubject, filter, Observable, share, Subject, tap } from "rxjs";
3
3
  import { isNetworkRequestInFlight, isNetworkRequestSettled, } from "@apollo/client/utilities";
4
4
  import { __DEV__ } from "@apollo/client/utilities/environment";
5
- import { compact, equalByQuery, extensionsSymbol, filterMap, getOperationDefinition, getOperationName, getQueryDefinition, preventUnhandledRejection, toQueryResult, variablesUnknownSymbol, } from "@apollo/client/utilities/internal";
5
+ import { compact, equalByQuery, extensionsSymbol, filterMap, getOperationDefinition, getOperationName, getQueryDefinition, handleIncrementalSymbol, preventUnhandledRejection, toDiffWithDataState, toQueryResult, variablesUnknownSymbol, } from "@apollo/client/utilities/internal";
6
6
  import { invariant } from "@apollo/client/utilities/invariant";
7
7
  import { dataStateErrorCache } from "./dataStateErrorCache.js";
8
8
  import { NetworkStatus } from "./networkStatus.js";
@@ -21,16 +21,29 @@ const empty = {
21
21
  dataState: "empty",
22
22
  partial: true,
23
23
  };
24
+ const destructiveMethodCounts = new WeakMap();
25
+ function wrapDestructiveCacheMethod(cache, methodName) {
26
+ const original = cache[methodName];
27
+ if (typeof original === "function") {
28
+ // @ts-expect-error this is just too generic to be typed correctly
29
+ cache[methodName] = function () {
30
+ destructiveMethodCounts.set(cache,
31
+ // The %1e15 allows the count to wrap around to 0 safely every
32
+ // quadrillion evictions, so there's no risk of overflow. To be
33
+ // clear, this is more of a pedantic principle than something
34
+ // that matters in any conceivable practical scenario.
35
+ (destructiveMethodCounts.get(cache) + 1) % 1e15);
36
+ // @ts-expect-error this is just too generic to be typed correctly
37
+ return original.apply(this, arguments);
38
+ };
39
+ }
40
+ }
24
41
  export class ObservableQuery {
25
42
  options;
26
43
  queryName;
27
44
  variablesUnknown = false;
28
- /**
29
- * @internal will be read and written from `QueryInfo`
30
- *
31
- * @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
32
- */
33
- _lastWrite;
45
+ didWarnOnFeud = false;
46
+ lastMissing;
34
47
  // The `query` computed property will always reflect the document transformed
35
48
  // by the last run query. `this.options.query` will always reflect the raw
36
49
  // untransformed query to ensure document transforms with runtime conditionals
@@ -67,6 +80,18 @@ export class ObservableQuery {
67
80
  }
68
81
  constructor({ queryManager, options, transformedQuery = queryManager.transform(options.query), }) {
69
82
  this.queryManager = queryManager;
83
+ // Track how often destructive cache methods are called, since we want
84
+ // eviction to override the feud-stopping logic in `shouldAutoRefetch`,
85
+ // by causing it to return true. Wrapping these cache methods is a bit of a
86
+ // hack, but it saves us from having to make eviction counting an official
87
+ // part of the ApolloCache API.
88
+ const { cache } = queryManager;
89
+ if (!destructiveMethodCounts.has(cache)) {
90
+ destructiveMethodCounts.set(cache, 0);
91
+ wrapDestructiveCacheMethod(cache, "evict");
92
+ wrapDestructiveCacheMethod(cache, "modify");
93
+ wrapDestructiveCacheMethod(cache, "reset");
94
+ }
70
95
  // active state
71
96
  this.waitForNetworkResult = options.fetchPolicy === "network-only";
72
97
  this.isTornDown = false;
@@ -206,12 +231,13 @@ export class ObservableQuery {
206
231
  * @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
207
232
  */
208
233
  getCacheDiff({ optimistic = true } = {}) {
209
- return this.cache.diff({
234
+ return toDiffWithDataState(this.cache.diff({
210
235
  query: this.query,
211
236
  variables: this.variables,
212
237
  returnPartialData: true,
213
238
  optimistic,
214
- });
239
+ [handleIncrementalSymbol]: undefined,
240
+ }));
215
241
  }
216
242
  getInitialResult(initialFetchPolicy) {
217
243
  let fetchPolicy = initialFetchPolicy || this.options.fetchPolicy;
@@ -221,16 +247,18 @@ export class ObservableQuery {
221
247
  }
222
248
  const cacheResult = () => {
223
249
  const diff = this.getCacheDiff();
250
+ let { dataState } = diff;
224
251
  // TODO: queryInfo.getDiff should handle this since cache.diff returns a
225
252
  // null when returnPartialData is false
226
253
  const data = this.options.returnPartialData || diff.complete ?
227
254
  diff.result ?? undefined
228
255
  : undefined;
256
+ if (data === undefined) {
257
+ dataState = "empty";
258
+ }
229
259
  return this.maskResult({
230
260
  data,
231
- dataState: diff.complete ? "complete"
232
- : data === undefined ? "empty"
233
- : "partial",
261
+ dataState,
234
262
  loading: !diff.complete,
235
263
  networkStatus: diff.complete ? NetworkStatus.ready : NetworkStatus.loading,
236
264
  partial: !diff.complete,
@@ -391,7 +419,6 @@ export class ObservableQuery {
391
419
  reobserveOptions.variables = this.options.variables =
392
420
  this.getVariablesWithDefaults({ ...this.variables, ...variables });
393
421
  }
394
- this._lastWrite = undefined;
395
422
  return this._reobserve(reobserveOptions, {
396
423
  newNetworkStatus: NetworkStatus.refetch,
397
424
  });
@@ -879,7 +906,6 @@ export class ObservableQuery {
879
906
  if (this.pollingInfo) {
880
907
  if (!isNetworkRequestInFlight(this.networkStatus) &&
881
908
  !this.options.skipPollAttempt?.()) {
882
- this._lastWrite = undefined;
883
909
  this._reobserve({
884
910
  // Most fetchPolicy options don't make sense to use in a polling context, as
885
911
  // users wouldn't want to be polling the cache directly. However, network-only and
@@ -925,7 +951,10 @@ export class ObservableQuery {
925
951
  }
926
952
  _reobserve(newOptions, internalOptions) {
927
953
  this.isTornDown = false;
928
- let { newNetworkStatus } = internalOptions || {};
954
+ let { newNetworkStatus, keepLastMissing } = internalOptions || {};
955
+ if (!keepLastMissing) {
956
+ this.lastMissing = undefined;
957
+ }
929
958
  this.queryManager.obsQueries.add(this);
930
959
  const useDisposableObservable =
931
960
  // Refetching uses a disposable Observable to allow refetches using different
@@ -1066,7 +1095,7 @@ export class ObservableQuery {
1066
1095
  this.queryManager.obsQueries.delete(this);
1067
1096
  this.isTornDown = true;
1068
1097
  this.abortActiveOperations();
1069
- this._lastWrite = undefined;
1098
+ this.lastMissing = undefined;
1070
1099
  }
1071
1100
  transformDocument(document) {
1072
1101
  return this.queryManager.transform(document);
@@ -1124,53 +1153,126 @@ export class ObservableQuery {
1124
1153
  return;
1125
1154
  }
1126
1155
  }
1127
- const { dirty } = this;
1156
+ const { dirty, lastMissing } = this;
1157
+ const { fetchPolicy } = this.options;
1128
1158
  this.resetNotifications();
1129
- if (dirty &&
1130
- (this.options.fetchPolicy === "cache-only" ||
1131
- this.options.fetchPolicy === "cache-and-network" ||
1132
- !this.activeOperations.size)) {
1133
- const diff = this.getCacheDiff();
1134
- if (
1135
- // `fromOptimisticTransaction` is not available through the `cache.diff`
1136
- // code path, so we need to check it this way
1137
- equal(diff.result, this.getCacheDiff({ optimistic: false }).result)) {
1138
- //If this diff did not come from an optimistic transaction
1139
- // make the ObservableQuery "reobserve" the latest data
1140
- // using a temporary fetch policy of "cache-first", so complete cache
1141
- // results have a chance to be delivered without triggering additional
1142
- // network requests, even when options.fetchPolicy is "network-only"
1143
- // or "cache-and-network". All other fetch policies are preserved by
1144
- // this method, and are handled by calling oq.reobserve(). If this
1145
- // reobservation is spurious, distinctUntilChanged still has a
1146
- // chance to catch it before delivery to ObservableQuery subscribers.
1147
- this.reobserveCacheFirst();
1159
+ if (!dirty ||
1160
+ (fetchPolicy !== "cache-only" &&
1161
+ fetchPolicy !== "cache-and-network" &&
1162
+ this.activeOperations.size)) {
1163
+ return;
1164
+ }
1165
+ const diff = this.getCacheDiff();
1166
+ const current = this.getCurrentResult();
1167
+ // `fromOptimisticTransaction` is not available through the `cache.diff`
1168
+ // code path, so we need to check whether the cache result is an optimistic
1169
+ // result this way.
1170
+ const isOptimistic = !equal(diff.result, this.getCacheDiff({ optimistic: false }).result);
1171
+ if (
1172
+ // When this diff came from an optimistic transaction, deliver the
1173
+ // current cache data to the ObservableQuery, but don't perform a
1174
+ // reobservation, since oq.reobserveCacheFirst might make a network
1175
+ // request, and we never want to trigger network requests in the
1176
+ // middle of optimistic updates.
1177
+ isOptimistic ||
1178
+ // If we get a cache update in the middle of streaming (possible with
1179
+ // cache-and-network fetch policy), just deliver the cache value without
1180
+ // going through the full reobserve which would otherwise trigger another
1181
+ // request (deduplication should kick in, but doing so replays any
1182
+ // previous emits from the link chain, which get rewritten into the cache
1183
+ // and might clobber this cache update)
1184
+ (!diff.complete && current.networkStatus === NetworkStatus.streaming)) {
1185
+ this.deliverCacheDiff(diff);
1186
+ return;
1187
+ }
1188
+ if (diff.complete) {
1189
+ this.lastMissing = undefined;
1190
+ }
1191
+ else if (!lastMissing ||
1192
+ // If a destructive cache method has been called since the last recorded
1193
+ // incomplete result, there's a chance fetching this data again will
1194
+ // restore what was evicted, even though the cache result looks the same
1195
+ // as before.
1196
+ lastMissing.dmCount !== destructiveMethodCounts.get(this.cache) ||
1197
+ !equal(lastMissing.variables, this.variables) ||
1198
+ !equal(lastMissing.missing, diff.missing?.missing)) {
1199
+ this.didWarnOnFeud = false;
1200
+ this.lastMissing = {
1201
+ variables: this.variables,
1202
+ missing: diff.missing?.missing,
1203
+ dmCount: destructiveMethodCounts.get(this.cache),
1204
+ };
1205
+ }
1206
+ else if (
1207
+ // reobserveCacheFirst with cache-only fetch policy only calls
1208
+ // reobserve which never fetches from the network so we are ok
1209
+ // allowing cache-only queries to fallthrough to reobserveCacheFirst.
1210
+ // This also prevents the feud warning which would be confusing for a
1211
+ // cache-only query anyways.
1212
+ fetchPolicy !== "cache-only") {
1213
+ // If we've fallen through to this case, a cache emit has returned the
1214
+ // same missing fields which means at least one value on the fields we've
1215
+ // already delivered have changed. We are ok delivering the updated
1216
+ // partial result in this case to keep the result as fresh as possible. We
1217
+ // NEVER want to downgrade this query from a complete query to a partial
1218
+ // query though, so we also make sure we only deliver if the previous
1219
+ // result was also partial.
1220
+ if (current.dataState === "partial") {
1221
+ this.deliverCacheDiff(diff);
1148
1222
  }
1149
- else {
1150
- // If this diff came from an optimistic transaction, deliver the
1151
- // current cache data to the ObservableQuery, but don't perform a
1152
- // reobservation, since oq.reobserveCacheFirst might make a network
1153
- // request, and we never want to trigger network requests in the
1154
- // middle of optimistic updates.
1155
- this.input.next({
1156
- kind: "N",
1157
- value: {
1158
- data: diff.result,
1159
- dataState: diff.complete ? "complete"
1160
- : diff.result ? "partial"
1161
- : "empty",
1162
- networkStatus: NetworkStatus.ready,
1163
- loading: false,
1164
- error: undefined,
1165
- partial: !diff.complete,
1166
- },
1167
- source: "cache",
1168
- query: this.query,
1169
- variables: this.variables,
1170
- meta: {},
1171
- });
1223
+ // If the (partial) result is the same as the last partial result
1224
+ // we recorded from a previous broadcast (and the variables match
1225
+ // too), avoid calling reobserveCacheFirst to refetch this query
1226
+ // again. If we allow refetching anytime this result becomes partial,
1227
+ // we risk feuds between queries competing to update the same data in
1228
+ // incompatible ways, which can lead to an endless cycle of cache
1229
+ // broadcasts and useless network requests. As with any
1230
+ // feud, eventually one side must step back from the brink,
1231
+ // letting the other side(s) have the last word(s). There may
1232
+ // be other points where we could break this cycle, such as
1233
+ // silencing the broadcast for cache.writeQuery (not a good
1234
+ // idea, since it just delays the feud a bit) or somehow
1235
+ // avoiding the network request that just happened (also bad,
1236
+ // because the server could return useful new data). All
1237
+ // options considered, returning early and stopping the
1238
+ // reobserveCacheFirst cycle seems to be the least damaging place to
1239
+ // break the cycle because it allows read functions/custom scalars to
1240
+ // be applied to the feuding query while avoiding the endless cycle of
1241
+ // requests.
1242
+ if (__DEV__ && !this.didWarnOnFeud) {
1243
+ this.didWarnOnFeud = true;
1244
+ warnOnFeud(this.query, diff);
1172
1245
  }
1246
+ return;
1173
1247
  }
1248
+ //If this diff did not come from an optimistic transaction
1249
+ // make the ObservableQuery "reobserve" the latest data
1250
+ // using a temporary fetch policy of "cache-first", so complete cache
1251
+ // results have a chance to be delivered without triggering additional
1252
+ // network requests, even when options.fetchPolicy is "network-only"
1253
+ // or "cache-and-network". All other fetch policies are preserved by
1254
+ // this method, and are handled by calling oq.reobserve(). If this
1255
+ // reobservation is spurious, distinctUntilChanged still has a
1256
+ // chance to catch it before delivery to ObservableQuery subscribers.
1257
+ this.reobserveCacheFirst();
1258
+ }
1259
+ deliverCacheDiff(diff) {
1260
+ const current = this.getCurrentResult();
1261
+ this.input.next({
1262
+ kind: "N",
1263
+ value: {
1264
+ data: diff.result,
1265
+ dataState: diff.dataState,
1266
+ networkStatus: current.networkStatus,
1267
+ loading: current.loading,
1268
+ error: undefined,
1269
+ partial: !diff.complete,
1270
+ },
1271
+ source: "cache",
1272
+ query: this.query,
1273
+ variables: this.variables,
1274
+ meta: {},
1275
+ });
1174
1276
  }
1175
1277
  activeOperations = new Set();
1176
1278
  pushOperation(networkStatus) {
@@ -1233,6 +1335,7 @@ export class ObservableQuery {
1233
1335
  // exception for cache-only queries - we reset them into a "ready" state
1234
1336
  // as we won't trigger a refetch for them
1235
1337
  const resetToEmpty = this.options.fetchPolicy === "cache-only";
1338
+ this.lastMissing = undefined;
1236
1339
  this.setResult(resetToEmpty ? empty : uninitialized, {
1237
1340
  shouldEmit: resetToEmpty ? 1 /* EmitBehavior.force */ : 2 /* EmitBehavior.never */,
1238
1341
  });
@@ -1302,7 +1405,7 @@ export class ObservableQuery {
1302
1405
  if (notification.source === "cache") {
1303
1406
  result = notification.value;
1304
1407
  if (result.networkStatus === NetworkStatus.ready &&
1305
- result.partial &&
1408
+ result.dataState === "partial" &&
1306
1409
  (!this.options.returnPartialData ||
1307
1410
  previous.result.networkStatus === NetworkStatus.error) &&
1308
1411
  this.options.fetchPolicy !== "cache-only") {
@@ -1377,7 +1480,10 @@ export class ObservableQuery {
1377
1480
  reobserveCacheFirst() {
1378
1481
  const { fetchPolicy, nextFetchPolicy } = this.options;
1379
1482
  if (fetchPolicy === "cache-and-network" || fetchPolicy === "network-only") {
1380
- this.reobserve({
1483
+ // Preserve this.lastMissing so a cache update that triggers this
1484
+ // reobserve doesn't reset feud detection. All user-initiated calls to
1485
+ // reobserve (refetch/poll/reobserve, etc) should clear it.
1486
+ this._reobserve({
1381
1487
  fetchPolicy: "cache-first",
1382
1488
  // Use a temporary nextFetchPolicy function that replaces itself with the
1383
1489
  // previous nextFetchPolicy value and returns the original fetchPolicy.
@@ -1393,10 +1499,10 @@ export class ObservableQuery {
1393
1499
  // Otherwise go back to the original this.options.fetchPolicy.
1394
1500
  return fetchPolicy;
1395
1501
  },
1396
- });
1502
+ }, { keepLastMissing: true });
1397
1503
  }
1398
1504
  else {
1399
- this.reobserve();
1505
+ this._reobserve(undefined, { keepLastMissing: true });
1400
1506
  }
1401
1507
  }
1402
1508
  getVariablesWithDefaults(variables) {
@@ -1448,4 +1554,7 @@ function getTrackingOperatorPromise(defaultValue) {
1448
1554
  });
1449
1555
  return { promise, operator };
1450
1556
  }
1557
+ function warnOnFeud(query, diff) {
1558
+ __DEV__ && invariant.warn(89, getOperationName(query, "(anonymous)"), diff.missing?.missing);
1559
+ }
1451
1560
  //# sourceMappingURL=ObservableQuery.js.map