relay-runtime 10.1.3 → 11.0.2

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 (106) hide show
  1. package/handlers/connection/ConnectionHandler.js.flow +60 -0
  2. package/handlers/connection/MutationHandlers.js.flow +28 -0
  3. package/index.js +1 -1
  4. package/index.js.flow +9 -3
  5. package/lib/handlers/RelayDefaultHandlerProvider.js +1 -1
  6. package/lib/handlers/connection/ConnectionHandler.js +68 -6
  7. package/lib/handlers/connection/MutationHandlers.js +67 -8
  8. package/lib/index.js +3 -0
  9. package/lib/multi-actor-environment/ActorIdentifier.js +23 -0
  10. package/lib/multi-actor-environment/ActorSpecificEnvironment.js +108 -0
  11. package/lib/multi-actor-environment/MultiActorEnvironment.js +156 -0
  12. package/lib/multi-actor-environment/MultiActorEnvironmentTypes.js +11 -0
  13. package/lib/multi-actor-environment/index.js +17 -0
  14. package/lib/mutations/RelayRecordProxy.js +1 -1
  15. package/lib/mutations/RelayRecordSourceMutator.js +1 -1
  16. package/lib/mutations/RelayRecordSourceProxy.js +1 -1
  17. package/lib/mutations/RelayRecordSourceSelectorProxy.js +1 -1
  18. package/lib/mutations/applyOptimisticMutation.js +1 -1
  19. package/lib/mutations/commitMutation.js +1 -1
  20. package/lib/mutations/validateMutation.js +36 -15
  21. package/lib/network/RelayNetwork.js +1 -1
  22. package/lib/network/RelayQueryResponseCache.js +3 -2
  23. package/lib/query/GraphQLTag.js +1 -1
  24. package/lib/query/fetchQuery.js +129 -13
  25. package/lib/query/fetchQueryInternal.js +3 -4
  26. package/lib/query/fetchQuery_DEPRECATED.js +39 -0
  27. package/lib/store/DataChecker.js +26 -14
  28. package/lib/store/{RelayModernQueryExecutor.js → OperationExecutor.js} +117 -47
  29. package/lib/store/RelayConcreteVariables.js +8 -4
  30. package/lib/store/RelayModernEnvironment.js +105 -136
  31. package/lib/store/RelayModernFragmentSpecResolver.js +16 -9
  32. package/lib/store/RelayModernRecord.js +1 -1
  33. package/lib/store/RelayModernSelector.js +1 -1
  34. package/lib/store/RelayModernStore.js +19 -20
  35. package/lib/store/RelayOperationTracker.js +55 -49
  36. package/lib/store/RelayPublishQueue.js +9 -5
  37. package/lib/store/RelayReader.js +68 -14
  38. package/lib/store/RelayReferenceMarker.js +28 -14
  39. package/lib/store/RelayResponseNormalizer.js +109 -15
  40. package/lib/store/RelayStoreReactFlightUtils.js +6 -4
  41. package/lib/store/RelayStoreSubscriptions.js +18 -8
  42. package/lib/store/RelayStoreSubscriptionsUsingMapByID.js +90 -30
  43. package/lib/store/RelayStoreUtils.js +3 -2
  44. package/lib/store/ResolverFragments.js +57 -0
  45. package/lib/store/cloneRelayHandleSourceField.js +1 -1
  46. package/lib/store/cloneRelayScalarHandleSourceField.js +1 -1
  47. package/lib/store/createFragmentSpecResolver.js +2 -2
  48. package/lib/store/createRelayContext.js +1 -1
  49. package/lib/store/defaultGetDataID.js +3 -1
  50. package/lib/store/hasOverlappingIDs.js +11 -3
  51. package/lib/store/readInlineData.js +1 -1
  52. package/lib/subscription/requestSubscription.js +33 -5
  53. package/lib/util/RelayConcreteNode.js +2 -0
  54. package/lib/util/RelayFeatureFlags.js +8 -3
  55. package/lib/util/RelayProfiler.js +17 -187
  56. package/lib/util/RelayReplaySubject.js +1 -1
  57. package/lib/util/deepFreeze.js +1 -0
  58. package/lib/util/getRelayHandleKey.js +1 -1
  59. package/lib/util/getRequestIdentifier.js +1 -1
  60. package/multi-actor-environment/ActorIdentifier.js.flow +27 -0
  61. package/multi-actor-environment/ActorSpecificEnvironment.js.flow +189 -0
  62. package/multi-actor-environment/MultiActorEnvironment.js.flow +233 -0
  63. package/multi-actor-environment/MultiActorEnvironmentTypes.js.flow +196 -0
  64. package/multi-actor-environment/index.js.flow +24 -0
  65. package/mutations/RelayRecordSourceProxy.js.flow +3 -2
  66. package/mutations/commitMutation.js.flow +1 -1
  67. package/mutations/validateMutation.js.flow +40 -15
  68. package/network/RelayNetworkTypes.js.flow +31 -11
  69. package/network/RelayQueryResponseCache.js.flow +2 -1
  70. package/package.json +3 -2
  71. package/query/fetchQuery.js.flow +147 -20
  72. package/query/fetchQueryInternal.js.flow +2 -3
  73. package/query/fetchQuery_DEPRECATED.js.flow +47 -0
  74. package/relay-runtime.js +2 -2
  75. package/relay-runtime.min.js +2 -2
  76. package/store/DataChecker.js.flow +23 -15
  77. package/store/{RelayModernQueryExecutor.js.flow → OperationExecutor.js.flow} +128 -40
  78. package/store/RelayConcreteVariables.js.flow +5 -0
  79. package/store/RelayModernEnvironment.js.flow +100 -130
  80. package/store/RelayModernFragmentSpecResolver.js.flow +30 -8
  81. package/store/RelayModernStore.js.flow +28 -24
  82. package/store/RelayOperationTracker.js.flow +69 -56
  83. package/store/RelayPublishQueue.js.flow +7 -4
  84. package/store/RelayReader.js.flow +63 -11
  85. package/store/RelayRecordSource.js.flow +3 -3
  86. package/store/RelayRecordSourceMapImpl.js.flow +6 -2
  87. package/store/RelayReferenceMarker.js.flow +28 -18
  88. package/store/RelayResponseNormalizer.js.flow +134 -23
  89. package/store/RelayStoreReactFlightUtils.js.flow +9 -4
  90. package/store/RelayStoreSubscriptions.js.flow +22 -7
  91. package/store/RelayStoreSubscriptionsUsingMapByID.js.flow +36 -12
  92. package/store/RelayStoreTypes.js.flow +51 -22
  93. package/store/RelayStoreUtils.js.flow +2 -1
  94. package/store/ResolverFragments.js.flow +125 -0
  95. package/store/createFragmentSpecResolver.js.flow +2 -0
  96. package/store/defaultGetDataID.js.flow +3 -1
  97. package/store/hasOverlappingIDs.js.flow +11 -9
  98. package/subscription/requestSubscription.js.flow +25 -2
  99. package/util/NormalizationNode.js.flow +13 -0
  100. package/util/ReaderNode.js.flow +14 -1
  101. package/util/RelayConcreteNode.js.flow +2 -0
  102. package/util/RelayFeatureFlags.js.flow +12 -2
  103. package/util/RelayProfiler.js.flow +22 -194
  104. package/util/RelayRuntimeTypes.js.flow +4 -5
  105. package/util/deepFreeze.js.flow +2 -1
  106. package/util/isEmptyObject.js.flow +1 -1
