relay-runtime 11.0.0-rc.0 → 12.0.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 (128) hide show
  1. package/handlers/connection/ConnectionHandler.js.flow +7 -0
  2. package/handlers/connection/MutationHandlers.js.flow +28 -0
  3. package/index.js +1 -1
  4. package/index.js.flow +20 -3
  5. package/lib/handlers/RelayDefaultHandlerProvider.js +1 -1
  6. package/lib/handlers/connection/ConnectionHandler.js +12 -6
  7. package/lib/handlers/connection/MutationHandlers.js +67 -8
  8. package/lib/index.js +15 -0
  9. package/lib/multi-actor-environment/ActorIdentifier.js +33 -0
  10. package/lib/multi-actor-environment/ActorSpecificEnvironment.js +148 -0
  11. package/lib/multi-actor-environment/ActorUtils.js +27 -0
  12. package/lib/multi-actor-environment/MultiActorEnvironment.js +406 -0
  13. package/lib/multi-actor-environment/MultiActorEnvironmentTypes.js +11 -0
  14. package/lib/multi-actor-environment/index.js +21 -0
  15. package/lib/mutations/RelayRecordProxy.js +1 -1
  16. package/lib/mutations/RelayRecordSourceMutator.js +1 -1
  17. package/lib/mutations/RelayRecordSourceProxy.js +1 -1
  18. package/lib/mutations/RelayRecordSourceSelectorProxy.js +7 -2
  19. package/lib/mutations/applyOptimisticMutation.js +1 -1
  20. package/lib/mutations/commitMutation.js +5 -2
  21. package/lib/mutations/validateMutation.js +39 -17
  22. package/lib/network/RelayNetwork.js +1 -1
  23. package/lib/network/RelayObservable.js +3 -1
  24. package/lib/network/RelayQueryResponseCache.js +20 -3
  25. package/lib/network/wrapNetworkWithLogObserver.js +78 -0
  26. package/lib/query/GraphQLTag.js +1 -1
  27. package/lib/query/fetchQuery.js +1 -1
  28. package/lib/query/fetchQueryInternal.js +1 -1
  29. package/lib/store/DataChecker.js +132 -50
  30. package/lib/store/{RelayModernQueryExecutor.js → OperationExecutor.js} +524 -187
  31. package/lib/store/RelayConcreteVariables.js +29 -4
  32. package/lib/store/RelayModernEnvironment.js +137 -220
  33. package/lib/store/RelayModernFragmentSpecResolver.js +49 -23
  34. package/lib/store/RelayModernRecord.js +36 -2
  35. package/lib/store/RelayModernSelector.js +1 -1
  36. package/lib/store/RelayModernStore.js +53 -22
  37. package/lib/store/RelayOperationTracker.js +34 -24
  38. package/lib/store/RelayPublishQueue.js +30 -8
  39. package/lib/store/RelayReader.js +177 -29
  40. package/lib/store/RelayRecordSource.js +87 -3
  41. package/lib/store/RelayReferenceMarker.js +53 -28
  42. package/lib/store/RelayResponseNormalizer.js +247 -108
  43. package/lib/store/RelayStoreReactFlightUtils.js +7 -11
  44. package/lib/store/RelayStoreSubscriptions.js +8 -5
  45. package/lib/store/RelayStoreUtils.js +10 -4
  46. package/lib/store/ResolverCache.js +213 -0
  47. package/lib/store/ResolverFragments.js +57 -0
  48. package/lib/store/cloneRelayHandleSourceField.js +1 -1
  49. package/lib/store/cloneRelayScalarHandleSourceField.js +1 -1
  50. package/lib/store/createRelayContext.js +2 -2
  51. package/lib/store/defaultGetDataID.js +3 -1
  52. package/lib/store/readInlineData.js +1 -1
  53. package/lib/subscription/requestSubscription.js +32 -6
  54. package/lib/util/RelayConcreteNode.js +3 -0
  55. package/lib/util/RelayFeatureFlags.js +5 -4
  56. package/lib/util/RelayProfiler.js +17 -187
  57. package/lib/util/RelayReplaySubject.js +22 -7
  58. package/lib/util/deepFreeze.js +1 -0
  59. package/lib/util/getPaginationMetadata.js +41 -0
  60. package/lib/util/getPaginationVariables.js +67 -0
  61. package/lib/util/getPendingOperationsForFragment.js +55 -0
  62. package/lib/util/getRefetchMetadata.js +36 -0
  63. package/lib/util/getRelayHandleKey.js +1 -1
  64. package/lib/util/getRequestIdentifier.js +1 -1
  65. package/lib/util/getValueAtPath.js +51 -0
  66. package/lib/util/isEmptyObject.js +1 -1
  67. package/lib/util/registerEnvironmentWithDevTools.js +26 -0
  68. package/lib/util/withDuration.js +31 -0
  69. package/multi-actor-environment/ActorIdentifier.js.flow +43 -0
  70. package/multi-actor-environment/ActorSpecificEnvironment.js.flow +217 -0
  71. package/multi-actor-environment/ActorUtils.js.flow +33 -0
  72. package/multi-actor-environment/MultiActorEnvironment.js.flow +485 -0
  73. package/multi-actor-environment/MultiActorEnvironmentTypes.js.flow +245 -0
  74. package/multi-actor-environment/index.js.flow +27 -0
  75. package/mutations/RelayRecordSourceSelectorProxy.js.flow +7 -2
  76. package/mutations/commitMutation.js.flow +3 -1
  77. package/mutations/validateMutation.js.flow +42 -16
  78. package/network/RelayNetworkTypes.js.flow +17 -8
  79. package/network/RelayObservable.js.flow +2 -0
  80. package/network/RelayQueryResponseCache.js.flow +31 -17
  81. package/network/wrapNetworkWithLogObserver.js.flow +99 -0
  82. package/package.json +3 -2
  83. package/relay-runtime.js +2 -2
  84. package/relay-runtime.min.js +2 -2
  85. package/store/ClientID.js.flow +5 -1
  86. package/store/DataChecker.js.flow +148 -44
  87. package/store/{RelayModernQueryExecutor.js.flow → OperationExecutor.js.flow} +578 -237
  88. package/store/RelayConcreteVariables.js.flow +31 -1
  89. package/store/RelayModernEnvironment.js.flow +132 -220
  90. package/store/RelayModernFragmentSpecResolver.js.flow +40 -14
  91. package/store/RelayModernOperationDescriptor.js.flow +9 -3
  92. package/store/RelayModernRecord.js.flow +49 -0
  93. package/store/RelayModernStore.js.flow +57 -17
  94. package/store/RelayOperationTracker.js.flow +56 -34
  95. package/store/RelayPublishQueue.js.flow +37 -11
  96. package/store/RelayReader.js.flow +186 -27
  97. package/store/RelayRecordSource.js.flow +72 -6
  98. package/store/RelayReferenceMarker.js.flow +51 -21
  99. package/store/RelayResponseNormalizer.js.flow +251 -67
  100. package/store/RelayStoreReactFlightUtils.js.flow +6 -9
  101. package/store/RelayStoreSubscriptions.js.flow +10 -3
  102. package/store/RelayStoreTypes.js.flow +144 -21
  103. package/store/RelayStoreUtils.js.flow +19 -4
  104. package/store/ResolverCache.js.flow +247 -0
  105. package/store/ResolverFragments.js.flow +128 -0
  106. package/store/createRelayContext.js.flow +1 -1
  107. package/store/defaultGetDataID.js.flow +3 -1
  108. package/subscription/requestSubscription.js.flow +43 -8
  109. package/util/NormalizationNode.js.flow +16 -3
  110. package/util/ReaderNode.js.flow +29 -2
  111. package/util/RelayConcreteNode.js.flow +3 -0
  112. package/util/RelayFeatureFlags.js.flow +10 -6
  113. package/util/RelayProfiler.js.flow +22 -194
  114. package/util/RelayReplaySubject.js.flow +7 -6
  115. package/util/RelayRuntimeTypes.js.flow +4 -2
  116. package/util/deepFreeze.js.flow +2 -1
  117. package/util/getPaginationMetadata.js.flow +74 -0
  118. package/util/getPaginationVariables.js.flow +112 -0
  119. package/util/getPendingOperationsForFragment.js.flow +62 -0
  120. package/util/getRefetchMetadata.js.flow +80 -0
  121. package/util/getValueAtPath.js.flow +46 -0
  122. package/util/isEmptyObject.js.flow +2 -1
  123. package/util/registerEnvironmentWithDevTools.js.flow +33 -0
  124. package/util/withDuration.js.flow +32 -0
  125. package/lib/store/RelayRecordSourceMapImpl.js +0 -107
  126. package/lib/store/RelayStoreSubscriptionsUsingMapByID.js +0 -318
  127. package/store/RelayRecordSourceMapImpl.js.flow +0 -91
  128. package/store/RelayStoreSubscriptionsUsingMapByID.js.flow +0 -283
