relay-runtime 10.0.1 → 10.1.3

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 (82) hide show
  1. package/handlers/RelayDefaultHandlerProvider.js.flow +6 -0
  2. package/handlers/connection/MutationHandlers.js.flow +152 -20
  3. package/index.js +1 -1
  4. package/index.js.flow +17 -1
  5. package/lib/handlers/RelayDefaultHandlerProvider.js +9 -0
  6. package/lib/handlers/connection/MutationHandlers.js +185 -21
  7. package/lib/index.js +7 -0
  8. package/lib/mutations/RelayDeclarativeMutationConfig.js +5 -7
  9. package/lib/mutations/commitMutation.js +1 -4
  10. package/lib/mutations/validateMutation.js +28 -12
  11. package/lib/network/RelayQueryResponseCache.js +3 -7
  12. package/lib/query/GraphQLTag.js +2 -1
  13. package/lib/query/fetchQuery.js +2 -3
  14. package/lib/query/fetchQueryInternal.js +2 -3
  15. package/lib/store/DataChecker.js +85 -10
  16. package/lib/store/RelayConcreteVariables.js +2 -6
  17. package/lib/store/RelayModernEnvironment.js +81 -72
  18. package/lib/store/RelayModernFragmentSpecResolver.js +14 -7
  19. package/lib/store/RelayModernOperationDescriptor.js +6 -5
  20. package/lib/store/RelayModernQueryExecutor.js +46 -33
  21. package/lib/store/RelayModernRecord.js +3 -7
  22. package/lib/store/RelayModernStore.js +39 -137
  23. package/lib/store/RelayOperationTracker.js +7 -9
  24. package/lib/store/RelayOptimisticRecordSource.js +2 -6
  25. package/lib/store/RelayPublishQueue.js +1 -1
  26. package/lib/store/RelayReader.js +196 -33
  27. package/lib/store/RelayRecordSourceMapImpl.js +3 -5
  28. package/lib/store/RelayReferenceMarker.js +87 -5
  29. package/lib/store/RelayResponseNormalizer.js +115 -19
  30. package/lib/store/RelayStoreReactFlightUtils.js +47 -0
  31. package/lib/store/RelayStoreSubscriptions.js +162 -0
  32. package/lib/store/RelayStoreSubscriptionsUsingMapByID.js +258 -0
  33. package/lib/store/StoreInspector.js +2 -6
  34. package/lib/store/createRelayContext.js +5 -0
  35. package/lib/store/defaultRequiredFieldLogger.js +18 -0
  36. package/lib/store/normalizeRelayPayload.js +2 -6
  37. package/lib/subscription/requestSubscription.js +2 -3
  38. package/lib/util/NormalizationNode.js +1 -5
  39. package/lib/util/RelayConcreteNode.js +2 -0
  40. package/lib/util/RelayFeatureFlags.js +7 -2
  41. package/lib/util/createPayloadFor3DField.js +2 -7
  42. package/lib/util/getFragmentIdentifier.js +12 -3
  43. package/lib/util/getOperation.js +33 -0
  44. package/lib/util/isEmptyObject.js +25 -0
  45. package/lib/util/recycleNodesInto.js +4 -1
  46. package/lib/util/reportMissingRequiredFields.js +48 -0
  47. package/mutations/commitMutation.js.flow +1 -2
  48. package/mutations/validateMutation.js.flow +34 -5
  49. package/network/RelayNetworkTypes.js.flow +22 -0
  50. package/package.json +2 -2
  51. package/query/GraphQLTag.js.flow +3 -1
  52. package/query/fetchQuery.js.flow +2 -2
  53. package/query/fetchQueryInternal.js.flow +0 -5
  54. package/relay-runtime.js +2 -2
  55. package/relay-runtime.min.js +2 -2
  56. package/store/DataChecker.js.flow +68 -2
  57. package/store/RelayModernEnvironment.js.flow +107 -87
  58. package/store/RelayModernFragmentSpecResolver.js.flow +13 -1
  59. package/store/RelayModernOperationDescriptor.js.flow +5 -1
  60. package/store/RelayModernQueryExecutor.js.flow +47 -23
  61. package/store/RelayModernStore.js.flow +33 -107
  62. package/store/RelayPublishQueue.js.flow +1 -1
  63. package/store/RelayReader.js.flow +180 -15
  64. package/store/RelayReferenceMarker.js.flow +72 -5
  65. package/store/RelayResponseNormalizer.js.flow +130 -19
  66. package/store/RelayStoreReactFlightUtils.js.flow +64 -0
  67. package/store/RelayStoreSubscriptions.js.flow +168 -0
  68. package/store/RelayStoreSubscriptionsUsingMapByID.js.flow +259 -0
  69. package/store/RelayStoreTypes.js.flow +130 -37
  70. package/store/createRelayContext.js.flow +3 -0
  71. package/store/defaultRequiredFieldLogger.js.flow +23 -0
  72. package/subscription/requestSubscription.js.flow +5 -2
  73. package/util/NormalizationNode.js.flow +17 -2
  74. package/util/ReaderNode.js.flow +20 -1
  75. package/util/RelayConcreteNode.js.flow +6 -0
  76. package/util/RelayFeatureFlags.js.flow +12 -1
  77. package/util/getFragmentIdentifier.js.flow +33 -9
  78. package/util/getOperation.js.flow +40 -0
  79. package/util/getRequestIdentifier.js.flow +1 -1
  80. package/util/isEmptyObject.js.flow +25 -0
  81. package/util/recycleNodesInto.js.flow +11 -0
  82. package/util/reportMissingRequiredFields.js.flow +51 -0