@@ -46,7 +46,7 @@ import type {
46
46
  MutableRecordSource,
47
47
  NormalizationSelector,
48
48
  OperationLoader,
49
- ReactFlightReachableQuery,
49
+ ReactFlightReachableExecutableDefinitions,
50
50
  Record,
51
51
  RecordSource,
52
52
  } from './RelayStoreTypes';
@@ -58,6 +58,7 @@ export type Availability = {|
58
58
 
59
59
  const {
60
60
  CONDITION,
61
+ CLIENT_COMPONENT,
61
62
  CLIENT_EXTENSION,
62
63
  DEFER,
63
64
  FLIGHT_FIELD,
@@ -95,6 +96,7 @@ function check(
95
96
  handlers: $ReadOnlyArray<MissingFieldHandler>,
96
97
  operationLoader: ?OperationLoader,
97
98
  getDataID: GetDataID,
99
+ shouldProcessClientComponents: ?boolean,
98
100
  ): Availability {
99
101
  const {dataID, node, variables} = selector;
100
102
  const checker = new DataChecker(
@@ -104,6 +106,7 @@ function check(
104
106
  handlers,
105
107
  operationLoader,
106
108
  getDataID,
109
+ shouldProcessClientComponents,
107
110
  );
108
111
  return checker.check(node, dataID);
109
112
  }
@@ -121,6 +124,7 @@ class DataChecker {
121
124
  _recordWasMissing: boolean;
122
125
  _source: RecordSource;
123
126
  _variables: Variables;
127
+ _shouldProcessClientComponents: ?boolean;
124
128
 
125
129
  constructor(
126
130
  source: RecordSource,
@@ -129,6 +133,7 @@ class DataChecker {
129
133
  handlers: $ReadOnlyArray<MissingFieldHandler>,
130
134
  operationLoader: ?OperationLoader,
131
135
  getDataID: GetDataID,
136
+ shouldProcessClientComponents: ?boolean,
132
137
  ) {
133
138
  const mutator = new RelayRecordSourceMutator(source, target);
134
139
  this._mostRecentlyInvalidatedAt = null;
@@ -139,6 +144,7 @@ class DataChecker {
139
144
  this._recordWasMissing = false;
140
145
  this._source = source;
141
146
  this._variables = variables;
147
+ this._shouldProcessClientComponents = shouldProcessClientComponents;
142
148
  }
143
149
 
144
150
  check(node: NormalizationNode, dataID: DataID): Availability {
@@ -161,6 +167,7 @@ class DataChecker {
161
167
  'RelayAsyncLoader(): Undefined variable `%s`.',
162
168
  name,
163
169
  );
170
+ // $FlowFixMe[cannot-write]
164
171
  return this._variables[name];
165
172
  }
166
173
 
@@ -383,12 +390,7 @@ class DataChecker {
383
390
  break;
384
391
  // $FlowFixMe[incompatible-type]
385
392
  case FRAGMENT_SPREAD:
386
- invariant(
387
- false,
388
- 'RelayAsyncLoader(): Unexpected ast kind `%s`.',
389
- selection.kind,
390
- );
391
- // $FlowExpectedError[unreachable-code] - we need the break; for OSS linter
393
+ this._traverseSelections(selection.fragment.selections, dataID);
392
394
  break;
393
395
  case CLIENT_EXTENSION:
394
396
  const recordWasMissing = this._recordWasMissing;
@@ -423,6 +425,12 @@ class DataChecker {
423
425
  throw new Error('Flight fields are not yet supported.');
424
426
  }
425
427
  break;
428
+ case CLIENT_COMPONENT:
429
+ if (this._shouldProcessClientComponents === false) {
430
+ break;
431
+ }
432
+ this._traverseSelections(selection.fragment.selections, dataID);
433
+ break;
426
434
  default:
427
435
  (selection: empty);
428
436
  invariant(
@@ -527,12 +535,12 @@ class DataChecker {
527
535
  linkedID,
528
536
  RelayStoreReactFlightUtils.REACT_FLIGHT_TREE_STORAGE_KEY,
529
537
  );
530
- const reachableQueries = this._mutator.getValue(
538
+ const reachableExecutableDefinitions = this._mutator.getValue(
531
539
  linkedID,
532
- RelayStoreReactFlightUtils.REACT_FLIGHT_QUERIES_STORAGE_KEY,
540
+ RelayStoreReactFlightUtils.REACT_FLIGHT_EXECUTABLE_DEFINITIONS_STORAGE_KEY,
533
541
  );
534
542
 
535
- if (tree == null || !Array.isArray(reachableQueries)) {
543
+ if (tree == null || !Array.isArray(reachableExecutableDefinitions)) {
536
544
  this._handleMissing();
537
545
  return;
538
546
  }
@@ -543,13 +551,13 @@ class DataChecker {
543
551
  'DataChecker: Expected an operationLoader to be configured when using ' +
544
552
  'React Flight.',
545
553
  );
546
- // In Flight, the variables that are in scope for reachable queries aren't
547
- // the same as what's in scope for the outer query.
554
+ // In Flight, the variables that are in scope for reachable executable
555
+ // definitions aren't the same as what's in scope for the outer query.
548
556
  const prevVariables = this._variables;
549
557
  // $FlowFixMe[incompatible-cast]
550
- for (const query of (reachableQueries: Array<ReactFlightReachableQuery>)) {
551
- this._variables = query.variables;
552
- const normalizationRootNode = operationLoader.get(query.module);
558
+ for (const definition of (reachableExecutableDefinitions: Array<ReactFlightReachableExecutableDefinitions>)) {
559
+ this._variables = definition.variables;
560
+ const normalizationRootNode = operationLoader.get(definition.module);
553
561
  if (normalizationRootNode != null) {
554
562
  const operation = getOperation(normalizationRootNode);
555
563
  this._traverseSelections(operation.selections, ROOT_ID);
@@ -14,6 +14,7 @@
14
14
  'use strict';
15
15
 
16
16
  const RelayError = require('../util/RelayError');
17
+ const RelayFeatureFlags = require('../util/RelayFeatureFlags');
17
18
  const RelayModernRecord = require('./RelayModernRecord');
18
19
  const RelayObservable = require('../network/RelayObservable');
19
20
  const RelayRecordSource = require('./RelayRecordSource');
@@ -24,8 +25,11 @@ const invariant = require('invariant');
24
25
  const stableCopy = require('../util/stableCopy');
25
26
  const warning = require('warning');
26
27
 
27
- const {generateClientID} = require('./ClientID');
28
- const {createNormalizationSelector} = require('./RelayModernSelector');
28
+ const {generateClientID, generateUniqueClientID} = require('./ClientID');
29
+ const {
30
+ createNormalizationSelector,
31
+ createReaderSelector,
32
+ } = require('./RelayModernSelector');
29
33
  const {ROOT_TYPE, TYPENAME_KEY, getStorageKey} = require('./RelayStoreUtils');
30
34
 
31
35
  import type {
@@ -48,6 +52,7 @@ import type {
48
52
  OptimisticUpdate,
49
53
  PublishQueue,
50
54
  ReactFlightPayloadDeserializer,
55
+ ReactFlightServerErrorHandler,
51
56
  Record,
52
57
  RelayResponsePayload,
53
58
  SelectorStoreUpdater,
@@ -71,16 +76,18 @@ export type ExecuteConfig = {|
71
76
  +operation: OperationDescriptor,
72
77
  +operationExecutions: Map<string, ActiveState>,
73
78
  +operationLoader: ?OperationLoader,
74
- +operationTracker?: ?OperationTracker,
79
+ +operationTracker: OperationTracker,
75
80
  +optimisticConfig: ?OptimisticResponseConfig,
76
81
  +publishQueue: PublishQueue,
77
82
  +reactFlightPayloadDeserializer?: ?ReactFlightPayloadDeserializer,
83
+ +reactFlightServerErrorHandler?: ?ReactFlightServerErrorHandler,
78
84
  +scheduler?: ?TaskScheduler,
79
85
  +sink: Sink<GraphQLResponse>,
80
86
  +source: RelayObservable<GraphQLResponse>,
81
87
  +store: Store,
82
88
  +updater?: ?SelectorStoreUpdater,
83
89
  +isClientPayload?: boolean,
90
+ +shouldProcessClientComponents?: ?boolean,
84
91
  |};
85
92
 
86
93
  export type ActiveState = 'active' | 'inactive';
@@ -126,12 +133,14 @@ class Executor {
126
133
  _operation: OperationDescriptor;
127
134
  _operationExecutions: Map<string, ActiveState>;
128
135
  _operationLoader: ?OperationLoader;
129
- _operationTracker: ?OperationTracker;
136
+ _operationTracker: OperationTracker;
130
137
  _operationUpdateEpochs: Map<string, number>;
131
138
  _optimisticUpdates: null | Array<OptimisticUpdate>;
132
139
  _pendingModulePayloadsCount: number;
133
140
  _publishQueue: PublishQueue;
134
141
  _reactFlightPayloadDeserializer: ?ReactFlightPayloadDeserializer;
142
+ _reactFlightServerErrorHandler: ?ReactFlightServerErrorHandler;
143
+ _shouldProcessClientComponents: ?boolean;
135
144
  _scheduler: ?TaskScheduler;
136
145
  _sink: Sink<GraphQLResponse>;
137
146
  _source: Map<
@@ -144,6 +153,7 @@ class Executor {
144
153
  _updater: ?SelectorStoreUpdater;
145
154
  _retainDisposable: ?Disposable;
146
155
  +_isClientPayload: boolean;
156
+ +_isSubscriptionOperation: boolean;
147
157
 
148
158
  constructor({
149
159
  operation,
@@ -161,6 +171,8 @@ class Executor {
161
171
  getDataID,
162
172
  isClientPayload,
163
173
  reactFlightPayloadDeserializer,
174
+ reactFlightServerErrorHandler,
175
+ shouldProcessClientComponents,
164
176
  }: ExecuteConfig): void {
165
177
  this._getDataID = getDataID;
166
178
  this._treatMissingFieldsAsNull = treatMissingFieldsAsNull;
@@ -184,6 +196,10 @@ class Executor {
184
196
  this._updater = updater;
185
197
  this._isClientPayload = isClientPayload === true;
186
198
  this._reactFlightPayloadDeserializer = reactFlightPayloadDeserializer;
199
+ this._reactFlightServerErrorHandler = reactFlightServerErrorHandler;
200
+ this._isSubscriptionOperation =
201
+ this._operation.request.node.params.operationKind === 'subscription';
202
+ this._shouldProcessClientComponents = shouldProcessClientComponents;
187
203
 
188
204
  const id = this._nextSubscriptionId++;
189
205
  source.subscribe({
@@ -228,6 +244,7 @@ class Executor {
228
244
  optimisticUpdates.forEach(update =>
229
245
  this._publishQueue.revertUpdate(update),
230
246
  );
247
+ // OK: run revert on cancel
231
248
  this._publishQueue.run();
232
249
  }
233
250
  this._incrementalResults.clear();
@@ -260,7 +277,7 @@ class Executor {
260
277
  }
261
278
  default:
262
279
  (this._state: empty);
263
- invariant(false, 'RelayModernQueryExecutor: invalid executor state.');
280
+ invariant(false, 'OperationExecutor: invalid executor state.');
264
281
  }
265
282
  this._operationExecutions.set(
266
283
  this._operation.request.identifier,
@@ -387,7 +404,7 @@ class Executor {
387
404
  if (isOptimistic && this._state !== 'started') {
388
405
  invariant(
389
406
  false,
390
- 'RelayModernQueryExecutor: optimistic payload received after server payload.',
407
+ 'OperationExecutor: optimistic payload received after server payload.',
391
408
  );
392
409
  }
393
410
  if (isOptimistic) {
@@ -433,6 +450,7 @@ class Executor {
433
450
  nonIncrementalResponses,
434
451
  incrementalResponses,
435
452
  ] = partitionGraphQLResponses(responsesWithData);
453
+ const hasNonIncrementalResponses = nonIncrementalResponses.length > 0;
436
454
 
437
455
  // In theory this doesn't preserve the ordering of the batch.
438
456
  // The idea is that a batch is always:
@@ -441,16 +459,20 @@ class Executor {
441
459
  // The non-incremental payload can appear if the server sends a batch
442
460
  // with the initial payload followed by some early-to-resolve incremental
443
461
  // payloads (although, can that even happen?)
444
- if (nonIncrementalResponses.length > 0) {
462
+ if (hasNonIncrementalResponses) {
445
463
  const payloadFollowups = this._processResponses(nonIncrementalResponses);
446
- // Please note that we're passing `this._operation` to the publish
447
- // queue here, which will later passed to the store (via notify)
448
- // to indicate that this is an operation that caused the store to update
449
- const updatedOwners = this._publishQueue.run(this._operation);
450
- this._updateOperationTracker(updatedOwners);
464
+
465
+ if (!RelayFeatureFlags.ENABLE_BATCHED_STORE_UPDATES) {
466
+ const updatedOwners = this._publishQueue.run(this._operation);
467
+ this._updateOperationTracker(updatedOwners);
468
+ }
469
+
451
470
  this._processPayloadFollowups(payloadFollowups);
452
- if (this._incrementalPayloadsPending && !this._retainDisposable) {
453
- this._retainDisposable = this._store.retain(this._operation);
471
+
472
+ if (!RelayFeatureFlags.ENABLE_BATCHED_STORE_UPDATES) {
473
+ if (this._incrementalPayloadsPending && !this._retainDisposable) {
474
+ this._retainDisposable = this._store.retain(this._operation);
475
+ }
454
476
  }
455
477
  }
456
478
 
@@ -458,13 +480,46 @@ class Executor {
458
480
  const payloadFollowups = this._processIncrementalResponses(
459
481
  incrementalResponses,
460
482
  );
461
- // For the incremental case, we're only handling follow-up responses
462
- // for already initiated operation (and we're not passing it to
463
- // the run(...) call)
464
- const updatedOwners = this._publishQueue.run();
465
- this._updateOperationTracker(updatedOwners);
483
+ if (!RelayFeatureFlags.ENABLE_BATCHED_STORE_UPDATES) {
484
+ // For the incremental case, we're only handling follow-up responses
485
+ // for already initiated operation (and we're not passing it to
486
+ // the run(...) call)
487
+ const updatedOwners = this._publishQueue.run();
488
+ this._updateOperationTracker(updatedOwners);
489
+ }
466
490
  this._processPayloadFollowups(payloadFollowups);
467
491
  }
492
+ if (
493
+ this._isSubscriptionOperation &&
494
+ RelayFeatureFlags.ENABLE_UNIQUE_SUBSCRIPTION_ROOT
495
+ ) {
496
+ // We attach the id to allow the `requestSubscription` to read from the store using
497
+ // the current id in its `onNext` callback
498
+ if (responsesWithData[0].extensions == null) {
499
+ // $FlowFixMe[cannot-write]
500
+ responsesWithData[0].extensions = {
501
+ __relay_subscription_root_id: this._operation.fragment.dataID,
502
+ };
503
+ } else {
504
+ responsesWithData[0].extensions.__relay_subscription_root_id = this._operation.fragment.dataID;
505
+ }
506
+ }
507
+
508
+ if (RelayFeatureFlags.ENABLE_BATCHED_STORE_UPDATES) {
509
+ // OK: run once after each new payload
510
+ // If we have non-incremental responses, we passing `this._operation` to
511
+ // the publish queue here, which will later be passed to the store (via
512
+ // notify) to indicate that this operation caused the store to update
513
+ const updatedOwners = this._publishQueue.run(
514
+ hasNonIncrementalResponses ? this._operation : undefined,
515
+ );
516
+ if (hasNonIncrementalResponses) {
517
+ if (this._incrementalPayloadsPending && !this._retainDisposable) {
518
+ this._retainDisposable = this._store.retain(this._operation);
519
+ }
520
+ }
521
+ this._updateOperationTracker(updatedOwners);
522
+ }
468
523
  this._sink.next(response);
469
524
  }
470
525
 
@@ -491,6 +546,8 @@ class Executor {
491
546
  getDataID: this._getDataID,
492
547
  path: [],
493
548
  reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
549
+ reactFlightServerErrorHandler: this._reactFlightServerErrorHandler,
550
+ shouldProcessClientComponents: this._shouldProcessClientComponents,
494
551
  treatMissingFieldsAsNull,
495
552
  },
496
553
  );
@@ -517,6 +574,8 @@ class Executor {
517
574
  }
518
575
  this._optimisticUpdates = optimisticUpdates;
519
576
  optimisticUpdates.forEach(update => this._publishQueue.applyUpdate(update));
577
+ // OK: only called on construction and when receiving an optimistic payload from network,
578
+ // which doesn't fall-through to the regular next() handling
520
579
  this._publishQueue.run();
521
580
  }
522
581
 
@@ -569,7 +628,9 @@ class Executor {
569
628
  getDataID: this._getDataID,
570
629
  path: moduleImportPayload.path,
571
630
  reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
631
+ reactFlightServerErrorHandler: this._reactFlightServerErrorHandler,
572
632
  treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
633
+ shouldProcessClientComponents: this._shouldProcessClientComponents,
573
634
  },
574
635
  );
575
636
  }
@@ -614,12 +675,13 @@ class Executor {
614
675
  if (this._optimisticUpdates == null) {
615
676
  warning(
616
677
  false,
617
- 'RelayModernQueryExecutor: Unexpected ModuleImport optimistic ' +
678
+ 'OperationExecutor: Unexpected ModuleImport optimistic ' +
618
679
  'update in operation %s.' +
619
680
  this._operation.request.node.params.name,
620
681
  );
621
682
  } else {
622
683
  this._optimisticUpdates.push(...moduleImportOptimisticUpdates);
684
+ // OK: always have to run() after an module import resolves async
623
685
  this._publishQueue.run();
624
686
  }
625
687
  });
@@ -645,7 +707,9 @@ class Executor {
645
707
  getDataID: this._getDataID,
646
708
  path: [],
647
709
  reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
710
+ reactFlightServerErrorHandler: this._reactFlightServerErrorHandler,
648
711
  treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
712
+ shouldProcessClientComponents: this._shouldProcessClientComponents,
649
713
  },
650
714
  );
651
715
  this._publishQueue.commitPayload(
@@ -723,8 +787,10 @@ class Executor {
723
787
  }
724
788
  });
725
789
  if (relayPayloads.length > 0) {
726
- const updatedOwners = this._publishQueue.run();
727
- this._updateOperationTracker(updatedOwners);
790
+ if (!RelayFeatureFlags.ENABLE_BATCHED_STORE_UPDATES) {
791
+ const updatedOwners = this._publishQueue.run();
792
+ this._updateOperationTracker(updatedOwners);
793
+ }
728
794
  this._processPayloadFollowups(relayPayloads);
729
795
  }
730
796
  }
@@ -733,9 +799,7 @@ class Executor {
733
799
  }
734
800
 
735
801
  _maybeCompleteSubscriptionOperationTracking() {
736
- const isSubscriptionOperation =
737
- this._operation.request.node.params.operationKind === 'subscription';
738
- if (!isSubscriptionOperation) {
802
+ if (!this._isSubscriptionOperation) {
739
803
  return;
740
804
  }
741
805
  if (
@@ -744,6 +808,23 @@ class Executor {
744
808
  ) {
745
809
  this._completeOperationTracker();
746
810
  }
811
+ if (RelayFeatureFlags.ENABLE_UNIQUE_SUBSCRIPTION_ROOT) {
812
+ const nextID = generateUniqueClientID();
813
+ this._operation = {
814
+ request: this._operation.request,
815
+ fragment: createReaderSelector(
816
+ this._operation.fragment.node,
817
+ nextID,
818
+ this._operation.fragment.variables,
819
+ this._operation.fragment.owner,
820
+ ),
821
+ root: createNormalizationSelector(
822
+ this._operation.root.node,
823
+ nextID,
824
+ this._operation.root.variables,
825
+ ),
826
+ };
827
+ }
747
828
  }
748
829
 
749
830
  /**
@@ -792,6 +873,9 @@ class Executor {
792
873
  moduleImportPayload,
793
874
  getOperation(operation),
794
875
  );
876
+ // OK: always have to run after an async module import resolves
877
+ const updatedOwners = this._publishQueue.run();
878
+ this._updateOperationTracker(updatedOwners);
795
879
  });
796
880
  }
797
881
  })
@@ -818,8 +902,10 @@ class Executor {
818
902
  operation,
819
903
  );
820
904
  this._publishQueue.commitPayload(this._operation, relayPayload);
821
- const updatedOwners = this._publishQueue.run();
822
- this._updateOperationTracker(updatedOwners);
905
+ if (!RelayFeatureFlags.ENABLE_BATCHED_STORE_UPDATES) {
906
+ const updatedOwners = this._publishQueue.run();
907
+ this._updateOperationTracker(updatedOwners);
908
+ }
823
909
  this._processPayloadFollowups([relayPayload]);
824
910
  }
825
911
 
@@ -924,8 +1010,10 @@ class Executor {
924
1010
  const payloadFollowups = this._processIncrementalResponses(
925
1011
  pendingResponses,
926
1012
  );
927
- const updatedOwners = this._publishQueue.run();
928
- this._updateOperationTracker(updatedOwners);
1013
+ if (!RelayFeatureFlags.ENABLE_BATCHED_STORE_UPDATES) {
1014
+ const updatedOwners = this._publishQueue.run();
1015
+ this._updateOperationTracker(updatedOwners);
1016
+ }
929
1017
  this._processPayloadFollowups(payloadFollowups);
930
1018
  }
931
1019
  }
@@ -1020,7 +1108,9 @@ class Executor {
1020
1108
  getDataID: this._getDataID,
1021
1109
  path: placeholder.path,
1022
1110
  reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
1111
+ reactFlightServerErrorHandler: this._reactFlightServerErrorHandler,
1023
1112
  treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
1113
+ shouldProcessClientComponents: this._shouldProcessClientComponents,
1024
1114
  },
1025
1115
  );
1026
1116
  this._publishQueue.commitPayload(this._operation, relayPayload);
@@ -1235,7 +1325,9 @@ class Executor {
1235
1325
  getDataID: this._getDataID,
1236
1326
  path: [...normalizationPath, responseKey, String(itemIndex)],
1237
1327
  reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
1328
+ reactFlightServerErrorHandler: this._reactFlightServerErrorHandler,
1238
1329
  treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
1330
+ shouldProcessClientComponents: this._shouldProcessClientComponents,
1239
1331
  });
1240
1332
  return {
1241
1333
  fieldPayloads,
@@ -1250,11 +1342,7 @@ class Executor {
1250
1342
  _updateOperationTracker(
1251
1343
  updatedOwners: ?$ReadOnlyArray<RequestDescriptor>,
1252
1344
  ): void {
1253
- if (
1254
- this._operationTracker != null &&
1255
- updatedOwners != null &&
1256
- updatedOwners.length > 0
1257
- ) {
1345
+ if (updatedOwners != null && updatedOwners.length > 0) {
1258
1346
  this._operationTracker.update(
1259
1347
  this._operation.request,
1260
1348
  new Set(updatedOwners),
@@ -1263,9 +1351,7 @@ class Executor {
1263
1351
  }
1264
1352
 
1265
1353
  _completeOperationTracker() {
1266
- if (this._operationTracker != null) {
1267
- this._operationTracker.complete(this._operation.request);
1268
- }
1354
+ this._operationTracker.complete(this._operation.request);
1269
1355
  }
1270
1356
  }
1271
1357
 
@@ -1283,7 +1369,7 @@ function partitionGraphQLResponses(
1283
1369
  if (label == null || path == null) {
1284
1370
  invariant(
1285
1371
  false,
1286
- 'RelayModernQueryExecutor: invalid incremental payload, expected ' +
1372
+ 'OperationExecutor: invalid incremental payload, expected ' +
1287
1373
  '`path` and `label` to either both be null/undefined, or ' +
1288
1374
  '`path` to be an `Array<string | number>` and `label` to be a ' +
1289
1375
  '`string`.',
@@ -1335,11 +1421,13 @@ function validateOptimisticResponsePayload(
1335
1421
  if (incrementalPlaceholders != null && incrementalPlaceholders.length !== 0) {
1336
1422
  invariant(
1337
1423
  false,
1338
- 'RelayModernQueryExecutor: optimistic responses cannot be returned ' +
1424
+ 'OperationExecutor: optimistic responses cannot be returned ' +
1339
1425
  'for operations that use incremental data delivery (@defer, ' +
1340
1426
  '@stream, and @stream_connection).',
1341
1427
  );
1342
1428
  }
1343
1429
  }
1344
1430
 
1345
- module.exports = {execute};
1431
+ module.exports = {
1432
+ execute,
1433
+ };
@@ -35,6 +35,7 @@ function getFragmentVariables(
35
35
  if (argumentVariables.hasOwnProperty(definition.name)) {
36
36
  return;
37
37
  }
38
+ // $FlowFixMe[cannot-spread-interface]
38
39
  variables = variables || {...argumentVariables};
39
40
  switch (definition.kind) {
40
41
  case 'LocalArgument':
@@ -51,9 +52,12 @@ function getFragmentVariables(
51
52
  * RelayStoreUtils.getStableVariableValue() that variable keys are all
52
53
  * present.
53
54
  */
55
+ // $FlowFixMe[incompatible-use]
54
56
  variables[definition.name] = undefined;
55
57
  break;
56
58
  }
59
+ // $FlowFixMe[incompatible-use]
60
+ // $FlowFixMe[cannot-write]
57
61
  variables[definition.name] = rootVariables[definition.name];
58
62
  break;
59
63
  default:
@@ -82,6 +86,7 @@ function getOperationVariables(
82
86
  const operationVariables = {};
83
87
  operation.argumentDefinitions.forEach(def => {
84
88
  let value = def.defaultValue;
89
+ // $FlowFixMe[cannot-write]
85
90
  if (variables[def.name] != null) {
86
91
  value = variables[def.name];
87
92
  }