@apollo/client 4.0.5 → 4.1.0-alpha.0

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 (76) hide show
  1. package/CHANGELOG.md +27 -2
  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 +4 -4
  6. package/__cjs/cache/inmemory/policies.cjs.map +1 -1
  7. package/__cjs/cache/inmemory/readFromStore.cjs +2 -2
  8. package/__cjs/cache/inmemory/writeToStore.cjs +5 -5
  9. package/__cjs/cache/inmemory/writeToStore.cjs.map +1 -1
  10. package/__cjs/core/ApolloClient.cjs +12 -12
  11. package/__cjs/core/ObservableQuery.cjs +157 -106
  12. package/__cjs/core/ObservableQuery.cjs.map +1 -1
  13. package/__cjs/core/ObservableQuery.d.cts +1 -0
  14. package/__cjs/core/QueryManager.cjs +12 -12
  15. package/__cjs/incremental/handlers/defer20220824.cjs +20 -9
  16. package/__cjs/incremental/handlers/defer20220824.cjs.map +1 -1
  17. package/__cjs/incremental/handlers/defer20220824.d.cts +14 -5
  18. package/__cjs/incremental/handlers/graphql17Alpha9.cjs +181 -0
  19. package/__cjs/incremental/handlers/graphql17Alpha9.cjs.map +1 -0
  20. package/__cjs/incremental/handlers/graphql17Alpha9.d.cts +97 -0
  21. package/__cjs/incremental/handlers/notImplemented.cjs +1 -1
  22. package/__cjs/incremental/index.cjs +3 -1
  23. package/__cjs/incremental/index.cjs.map +1 -1
  24. package/__cjs/incremental/index.d.cts +1 -0
  25. package/__cjs/invariantErrorCodes.cjs +51 -45
  26. package/__cjs/react/internal/cache/QueryReference.cjs +16 -0
  27. package/__cjs/react/internal/cache/QueryReference.cjs.map +1 -1
  28. package/__cjs/react/internal/cache/QueryReference.d.cts +1 -0
  29. package/__cjs/testing/core/mocking/mockLink.cjs.map +1 -1
  30. package/__cjs/testing/core/mocking/mockLink.d.cts +1 -3
  31. package/__cjs/utilities/internal/DeepMerger.cjs +10 -1
  32. package/__cjs/utilities/internal/DeepMerger.cjs.map +1 -1
  33. package/__cjs/utilities/internal/DeepMerger.d.cts +14 -2
  34. package/__cjs/utilities/internal/getStoreKeyName.cjs +1 -0
  35. package/__cjs/utilities/internal/getStoreKeyName.cjs.map +1 -1
  36. package/__cjs/version.cjs +1 -1
  37. package/__cjs/version.cjs.map +1 -1
  38. package/cache/core/cache.js +1 -1
  39. package/cache/inmemory/entityStore.js +3 -3
  40. package/cache/inmemory/key-extractor.js +1 -1
  41. package/cache/inmemory/policies.js +4 -4
  42. package/cache/inmemory/policies.js.map +1 -1
  43. package/cache/inmemory/readFromStore.js +2 -2
  44. package/cache/inmemory/writeToStore.js +5 -5
  45. package/cache/inmemory/writeToStore.js.map +1 -1
  46. package/core/ApolloClient.js +12 -12
  47. package/core/ObservableQuery.d.ts +1 -0
  48. package/core/ObservableQuery.js +159 -108
  49. package/core/ObservableQuery.js.map +1 -1
  50. package/core/QueryManager.js +12 -12
  51. package/incremental/handlers/defer20220824.d.ts +14 -5
  52. package/incremental/handlers/defer20220824.js +20 -9
  53. package/incremental/handlers/defer20220824.js.map +1 -1
  54. package/incremental/handlers/graphql17Alpha9.d.ts +97 -0
  55. package/incremental/handlers/graphql17Alpha9.js +177 -0
  56. package/incremental/handlers/graphql17Alpha9.js.map +1 -0
  57. package/incremental/handlers/notImplemented.js +1 -1
  58. package/incremental/index.d.ts +1 -0
  59. package/incremental/index.js +3 -2
  60. package/incremental/index.js.map +1 -1
  61. package/invariantErrorCodes.js +51 -45
  62. package/package.json +1 -1
  63. package/react/internal/cache/QueryReference.d.ts +1 -0
  64. package/react/internal/cache/QueryReference.js +16 -0
  65. package/react/internal/cache/QueryReference.js.map +1 -1
  66. package/testing/core/mocking/mockLink.d.ts +1 -3
  67. package/testing/core/mocking/mockLink.js.map +1 -1
  68. package/utilities/internal/DeepMerger.d.ts +14 -2
  69. package/utilities/internal/DeepMerger.js +10 -1
  70. package/utilities/internal/DeepMerger.js.map +1 -1
  71. package/utilities/internal/getStoreKeyName.js +1 -0
  72. package/utilities/internal/getStoreKeyName.js.map +1 -1
  73. package/utilities/internal/globals/global.js +2 -2
  74. package/utilities/internal/globals/global.js.map +1 -1
  75. package/version.js +1 -1
  76. package/version.js.map +1 -1
