relay-runtime 11.0.1 → 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 (71) hide show
  1. package/index.js +1 -1
  2. package/index.js.flow +4 -2
  3. package/lib/handlers/RelayDefaultHandlerProvider.js +1 -1
  4. package/lib/handlers/connection/ConnectionHandler.js +1 -1
  5. package/lib/handlers/connection/MutationHandlers.js +1 -1
  6. package/lib/multi-actor-environment/ActorIdentifier.js +23 -0
  7. package/lib/multi-actor-environment/ActorSpecificEnvironment.js +108 -0
  8. package/lib/multi-actor-environment/MultiActorEnvironment.js +156 -0
  9. package/lib/multi-actor-environment/MultiActorEnvironmentTypes.js +11 -0
  10. package/lib/multi-actor-environment/index.js +17 -0
  11. package/lib/mutations/RelayRecordProxy.js +1 -1
  12. package/lib/mutations/RelayRecordSourceMutator.js +1 -1
  13. package/lib/mutations/RelayRecordSourceProxy.js +1 -1
  14. package/lib/mutations/RelayRecordSourceSelectorProxy.js +1 -1
  15. package/lib/mutations/applyOptimisticMutation.js +1 -1
  16. package/lib/mutations/commitMutation.js +1 -1
  17. package/lib/network/RelayNetwork.js +1 -1
  18. package/lib/network/RelayQueryResponseCache.js +1 -1
  19. package/lib/query/GraphQLTag.js +1 -1
  20. package/lib/query/fetchQuery.js +1 -1
  21. package/lib/query/fetchQueryInternal.js +1 -1
  22. package/lib/store/DataChecker.js +1 -1
  23. package/lib/store/{RelayModernQueryExecutor.js → OperationExecutor.js} +81 -37
  24. package/lib/store/RelayConcreteVariables.js +1 -1
  25. package/lib/store/RelayModernEnvironment.js +99 -144
  26. package/lib/store/RelayModernFragmentSpecResolver.js +1 -1
  27. package/lib/store/RelayModernRecord.js +1 -1
  28. package/lib/store/RelayModernSelector.js +1 -1
  29. package/lib/store/RelayModernStore.js +1 -6
  30. package/lib/store/RelayOperationTracker.js +1 -1
  31. package/lib/store/RelayPublishQueue.js +9 -5
  32. package/lib/store/RelayReader.js +63 -10
  33. package/lib/store/RelayReferenceMarker.js +1 -1
  34. package/lib/store/RelayResponseNormalizer.js +47 -22
  35. package/lib/store/RelayStoreReactFlightUtils.js +1 -1
  36. package/lib/store/RelayStoreUtils.js +1 -1
  37. package/lib/store/ResolverFragments.js +57 -0
  38. package/lib/store/cloneRelayHandleSourceField.js +1 -1
  39. package/lib/store/cloneRelayScalarHandleSourceField.js +1 -1
  40. package/lib/store/createRelayContext.js +1 -1
  41. package/lib/store/readInlineData.js +1 -1
  42. package/lib/subscription/requestSubscription.js +18 -7
  43. package/lib/util/RelayConcreteNode.js +1 -0
  44. package/lib/util/RelayFeatureFlags.js +3 -1
  45. package/lib/util/RelayProfiler.js +17 -187
  46. package/lib/util/RelayReplaySubject.js +1 -1
  47. package/lib/util/getRelayHandleKey.js +1 -1
  48. package/lib/util/getRequestIdentifier.js +1 -1
  49. package/multi-actor-environment/ActorIdentifier.js.flow +27 -0
  50. package/multi-actor-environment/ActorSpecificEnvironment.js.flow +189 -0
  51. package/multi-actor-environment/MultiActorEnvironment.js.flow +233 -0
  52. package/multi-actor-environment/MultiActorEnvironmentTypes.js.flow +196 -0
  53. package/multi-actor-environment/index.js.flow +24 -0
  54. package/network/RelayNetworkTypes.js.flow +5 -4
  55. package/package.json +3 -2
  56. package/relay-runtime.js +2 -2
  57. package/relay-runtime.min.js +2 -2
  58. package/store/{RelayModernQueryExecutor.js.flow → OperationExecutor.js.flow} +82 -35
  59. package/store/RelayModernEnvironment.js.flow +88 -131
  60. package/store/RelayModernStore.js.flow +0 -5
  61. package/store/RelayPublishQueue.js.flow +7 -4
  62. package/store/RelayReader.js.flow +57 -5
  63. package/store/RelayResponseNormalizer.js.flow +67 -26
  64. package/store/RelayStoreTypes.js.flow +15 -8
  65. package/store/ResolverFragments.js.flow +125 -0
  66. package/subscription/requestSubscription.js.flow +15 -7
  67. package/util/ReaderNode.js.flow +14 -1
  68. package/util/RelayConcreteNode.js.flow +1 -0
  69. package/util/RelayFeatureFlags.js.flow +4 -0
  70. package/util/RelayProfiler.js.flow +22 -194
  71. package/util/RelayRuntimeTypes.js.flow +3 -1
