relay-runtime 11.0.2 → 13.0.0-rc.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 (219) hide show
  1. package/README.md +67 -0
  2. package/handlers/RelayDefaultHandlerProvider.js.flow +3 -3
  3. package/handlers/connection/ConnectionHandler.js.flow +9 -18
  4. package/handlers/connection/ConnectionInterface.js.flow +1 -1
  5. package/handlers/connection/MutationHandlers.js.flow +8 -12
  6. package/index.js +1 -1
  7. package/index.js.flow +57 -35
  8. package/lib/handlers/RelayDefaultHandlerProvider.js +1 -1
  9. package/lib/handlers/connection/ConnectionHandler.js +13 -19
  10. package/lib/handlers/connection/ConnectionInterface.js +1 -1
  11. package/lib/handlers/connection/MutationHandlers.js +4 -7
  12. package/lib/index.js +59 -44
  13. package/lib/multi-actor-environment/ActorIdentifier.js +12 -2
  14. package/lib/multi-actor-environment/ActorSpecificEnvironment.js +64 -20
  15. package/lib/multi-actor-environment/ActorUtils.js +27 -0
  16. package/lib/multi-actor-environment/MultiActorEnvironment.js +324 -61
  17. package/lib/multi-actor-environment/MultiActorEnvironmentTypes.js +1 -1
  18. package/lib/multi-actor-environment/index.js +6 -2
  19. package/lib/mutations/RelayDeclarativeMutationConfig.js +5 -2
  20. package/lib/mutations/RelayRecordProxy.js +4 -3
  21. package/lib/mutations/RelayRecordSourceMutator.js +4 -3
  22. package/lib/mutations/RelayRecordSourceProxy.js +13 -5
  23. package/lib/mutations/RelayRecordSourceSelectorProxy.js +19 -6
  24. package/lib/mutations/applyOptimisticMutation.js +7 -7
  25. package/lib/mutations/commitLocalUpdate.js +1 -1
  26. package/lib/mutations/commitMutation.js +15 -11
  27. package/lib/mutations/readUpdatableQuery_EXPERIMENTAL.js +242 -0
  28. package/lib/mutations/validateMutation.js +11 -6
  29. package/lib/network/ConvertToExecuteFunction.js +3 -2
  30. package/lib/network/RelayNetwork.js +4 -3
  31. package/lib/network/RelayNetworkTypes.js +1 -1
  32. package/lib/network/RelayObservable.js +1 -1
  33. package/lib/network/RelayQueryResponseCache.js +22 -6
  34. package/lib/network/wrapNetworkWithLogObserver.js +79 -0
  35. package/lib/query/GraphQLTag.js +3 -2
  36. package/lib/query/PreloadableQueryRegistry.js +1 -1
  37. package/lib/query/fetchQuery.js +7 -6
  38. package/lib/query/fetchQueryInternal.js +1 -1
  39. package/lib/query/fetchQuery_DEPRECATED.js +3 -2
  40. package/lib/store/ClientID.js +8 -2
  41. package/lib/store/DataChecker.js +124 -55
  42. package/lib/store/OperationExecutor.js +489 -215
  43. package/lib/store/RelayConcreteVariables.js +27 -9
  44. package/lib/store/RelayExperimentalGraphResponseHandler.js +153 -0
  45. package/lib/store/RelayExperimentalGraphResponseTransform.js +391 -0
  46. package/lib/store/RelayModernEnvironment.js +100 -120
  47. package/lib/store/RelayModernFragmentSpecResolver.js +53 -27
  48. package/lib/store/RelayModernOperationDescriptor.js +3 -2
  49. package/lib/store/RelayModernRecord.js +48 -13
  50. package/lib/store/RelayModernSelector.js +15 -9
  51. package/lib/store/RelayModernStore.js +56 -23
  52. package/lib/store/RelayOperationTracker.js +34 -24
  53. package/lib/store/RelayOptimisticRecordSource.js +1 -1
  54. package/lib/store/RelayPublishQueue.js +35 -11
  55. package/lib/store/RelayReader.js +257 -72
  56. package/lib/store/RelayRecordSource.js +88 -4
  57. package/lib/store/RelayRecordState.js +1 -1
  58. package/lib/store/RelayReferenceMarker.js +34 -22
  59. package/lib/store/RelayResponseNormalizer.js +172 -96
  60. package/lib/store/RelayStoreReactFlightUtils.js +5 -11
  61. package/lib/store/RelayStoreSubscriptions.js +15 -10
  62. package/lib/store/RelayStoreTypes.js +1 -1
  63. package/lib/store/RelayStoreUtils.js +13 -8
  64. package/lib/store/ResolverCache.js +213 -0
  65. package/lib/store/ResolverFragments.js +10 -6
  66. package/lib/store/StoreInspector.js +1 -1
  67. package/lib/store/TypeID.js +1 -1
  68. package/lib/store/ViewerPattern.js +1 -1
  69. package/lib/store/cloneRelayHandleSourceField.js +6 -5
  70. package/lib/store/cloneRelayScalarHandleSourceField.js +6 -5
  71. package/lib/store/createFragmentSpecResolver.js +1 -1
  72. package/lib/store/createRelayContext.js +5 -3
  73. package/lib/store/defaultGetDataID.js +1 -1
  74. package/lib/store/defaultRequiredFieldLogger.js +1 -1
  75. package/lib/store/hasOverlappingIDs.js +1 -1
  76. package/lib/store/isRelayModernEnvironment.js +1 -1
  77. package/lib/store/normalizeRelayPayload.js +1 -1
  78. package/lib/store/readInlineData.js +7 -3
  79. package/lib/subscription/requestSubscription.js +32 -34
  80. package/lib/util/JSResourceTypes.flow.js +1 -1
  81. package/lib/util/NormalizationNode.js +1 -1
  82. package/lib/util/ReaderNode.js +1 -1
  83. package/lib/util/RelayConcreteNode.js +3 -1
  84. package/lib/util/RelayDefaultHandleKey.js +1 -1
  85. package/lib/util/RelayError.js +1 -1
  86. package/lib/util/RelayFeatureFlags.js +10 -7
  87. package/lib/util/RelayProfiler.js +1 -1
  88. package/lib/util/RelayReplaySubject.js +22 -7
  89. package/lib/util/RelayRuntimeTypes.js +1 -7
  90. package/lib/util/StringInterner.js +71 -0
  91. package/lib/util/createPayloadFor3DField.js +1 -1
  92. package/lib/util/deepFreeze.js +1 -1
  93. package/lib/util/generateID.js +1 -1
  94. package/lib/util/getAllRootVariables.js +29 -0
  95. package/lib/util/getFragmentIdentifier.js +16 -8
  96. package/lib/util/getOperation.js +3 -2
  97. package/lib/util/getPaginationMetadata.js +41 -0
  98. package/lib/util/getPaginationVariables.js +66 -0
  99. package/lib/util/getPendingOperationsForFragment.js +55 -0
  100. package/lib/util/getRefetchMetadata.js +36 -0
  101. package/lib/util/getRelayHandleKey.js +3 -3
  102. package/lib/util/getRequestIdentifier.js +3 -3
  103. package/lib/util/getValueAtPath.js +51 -0
  104. package/lib/util/isEmptyObject.js +2 -2
  105. package/lib/util/isPromise.js +1 -1
  106. package/lib/util/isScalarAndEqual.js +1 -1
  107. package/lib/util/recycleNodesInto.js +1 -1
  108. package/lib/util/registerEnvironmentWithDevTools.js +26 -0
  109. package/lib/util/reportMissingRequiredFields.js +1 -1
  110. package/lib/util/resolveImmediate.js +1 -1
  111. package/lib/util/stableCopy.js +1 -1
  112. package/lib/util/withDuration.js +31 -0
  113. package/multi-actor-environment/ActorIdentifier.js.flow +18 -2
  114. package/multi-actor-environment/ActorSpecificEnvironment.js.flow +94 -58
  115. package/multi-actor-environment/ActorUtils.js.flow +33 -0
  116. package/multi-actor-environment/MultiActorEnvironment.js.flow +366 -93
  117. package/multi-actor-environment/MultiActorEnvironmentTypes.js.flow +88 -23
  118. package/multi-actor-environment/index.js.flow +3 -1
  119. package/mutations/RelayDeclarativeMutationConfig.js.flow +33 -27
  120. package/mutations/RelayRecordProxy.js.flow +5 -6
  121. package/mutations/RelayRecordSourceMutator.js.flow +5 -7
  122. package/mutations/RelayRecordSourceProxy.js.flow +20 -11
  123. package/mutations/RelayRecordSourceSelectorProxy.js.flow +23 -8
  124. package/mutations/applyOptimisticMutation.js.flow +14 -15
  125. package/mutations/commitLocalUpdate.js.flow +2 -2
  126. package/mutations/commitMutation.js.flow +36 -47
  127. package/mutations/readUpdatableQuery_EXPERIMENTAL.js.flow +318 -0
  128. package/mutations/validateMutation.js.flow +27 -17
  129. package/network/ConvertToExecuteFunction.js.flow +3 -3
  130. package/network/RelayNetwork.js.flow +5 -6
  131. package/network/RelayNetworkTypes.js.flow +1 -1
  132. package/network/RelayObservable.js.flow +2 -2
  133. package/network/RelayQueryResponseCache.js.flow +35 -22
  134. package/network/wrapNetworkWithLogObserver.js.flow +99 -0
  135. package/package.json +2 -2
  136. package/query/GraphQLTag.js.flow +11 -11
  137. package/query/PreloadableQueryRegistry.js.flow +5 -3
  138. package/query/fetchQuery.js.flow +19 -19
  139. package/query/fetchQueryInternal.js.flow +7 -10
  140. package/query/fetchQuery_DEPRECATED.js.flow +7 -7
  141. package/relay-runtime.js +2 -2
  142. package/relay-runtime.min.js +2 -2
  143. package/store/ClientID.js.flow +15 -4
  144. package/store/DataChecker.js.flow +142 -60
  145. package/store/OperationExecutor.js.flow +575 -320
  146. package/store/RelayConcreteVariables.js.flow +28 -9
  147. package/store/RelayExperimentalGraphResponseHandler.js.flow +121 -0
  148. package/store/RelayExperimentalGraphResponseTransform.js.flow +470 -0
  149. package/store/RelayModernEnvironment.js.flow +91 -115
  150. package/store/RelayModernFragmentSpecResolver.js.flow +56 -32
  151. package/store/RelayModernOperationDescriptor.js.flow +13 -8
  152. package/store/RelayModernRecord.js.flow +68 -12
  153. package/store/RelayModernSelector.js.flow +25 -15
  154. package/store/RelayModernStore.js.flow +67 -32
  155. package/store/RelayOperationTracker.js.flow +60 -44
  156. package/store/RelayOptimisticRecordSource.js.flow +3 -3
  157. package/store/RelayPublishQueue.js.flow +74 -32
  158. package/store/RelayReader.js.flow +319 -100
  159. package/store/RelayRecordSource.js.flow +73 -7
  160. package/store/RelayRecordState.js.flow +1 -1
  161. package/store/RelayReferenceMarker.js.flow +41 -27
  162. package/store/RelayResponseNormalizer.js.flow +204 -86
  163. package/store/RelayStoreReactFlightUtils.js.flow +5 -12
  164. package/store/RelayStoreSubscriptions.js.flow +20 -12
  165. package/store/RelayStoreTypes.js.flow +200 -41
  166. package/store/RelayStoreUtils.js.flow +25 -12
  167. package/store/ResolverCache.js.flow +249 -0
  168. package/store/ResolverFragments.js.flow +16 -20
  169. package/store/StoreInspector.js.flow +3 -3
  170. package/store/TypeID.js.flow +2 -2
  171. package/store/ViewerPattern.js.flow +3 -3
  172. package/store/cloneRelayHandleSourceField.js.flow +6 -7
  173. package/store/cloneRelayScalarHandleSourceField.js.flow +6 -7
  174. package/store/createFragmentSpecResolver.js.flow +4 -5
  175. package/store/createRelayContext.js.flow +4 -4
  176. package/store/defaultGetDataID.js.flow +1 -1
  177. package/store/defaultRequiredFieldLogger.js.flow +1 -1
  178. package/store/hasOverlappingIDs.js.flow +1 -1
  179. package/store/isRelayModernEnvironment.js.flow +1 -1
  180. package/store/normalizeRelayPayload.js.flow +7 -8
  181. package/store/readInlineData.js.flow +8 -9
  182. package/subscription/requestSubscription.js.flow +55 -51
  183. package/util/JSResourceTypes.flow.js.flow +1 -1
  184. package/util/NormalizationNode.js.flow +11 -4
  185. package/util/ReaderNode.js.flow +25 -2
  186. package/util/RelayConcreteNode.js.flow +5 -1
  187. package/util/RelayDefaultHandleKey.js.flow +1 -1
  188. package/util/RelayError.js.flow +1 -1
  189. package/util/RelayFeatureFlags.js.flow +23 -15
  190. package/util/RelayProfiler.js.flow +1 -1
  191. package/util/RelayReplaySubject.js.flow +10 -10
  192. package/util/RelayRuntimeTypes.js.flow +70 -3
  193. package/util/StringInterner.js.flow +69 -0
  194. package/util/createPayloadFor3DField.js.flow +4 -4
  195. package/util/deepFreeze.js.flow +1 -1
  196. package/util/generateID.js.flow +1 -1
  197. package/util/getAllRootVariables.js.flow +36 -0
  198. package/util/getFragmentIdentifier.js.flow +28 -16
  199. package/util/getOperation.js.flow +3 -3
  200. package/util/getPaginationMetadata.js.flow +69 -0
  201. package/util/getPaginationVariables.js.flow +108 -0
  202. package/util/getPendingOperationsForFragment.js.flow +62 -0
  203. package/util/getRefetchMetadata.js.flow +76 -0
  204. package/util/getRelayHandleKey.js.flow +2 -3
  205. package/util/getRequestIdentifier.js.flow +4 -4
  206. package/util/getValueAtPath.js.flow +46 -0
  207. package/util/isEmptyObject.js.flow +2 -1
  208. package/util/isPromise.js.flow +1 -1
  209. package/util/isScalarAndEqual.js.flow +1 -1
  210. package/util/recycleNodesInto.js.flow +1 -1
  211. package/util/registerEnvironmentWithDevTools.js.flow +33 -0
  212. package/util/reportMissingRequiredFields.js.flow +1 -1
  213. package/util/resolveImmediate.js.flow +2 -2
  214. package/util/stableCopy.js.flow +1 -1
  215. package/util/withDuration.js.flow +32 -0
  216. package/lib/store/RelayRecordSourceMapImpl.js +0 -107
  217. package/lib/store/RelayStoreSubscriptionsUsingMapByID.js +0 -318
  218. package/store/RelayRecordSourceMapImpl.js.flow +0 -91
  219. package/store/RelayStoreSubscriptionsUsingMapByID.js.flow +0 -283
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
3
  *
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
@@ -12,17 +12,41 @@
12
12
 