@@ -72,8 +72,8 @@ export class ApolloClient {
72
72
  */
73
73
  constructor(options) {
74
74
  if (__DEV__) {
75
- invariant(options.cache, 65);
76
- invariant(options.link, 66);
75
+ invariant(options.cache, 66);
76
+ invariant(options.link, 67);
77
77
  }
78
78
  const { cache, documentTransform, ssrMode = false, ssrForceFetchDelay = 0, queryDeduplication = true, defaultOptions, defaultContext, assumeImmutableResults = cache.assumeImmutableResults, localState, devtools, dataMasking, link, incrementalHandler = new NotImplementedHandler(), } = options;
79
79
  this.link = link;
@@ -233,13 +233,13 @@ export class ApolloClient {
233
233
  options = mergeOptions(this.defaultOptions.query, options);
234
234
  }
235
235
  if (__DEV__) {
236
- invariant(options.fetchPolicy !== "cache-and-network", 67);
237
- invariant(options.fetchPolicy !== "standby", 68);
238
- invariant(options.query, 69);
239
- invariant(options.query.kind === "Document", 70);
240
- invariant(!options.returnPartialData, 71);
241
- invariant(!options.pollInterval, 72);
242
- invariant(!options.notifyOnNetworkStatusChange, 73);
236
+ invariant(options.fetchPolicy !== "cache-and-network", 68);
237
+ invariant(options.fetchPolicy !== "standby", 69);
238
+ invariant(options.query, 70);
239
+ invariant(options.query.kind === "Document", 71);
240
+ invariant(!options.returnPartialData, 72);
241
+ invariant(!options.pollInterval, 73);
242
+ invariant(!options.notifyOnNetworkStatusChange, 74);
243
243
  }
244
244
  return this.queryManager.query(options);
245
245
  }
@@ -257,9 +257,9 @@ export class ApolloClient {
257
257
  errorPolicy: "none",
258
258
  }, this.defaultOptions.mutate), options);
259
259
  if (__DEV__) {
260
- invariant(optionsWithDefaults.mutation, 74);
260
+ invariant(optionsWithDefaults.mutation, 75);
261
261
  invariant(optionsWithDefaults.fetchPolicy === "network-only" ||
262
- optionsWithDefaults.fetchPolicy === "no-cache", 75);
262
+ optionsWithDefaults.fetchPolicy === "no-cache", 76);
263
263
  }
264
264
  checkDocument(optionsWithDefaults.mutation, OperationTypeNode.MUTATION);
265
265
  return this.queryManager.mutate(optionsWithDefaults);
@@ -484,7 +484,7 @@ export class ApolloClient {
484
484
  // result.queries and result.results instead, you shouldn't have to worry
485
485
  // about preventing uncaught rejections for the Promise.all result.
486
486
  result.catch((error) => {
487
- __DEV__ && invariant.debug(76, error);
487
+ __DEV__ && invariant.debug(77, error);
488
488
  });
489
489
  return result;
490
490
  }