@@ -0,0 +1,245 @@
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
+ * @emails oncall+relay
8
+ * @flow strict-local
9
+ * @format
10
+ */
11
+
12
+ 'use strict';
13
+
14
+ import type {PayloadData, GraphQLResponse} from '../network/RelayNetworkTypes';
15
+ import type RelayObservable from '../network/RelayObservable';
16
+ import type RelayPublishQueue from '../store/RelayPublishQueue';
17
+ import type {
18
+ OperationAvailability,
19
+ OperationDescriptor,
20
+ OptimisticResponseConfig,
21
+ OptimisticUpdateFunction,
22
+ SelectorStoreUpdater,
23
+ SingularReaderSelector,
24
+ Snapshot,
25
+ StoreUpdater,
26
+ IEnvironment,
27
+ ExecuteMutationConfig,
28
+ RecordSourceProxy,
29
+ } from '../store/RelayStoreTypes';
30
+ import type {Disposable} from '../util/RelayRuntimeTypes';
31
+ import type {ActorIdentifier} from './ActorIdentifier';
32
+
33
+ export type MultiActorStoreUpdater = (
34
+ actorIdentifier: ActorIdentifier,
35
+ environment: IActorEnvironment,
36
+ store: RecordSourceProxy,
37
+ ) => void;
38
+
39
+ /**
40
+ * Interface of actor specific sub-environment
41
+ */
42
+ export interface IActorEnvironment extends IEnvironment {
43
+ /**
44
+ * Reference to the main MultiActorEnvironment that handles
45
+ * the network execution/and responsible for network integration
46
+ */
47
+ +multiActorEnvironment: IMultiActorEnvironment;
48
+
49
+ /**
50
+ * Identifier of the actor for the current active environment
51
+ */
52
+ +actorIdentifier: ActorIdentifier;
53
+
54
+ /**
55
+ * TODO: this needs to move the the MultiActorEnvironment with different API.
56
+ */
57
+ getPublishQueue(): RelayPublishQueue;
58
+
59
+ /**
60
+ * Optional. A human-readable identifier of the environment.
61
+ * This value should be visible in the dev tools.
62
+ */
63
+ +configName: ?string;
64
+ }
65
+
66
+ /**
67
+ * Interface for the main (or parent) multi-actor environment that contains
68
+ * the map of individual actor-specific sub-environments. These sub-environments
69
+ * implement the Relay IEnvironment interface.
70
+ */
71
+ export interface IMultiActorEnvironment {
72
+ /**
73
+ * A factory of actor-specific environments.
74
+ */
75
+ forActor(actorIdentifier: ActorIdentifier): IActorEnvironment;
76
+
77
+ /**
78
+ * Determine if the operation can be resolved with data in the store (i.e. no
79
+ * fields are missing).
80
+ *
81
+ * Note that this operation effectively "executes" the selector against the
82
+ * cache and therefore takes time proportional to the size/complexity of the
83
+ * selector.
84
+ */
85
+ check(
86
+ actorEnvironment: IActorEnvironment,
87
+ operation: OperationDescriptor,
88
+ ): OperationAvailability;
89
+
90
+ /**
91
+ * Subscribe to changes to the results of a selector. The callback is called
92
+ * when data has been committed to the store that would cause the results of
93
+ * the snapshot's selector to change.
94
+ */
95
+ subscribe(
96
+ actorEnvironment: IActorEnvironment,
97
+ snapshot: Snapshot,
98
+ callback: (snapshot: Snapshot) => void,
99
+ ): Disposable;
100
+
101
+ /**
102
+ * Ensure that all the records necessary to fulfill the given selector are
103
+ * retained in-memory. The records will not be eligible for garbage collection
104
+ * until the returned reference is disposed.
105
+ */
106
+ retain(
107
+ actorEnvironment: IActorEnvironment,
108
+ operation: OperationDescriptor,
109
+ ): Disposable;
110
+
111
+ /**
112
+ * Apply an optimistic update to the environment. The mutation can be reverted
113
+ * by calling `dispose()` on the returned value.
114
+ */
115
+ applyUpdate(
116
+ actorEnvironment: IActorEnvironment,
117
+ optimisticUpdate: OptimisticUpdateFunction,
118
+ ): Disposable;
119
+
120
+ /**
121
+ * Revert updates for the `update` function.
122
+ */
123
+ revertUpdate(
124
+ actorEnvironment: IActorEnvironment,
125
+ update: OptimisticUpdateFunction,
126
+ ): void;
127
+
128
+ /**
129
+ * Revert updates for the `update` function, and apply the `replacement` update.
130
+ */
131
+ replaceUpdate(
132
+ actorEnvironment: IActorEnvironment,
133
+ update: OptimisticUpdateFunction,
134
+ replacement: OptimisticUpdateFunction,
135
+ ): void;
136
+
137
+ /**
138
+ * Apply an optimistic mutation response and/or updater. The mutation can be
139
+ * reverted by calling `dispose()` on the returned value.
140
+ */
141
+ applyMutation(
142
+ actorEnvironment: IActorEnvironment,
143
+ optimisticConfig: OptimisticResponseConfig,
144
+ ): Disposable;
145
+
146
+ /**
147
+ * Commit an updater to the environment. This mutation cannot be reverted and
148
+ * should therefore not be used for optimistic updates. This is mainly
149
+ * intended for updating fields from client schema extensions.
150
+ */
151
+ commitUpdate(
152
+ actorEnvironment: IActorEnvironment,
153
+ updater: StoreUpdater,
154
+ ): void;
155
+
156
+ /**
157
+ * Commit store updates for each actor-specific environment known to MultiActorEnvironment
158
+ */
159
+ commitMultiActorUpdate(updater: MultiActorStoreUpdater): void;
160
+
161
+ /**
162
+ * Commit a payload to the environment using the given operation selector.
163
+ */
164
+ commitPayload(
165
+ actorEnvironment: IActorEnvironment,
166
+ operationDescriptor: OperationDescriptor,
167
+ payload: PayloadData,
168
+ ): void;
169
+
170
+ /**
171
+ * Read the results of a selector from in-memory records in the store.
172
+ */
173
+ lookup(
174
+ actorEnvironment: IActorEnvironment,
175
+ selector: SingularReaderSelector,
176
+ ): Snapshot;
177
+
178
+ /**
179
+ * Send a query to the server with Observer semantics: one or more
180
+ * responses may be returned (via `next`) over time followed by either
181
+ * the request completing (`completed`) or an error (`error`).
182
+ *
183
+ * Networks/servers that support subscriptions may choose to hold the
184
+ * subscription open indefinitely such that `complete` is not called.
185
+ *
186
+ * Note: Observables are lazy, so calling this method will do nothing until
187
+ * the result is subscribed to: environment.execute({...}).subscribe({...}).
188
+ */
189
+ execute(
190
+ actorEnvironment: IActorEnvironment,
191
+ config: {
192
+ operation: OperationDescriptor,
193
+ updater?: ?SelectorStoreUpdater,
194
+ },
195
+ ): RelayObservable<GraphQLResponse>;
196
+
197
+ /**
198
+ * Returns an Observable of GraphQLResponse resulting from executing the
199
+ * provided Mutation operation, the result of which is then normalized and
200
+ * committed to the publish queue along with an optional optimistic response
201
+ * or updater.
202
+ *
203
+ * Note: Observables are lazy, so calling this method will do nothing until
204
+ * the result is subscribed to:
205
+ * environment.executeMutation({...}).subscribe({...}).
206
+ */
207
+ executeMutation(
208
+ actorEnvironment: IActorEnvironment,
209
+ config: ExecuteMutationConfig,
210
+ ): RelayObservable<GraphQLResponse>;
211
+
212
+ /**
213
+ * Returns an Observable of GraphQLResponse resulting from executing the
214
+ * provided Query or Subscription operation responses, the result of which is
215
+ * then normalized and committed to the publish queue.
216
+ *
217
+ * Note: Observables are lazy, so calling this method will do nothing until
218
+ * the result is subscribed to:
219
+ * environment.executeWithSource({...}).subscribe({...}).
220
+ */
221
+ executeWithSource(
222
+ actorEnvironment: IActorEnvironment,
223
+ {
224
+ operation: OperationDescriptor,
225
+ source: RelayObservable<GraphQLResponse>,
226
+ },
227
+ ): RelayObservable<GraphQLResponse>;
228
+
229
+ /**
230
+ * Returns true if a request is currently "active", meaning it's currently
231
+ * actively receiving payloads or downloading modules, and has not received
232
+ * a final payload yet. Note that a request might still be pending (or "in flight")
233
+ * without actively receiving payload, for example a live query or an
234
+ * active GraphQL subscription
235
+ */
236
+ isRequestActive(
237
+ actorEnvironment: IActorEnvironment,
238
+ requestIdentifier: string,
239
+ ): boolean;
240
+
241
+ /**
242
+ * Returns `true` if execute in the server environment
243
+ */
244
+ isServer(): boolean;
245
+ }
@@ -0,0 +1,27 @@
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
+ * @emails oncall+relay
8
+ * @flow strict-local
9
+ * @format
10
+ */
11
+
12
+ 'use strict';
13
+
14
+ const MultiActorEnvironment = require('./MultiActorEnvironment');
15
+
16
+ const {getActorIdentifier} = require('./ActorIdentifier');
17
+
18
+ export type {ActorIdentifier} from './ActorIdentifier';
19
+ export type {
20
+ IActorEnvironment,
21
+ IMultiActorEnvironment,
22
+ } from './MultiActorEnvironmentTypes';
23
+
24
+ module.exports = {
25
+ MultiActorEnvironment,
26
+ getActorIdentifier,
27
+ };
@@ -78,10 +78,15 @@ class RelayRecordSourceSelectorProxy implements RecordSourceSelectorProxy {
78
78
  fieldName: string,
79
79
  plural: boolean,
80
80
  ): ReaderLinkedField {
81
- const field = selector.node.selections.find(
81
+ let field = selector.node.selections.find(
82
82
  selection =>
83
- selection.kind === 'LinkedField' && selection.name === fieldName,
83
+ (selection.kind === 'LinkedField' && selection.name === fieldName) ||
84
+ (selection.kind === 'RequiredField' &&
85
+ selection.field.name === fieldName),
84
86
  );
87
+ if (field && field.kind === 'RequiredField') {
88
+ field = field.field;
89
+ }
85
90
  invariant(
86
91
  field && field.kind === 'LinkedField',
87
92
  'RelayRecordSourceSelectorProxy#getRootField(): Cannot find root ' +
@@ -54,7 +54,7 @@ export type DEPRECATED_MutationConfig<T> = {|
54
54
 
55
55
  export type MutationParameters = {|
56
56
  +response: {...},
57
- +variables: {...},
57
+ +variables: interface {},
58
58
  +rawResponse?: {...},
59
59
  |};
60
60
 
@@ -113,6 +113,8 @@ function commitMutation<T: MutationParameters>(
113
113
  } = config;
114
114
  const operation = createOperationDescriptor(
115
115
  mutation,
116
+ /* $FlowFixMe[class-object-subtyping] added when improving typing for this
117
+ * parameters */
116
118
  variables,
117
119
  cacheConfig,
118
120
  generateUniqueClientID(),
@@ -30,8 +30,27 @@ type ValidationContext = {|
30
30
 
31
31
  const warning = require('warning');
32
32
 
33
+ // $FlowFixMe[method-unbinding] added when improving typing for this parameters
33
34
  const hasOwnProperty = Object.prototype.hasOwnProperty;
34
35
 
36
+ const {
37
+ ACTOR_CHANGE,
38
+ CONDITION,
39
+ CLIENT_COMPONENT,
40
+ CLIENT_EXTENSION,
41
+ DEFER,
42
+ FLIGHT_FIELD,
43
+ FRAGMENT_SPREAD,
44
+ INLINE_FRAGMENT,
45
+ LINKED_FIELD,
46
+ LINKED_HANDLE,
47
+ MODULE_IMPORT,
48
+ SCALAR_FIELD,
49
+ SCALAR_HANDLE,
50
+ STREAM,
51
+ TYPE_DISCRIMINATOR,
52
+ } = require('../util/RelayConcreteNode');
53
+
35
54
  let validateMutation = () => {};
36
55
  if (__DEV__) {
37
56
  const addFieldToDiff = (path: string, diff: Object, isScalar) => {
@@ -96,21 +115,28 @@ if (__DEV__) {
96
115
  context: ValidationContext,
97
116
  ) => {
98
117
  switch (selection.kind) {
99
- case 'Condition':
118
+ case CONDITION:
100
119
  validateSelections(optimisticResponse, selection.selections, context);
101
120
  return;
102
- case 'FragmentSpread':
121
+ case CLIENT_COMPONENT:
122
+ case FRAGMENT_SPREAD:
103
123
  validateSelections(
104
124
  optimisticResponse,
105
125
  selection.fragment.selections,
106
126
  context,
107
127
  );
108
128
  return;
109
- case 'ScalarField':
110
- case 'LinkedField':
111
- case 'FlightField':
129
+ case SCALAR_FIELD:
130
+ case LINKED_FIELD:
131
+ case FLIGHT_FIELD:
112
132
  return validateField(optimisticResponse, selection, context);
113
- case 'InlineFragment':
133
+ case ACTOR_CHANGE:
134
+ return validateField(
135
+ optimisticResponse,
136
+ selection.linkedField,
137
+ context,
138
+ );
139
+ case INLINE_FRAGMENT:
114
140
  const type = selection.type;
115
141
  const isConcreteType = selection.abstractKey == null;
116
142
  selection.selections.forEach(subselection => {
@@ -120,18 +146,18 @@ if (__DEV__) {
120
146
  validateSelection(optimisticResponse, subselection, context);
121
147
  });
122
148
  return;
123
- case 'ClientExtension':
149
+ case CLIENT_EXTENSION:
124
150
  selection.selections.forEach(subselection => {
125
151
  validateSelection(optimisticResponse, subselection, context);
126
152
  });
127
153
  return;
128
- case 'ModuleImport':
154
+ case MODULE_IMPORT:
129
155
  return validateModuleImport(context);
130
- case 'LinkedHandle':
131
- case 'ScalarHandle':
132
- case 'Defer':
133
- case 'Stream':
134
- case 'TypeDiscriminator': {
156
+ case LINKED_HANDLE:
157
+ case SCALAR_HANDLE:
158
+ case DEFER:
159
+ case STREAM:
160
+ case TYPE_DISCRIMINATOR: {
135
161
  // TODO(T35864292) - Add missing validations for these types
136
162
  return;
137
163
  }
@@ -154,12 +180,12 @@ if (__DEV__) {
154
180
  const path = `${context.path}.${fieldName}`;
155
181
  context.visitedPaths.add(path);
156
182
  switch (field.kind) {
157
- case 'ScalarField':
183
+ case SCALAR_FIELD:
158
184
  if (hasOwnProperty.call(optimisticResponse, fieldName) === false) {
159
185
  addFieldToDiff(path, context.missingDiff, true);
160
186
  }
161
187
  return;
162
- case 'LinkedField':
188
+ case LINKED_FIELD:
163
189
  const selections = field.selections;
164
190
  if (
165
191
  optimisticResponse[fieldName] === null ||
@@ -195,7 +221,7 @@ if (__DEV__) {
195
221
  return;
196
222
  }
197
223
  }
198
- case 'FlightField':
224
+ case FLIGHT_FIELD:
199
225
  if (
200
226
  optimisticResponse[fieldName] === null ||
201
227
  (hasOwnProperty.call(optimisticResponse, fieldName) &&
@@ -20,14 +20,15 @@ import type RelayObservable, {ObservableFromValue} from './RelayObservable';
20
20
  * An interface for fetching the data for one or more (possibly interdependent)
21
21
  * queries.
22
22
  */
23
- export type INetwork = {|
24
- execute: ExecuteFunction,
25
- |};
23
+ export interface INetwork {
24
+ +execute: ExecuteFunction;
25
+ }
26
+
26
27
  export type LogRequestInfoFunction = mixed => void;
27
28
 
28
- export type PayloadData = {[key: string]: mixed, ...};
29
+ export type PayloadData = interface {[key: string]: mixed};
29
30
 
30
- export type PayloadError = {
31
+ export type PayloadError = interface {
31
32
  message: string,
32
33
  locations?: Array<{
33
34
  line: number,
@@ -36,14 +37,13 @@ export type PayloadError = {
36
37
  }>,
37
38
  // Not officially part of the spec, but used at Facebook
38
39
  severity?: 'CRITICAL' | 'ERROR' | 'WARNING',
39
- ...
40
40
  };
41
41
 
42
42
  export type PayloadExtensions = {[key: string]: mixed, ...};
43
43
 
44
44
  /**
45
45
  * The shape of a GraphQL response as dictated by the
46
- * [spec](https://graphql.github.io/graphql-spec/June2018/#sec-Response-Format)
46
+ * [spec](https://spec.graphql.org/June2018/#sec-Response-Format).
47
47
  */
48
48
  export type GraphQLResponseWithData = {|
49
49
  +data: PayloadData,
@@ -120,7 +120,7 @@ export type SubscribeFunction = (
120
120
  ) => RelayObservable<GraphQLResponse>;
121
121
 
122
122
  export type Uploadable = File | Blob;
123
- export type UploadableMap = {[key: string]: Uploadable, ...};
123
+ export type UploadableMap = interface {[key: string]: Uploadable};
124
124
 
125
125
  /**
126
126
  * React Flight tree created on the server.
@@ -132,6 +132,13 @@ export type ReactFlightPayloadQuery = {|
132
132
  +response: GraphQLSingularResponse,
133
133
  +variables: Variables,
134
134
  |};
135
+ export type ReactFlightPayloadFragment = {|
136
+ +__id: string,
137
+ +__typename: string,
138
+ +module: mixed,
139
+ +response: GraphQLSingularResponse,
140
+ +variables: Variables,
141
+ |};
135
142
  export type ReactFlightServerError = {
136
143
  +message: string,
137
144
  +stack: string,
@@ -147,10 +154,12 @@ export type ReactFlightServerError = {
147
154
  * - queries: an array of queries that the server preloaded for the client.
148
155
  * - errors: an array of errors that were encountered while rendering the
149
156
  * Server Component.
157
+ * - fragments: an array of fragments that the server preloaded for the client.
150
158
  */
151
159
  export type ReactFlightPayloadData = {|
152
160
  +status: string,
153
161
  +tree: ?Array<ReactFlightServerTree>,
154
162
  +queries: Array<ReactFlightPayloadQuery>,
155
163
  +errors: Array<ReactFlightServerError>,
164
+ +fragments: Array<ReactFlightPayloadFragment>,
156
165
  |};
@@ -355,11 +355,13 @@ class RelayObservable<+T> implements Subscribable<T> {
355
355
  }
356
356
  }
357
357
 
358
+ // $FlowFixMe[incompatible-call]
358
359
  this.subscribe({
359
360
  start,
360
361
  next(value) {
361
362
  try {
362
363
  if (!sink.closed) {
364
+ // $FlowFixMe[incompatible-call]
363
365
  RelayObservable.from(fn(value)).subscribe({
364
366
  start,
365
367
  next: sink.next,
@@ -16,11 +16,14 @@ const invariant = require('invariant');
16
16
  const stableCopy = require('../util/stableCopy');
17
17
 
18
18
  import type {Variables} from '../util/RelayRuntimeTypes';
19
- import type {GraphQLSingularResponse} from './RelayNetworkTypes';
19
+ import type {
20
+ GraphQLResponse,
21
+ GraphQLSingularResponse,
22
+ } from './RelayNetworkTypes';
20
23
 
21
24
  type Response = {
22
25
  fetchTime: number,
23
- payload: GraphQLSingularResponse,
26
+ payload: GraphQLResponse,
24
27
  ...
25
28
  };
26
29
 
@@ -55,7 +58,7 @@ class RelayQueryResponseCache {
55
58
  this._responses.clear();
56
59
  }
57
60
 
58
- get(queryID: string, variables: Variables): ?GraphQLSingularResponse {
61
+ get(queryID: string, variables: Variables): ?GraphQLResponse {
59
62
  const cacheKey = getCacheKey(queryID, variables);
60
63
  this._responses.forEach((response, key) => {
61
64
  if (!isCurrent(response.fetchTime, this._ttl)) {
@@ -63,22 +66,33 @@ class RelayQueryResponseCache {
63
66
  }
64
67
  });
65
68
  const response = this._responses.get(cacheKey);
66
- return response != null
67
- ? ({
68
- ...response.payload,
69
- extensions: {
70
- ...response.payload.extensions,
71
- cacheTimestamp: response.fetchTime,
72
- },
73
- }: GraphQLSingularResponse)
74
- : null;
69
+ if (response == null) {
70
+ return null;
71
+ }
72
+ if (Array.isArray(response.payload)) {
73
+ return response.payload.map(
74
+ payload =>
75
+ // $FlowFixMe[incompatible-cast]
76
+ ({
77
+ ...payload,
78
+ extensions: {
79
+ ...payload.extensions,
80
+ cacheTimestamp: response.fetchTime,
81
+ },
82
+ }: GraphQLSingularResponse),
83
+ );
84
+ }
85
+ // $FlowFixMe[incompatible-cast]
86
+ return ({
87
+ ...response.payload,
88
+ extensions: {
89
+ ...response.payload.extensions,
90
+ cacheTimestamp: response.fetchTime,
91
+ },
92
+ }: GraphQLSingularResponse);
75
93
  }
76
94
 
77
- set(
78
- queryID: string,
79
- variables: Variables,
80
- payload: GraphQLSingularResponse,
81
- ): void {
95
+ set(queryID: string, variables: Variables, payload: GraphQLResponse): void {
82
96
  const fetchTime = Date.now();
83
97
  const cacheKey = getCacheKey(queryID, variables);
84
98
  this._responses.delete(cacheKey); // deletion resets key ordering
@@ -0,0 +1,99 @@
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
8
+ * @format
9
+ */
10
+
11
+ // flowlint ambiguous-object-type:error
12
+
13
+ 'use strict';
14
+
15
+ const generateID = require('../util/generateID');
16
+
17
+ import type ActorSpecificEnvironment from '../multi-actor-environment/ActorSpecificEnvironment';
18
+ import type RelayModernEnvironment from '../store/RelayModernEnvironment';
19
+ import type {RequestParameters} from '../util/RelayConcreteNode';
20
+ import type {CacheConfig, Variables} from '../util/RelayRuntimeTypes';
21
+ import type {
22
+ INetwork,
23
+ GraphQLResponse,
24
+ UploadableMap,
25
+ } from './RelayNetworkTypes';
26
+ import type RelayObservable from './RelayObservable';
27
+
28
+ /**
29
+ * Wraps the network with logging to ensure that network requests are
30
+ * always logged. Relying on each network callsite to be wrapped is
31
+ * untenable and will eventually lead to holes in the logging.
32
+ * NOTE: This function takes an environment instance, because Relay
33
+ * devtools will mutate the `env.__log` method, and the devtools rely
34
+ * on it to receive network events.
35
+ */
36
+ function wrapNetworkWithLogObserver(
37
+ env: RelayModernEnvironment | ActorSpecificEnvironment,
38
+ network: INetwork,
39
+ ): INetwork {
40
+ return {
41
+ execute(
42
+ params: RequestParameters,
43
+ variables: Variables,
44
+ cacheConfig: CacheConfig,
45
+ uploadables?: ?UploadableMap,
46
+ ): RelayObservable<GraphQLResponse> {
47
+ const networkRequestId = generateID();
48
+ const logObserver = {
49
+ start: subscription => {
50
+ env.__log({
51
+ name: 'network.start',
52
+ networkRequestId,
53
+ params,
54
+ variables,
55
+ cacheConfig,
56
+ });
57
+ },
58
+ next: response => {
59
+ env.__log({
60
+ name: 'network.next',
61
+ networkRequestId,
62
+ response,
63
+ });
64
+ },
65
+ error: error => {
66
+ env.__log({
67
+ name: 'network.error',
68
+ networkRequestId,
69
+ error,
70
+ });
71
+ },
72
+ complete: () => {
73
+ env.__log({
74
+ name: 'network.complete',
75
+ networkRequestId,
76
+ });
77
+ },
78
+ unsubscribe: () => {
79
+ env.__log({
80
+ name: 'network.unsubscribe',
81
+ networkRequestId,
82
+ });
83
+ },
84
+ };
85
+ const logRequestInfo = info => {
86
+ env.__log({
87
+ name: 'network.info',
88
+ networkRequestId,
89
+ info,
90
+ });
91
+ };
92
+ return network
93
+ .execute(params, variables, cacheConfig, uploadables, logRequestInfo)
94
+ .do(logObserver);
95
+ },
96
+ };
97
+ }
98
+
99
+ module.exports = wrapNetworkWithLogObserver;