13
13
  'use strict';
14
14
 
15
- const RelayFeatureFlags = require('../util/RelayFeatureFlags');
16
- const RelayModernRecord = require('./RelayModernRecord');
17
-
18
- const areEqual = require('areEqual');
19
- const invariant = require('invariant');
20
- const warning = require('warning');
15
+ import type {ActorIdentifier} from '../multi-actor-environment/ActorIdentifier';
16
+ import type {PayloadData} from '../network/RelayNetworkTypes';
17
+ import type {
18
+ NormalizationActorChange,
19
+ NormalizationDefer,
20
+ NormalizationFlightField,
21
+ NormalizationLinkedField,
22
+ NormalizationModuleImport,
23
+ NormalizationNode,
24
+ NormalizationScalarField,
25
+ NormalizationStream,
26
+ } from '../util/NormalizationNode';
27
+ import type {DataID, Variables} from '../util/RelayRuntimeTypes';
28
+ import type {
29
+ FollowupPayload,
30
+ HandleFieldPayload,
31
+ IncrementalDataPlaceholder,
32
+ MutableRecordSource,
33
+ NormalizationSelector,
34
+ ReactFlightPayloadDeserializer,
35
+ ReactFlightReachableExecutableDefinitions,
36
+ ReactFlightServerErrorHandler,
37
+ Record,
38
+ RelayResponsePayload,
39
+ } from './RelayStoreTypes';
21
40
 