@@ -285,6 +285,7 @@ export declare class ObservableQuery<TData = unknown, TVariables extends Operati
285
285
  private linkSubscription?;
286
286
  private pollingInfo?;
287
287
  private get networkStatus();
288
+ private get cache();
288
289
  constructor({ queryManager, options, transformedQuery, }: {
289
290
  queryManager: QueryManager;
290
291
  options: ApolloClient.WatchQueryOptions<TData, TVariables>;
@@ -1,6 +1,6 @@
1
1
  import { equal } from "@wry/equality";
2
- import { BehaviorSubject, Observable, share, Subject, tap } from "rxjs";
3
- import { isNetworkRequestInFlight } from "@apollo/client/utilities";
2
+ import { BehaviorSubject, filter, Observable, share, Subject, tap } from "rxjs";
3
+ import { isNetworkRequestInFlight, isNetworkRequestSettled, } from "@apollo/client/utilities";
4
4
  import { __DEV__ } from "@apollo/client/utilities/environment";
5
5
  import { compact, equalByQuery, filterMap, getOperationDefinition, getOperationName, getQueryDefinition, preventUnhandledRejection, toQueryResult, } from "@apollo/client/utilities/internal";
6
6
  import { invariant } from "@apollo/client/utilities/invariant";
@@ -60,6 +60,9 @@ export class ObservableQuery {
60
60
  get networkStatus() {
61
61
  return this.subject.getValue().result.networkStatus;
62
62
  }
63
+ get cache() {
64
+ return this.queryManager.cache;
65
+ }
63
66
  constructor({ queryManager, options, transformedQuery = queryManager.transform(options.query), }) {
64
67
  this.queryManager = queryManager;
65
68
  // active state
@@ -197,7 +200,7 @@ export class ObservableQuery {
197
200
  * @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
198
201
  */
199
202
  getCacheDiff({ optimistic = true } = {}) {
200
- return this.queryManager.cache.diff({
203
+ return this.cache.diff({
201
204
  query: this.query,
202
205
  variables: this.variables,
203
206
  returnPartialData: true,
@@ -308,7 +311,7 @@ export class ObservableQuery {
308
311
  }
309
312
  },
310
313
  };
311
- const cancelWatch = this.queryManager.cache.watch(watch);
314
+ const cancelWatch = this.cache.watch(watch);
312
315
  this.unsubscribeFromCache = Object.assign(() => {
313
316
  this.unsubscribeFromCache = undefined;
314
317
  cancelWatch();
@@ -372,7 +375,7 @@ export class ObservableQuery {
372
375
  const queryDef = getQueryDefinition(this.query);
373
376
  const vars = queryDef.variableDefinitions;
374
377
  if (!vars || !vars.some((v) => v.variable.name.value === "variables")) {
375
- __DEV__ && invariant.warn(77, variables, queryDef.name?.value || queryDef);
378
+ __DEV__ && invariant.warn(78, variables, queryDef.name?.value || queryDef);
376
379
  }
377
380
  }
378
381
  if (variables && !equal(this.variables, variables)) {
@@ -388,7 +391,7 @@ export class ObservableQuery {
388
391
  fetchMore({ query, variables, context, errorPolicy, updateQuery, }) {
389
392
  invariant(
390
393
  this.options.fetchPolicy !== "cache-only",
391
- 78,
394
+ 79,
392
395
  getOperationName(this.query, "(anonymous)")
393
396
  );
394
397
  const combinedOptions = {
@@ -422,7 +425,7 @@ export class ObservableQuery {
422
425
  let wasUpdated = false;
423
426
  const isCached = this.options.fetchPolicy !== "no-cache";
424
427
  if (!isCached) {
425
- invariant(updateQuery, 79);
428
+ invariant(updateQuery, 80);
426
429
  }
427
430
  const { finalize, pushNotification } = this.pushOperation(NetworkStatus.fetchMore);
428
431
  pushNotification({
@@ -430,105 +433,153 @@ export class ObservableQuery {
430
433
  kind: "N",
431
434
  value: {},
432
435
  }, { shouldEmit: 3 /* EmitBehavior.networkStatusChange */ });
433
- return this.queryManager
434
- .fetchQuery(combinedOptions, NetworkStatus.fetchMore)
435
- .then((fetchMoreResult) => {
436
- // disable the `fetchMore` override that is currently active
437
- // the next updates caused by this should not be `fetchMore` anymore,
438
- // but `ready` or whatever other calculated loading state is currently
439
- // appropriate
440
- finalize();
441
- if (isCached) {
442
- // Performing this cache update inside a cache.batch transaction ensures
443
- // any affected cache.watch watchers are notified at most once about any
444
- // updates. Most watchers will be using the QueryInfo class, which
445
- // responds to notifications by calling reobserveCacheFirst to deliver
446
- // fetchMore cache results back to this ObservableQuery.
447
- this.queryManager.cache.batch({
448
- update: (cache) => {
449
- if (updateQuery) {
450
- cache.updateQuery({
451
- query: this.query,
452
- variables: this.variables,
453
- returnPartialData: true,
454
- optimistic: false,
455
- }, (previous) => updateQuery(previous, {
456
- fetchMoreResult: fetchMoreResult.data,
457
- variables: combinedOptions.variables,
458
- }));
459
- }
460
- else {
461
- // If we're using a field policy instead of updateQuery, the only
462
- // thing we need to do is write the new data to the cache using
463
- // combinedOptions.variables (instead of this.variables, which is
464
- // what this.updateQuery uses, because it works by abusing the
465
- // original field value, keyed by the original variables).
466
- cache.writeQuery({
467
- query: combinedOptions.query,
468
- variables: combinedOptions.variables,
469
- data: fetchMoreResult.data,
470
- });
471
- }
472
- },
473
- onWatchUpdated: (watch) => {
474
- if (watch.watcher === this) {
475
- wasUpdated = true;
476
- }
477
- },
478
- });
479
- }
480
- else {
481
- // There is a possibility `lastResult` may not be set when
482
- // `fetchMore` is called which would cause this to crash. This should
483
- // only happen if we haven't previously reported a result. We don't
484
- // quite know what the right behavior should be here since this block
485
- // of code runs after the fetch result has executed on the network.
486
- // We plan to let it crash in the meantime.
487
- //
488
- // If we get bug reports due to the `data` property access on
489
- // undefined, this should give us a real-world scenario that we can
490
- // use to test against and determine the right behavior. If we do end
491
- // up changing this behavior, this may require, for example, an
492
- // adjustment to the types on `updateQuery` since that function
493
- // expects that the first argument always contains previous result
494
- // data, but not `undefined`.
495
- const lastResult = this.getCurrentResult();
496
- const data = updateQuery(lastResult.data, {
497
- fetchMoreResult: fetchMoreResult.data,
498
- variables: combinedOptions.variables,
499
- });
500
- // was reportResult
501
- pushNotification({
502
- kind: "N",
503
- value: {
504
- ...lastResult,
505
- networkStatus: NetworkStatus.ready,
506
- // will be overwritten anyways, just here for types sake
507
- loading: false,
508
- data: data,
509
- dataState: lastResult.dataState === "streaming" ? "streaming" : "complete",
510
- },
511
- source: "network",
512
- });
436
+ const { promise, operator } = getTrackingOperatorPromise((value) => {
437
+ switch (value.kind) {
438
+ case "E": {
439
+ throw value.error;
440
+ }
441
+ case "N": {
442
+ if (value.source !== "newNetworkStatus" && !value.value.loading) {
443
+ return value.value;
444
+ }
445
+ }
513
446
  }
514
- return this.maskResult(fetchMoreResult);
515
- })
447
+ });
448
+ const { observable } = this.queryManager.fetchObservableWithInfo(combinedOptions, { networkStatus: NetworkStatus.fetchMore });
449
+ const subscription = observable
450
+ .pipe(operator, filter((notification) => notification.kind === "N" && notification.source === "network"))
451
+ .subscribe({
452
+ next: (notification) => {
453
+ wasUpdated = false;
454
+ const fetchMoreResult = notification.value;
455
+ if (isNetworkRequestSettled(notification.value.networkStatus)) {
456
+ finalize();
457
+ }
458
+ if (isCached) {
459
+ // Performing this cache update inside a cache.batch transaction ensures
460
+ // any affected cache.watch watchers are notified at most once about any
461
+ // updates. Most watchers will be using the QueryInfo class, which
462
+ // responds to notifications by calling reobserveCacheFirst to deliver
463
+ // fetchMore cache results back to this ObservableQuery.
464
+ this.cache.batch({
465
+ update: (cache) => {
466
+ if (updateQuery) {
467
+ cache.updateQuery({
468
+ query: this.query,
469
+ variables: this.variables,
470
+ returnPartialData: true,
471
+ optimistic: false,
472
+ }, (previous) => updateQuery(previous, {
473
+ fetchMoreResult: fetchMoreResult.data,
474
+ variables: combinedOptions.variables,
475
+ }));
476
+ }
477
+ else {
478
+ // If we're using a field policy instead of updateQuery, the only
479
+ // thing we need to do is write the new data to the cache using
480
+ // combinedOptions.variables (instead of this.variables, which is
481
+ // what this.updateQuery uses, because it works by abusing the
482
+ // original field value, keyed by the original variables).
483
+ cache.writeQuery({
484
+ query: combinedOptions.query,
485
+ variables: combinedOptions.variables,
486
+ data: fetchMoreResult.data,
487
+ });
488
+ }
489
+ },
490
+ onWatchUpdated: (watch, diff) => {
491
+ if (watch.watcher === this) {
492
+ wasUpdated = true;
493
+ const lastResult = this.getCurrentResult();
494
+ // Let the cache watch from resubscribeCache handle the final
495
+ // result
496
+ if (isNetworkRequestInFlight(fetchMoreResult.networkStatus)) {
497
+ pushNotification({
498
+ kind: "N",
499
+ source: "network",
500
+ value: {
501
+ ...lastResult,
502
+ networkStatus: (fetchMoreResult.networkStatus ===
503
+ NetworkStatus.error) ?
504
+ NetworkStatus.ready
505
+ : fetchMoreResult.networkStatus,
506
+ // will be overwritten anyways, just here for types sake
507
+ loading: false,
508
+ data: diff.result,
509
+ dataState: fetchMoreResult.dataState === "streaming" ?
510
+ "streaming"
511
+ : "complete",
512
+ },
513
+ });
514
+ }
515
+ }
516
+ },
517
+ });
518
+ }
519
+ else {
520
+ // There is a possibility `lastResult` may not be set when
521
+ // `fetchMore` is called which would cause this to crash. This should
522
+ // only happen if we haven't previously reported a result. We don't
523
+ // quite know what the right behavior should be here since this block
524
+ // of code runs after the fetch result has executed on the network.
525
+ // We plan to let it crash in the meantime.
526
+ //
527
+ // If we get bug reports due to the `data` property access on
528
+ // undefined, this should give us a real-world scenario that we can
529
+ // use to test against and determine the right behavior. If we do end
530
+ // up changing this behavior, this may require, for example, an
531
+ // adjustment to the types on `updateQuery` since that function
532
+ // expects that the first argument always contains previous result
533
+ // data, but not `undefined`.
534
+ const lastResult = this.getCurrentResult();
535
+ const data = updateQuery(lastResult.data, {
536
+ fetchMoreResult: fetchMoreResult.data,
537
+ variables: combinedOptions.variables,
538
+ });
539
+ pushNotification({
540
+ kind: "N",
541
+ value: {
542
+ ...lastResult,
543
+ networkStatus: NetworkStatus.ready,
544
+ // will be overwritten anyways, just here for types sake
545
+ loading: false,
546
+ data: data,
547
+ dataState: lastResult.dataState === "streaming" ?
548
+ "streaming"
549
+ : "complete",
550
+ },
551
+ source: "network",
552
+ });
553
+ }
554
+ },
555
+ });
556
+ return preventUnhandledRejection(promise
557
+ .then((result) => toQueryResult(this.maskResult(result)))
516
558
  .finally(() => {
517
- // call `finalize` a second time in case the `.then` case above was not reached
518
- finalize();
519
- // In case the cache writes above did not generate a broadcast
520
- // notification (which would have been intercepted by onWatchUpdated),
521
- // likely because the written data were the same as what was already in
522
- // the cache, we still want fetchMore to deliver its final loading:false
523
- // result with the unchanged data.
559
+ subscription.unsubscribe();
524
560
  if (isCached && !wasUpdated) {
525
- pushNotification({
526
- kind: "N",
527
- source: "newNetworkStatus",
528
- value: {},
529
- }, { shouldEmit: 1 /* EmitBehavior.force */ });
561
+ finalize();
562
+ const lastResult = this.getCurrentResult();
563
+ if (lastResult.networkStatus === NetworkStatus.streaming) {
564
+ pushNotification({
565
+ kind: "N",
566
+ source: "network",
567
+ value: {
568
+ ...lastResult,
569
+ dataState: "complete",
570
+ networkStatus: NetworkStatus.ready,
571
+ },
572
+ });
573
+ }
574
+ else {
575
+ pushNotification({
576
+ kind: "N",
577
+ source: "newNetworkStatus",
578
+ value: {},
579
+ }, { shouldEmit: 1 /* EmitBehavior.force */ });
580
+ }
530
581
  }
531
- });
582
+ }));
532
583
  }
533
584
  // XXX the subscription variables are separate from the query variables.
534
585
  // if you want to update subscription variables, right now you have to do that separately,
@@ -554,7 +605,7 @@ export class ObservableQuery {
554
605
  onError(error);
555
606
  }
556
607
  else {
557
- invariant.error(80, error);
608
+ invariant.error(81, error);
558
609
  }
559
610
  return;
560
611
  }
@@ -632,7 +683,7 @@ export class ObservableQuery {
632
683
  previousData: result,
633
684
  });
634
685
  if (newResult) {
635
- queryManager.cache.writeQuery({
686
+ this.cache.writeQuery({
636
687
  query: this.options.query,
637
688
  data: newResult,
638
689
  variables: this.variables,
@@ -798,7 +849,7 @@ export class ObservableQuery {
798
849
  if (!this.didWarnCacheOnlyPolling &&
799
850
  pollInterval &&
800
851
  fetchPolicy === "cache-only") {
801
- __DEV__ && invariant.warn(81, getOperationName(this.query, "(anonymous)"));
852
+ __DEV__ && invariant.warn(82, getOperationName(this.query, "(anonymous)"));
802
853
  this.didWarnCacheOnlyPolling = true;
803
854
  }
804
855
  }
@@ -1065,8 +1116,8 @@ export class ObservableQuery {
1065
1116
  const { dirty } = this;
1066
1117
  this.resetNotifications();
1067
1118
  if (dirty &&
1068
- (this.options.fetchPolicy == "cache-only" ||
1069
- this.options.fetchPolicy == "cache-and-network" ||
1119
+ (this.options.fetchPolicy === "cache-only" ||
1120
+ this.options.fetchPolicy === "cache-and-network" ||
1070
1121
  !this.activeOperations.size)) {
1071
1122
  const diff = this.getCacheDiff();
1072
1123
  if (
@@ -1294,7 +1345,7 @@ export class ObservableQuery {
1294
1345
  }
1295
1346
  export function logMissingFieldErrors(missing) {
1296
1347
  if (__DEV__ && missing) {
1297
- __DEV__ && invariant.debug(82, missing);
1348
+ __DEV__ && invariant.debug(83, missing);
1298
1349
  }
1299
1350
  }
1300
1351
  function isEqualQuery(a, b) {