@@ -28,6 +28,7 @@ const {
28
28
  LINKED_FIELD,
29
29
  MODULE_IMPORT,
30
30
  REQUIRED_FIELD,
31
+ RELAY_RESOLVER,
31
32
  SCALAR_FIELD,
32
33
  STREAM,
33
34
  } = require('../util/RelayConcreteNode');
@@ -44,15 +45,18 @@ const {
44
45
  getStorageKey,
45
46
  getModuleComponentKey,
46
47
  } = require('./RelayStoreUtils');
48
+ const {withResolverContext} = require('./ResolverFragments');
47
49
  const {generateTypeID} = require('./TypeID');
48
50
 
49
51
  import type {
50
52
  ReaderFlightField,
53
+ ReaderFragment,
51
54
  ReaderFragmentSpread,
52
55
  ReaderInlineDataFragmentSpread,
53
56
  ReaderLinkedField,
54
57
  ReaderModuleImport,
55
58
  ReaderNode,
59
+ ReaderRelayResolver,
56
60
  ReaderRequiredField,
57
61
  ReaderScalarField,
58
62
  ReaderSelection,
@@ -327,6 +331,13 @@ class RelayReader {
327
331
  }
328
332
  break;
329
333
  }
334
+ case RELAY_RESOLVER: {
335
+ if (!RelayFeatureFlags.ENABLE_RELAY_RESOLVERS) {
336
+ throw new Error('Relay Resolver fields are not yet supported.');
337
+ }
338
+ this._readResolverField(selection, record, data);
339
+ break;
340
+ }
330
341
  case FRAGMENT_SPREAD:
331
342
  this._createFragmentPointer(selection, record, data);
332
343
  break;