22
41
  const {
23
- CONDITION,
42
+ ACTOR_IDENTIFIER_FIELD_NAME,
43
+ getActorIdentifierFromPayload,
44
+ } = require('../multi-actor-environment/ActorUtils');
45
+ const {
46
+ ACTOR_CHANGE,
24
47
  CLIENT_COMPONENT,
25
48
  CLIENT_EXTENSION,
49
+ CONDITION,
26
50
  DEFER,
27
51
  FLIGHT_FIELD,
28
52
  FRAGMENT_SPREAD,
@@ -35,49 +59,31 @@ const {
35
59
  STREAM,
36
60
  TYPE_DISCRIMINATOR,
37
61
  } = require('../util/RelayConcreteNode');
62
+ const RelayFeatureFlags = require('../util/RelayFeatureFlags');
38
63
  const {generateClientID, isClientID} = require('./ClientID');
64
+ const {getLocalVariables} = require('./RelayConcreteVariables');
65
+ const RelayModernRecord = require('./RelayModernRecord');
39
66
  const {createNormalizationSelector} = require('./RelayModernSelector');
40
67
  const {
41
- refineToReactFlightPayloadData,
42
68
  REACT_FLIGHT_EXECUTABLE_DEFINITIONS_STORAGE_KEY,
43
69
  REACT_FLIGHT_TREE_STORAGE_KEY,
44
70
  REACT_FLIGHT_TYPE_NAME,
71
+ refineToReactFlightPayloadData,
45
72
  } = require('./RelayStoreReactFlightUtils');
46
73
  const {
74
+ ROOT_ID,
75
+ ROOT_TYPE,
76
+ TYPENAME_KEY,
47
77
  getArgumentValues,
48
78
  getHandleStorageKey,
49
79
  getModuleComponentKey,
50
80
  getModuleOperationKey,
51
81
  getStorageKey,
52
- TYPENAME_KEY,
53
- ROOT_ID,
54
- ROOT_TYPE,
55
82
  } = require('./RelayStoreUtils');
56
- const {generateTypeID, TYPE_SCHEMA_TYPE} = require('./TypeID');
57
-
58
- import type {PayloadData} from '../network/RelayNetworkTypes';
59
- import type {
60
- NormalizationDefer,
61
- NormalizationFlightField,
62
- NormalizationLinkedField,
63
- NormalizationModuleImport,
64
- NormalizationNode,
65
- NormalizationScalarField,
66
- NormalizationStream,
67
- } from '../util/NormalizationNode';
68
- import type {DataID, Variables} from '../util/RelayRuntimeTypes';
69
- import type {
70
- HandleFieldPayload,
71
- IncrementalDataPlaceholder,
72
- ModuleImportPayload,
73
- MutableRecordSource,
74
- NormalizationSelector,
75
- ReactFlightReachableExecutableDefinitions,
76
- ReactFlightPayloadDeserializer,
77
- ReactFlightServerErrorHandler,
78
- Record,
79
- RelayResponsePayload,
80
- } from './RelayStoreTypes';
83
+ const {TYPE_SCHEMA_TYPE, generateTypeID} = require('./TypeID');
84
+ const areEqual = require('areEqual');
85
+ const invariant = require('invariant');
86
+ const warning = require('warning');
81
87
 
82
88
  export type GetDataID = (
83
89
  fieldValue: interface {[string]: mixed},
@@ -91,6 +97,7 @@ export type NormalizationOptions = {|
91
97
  +reactFlightPayloadDeserializer?: ?ReactFlightPayloadDeserializer,
92
98
  +reactFlightServerErrorHandler?: ?ReactFlightServerErrorHandler,
93
99
  +shouldProcessClientComponents?: ?boolean,
100
+ +actorIdentifier?: ?ActorIdentifier,
94
101
  |};
95
102
 
96
103
  /**
@@ -118,13 +125,14 @@ function normalize(
118
125
  * Helper for handling payloads.
119
126
  */
120
127
  class RelayResponseNormalizer {
128
+ _actorIdentifier: ?ActorIdentifier;
121
129
  _getDataId: GetDataID;
122
130
  _handleFieldPayloads: Array<HandleFieldPayload>;
123
131
  _treatMissingFieldsAsNull: boolean;
124
132
  _incrementalPlaceholders: Array<IncrementalDataPlaceholder>;
125
133
  _isClientExtension: boolean;
126
134
  _isUnmatchedAbstractType: boolean;
127
- _moduleImportPayloads: Array<ModuleImportPayload>;
135
+ _followupPayloads: Array<FollowupPayload>;
128
136
  _path: Array<string>;
129
137
  _recordSource: MutableRecordSource;
130
138
  _variables: Variables;
@@ -137,13 +145,14 @@ class RelayResponseNormalizer {
137
145
  variables: Variables,
138
146
  options: NormalizationOptions,
139
147
  ) {
148
+ this._actorIdentifier = options.actorIdentifier;
140
149
  this._getDataId = options.getDataID;
141
150
  this._handleFieldPayloads = [];
142
151
  this._treatMissingFieldsAsNull = options.treatMissingFieldsAsNull;
143
152
  this._incrementalPlaceholders = [];
144
153
  this._isClientExtension = false;
145
154
  this._isUnmatchedAbstractType = false;
146
- this._moduleImportPayloads = [];
155
+ this._followupPayloads = [];
147
156
  this._path = options.path ? [...options.path] : [];
148
157
  this._recordSource = recordSource;
149
158
  this._variables = variables;
@@ -169,7 +178,7 @@ class RelayResponseNormalizer {
169
178
  errors: null,
170
179
  fieldPayloads: this._handleFieldPayloads,
171
180
  incrementalPlaceholders: this._incrementalPlaceholders,
172
- moduleImportPayloads: this._moduleImportPayloads,
181
+ followupPayloads: this._followupPayloads,
173
182
  source: this._recordSource,
174
183
  isFinal: false,
175
184
  };
@@ -181,7 +190,6 @@ class RelayResponseNormalizer {
181
190
  'RelayResponseNormalizer(): Undefined variable `%s`.',
182
191
  name,
183
192
  );
184
- // $FlowFixMe[cannot-write]
185
193
  return this._variables[name];
186
194
  }
187
195
 
@@ -208,13 +216,22 @@ class RelayResponseNormalizer {
208
216
  this._normalizeField(node, selection, record, data);
209
217
  break;
210
218
  case CONDITION:
211
- const conditionValue = this._getVariableValue(selection.condition);
219
+ const conditionValue = Boolean(
220
+ this._getVariableValue(selection.condition),
221
+ );
212
222
  if (conditionValue === selection.passingValue) {
213
223
  this._traverseSelections(selection, record, data);
214
224
  }
215
225
  break;
216
226
  case FRAGMENT_SPREAD: {
227
+ const prevVariables = this._variables;
228
+ this._variables = getLocalVariables(
229
+ this._variables,
230
+ selection.fragment.argumentDefinitions,
231
+ selection.args,
232
+ );
217
233
  this._traverseSelections(selection.fragment, record, data);
234
+ this._variables = prevVariables;
218
235
  break;
219
236
  }
220
237
  case INLINE_FRAGMENT: {
@@ -224,7 +241,7 @@ class RelayResponseNormalizer {
224
241
  if (typeName === selection.type) {
225
242
  this._traverseSelections(selection, record, data);
226
243
  }
227
- } else if (RelayFeatureFlags.ENABLE_PRECISE_TYPE_REFINEMENT) {
244
+ } else {
228
245
  const implementsInterface = data.hasOwnProperty(abstractKey);
229
246
  const typeName = RelayModernRecord.getType(record);
230
247
  const typeID = generateTypeID(typeName);
@@ -241,36 +258,24 @@ class RelayResponseNormalizer {
241
258
  if (implementsInterface) {
242
259
  this._traverseSelections(selection, record, data);
243
260
  }
244
- } else {
245
- // legacy behavior for abstract refinements: always normalize even
246
- // if the type doesn't conform, but track if the type matches or not
247
- // for determining whether response fields are expected to be present
248
- const implementsInterface = data.hasOwnProperty(abstractKey);
249
- const parentIsUnmatchedAbstractType = this._isUnmatchedAbstractType;
250
- this._isUnmatchedAbstractType =
251
- this._isUnmatchedAbstractType || !implementsInterface;
252
- this._traverseSelections(selection, record, data);
253
- this._isUnmatchedAbstractType = parentIsUnmatchedAbstractType;
254
261
  }
255
262
  break;
256
263
  }
257
264
  case TYPE_DISCRIMINATOR: {
258
- if (RelayFeatureFlags.ENABLE_PRECISE_TYPE_REFINEMENT) {
259
- const {abstractKey} = selection;
260
- const implementsInterface = data.hasOwnProperty(abstractKey);
261
- const typeName = RelayModernRecord.getType(record);
262
- const typeID = generateTypeID(typeName);
263
- let typeRecord = this._recordSource.get(typeID);
264
- if (typeRecord == null) {
265
- typeRecord = RelayModernRecord.create(typeID, TYPE_SCHEMA_TYPE);
266
- this._recordSource.set(typeID, typeRecord);
267
- }
268
- RelayModernRecord.setValue(
269
- typeRecord,
270
- abstractKey,
271
- implementsInterface,
272
- );
265
+ const {abstractKey} = selection;
266
+ const implementsInterface = data.hasOwnProperty(abstractKey);
267
+ const typeName = RelayModernRecord.getType(record);
268
+ const typeID = generateTypeID(typeName);
269
+ let typeRecord = this._recordSource.get(typeID);
270
+ if (typeRecord == null) {
271
+ typeRecord = RelayModernRecord.create(typeID, TYPE_SCHEMA_TYPE);
272
+ this._recordSource.set(typeID, typeRecord);
273
273
  }
274
+ RelayModernRecord.setValue(
275
+ typeRecord,
276
+ abstractKey,
277
+ implementsInterface,
278
+ );
274
279
  break;
275
280
  }
276
281
  case LINKED_HANDLE:
@@ -281,13 +286,17 @@ class RelayResponseNormalizer {
281
286
  const fieldKey = getStorageKey(selection, this._variables);
282
287
  const handleKey = getHandleStorageKey(selection, this._variables);
283
288
  this._handleFieldPayloads.push({
289
+ /* $FlowFixMe[class-object-subtyping] added when improving typing
290
+ * for this parameters */
284
291
  args,
285
292
  dataID: RelayModernRecord.getDataID(record),
286
293
  fieldKey,
287
294
  handle: selection.handle,
288
295
  handleKey,
289
296
  handleArgs: selection.handleArgs
290
- ? getArgumentValues(selection.handleArgs, this._variables)
297
+ ? /* $FlowFixMe[class-object-subtyping] added when improving typing
298
+ * for this parameters */
299
+ getArgumentValues(selection.handleArgs, this._variables)
291
300
  : {},
292
301
  });
293
302
  break;
@@ -319,6 +328,9 @@ class RelayResponseNormalizer {
319
328
  throw new Error('Flight fields are not yet supported.');
320
329
  }
321
330
  break;
331
+ case ACTOR_CHANGE:
332
+ this._normalizeActorChange(node, selection, record, data);
333
+ break;
322
334
  default:
323
335
  (selection: empty);
324
336
  invariant(
@@ -362,6 +374,7 @@ class RelayResponseNormalizer {
362
374
  this._variables,
363
375
  ),
364
376
  typeName: RelayModernRecord.getType(record),
377
+ actorIdentifier: this._actorIdentifier,
365
378
  });
366
379
  }
367
380
  }
@@ -394,6 +407,7 @@ class RelayResponseNormalizer {
394
407
  parentID: RelayModernRecord.getDataID(record),
395
408
  node: stream,
396
409
  variables: this._variables,
410
+ actorIdentifier: this._actorIdentifier,
397
411
  });
398
412
  }
399
413
  }
@@ -424,13 +438,16 @@ class RelayResponseNormalizer {
424
438
  operationReference ?? null,
425
439
  );
426
440
  if (operationReference != null) {
427
- this._moduleImportPayloads.push({
441
+ this._followupPayloads.push({
442
+ kind: 'ModuleImportPayload',
443
+ args: moduleImport.args,
428
444
  data,
429
445
  dataID: RelayModernRecord.getDataID(record),
430
446
  operationReference,
431
447
  path: [...this._path],
432
448
  typeName,
433
449
  variables: this._variables,
450
+ actorIdentifier: this._actorIdentifier,
434
451
  });
435
452
  }
436
453
  }
@@ -488,7 +505,11 @@ class RelayResponseNormalizer {
488
505
  this._validateConflictingFieldsWithIdenticalId(
489
506
  record,
490
507
  storageKey,
491
- fieldValue,
508
+ // When using `treatMissingFieldsAsNull` the conflicting validation raises a false positive
509
+ // because the value is set using `null` but validated using `fieldValue` which at this point
510
+ // will be `undefined`.
511
+ // Setting this to `null` matches the value that we actually set to the `fieldValue`.
512
+ null,
492
513
  );
493
514
  }
494
515
  }
@@ -523,6 +544,99 @@ class RelayResponseNormalizer {
523
544
  }
524
545
  }