@@ -18,10 +18,12 @@ const RelayFeatureFlags = require('../util/RelayFeatureFlags');
18
18
  const RelayModernRecord = require('./RelayModernRecord');
19
19
  const RelayRecordSourceMutator = require('../mutations/RelayRecordSourceMutator');
20
20
  const RelayRecordSourceProxy = require('../mutations/RelayRecordSourceProxy');
21
+ const RelayStoreReactFlightUtils = require('./RelayStoreReactFlightUtils');
21
22
  const RelayStoreUtils = require('./RelayStoreUtils');
22
23
 
23
24
  const cloneRelayHandleSourceField = require('./cloneRelayHandleSourceField');
24
25
  const cloneRelayScalarHandleSourceField = require('./cloneRelayScalarHandleSourceField');
26
+ const getOperation = require('../util/getOperation');
25
27
  const invariant = require('invariant');
26
28
 
27
29
  const {isClientID} = require('./ClientID');
@@ -30,6 +32,7 @@ const {generateTypeID} = require('./TypeID');
30
32
 
31
33
  import type {
32
34
  NormalizationField,
35
+ NormalizationFlightField,
33
36
  NormalizationLinkedField,
34
37
  NormalizationModuleImport,
35
38
  NormalizationNode,
@@ -43,6 +46,7 @@ import type {
43
46
  MutableRecordSource,
44
47
  NormalizationSelector,
45
48
  OperationLoader,
49
+ ReactFlightReachableQuery,
46
50
  Record,
47
51
  RecordSource,
48
52
  } from './RelayStoreTypes';
@@ -56,6 +60,7 @@ const {
56
60
  CONDITION,
57
61
  CLIENT_EXTENSION,
58
62
  DEFER,
63
+ FLIGHT_FIELD,
59
64
  FRAGMENT_SPREAD,
60
65
  INLINE_FRAGMENT,
61
66
  LINKED_FIELD,
@@ -67,6 +72,7 @@ const {
67
72
  TYPE_DISCRIMINATOR,
68
73
  } = RelayConcreteNode;
69
74
  const {
75
+ ROOT_ID,
70
76
  getModuleOperationKey,
71
77
  getStorageKey,
72
78
  getArgumentValues,
@@ -375,6 +381,7 @@ class DataChecker {
375
381
  case STREAM:
376
382
  this._traverseSelections(selection.selections, dataID);
377
383
  break;
384
+ // $FlowFixMe[incompatible-type]
378
385
  case FRAGMENT_SPREAD:
379
386
  invariant(
380
387
  false,
@@ -409,6 +416,13 @@ class DataChecker {
409
416
  } // else: if it does or doesn't implement, we don't need to check or skip anything else
410
417
  }
411
418
  break;
419
+ case FLIGHT_FIELD:
420
+ if (RelayFeatureFlags.ENABLE_REACT_FLIGHT_COMPONENT_FIELD) {
421
+ this._checkFlightField(selection, dataID);
422
+ } else {
423
+ throw new Error('Flight fields are not yet supported.');
424
+ }
425
+ break;
412
426
  default:
413
427
  (selection: empty);
414
428
  invariant(
@@ -437,8 +451,9 @@ class DataChecker {
437
451
  }
438
452
  return;
439
453
  }
440
- const operation = operationLoader.get(operationReference);
441
- if (operation != null) {
454
+ const normalizationRootNode = operationLoader.get(operationReference);
455
+ if (normalizationRootNode != null) {
456
+ const operation = getOperation(normalizationRootNode);
442
457
  this._traverse(operation, dataID);
443
458
  } else {
444
459
  // If the fragment is not available, we assume that the data cannot have been
@@ -495,6 +510,57 @@ class DataChecker {
495
510
  });
496
511
  }
497
512
  }
513
+
514
+ _checkFlightField(field: NormalizationFlightField, dataID: DataID): void {
515
+ const storageKey = getStorageKey(field, this._variables);
516
+ const linkedID = this._mutator.getLinkedRecordID(dataID, storageKey);
517
+
518
+ if (linkedID == null) {
519
+ if (linkedID === undefined) {
520
+ this._handleMissing();
521
+ return;
522
+ }
523
+ return;
524
+ }
525
+
526
+ const tree = this._mutator.getValue(
527
+ linkedID,
528
+ RelayStoreReactFlightUtils.REACT_FLIGHT_TREE_STORAGE_KEY,
529
+ );
530
+ const reachableQueries = this._mutator.getValue(
531
+ linkedID,
532
+ RelayStoreReactFlightUtils.REACT_FLIGHT_QUERIES_STORAGE_KEY,
533
+ );
534
+
535
+ if (tree == null || !Array.isArray(reachableQueries)) {
536
+ this._handleMissing();
537
+ return;
538
+ }
539
+
540
+ const operationLoader = this._operationLoader;
541
+ invariant(
542
+ operationLoader !== null,
543
+ 'DataChecker: Expected an operationLoader to be configured when using ' +
544
+ 'React Flight.',
545
+ );
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.
548
+ const prevVariables = this._variables;
549
+ // $FlowFixMe[incompatible-cast]
550
+ for (const query of (reachableQueries: Array<ReactFlightReachableQuery>)) {
551
+ this._variables = query.variables;
552
+ const normalizationRootNode = operationLoader.get(query.module);
553
+ if (normalizationRootNode != null) {
554
+ const operation = getOperation(normalizationRootNode);
555
+ this._traverseSelections(operation.selections, ROOT_ID);
556
+ } else {
557
+ // If the fragment is not available, we assume that the data cannot have
558
+ // been processed yet and must therefore be missing.
559
+ this._handleMissing();
560
+ }
561
+ }
562
+ this._variables = prevVariables;
563
+ }
498
564
  }
499
565
 
500
566
  module.exports = {
@@ -22,6 +22,7 @@ const RelayPublishQueue = require('./RelayPublishQueue');
22
22
  const RelayRecordSource = require('./RelayRecordSource');
23
23
 
24
24
  const defaultGetDataID = require('./defaultGetDataID');
25
+ const defaultRequiredFieldLogger = require('./defaultRequiredFieldLogger');
25
26
  const generateID = require('../util/generateID');
26
27
  const invariant = require('invariant');
27
28
 
@@ -29,7 +30,6 @@ import type {HandlerProvider} from '../handlers/RelayDefaultHandlerProvider';
29
30
  import type {
30
31
  GraphQLResponse,
31
32
  INetwork,
32
- LogRequestInfoFunction,
33
33
  PayloadData,
34
34
  UploadableMap,
35
35
  } from '../network/RelayNetworkTypes';
@@ -48,6 +48,7 @@ import type {
48
48
  IEnvironment,
49
49
  LogFunction,
50
50
  MissingFieldHandler,
51
+ RequiredFieldLogger,
51
52
  OperationAvailability,
52
53
  OperationDescriptor,
53
54
  OperationLoader,
@@ -55,6 +56,7 @@ import type {
55
56
  OptimisticResponseConfig,
56
57
  OptimisticUpdateFunction,
57
58
  PublishQueue,
59
+ ReactFlightPayloadDeserializer,
58
60
  SelectorStoreUpdater,
59
61
  SingularReaderSelector,
60
62
  Snapshot,
@@ -68,6 +70,7 @@ export type EnvironmentConfig = {|
68
70
  +treatMissingFieldsAsNull?: boolean,
69
71
  +log?: ?LogFunction,
70
72
  +operationLoader?: ?OperationLoader,
73
+ +reactFlightPayloadDeserializer?: ?ReactFlightPayloadDeserializer,
71
74
  +network: INetwork,
72
75
  +scheduler?: ?TaskScheduler,
73
76
  +store: Store,
@@ -82,12 +85,14 @@ export type EnvironmentConfig = {|
82
85
  +UNSTABLE_defaultRenderPolicy?: ?RenderPolicy,
83
86
  +options?: mixed,
84
87
  +isServer?: boolean,
88
+ +requiredFieldLogger?: ?RequiredFieldLogger,
85
89
  |};
86
90
 
87
91
  class RelayModernEnvironment implements IEnvironment {
88
92
  __log: LogFunction;
89
93
  +_defaultRenderPolicy: RenderPolicy;
90
94
  _operationLoader: ?OperationLoader;
95
+ _reactFlightPayloadDeserializer: ?ReactFlightPayloadDeserializer;
91
96
  _network: INetwork;
92
97
  _publishQueue: PublishQueue;
93
98
  _scheduler: ?TaskScheduler;
@@ -100,6 +105,7 @@ class RelayModernEnvironment implements IEnvironment {
100
105
  _operationExecutions: Map<string, ActiveState>;
101
106
  +options: mixed;
102
107
  +_isServer: boolean;
108
+ requiredFieldLogger: RequiredFieldLogger;
103
109
 
104
110
  constructor(config: EnvironmentConfig) {
105
111
  this.configName = config.configName;
@@ -108,6 +114,8 @@ class RelayModernEnvironment implements IEnvironment {
108
114
  : RelayDefaultHandlerProvider;
109
115
  this._treatMissingFieldsAsNull = config.treatMissingFieldsAsNull === true;
110
116
  const operationLoader = config.operationLoader;
117
+ const reactFlightPayloadDeserializer =
118
+ config.reactFlightPayloadDeserializer;
111
119
  if (__DEV__) {
112
120
  if (operationLoader != null) {
113
121
  invariant(
@@ -119,8 +127,18 @@ class RelayModernEnvironment implements IEnvironment {
119
127
  operationLoader,
120
128
  );
121
129
  }
130
+ if (reactFlightPayloadDeserializer != null) {
131
+ invariant(
132
+ typeof reactFlightPayloadDeserializer === 'function',
133
+ 'RelayModernEnvironment: Expected `reactFlightPayloadDeserializer` ' +
134
+ ' to be a function, got `%s`.',
135
+ reactFlightPayloadDeserializer,
136
+ );
137
+ }
122
138
  }
123
139
  this.__log = config.log ?? emptyFunction;
140
+ this.requiredFieldLogger =
141
+ config.requiredFieldLogger ?? defaultRequiredFieldLogger;
124
142
  this._defaultRenderPolicy =
125
143
  config.UNSTABLE_defaultRenderPolicy ??
126
144
  RelayFeatureFlags.ENABLE_PARTIAL_RENDERING_DEFAULT === true
@@ -128,7 +146,7 @@ class RelayModernEnvironment implements IEnvironment {
128
146
  : 'full';
129
147
  this._operationLoader = operationLoader;
130
148
  this._operationExecutions = new Map();
131
- this._network = config.network;
149
+ this._network = this.__wrapNetworkWithLogObserver(config.network);
132
150
  this._getDataID = config.UNSTABLE_DO_NOT_USE_getDataID ?? defaultGetDataID;
133
151
  this._publishQueue = new RelayPublishQueue(
134
152
  config.store,
@@ -140,7 +158,8 @@ class RelayModernEnvironment implements IEnvironment {
140
158
  this.options = config.options;
141
159
  this._isServer = config.isServer ?? false;
142
160
 
143
- (this: any).__setNet = newNet => (this._network = newNet);
161
+ (this: any).__setNet = newNet =>
162
+ (this._network = this.__wrapNetworkWithLogObserver(newNet));
144
163
 
145
164
  if (__DEV__) {
146
165
  const {inspect} = require('./StoreInspector');
@@ -162,6 +181,7 @@ class RelayModernEnvironment implements IEnvironment {
162
181
  this._missingFieldHandlers = config.missingFieldHandlers;
163
182
  this._operationTracker =
164
183
  config.operationTracker ?? new RelayOperationTracker();
184
+ this._reactFlightPayloadDeserializer = reactFlightPayloadDeserializer;
165
185
  }
166
186
 
167
187
  getStore(): Store {
@@ -226,6 +246,7 @@ class RelayModernEnvironment implements IEnvironment {
226
246
  operationLoader: this._operationLoader,
227
247
  optimisticConfig,
228
248
  publishQueue: this._publishQueue,
249
+ reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
229
250
  scheduler: this._scheduler,
230
251
  sink,
231
252
  source,
@@ -263,6 +284,7 @@ class RelayModernEnvironment implements IEnvironment {
263
284
  operationLoader: this._operationLoader,
264
285
  optimisticConfig: null,
265
286
  publishQueue: this._publishQueue,
287
+ reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
266
288
  scheduler: this._scheduler,
267
289
  sink,
268
290
  source: RelayObservable.from({
@@ -339,34 +361,25 @@ class RelayModernEnvironment implements IEnvironment {
339
361
  */
340
362
  execute({
341
363
  operation,
342
- cacheConfig,
343
364
  updater,
344
- }: {
365
+ }: {|
345
366
  operation: OperationDescriptor,
346
- cacheConfig?: ?CacheConfig,
347
367
  updater?: ?SelectorStoreUpdater,
348
- ...
349
- }): RelayObservable<GraphQLResponse> {
350
- const [logObserver, logRequestInfo] = this.__createLogObserver(
351
- operation.request.node.params,
352
- operation.request.variables,
353
- );
368
+ |}): RelayObservable<GraphQLResponse> {
354
369
  return RelayObservable.create(sink => {
355
- const source = this._network
356
- .execute(
357
- operation.request.node.params,
358
- operation.request.variables,
359
- cacheConfig || {},
360
- null,
361
- logRequestInfo,
362
- )
363
- .do(logObserver);
370
+ const source = this._network.execute(
371
+ operation.request.node.params,
372
+ operation.request.variables,
373
+ operation.request.cacheConfig || {},
374
+ null,
375
+ );
364
376
  const executor = RelayModernQueryExecutor.execute({
365
377
  operation,
366
378
  operationExecutions: this._operationExecutions,
367
379
  operationLoader: this._operationLoader,
368
380
  optimisticConfig: null,
369
381
  publishQueue: this._publishQueue,
382
+ reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
370
383
  scheduler: this._scheduler,
371
384
  sink,
372
385
  source,
@@ -391,24 +404,18 @@ class RelayModernEnvironment implements IEnvironment {
391
404
  * environment.executeMutation({...}).subscribe({...}).
392
405
  */
393
406
  executeMutation({
394
- cacheConfig,
395
407
  operation,
396
408
  optimisticResponse,
397
409
  optimisticUpdater,
398
410
  updater,
399
411
  uploadables,
400
412
  }: {|
401
- cacheConfig?: ?CacheConfig,
402
413
  operation: OperationDescriptor,
403
414
  optimisticUpdater?: ?SelectorStoreUpdater,
404
415
  optimisticResponse?: ?Object,
405
416
  updater?: ?SelectorStoreUpdater,
406
417
  uploadables?: ?UploadableMap,
407
418
  |}): RelayObservable<GraphQLResponse> {
408
- const [logObserver, logRequestInfo] = this.__createLogObserver(
409
- operation.request.node.params,
410
- operation.request.variables,
411
- );
412
419
  return RelayObservable.create(sink => {
413
420
  let optimisticConfig;
414
421
  if (optimisticResponse || optimisticUpdater) {
@@ -418,24 +425,22 @@ class RelayModernEnvironment implements IEnvironment {
418
425
  updater: optimisticUpdater,
419
426
  };
420
427
  }
421
- const source = this._network
422
- .execute(
423
- operation.request.node.params,
424
- operation.request.variables,
425
- {
426
- ...cacheConfig,
427
- force: true,
428
- },
429
- uploadables,
430
- logRequestInfo,
431
- )
432
- .do(logObserver);
428
+ const source = this._network.execute(
429
+ operation.request.node.params,
430
+ operation.request.variables,
431
+ {
432
+ ...operation.request.cacheConfig,
433
+ force: true,
434
+ },
435
+ uploadables,
436
+ );
433
437
  const executor = RelayModernQueryExecutor.execute({
434
438
  operation,
435
439
  operationExecutions: this._operationExecutions,
436
440
  operationLoader: this._operationLoader,
437
441
  optimisticConfig,
438
442
  publishQueue: this._publishQueue,
443
+ reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
439
444
  scheduler: this._scheduler,
440
445
  sink,
441
446
  source,
@@ -473,6 +478,7 @@ class RelayModernEnvironment implements IEnvironment {
473
478
  operationTracker: this._operationTracker,
474
479
  optimisticConfig: null,
475
480
  publishQueue: this._publishQueue,
481
+ reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
476
482
  scheduler: this._scheduler,
477
483
  sink,
478
484
  source,
@@ -488,56 +494,70 @@ class RelayModernEnvironment implements IEnvironment {
488
494
  return `RelayModernEnvironment(${this.configName ?? ''})`;
489
495
  }
490
496
 
491
- __createLogObserver(
492
- params: RequestParameters,
493
- variables: Variables,
494
- ): [Observer<GraphQLResponse>, LogRequestInfoFunction] {
495
- const transactionID = generateID();
496
- const log = this.__log;
497
- const logObserver = {
498
- start: subscription => {
499
- log({
500
- name: 'execute.start',
501
- transactionID,
502
- params,
503
- variables,
504
- });
505
- },
506
- next: response => {
507
- log({
508
- name: 'execute.next',
509
- transactionID,
510
- response,
511
- });
512
- },
513
- error: error => {
514
- log({
515
- name: 'execute.error',
516
- transactionID,
517
- error,
518
- });
519
- },
520
- complete: () => {
521
- log({
522
- name: 'execute.complete',
523
- transactionID,
524
- });
525
- },
526
- unsubscribe: () => {
527
- log({
528
- name: 'execute.unsubscribe',
529
- transactionID,
530
- });
497
+ /**
498
+ * Wraps the network with logging to ensure that network requests are
499
+ * always logged. Relying on each network callsite to be wrapped is
500
+ * untenable and will eventually lead to holes in the logging.
501
+ */
502
+ __wrapNetworkWithLogObserver(network: INetwork): INetwork {
503
+ const that = this;
504
+ return {
505
+ execute(
506
+ params: RequestParameters,
507
+ variables: Variables,
508
+ cacheConfig: CacheConfig,
509
+ uploadables?: ?UploadableMap,
510
+ ): RelayObservable<GraphQLResponse> {
511
+ const transactionID = generateID();
512
+ const log = that.__log;
513
+ const logObserver = {
514
+ start: subscription => {
515
+ log({
516
+ name: 'network.start',
517
+ transactionID,
518
+ params,
519
+ variables,
520
+ });
521
+ },
522
+ next: response => {
523
+ log({
524
+ name: 'network.next',
525
+ transactionID,
526
+ response,
527
+ });
528
+ },
529
+ error: error => {
530
+ log({
531
+ name: 'network.error',
532
+ transactionID,
533
+ error,
534
+ });
535
+ },
536
+ complete: () => {
537
+ log({
538
+ name: 'network.complete',
539
+ transactionID,
540
+ });
541
+ },
542
+ unsubscribe: () => {
543
+ log({
544
+ name: 'network.unsubscribe',
545
+ transactionID,
546
+ });
547
+ },
548
+ };
549
+ const logRequestInfo = info => {
550
+ log({
551
+ name: 'network.info',
552
+ transactionID,
553
+ info,
554
+ });
555
+ };
556
+ return network
557
+ .execute(params, variables, cacheConfig, uploadables, logRequestInfo)
558
+ .do(logObserver);
531
559
  },
532
560
  };
533
- const logRequestInfo = info => {
534
- log({
535
- name: 'execute.info',
536
- transactionID,
537
- info,
538
- });
539
- };
540
- return [logObserver, logRequestInfo];
541
561
  }
542
562
  }
543
563
 
@@ -17,6 +17,7 @@ const RelayFeatureFlags = require('../util/RelayFeatureFlags');
17
17
  const areEqual = require('areEqual');
18
18
  const invariant = require('invariant');
19
19
  const isScalarAndEqual = require('../util/isScalarAndEqual');
20
+ const reportMissingRequiredFields = require('../util/reportMissingRequiredFields');
20
21
  const warning = require('warning');
21
22
 
22
23
  const {getPromiseForActiveRequest} = require('../query/fetchQueryInternal');
@@ -34,6 +35,7 @@ import type {
34
35
  FragmentMap,
35
36
  FragmentSpecResolver,
36
37
  FragmentSpecResults,
38
+ MissingRequiredFields,
37
39
  PluralReaderSelector,
38
40
  RelayContext,
39
41
  SelectorData,
@@ -216,6 +218,7 @@ class SelectorResolver {
216
218
  _data: ?SelectorData;
217
219
  _environment: IEnvironment;
218
220
  _isMissingData: boolean;
221
+ _missingRequiredFields: ?MissingRequiredFields;
219
222
  _selector: SingularReaderSelector;
220
223
  _subscription: ?Disposable;
221
224
 
@@ -228,6 +231,7 @@ class SelectorResolver {
228
231
  this._callback = callback;
229
232
  this._data = snapshot.data;
230
233
  this._isMissingData = snapshot.isMissingData;
234
+ this._missingRequiredFields = snapshot.missingRequiredFields;
231
235
  this._environment = environment;
232
236
  this._selector = selector;
233
237
  this._subscription = environment.subscribe(snapshot, this._onChange);
@@ -282,6 +286,12 @@ class SelectorResolver {
282
286
  throw promise;
283
287
  }
284
288
  }
289
+ if (this._missingRequiredFields != null) {
290
+ reportMissingRequiredFields(
291
+ this._environment,
292
+ this._missingRequiredFields,
293
+ );
294
+ }
285
295
  return this._data;
286
296
  }
287
297
 
@@ -296,6 +306,7 @@ class SelectorResolver {
296
306
  const snapshot = this._environment.lookup(selector);
297
307
  this._data = snapshot.data;
298
308
  this._isMissingData = snapshot.isMissingData;
309
+ this._missingRequiredFields = snapshot.missingRequiredFields;
299
310
  this._selector = selector;
300
311
  this._subscription = this._environment.subscribe(snapshot, this._onChange);
301
312
  }
@@ -314,7 +325,7 @@ class SelectorResolver {
314
325
  // NOTE: We manually create the request descriptor here instead of
315
326
  // calling createOperationDescriptor() because we want to set a
316
327
  // descriptor with *unaltered* variables as the fragment owner.
317
- // This is a hack that allows us to preserve exisiting (broken)
328
+ // This is a hack that allows us to preserve existing (broken)
318
329
  // behavior of RelayModern containers while using fragment ownership
319
330
  // to propagate variables instead of Context.
320
331
  // For more details, see the summary of D13999308
@@ -331,6 +342,7 @@ class SelectorResolver {
331
342
  _onChange = (snapshot: Snapshot): void => {
332
343
  this._data = snapshot.data;
333
344
  this._isMissingData = snapshot.isMissingData;
345
+ this._missingRequiredFields = snapshot.missingRequiredFields;
334
346
  this._callback();
335
347
  };
336
348
  }
@@ -23,7 +23,7 @@ const {
23
23
  const {ROOT_ID} = require('./RelayStoreUtils');
24
24
 
25
25
  import type {ConcreteRequest} from '../util/RelayConcreteNode';
26
- import type {DataID, Variables} from '../util/RelayRuntimeTypes';
26
+ import type {CacheConfig, DataID, Variables} from '../util/RelayRuntimeTypes';
27
27
  import type {OperationDescriptor, RequestDescriptor} from './RelayStoreTypes';
28
28
 
29
29
  /**
@@ -35,6 +35,7 @@ import type {OperationDescriptor, RequestDescriptor} from './RelayStoreTypes';
35
35
  function createOperationDescriptor(
36
36
  request: ConcreteRequest,
37
37
  variables: Variables,
38
+ cacheConfig?: ?CacheConfig,
38
39
  dataID?: DataID = ROOT_ID,
39
40
  ): OperationDescriptor {
40
41
  const operation = request.operation;
@@ -42,6 +43,7 @@ function createOperationDescriptor(
42
43
  const requestDescriptor = createRequestDescriptor(
43
44
  request,
44
45
  operationVariables,
46
+ cacheConfig,
45
47
  );
46
48
  const operationDescriptor = {
47
49
  fragment: createReaderSelector(
@@ -68,11 +70,13 @@ function createOperationDescriptor(
68
70
  function createRequestDescriptor(
69
71
  request: ConcreteRequest,
70
72
  variables: Variables,
73
+ cacheConfig?: ?CacheConfig,
71
74
  ): RequestDescriptor {
72
75
  const requestDescriptor = {
73
76
  identifier: getRequestIdentifier(request.params, variables),
74
77
  node: request,
75
78
  variables: variables,
79
+ cacheConfig: cacheConfig,
76
80
  };
77
81
  if (__DEV__) {
78
82
  deepFreeze(variables);