@@ -334,7 +345,11 @@ class RelayReader {
334
345
  this._readModuleImport(selection, record, data);
335
346
  break;
336
347
  case INLINE_DATA_FRAGMENT_SPREAD:
337
- this._createInlineDataFragmentPointer(selection, record, data);
348
+ this._createInlineDataOrResolverFragmentPointer(
349
+ selection,
350
+ record,
351
+ data,
352
+ );
338
353
  break;
339
354
  case DEFER:
340
355
  case CLIENT_EXTENSION: {
@@ -404,6 +419,43 @@ class RelayReader {
404
419
  }
405
420
  }
406
421
 
422
+ _readResolverField(
423
+ selection: ReaderRelayResolver,
424
+ record: Record,
425
+ data: SelectorData,
426
+ ): ?mixed {
427
+ const {name, alias, resolverModule, fragment} = selection;
428
+ const key = {
429
+ __id: RelayModernRecord.getDataID(record),
430
+ __fragmentOwner: this._owner,
431
+ __fragments: {
432
+ [fragment.name]: {}, // Arguments to this fragment; not yet supported.
433
+ },
434
+ };
435
+ const resolverContext = {
436
+ getDataForResolverFragment: singularReaderSelector => {
437
+ const resolverFragmentData = {};
438
+ this._createInlineDataOrResolverFragmentPointer(
439
+ singularReaderSelector.node,
440
+ record,
441
+ resolverFragmentData,
442
+ );
443
+ const answer = resolverFragmentData[FRAGMENTS_KEY]?.[fragment.name];
444
+ invariant(
445
+ typeof answer === 'object' && answer !== null,
446
+ `Expected reader data to contain a __fragments property with a property for the fragment named ${fragment.name}, but it is missing.`,
447
+ );
448
+ return answer;
449
+ },
450
+ };
451
+ const resolverResult = withResolverContext(resolverContext, () =>
452
+ // $FlowFixMe[prop-missing] - resolver module's type signature is a lie
453
+ resolverModule(key),
454
+ );
455
+ data[alias ?? name] = resolverResult;
456
+ return resolverResult;
457
+ }
458
+
407
459
  _readFlightField(
408
460
  field: ReaderFlightField,
409
461
  record: Record,
@@ -607,8 +659,8 @@ class RelayReader {
607
659
  }
608
660
  }
609
661
 
610
- _createInlineDataFragmentPointer(
611
- inlineDataFragmentSpread: ReaderInlineDataFragmentSpread,
662
+ _createInlineDataOrResolverFragmentPointer(
663
+ fragmentSpreadOrFragment: ReaderInlineDataFragmentSpread | ReaderFragment,
612
664
  record: Record,
613
665
  data: SelectorData,
614
666
  ): void {
@@ -626,12 +678,12 @@ class RelayReader {
626
678
  }
627
679
  const inlineData = {};
628
680
  this._traverseSelections(
629
- inlineDataFragmentSpread.selections,
681
+ fragmentSpreadOrFragment.selections,
630
682
  record,
631
683
  inlineData,
632
684
  );
633
685
  // $FlowFixMe[cannot-write] - writing into read-only field
634
- fragmentPointers[inlineDataFragmentSpread.name] = inlineData;
686
+ fragmentPointers[fragmentSpreadOrFragment.name] = inlineData;
635
687
  }
636
688
  }
637
689
 
@@ -14,7 +14,6 @@
14
14
 
15
15
  const RelayFeatureFlags = require('../util/RelayFeatureFlags');
16
16
  const RelayModernRecord = require('./RelayModernRecord');
17
- const RelayProfiler = require('../util/RelayProfiler');
18
17
 
19
18
  const areEqual = require('areEqual');
20
19
  const invariant = require('invariant');
@@ -535,11 +534,40 @@ class RelayResponseNormalizer {
535
534
  const fieldValue = data[responseKey];
536
535
 
537
536
  if (fieldValue == null) {
537
+ if (fieldValue === undefined) {
538
+ // Flight field may be missing in the response if:
539
+ // - It is inside an abstract type refinement where the concrete type does
540
+ // not conform to the interface/union.
541
+ // However an otherwise-required field may also be missing if the server
542
+ // is configured to skip fields with `null` values, in which case the
543
+ // client is assumed to be correctly configured with
544
+ // treatMissingFieldsAsNull=true.
545
+ if (this._isUnmatchedAbstractType) {
546
+ // Field not expected to exist regardless of whether the server is pruning null
547
+ // fields or not.
548
+ return;
549
+ } else if (!this._treatMissingFieldsAsNull) {
550
+ // Not optional and the server is not pruning null fields: field is expected
551
+ // to be present
552
+ if (__DEV__) {
553
+ warning(
554
+ false,
555
+ 'RelayResponseNormalizer: Payload did not contain a value ' +
556
+ 'for field `%s: %s`. Check that you are parsing with the same ' +
557
+ 'query that was used to fetch the payload.',
558
+ responseKey,
559
+ storageKey,
560
+ );
561
+ }
562
+ return;
563
+ }
564
+ }
538
565
  RelayModernRecord.setValue(record, storageKey, null);
539
566
  return;
540
567
  }
541
568
 
542
569
  const reactFlightPayload = refineToReactFlightPayloadData(fieldValue);
570
+ const reactFlightPayloadDeserializer = this._reactFlightPayloadDeserializer;
543
571
 
544
572
  invariant(
545
573
  reactFlightPayload != null,
@@ -549,10 +577,10 @@ class RelayResponseNormalizer {
549
577
  fieldValue,
550
578
  );
551
579
  invariant(
552
- typeof this._reactFlightPayloadDeserializer === 'function',
580
+ typeof reactFlightPayloadDeserializer === 'function',
553
581
  'RelayResponseNormalizer: Expected reactFlightPayloadDeserializer to ' +
554
582
  'be a function, got `%s`.',
555
- this._reactFlightPayloadDeserializer,
583
+ reactFlightPayloadDeserializer,
556
584
  );
557
585
 
558
586
  if (reactFlightPayload.errors.length > 0) {
@@ -573,44 +601,60 @@ class RelayResponseNormalizer {
573
601
  }
574
602
  }
575
603
 
576
- // This typically indicates that a fatal server error prevented rows from
577
- // being written. When this occurs, we should not continue normalization of
578
- // the Flight field because the row response is malformed.
579
- //
580
- // Receiving empty rows is OK because it can indicate the start of a stream.
604
+ const reactFlightID = generateClientID(
605
+ RelayModernRecord.getDataID(record),
606
+ getStorageKey(selection, this._variables),
607
+ );
608
+ let reactFlightClientResponseRecord = this._recordSource.get(reactFlightID);
609
+ if (reactFlightClientResponseRecord == null) {
610
+ reactFlightClientResponseRecord = RelayModernRecord.create(
611
+ reactFlightID,
612
+ REACT_FLIGHT_TYPE_NAME,
613
+ );
614
+ this._recordSource.set(reactFlightID, reactFlightClientResponseRecord);
615
+ }
616
+
581
617
  if (reactFlightPayload.tree == null) {
618
+ // This typically indicates that a fatal server error prevented rows from
619
+ // being written. When this occurs, we should not continue normalization of
620
+ // the Flight field because the row response is malformed.
621
+ //
622
+ // Receiving empty rows is OK because it can indicate the start of a stream.
582
623
  warning(
583
624
  false,
584
625
  'RelayResponseNormalizer: Expected `tree` not to be null. This ' +
585
626
  'typically indicates that a fatal server error prevented any Server ' +
586
627
  'Component rows from being written.',
587
628
  );
629
+ // We create the flight record with a null value for the tree
630
+ // and empty reachable definitions
631
+ RelayModernRecord.setValue(
632
+ reactFlightClientResponseRecord,
633
+ REACT_FLIGHT_TREE_STORAGE_KEY,
634
+ null,
635
+ );
636
+ RelayModernRecord.setValue(
637
+ reactFlightClientResponseRecord,
638
+ REACT_FLIGHT_EXECUTABLE_DEFINITIONS_STORAGE_KEY,
639
+ [],
640
+ );
641
+ RelayModernRecord.setLinkedRecordID(record, storageKey, reactFlightID);
588
642
  return;
589
643
  }
590
644
 
591
645
  // We store the deserialized reactFlightClientResponse in a separate
592
646
  // record and link it to the parent record. This is so we can GC the Flight
593
647
  // tree later even if the parent record is still reachable.
594
- const reactFlightClientResponse = this._reactFlightPayloadDeserializer(
648
+ const reactFlightClientResponse = reactFlightPayloadDeserializer(
595
649
  reactFlightPayload.tree,
596
650
  );
597
- const reactFlightID = generateClientID(
598
- RelayModernRecord.getDataID(record),
599
- getStorageKey(selection, this._variables),
600
- );
601
- let reactFlightClientResponseRecord = this._recordSource.get(reactFlightID);
602
- if (reactFlightClientResponseRecord == null) {
603
- reactFlightClientResponseRecord = RelayModernRecord.create(
604
- reactFlightID,
605
- REACT_FLIGHT_TYPE_NAME,
606
- );
607
- this._recordSource.set(reactFlightID, reactFlightClientResponseRecord);
608
- }
651
+
609
652
  RelayModernRecord.setValue(
610
653
  reactFlightClientResponseRecord,
611
654
  REACT_FLIGHT_TREE_STORAGE_KEY,
612
655
  reactFlightClientResponse,
613
656
  );
657
+
614
658
  const reachableExecutableDefinitions: Array<ReactFlightReachableExecutableDefinitions> = [];
615
659
  for (const query of reactFlightPayload.queries) {
616
660
  if (query.response.data != null) {
@@ -853,9 +897,6 @@ class RelayResponseNormalizer {
853
897
  }
854
898
  }
855
899
 
856
- const instrumentedNormalize: typeof normalize = RelayProfiler.instrument(
857
- 'RelayResponseNormalizer.normalize',
900
+ module.exports = {
858
901
  normalize,
859
- );
860
-
861
- module.exports = {normalize: instrumentedNormalize};
902
+ };
@@ -658,13 +658,9 @@ export interface IEnvironment {
658
658
  * the result is subscribed to:
659
659
  * environment.executeMutation({...}).subscribe({...}).
660
660
  */
661
- executeMutation({|
662
- operation: OperationDescriptor,
663
- optimisticUpdater?: ?SelectorStoreUpdater,
664
- optimisticResponse?: ?Object,
665
- updater?: ?SelectorStoreUpdater,
666
- uploadables?: ?UploadableMap,
667
- |}): RelayObservable<GraphQLResponse>;
661
+ executeMutation(
662
+ config: ExecuteMutationConfig,
663
+ ): RelayObservable<GraphQLResponse>;
668
664
 
669
665
  /**
670
666
  * Returns an Observable of GraphQLResponse resulting from executing the
@@ -936,7 +932,18 @@ export type RelayResponsePayload = {|
936
932
  |};
937
933
 
938
934
  /**
939
- * Public interface for Publish Queue
935
+ * Configuration on the executeMutation(...).
936
+ */
937
+ export type ExecuteMutationConfig = {|
938
+ operation: OperationDescriptor,
939
+ optimisticUpdater?: ?SelectorStoreUpdater,
940
+ optimisticResponse?: ?Object,
941
+ updater?: ?SelectorStoreUpdater,
942
+ uploadables?: ?UploadableMap,
943
+ |};
944
+
945
+ /**
946
+ * Public interface for Publish Queue.
940
947
  */
941
948
  export interface PublishQueue {
942
949
  /**
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow strict-local
8
+ * @format
9
+ */
10
+
11
+ // flowlint ambiguous-object-type:error
12
+
13
+ 'use strict';
14
+
15
+ const invariant = require('invariant');
16
+
17
+ const {getFragment} = require('../query/GraphQLTag');
18
+ const {getSelector} = require('./RelayModernSelector');
19
+
20
+ import type {GraphQLTaggedNode} from '../query/GraphQLTag';
21
+ import type {
22
+ FragmentReference,
23
+ SingularReaderSelector,
24
+ } from './RelayStoreTypes';
25
+
26
+ // When we call the user-supplied resolver function, it will in turn call
27
+ // `readFragment`, but that's a global function -- it needs information
28
+ // about what resolver is being executed, which is supplied by putting the
29
+ // info on this stack before we call the resolver function.
30
+ type ResolverContext = {|
31
+ getDataForResolverFragment: SingularReaderSelector => mixed,
32
+ |};
33
+ const contextStack: Array<ResolverContext> = [];
34
+
35
+ function withResolverContext<T>(context: ResolverContext, cb: () => T): T {
36
+ contextStack.push(context);
37
+ try {
38
+ return cb();
39
+ } finally {
40
+ contextStack.pop();
41
+ }
42
+ }
43
+
44
+ // NOTE: these declarations are copied from 'useFragment'; it would be good
45
+ // to figure out how to share the same type signature between the two functions.
46
+ // The declarations ensure that the type of the returned data is:
47
+ // - non-nullable if the provided ref type is non-nullable
48
+ // - nullable if the provided ref type is nullable
49
+ // - array of non-nullable if the privoided ref type is an array of
50
+ // non-nullable refs
51
+ // - array of nullable if the privoided ref type is an array of nullable refs
52
+
53
+ declare function readFragment<
54
+ TKey: {+$data?: mixed, +$fragmentRefs: FragmentReference, ...},
55
+ >(
56
+ fragmentInput: GraphQLTaggedNode,
57
+ fragmentRef: TKey,
58
+ ): $Call<<TFragmentData>({+$data?: TFragmentData, ...}) => TFragmentData, TKey>;
59
+
60
+ declare function readFragment<
61
+ TKey: ?{+$data?: mixed, +$fragmentRefs: FragmentReference, ...},
62
+ >(
63
+ fragmentInput: GraphQLTaggedNode,
64
+ fragmentRef: TKey,
65
+ ): $Call<
66
+ <TFragmentData>(?{+$data?: TFragmentData, ...}) => ?TFragmentData,
67
+ TKey,
68
+ >;
69
+
70
+ declare function readFragment<
71
+ TKey: $ReadOnlyArray<{
72
+ +$data?: mixed,
73
+ +$fragmentRefs: FragmentReference,
74
+ ...
75
+ }>,
76
+ >(
77
+ fragmentInput: GraphQLTaggedNode,
78
+ fragmentRef: TKey,
79
+ ): $Call<
80
+ <TFragmentData>(
81
+ $ReadOnlyArray<{+$data?: TFragmentData, ...}>,
82
+ ) => TFragmentData,
83
+ TKey,
84
+ >;
85
+
86
+ declare function readFragment<
87
+ TKey: ?$ReadOnlyArray<{
88
+ +$data?: mixed,
89
+ +$fragmentRefs: FragmentReference,
90
+ ...
91
+ }>,
92
+ >(
93
+ fragmentInput: GraphQLTaggedNode,
94
+ fragmentRef: TKey,
95
+ ): $Call<
96
+ <TFragmentData>(
97
+ ?$ReadOnlyArray<{+$data?: TFragmentData, ...}>,
98
+ ) => ?TFragmentData,
99
+ TKey,
100
+ >;
101
+
102
+ function readFragment(
103
+ fragmentInput: GraphQLTaggedNode,
104
+ fragmentRef: mixed,
105
+ ): mixed {
106
+ if (!contextStack.length) {
107
+ throw new Error(
108
+ 'readFragment should be called only from within a Relay Resolver function.',
109
+ );
110
+ }
111
+ const context = contextStack[contextStack.length - 1];
112
+ const fragmentNode = getFragment(fragmentInput);
113
+ const fragmentSelector = getSelector(fragmentNode, fragmentRef);
114
+ invariant(
115
+ fragmentSelector != null,
116
+ `Expected a selector for the fragment of the resolver ${fragmentNode.name}, but got null.`,
117
+ );
118
+ invariant(
119
+ fragmentSelector.kind === 'SingularReaderSelector',
120
+ `Expected a singular reader selector for the fragment of the resolver ${fragmentNode.name}, but it was plural.`,
121
+ );
122
+ return context.getDataForResolverFragment(fragmentSelector);
123
+ }
124
+
125
+ module.exports = {readFragment, withResolverContext};
@@ -22,6 +22,7 @@ const {generateUniqueClientID} = require('../store/ClientID');
22
22
  const {
23
23
  createOperationDescriptor,
24
24
  } = require('../store/RelayModernOperationDescriptor');
25
+ const {createReaderSelector} = require('../store/RelayModernSelector');
25
26
 
26
27
  import type {DeclarativeMutationConfig} from '../mutations/RelayDeclarativeMutationConfig';
27
28
  import type {GraphQLTaggedNode} from '../query/GraphQLTag';
@@ -91,17 +92,24 @@ function requestSubscription<TSubscriptionPayload>(
91
92
  updater,
92
93
  })
93
94
  .map(responses => {
95
+ let selector = operation.fragment;
94
96
  if (RelayFeatureFlags.ENABLE_UNIQUE_SUBSCRIPTION_ROOT) {
97
+ let nextID;
95
98
  if (Array.isArray(responses)) {
96
- // $FlowFixMe[incompatible-cast]
97
- return (responses.map(
98
- response => response.data,
99
- ): TSubscriptionPayload);
99
+ nextID = responses[0]?.extensions?.__relay_subscription_root_id;
100
+ } else {
101
+ nextID = responses.extensions?.__relay_subscription_root_id;
102
+ }
103
+ if (typeof nextID === 'string') {
104
+ selector = createReaderSelector(
105
+ selector.node,
106
+ nextID,
107
+ selector.variables,
108
+ selector.owner,
109
+ );
100
110
  }
101
- // $FlowFixMe[incompatible-cast]
102
- return (responses.data: TSubscriptionPayload);
103
111
  }
104
- const data = environment.lookup(operation.fragment).data;
112
+ const data = environment.lookup(selector).data;
105
113
  // $FlowFixMe[incompatible-cast]
106
114
  return (data: TSubscriptionPayload);
107
115
  })
@@ -206,6 +206,18 @@ export type ReaderRequiredField = {|
206
206
  +path: string,
207
207
  |};
208
208
 
209
+ export type ReaderRelayResolver = {|
210
+ +kind: 'RelayResolver',
211
+ +alias: ?string,
212
+ +name: string,
213
+ +fragment: ReaderFragmentSpread,
214
+ +resolverModule: (rootKey: {
215
+ +$data?: any, // flowlint-line unclear-type:off
216
+ +$fragmentRefs: any, // flowlint-line unclear-type:off
217
+ ...
218
+ }) => mixed,
219
+ |};
220
+
209
221
  export type ReaderSelection =
210
222
  | ReaderCondition
211
223
  | ReaderClientExtension
@@ -217,7 +229,8 @@ export type ReaderSelection =
217
229
  | ReaderInlineFragment
218
230
  | ReaderModuleImport
219
231
  | ReaderStream
220
- | ReaderRequiredField;
232
+ | ReaderRequiredField
233
+ | ReaderRelayResolver;
221
234
 
222
235
  export type ReaderVariableArgument = {|
223
236
  +kind: 'Variable',
@@ -84,6 +84,7 @@ const RelayConcreteNode = {
84
84
  LIST_VALUE: 'ListValue',
85
85
  LOCAL_ARGUMENT: 'LocalArgument',
86
86
  MODULE_IMPORT: 'ModuleImport',
87
+ RELAY_RESOLVER: 'RelayResolver',
87
88
  REQUIRED_FIELD: 'RequiredField',
88
89
  OBJECT_VALUE: 'ObjectValue',
89
90
  OPERATION: 'Operation',
@@ -19,6 +19,7 @@ type FeatureFlags = {|
19
19
  ENABLE_PRECISE_TYPE_REFINEMENT: boolean,
20
20
  ENABLE_REACT_FLIGHT_COMPONENT_FIELD: boolean,
21
21
  ENABLE_REQUIRED_DIRECTIVES: boolean | string,
22
+ ENABLE_RELAY_RESOLVERS: boolean,
22
23
  ENABLE_GETFRAGMENTIDENTIFIER_OPTIMIZATION: boolean,
23
24
  ENABLE_FRIENDLY_QUERY_NAME_GQL_URL: boolean,
24
25
  ENABLE_STORE_SUBSCRIPTIONS_REFACTOR: boolean,
@@ -26,6 +27,7 @@ type FeatureFlags = {|
26
27
  ENABLE_DO_NOT_WRAP_LIVE_QUERY: boolean,
27
28
  ENABLE_NOTIFY_SUBSCRIPTION: boolean,
28
29
  ENABLE_UNIQUE_SUBSCRIPTION_ROOT: boolean,
30
+ ENABLE_BATCHED_STORE_UPDATES: boolean,
29
31
  |};
30
32
 
31
33
  const RelayFeatureFlags: FeatureFlags = {
@@ -35,6 +37,7 @@ const RelayFeatureFlags: FeatureFlags = {
35
37
  ENABLE_PRECISE_TYPE_REFINEMENT: false,
36
38
  ENABLE_REACT_FLIGHT_COMPONENT_FIELD: false,
37
39
  ENABLE_REQUIRED_DIRECTIVES: false,
40
+ ENABLE_RELAY_RESOLVERS: false,
38
41
  ENABLE_GETFRAGMENTIDENTIFIER_OPTIMIZATION: false,
39
42
  ENABLE_FRIENDLY_QUERY_NAME_GQL_URL: false,
40
43
  ENABLE_STORE_SUBSCRIPTIONS_REFACTOR: false,
@@ -42,6 +45,7 @@ const RelayFeatureFlags: FeatureFlags = {
42
45
  ENABLE_DO_NOT_WRAP_LIVE_QUERY: false,
43
46
  ENABLE_NOTIFY_SUBSCRIPTION: false,
44
47
  ENABLE_UNIQUE_SUBSCRIPTION_ROOT: false,
48
+ ENABLE_BATCHED_STORE_UPDATES: false,
45
49
  };
46
50
 
47
51
  module.exports = RelayFeatureFlags;