525
546
 
547
+ _normalizeActorChange(
548
+ parent: NormalizationNode,
549
+ selection: NormalizationActorChange,
550
+ record: Record,
551
+ data: PayloadData,
552
+ ) {
553
+ const field = selection.linkedField;
554
+ invariant(
555
+ typeof data === 'object' && data,
556
+ '_normalizeActorChange(): Expected data for field `%s` to be an object.',
557
+ field.name,
558
+ );
559
+ const responseKey = field.alias || field.name;
560
+ const storageKey = getStorageKey(field, this._variables);
561
+ const fieldValue = data[responseKey];
562
+
563
+ if (fieldValue == null) {
564
+ if (fieldValue === undefined) {
565
+ const isOptionalField =
566
+ this._isClientExtension || this._isUnmatchedAbstractType;
567
+
568
+ if (isOptionalField) {
569
+ return;
570
+ } else if (!this._treatMissingFieldsAsNull) {
571
+ if (__DEV__) {
572
+ warning(
573
+ false,
574
+ 'RelayResponseNormalizer: Payload did not contain a value ' +
575
+ 'for field `%s: %s`. Check that you are parsing with the same ' +
576
+ 'query that was used to fetch the payload.',
577
+ responseKey,
578
+ storageKey,
579
+ );
580
+ }
581
+ return;
582
+ }
583
+ }
584
+ RelayModernRecord.setValue(record, storageKey, null);
585
+ return;
586
+ }
587
+
588
+ const actorIdentifier = getActorIdentifierFromPayload(fieldValue);
589
+ if (actorIdentifier == null) {
590
+ if (__DEV__) {
591
+ warning(
592
+ false,
593
+ 'RelayResponseNormalizer: Payload did not contain a value ' +
594
+ 'for field `%s`. Check that you are parsing with the same ' +
595
+ 'query that was used to fetch the payload. Payload is `%s`.',
596
+ ACTOR_IDENTIFIER_FIELD_NAME,
597
+ JSON.stringify(fieldValue, null, 2),
598
+ );
599
+ }
600
+ RelayModernRecord.setValue(record, storageKey, null);
601
+ return;
602
+ }
603
+
604
+ // $FlowFixMe[incompatible-call]
605
+ const typeName = field.concreteType ?? this._getRecordType(fieldValue);
606
+ const nextID =
607
+ this._getDataId(
608
+ // $FlowFixMe[incompatible-call]
609
+ fieldValue,
610
+ typeName,
611
+ ) ||
612
+ RelayModernRecord.getLinkedRecordID(record, storageKey) ||
613
+ generateClientID(RelayModernRecord.getDataID(record), storageKey);
614
+
615
+ invariant(
616
+ typeof nextID === 'string',
617
+ 'RelayResponseNormalizer: Expected id on field `%s` to be a string.',
618
+ storageKey,
619
+ );
620
+
621
+ RelayModernRecord.setActorLinkedRecordID(
622
+ record,
623
+ storageKey,
624
+ actorIdentifier,
625
+ nextID,
626
+ );
627
+
628
+ this._followupPayloads.push({
629
+ kind: 'ActorPayload',
630
+ data: (fieldValue: $FlowFixMe),
631
+ dataID: nextID,
632
+ path: [...this._path, responseKey],
633
+ typeName,
634
+ variables: this._variables,
635
+ node: field,
636
+ actorIdentifier,
637
+ });
638
+ }
639
+
526
640
  _normalizeFlightField(
527
641
  parent: NormalizationNode,
528
642
  selection: NormalizationFlightField,
@@ -546,20 +660,17 @@ class RelayResponseNormalizer {
546
660
  // Field not expected to exist regardless of whether the server is pruning null
547
661
  // fields or not.
548
662
  return;
549
- } else if (!this._treatMissingFieldsAsNull) {
663
+ } else {
550
664
  // Not optional and the server is not pruning null fields: field is expected
551
665
  // 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;
666
+ invariant(
667
+ this._treatMissingFieldsAsNull,
668
+ 'RelayResponseNormalizer: Payload did not contain a value for ' +
669
+ 'field `%s: %s`. Check that you are parsing with the same ' +
670
+ 'query that was used to fetch the payload.',
671
+ responseKey,
672
+ storageKey,
673
+ );
563
674
  }
564
675
  }
565
676
  RelayModernRecord.setValue(record, storageKey, null);
@@ -655,16 +766,20 @@ class RelayResponseNormalizer {
655
766
  reactFlightClientResponse,
656
767
  );
657
768
 
658
- const reachableExecutableDefinitions: Array<ReactFlightReachableExecutableDefinitions> = [];
769
+ const reachableExecutableDefinitions: Array<ReactFlightReachableExecutableDefinitions> =
770
+ [];
659
771
  for (const query of reactFlightPayload.queries) {
660
772
  if (query.response.data != null) {
661
- this._moduleImportPayloads.push({
773
+ this._followupPayloads.push({
774
+ kind: 'ModuleImportPayload',
775
+ args: null,
662
776
  data: query.response.data,
663
777
  dataID: ROOT_ID,
664
778
  operationReference: query.module,
665
779
  path: [],
666
780
  typeName: ROOT_TYPE,
667
781
  variables: query.variables,
782
+ actorIdentifier: this._actorIdentifier,
668
783
  });
669
784
  }
670
785
  reachableExecutableDefinitions.push({
@@ -674,13 +789,16 @@ class RelayResponseNormalizer {
674
789
  }
675
790
  for (const fragment of reactFlightPayload.fragments) {
676
791
  if (fragment.response.data != null) {
677
- this._moduleImportPayloads.push({
792
+ this._followupPayloads.push({
793
+ kind: 'ModuleImportPayload',
794
+ args: null,
678
795
  data: fragment.response.data,
679
796
  dataID: fragment.__id,
680
797
  operationReference: fragment.module,
681
798
  path: [],
682
799
  typeName: fragment.__typename,
683
800
  variables: fragment.variables,
801
+ actorIdentifier: this._actorIdentifier,
684
802
  });
685
803
  }
686
804
  reachableExecutableDefinitions.push({
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
3
  *
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
@@ -12,13 +12,12 @@
12
12
 
13
13
  'use strict';
14
14
 
15
- const invariant = require('invariant');
16
-
17
- const {getType} = require('./RelayModernRecord');
18
-
19
15
  import type {ReactFlightPayloadData} from '../network/RelayNetworkTypes';
20
16
  import type {ReactFlightClientResponse, Record} from './RelayStoreTypes';
21
17
 
18
+ const {getType} = require('./RelayModernRecord');
19
+ const invariant = require('invariant');
20
+
22
21
  // Reachable (client) executable definitions encountered while server component
23
22
  // rendering
24
23
  const REACT_FLIGHT_EXECUTABLE_DEFINITIONS_STORAGE_KEY = 'executableDefinitions';
@@ -51,13 +50,7 @@ function getReactFlightClientResponse(
51
50
  'got %s.',
52
51
  record,
53
52
  );
54
- const response: ?ReactFlightClientResponse = (record[
55
- REACT_FLIGHT_TREE_STORAGE_KEY
56
- ]: $FlowFixMe);
57
- if (response != null) {
58
- return response;
59
- }
60
- return null;
53
+ return (record[REACT_FLIGHT_TREE_STORAGE_KEY]: $FlowFixMe);
61
54
  }
62
55
 
63
56
  module.exports = {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
3
  *
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
@@ -12,23 +12,23 @@
12
12
 
13
13
  'use strict';
14
14
 
15
- const RelayFeatureFlags = require('../util/RelayFeatureFlags');
16
- const RelayReader = require('./RelayReader');
17
-
18
- const deepFreeze = require('../util/deepFreeze');
19
- const hasOverlappingIDs = require('./hasOverlappingIDs');
20
- const recycleNodesInto = require('../util/recycleNodesInto');
21
-
22
15
  import type {Disposable} from '../util/RelayRuntimeTypes';
23
16
  import type {
17
+ DataIDSet,
24
18
  LogFunction,
25
19
  OperationDescriptor,
26
- DataIDSet,
27
20
  RecordSource,
28
21
  RequestDescriptor,
29
22
  Snapshot,
30
23
  StoreSubscriptions,
31
24
  } from './RelayStoreTypes';
25
+ import type {ResolverCache} from './ResolverCache';
26
+
27
+ const deepFreeze = require('../util/deepFreeze');
28
+ const recycleNodesInto = require('../util/recycleNodesInto');
29
+ const RelayFeatureFlags = require('../util/RelayFeatureFlags');
30
+ const hasOverlappingIDs = require('./hasOverlappingIDs');
31
+ const RelayReader = require('./RelayReader');
32
32
 
33
33
  type Subscription = {|
34
34
  callback: (snapshot: Snapshot) => void,
@@ -40,10 +40,12 @@ type Subscription = {|
40
40
  class RelayStoreSubscriptions implements StoreSubscriptions {
41
41
  _subscriptions: Set<Subscription>;
42
42
  __log: ?LogFunction;
43
+ _resolverCache: ResolverCache;
43
44
 
44
- constructor(log?: ?LogFunction) {
45
+ constructor(log?: ?LogFunction, resolverCache: ResolverCache) {
45
46
  this._subscriptions = new Set();
46
47
  this.__log = log;
48
+ this._resolverCache = resolverCache;
47
49
  }
48
50
 
49
51
  subscribe(
@@ -77,7 +79,11 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
77
79
  return;
78
80
  }
79
81
  const snapshot = subscription.snapshot;
80
- const backup = RelayReader.read(source, snapshot.selector);
82
+ const backup = RelayReader.read(
83
+ source,
84
+ snapshot.selector,
85
+ this._resolverCache,
86
+ );
81
87
  const nextData = recycleNodesInto(snapshot.data, backup.data);
82
88
  (backup: $FlowFixMe).data = nextData; // backup owns the snapshot and can safely mutate
83
89
  subscription.backup = backup;
@@ -95,6 +101,7 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
95
101
  subscription.snapshot = {
96
102
  data: subscription.snapshot.data,
97
103
  isMissingData: backup.isMissingData,
104
+ missingClientEdges: backup.missingClientEdges,
98
105
  seenRecords: backup.seenRecords,
99
106
  selector: backup.selector,
100
107
  missingRequiredFields: backup.missingRequiredFields,
@@ -150,12 +157,13 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
150
157
  }
151
158
  let nextSnapshot: Snapshot =
152
159
  hasOverlappingUpdates || !backup
153
- ? RelayReader.read(source, snapshot.selector)
160
+ ? RelayReader.read(source, snapshot.selector, this._resolverCache)
154
161
  : backup;
155
162
  const nextData = recycleNodesInto(snapshot.data, nextSnapshot.data);
156
163
  nextSnapshot = ({
157
164
  data: nextData,
158
165
  isMissingData: nextSnapshot.isMissingData,
166
+ missingClientEdges: nextSnapshot.missingClientEdges,
159
167
  seenRecords: nextSnapshot.seenRecords,
160
168
  selector: nextSnapshot.selector,
161
169
  missingRequiredFields: nextSnapshot.missingRequiredFields,