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.
- package/handlers/connection/ConnectionHandler.js.flow +7 -0
- package/handlers/connection/MutationHandlers.js.flow +28 -0
- package/index.js +1 -1
- package/index.js.flow +20 -3
- package/lib/handlers/RelayDefaultHandlerProvider.js +1 -1
- package/lib/handlers/connection/ConnectionHandler.js +12 -6
- package/lib/handlers/connection/MutationHandlers.js +67 -8
- package/lib/index.js +15 -0
- package/lib/multi-actor-environment/ActorIdentifier.js +33 -0
- package/lib/multi-actor-environment/ActorSpecificEnvironment.js +148 -0
- package/lib/multi-actor-environment/ActorUtils.js +27 -0
- package/lib/multi-actor-environment/MultiActorEnvironment.js +406 -0
- package/lib/multi-actor-environment/MultiActorEnvironmentTypes.js +11 -0
- package/lib/multi-actor-environment/index.js +21 -0
- package/lib/mutations/RelayRecordProxy.js +1 -1
- package/lib/mutations/RelayRecordSourceMutator.js +1 -1
- package/lib/mutations/RelayRecordSourceProxy.js +1 -1
- package/lib/mutations/RelayRecordSourceSelectorProxy.js +7 -2
- package/lib/mutations/applyOptimisticMutation.js +1 -1
- package/lib/mutations/commitMutation.js +5 -2
- package/lib/mutations/validateMutation.js +39 -17
- package/lib/network/RelayNetwork.js +1 -1
- package/lib/network/RelayObservable.js +3 -1
- package/lib/network/RelayQueryResponseCache.js +20 -3
- package/lib/network/wrapNetworkWithLogObserver.js +78 -0
- package/lib/query/GraphQLTag.js +1 -1
- package/lib/query/fetchQuery.js +1 -1
- package/lib/query/fetchQueryInternal.js +1 -1
- package/lib/store/DataChecker.js +132 -50
- package/lib/store/{RelayModernQueryExecutor.js → OperationExecutor.js} +524 -187
- package/lib/store/RelayConcreteVariables.js +29 -4
- package/lib/store/RelayModernEnvironment.js +137 -220
- package/lib/store/RelayModernFragmentSpecResolver.js +49 -23
- package/lib/store/RelayModernRecord.js +36 -2
- package/lib/store/RelayModernSelector.js +1 -1
- package/lib/store/RelayModernStore.js +53 -22
- package/lib/store/RelayOperationTracker.js +34 -24
- package/lib/store/RelayPublishQueue.js +30 -8
- package/lib/store/RelayReader.js +177 -29
- package/lib/store/RelayRecordSource.js +87 -3
- package/lib/store/RelayReferenceMarker.js +53 -28
- package/lib/store/RelayResponseNormalizer.js +247 -108
- package/lib/store/RelayStoreReactFlightUtils.js +7 -11
- package/lib/store/RelayStoreSubscriptions.js +8 -5
- package/lib/store/RelayStoreUtils.js +10 -4
- package/lib/store/ResolverCache.js +213 -0
- package/lib/store/ResolverFragments.js +57 -0
- package/lib/store/cloneRelayHandleSourceField.js +1 -1
- package/lib/store/cloneRelayScalarHandleSourceField.js +1 -1
- package/lib/store/createRelayContext.js +2 -2
- package/lib/store/defaultGetDataID.js +3 -1
- package/lib/store/readInlineData.js +1 -1
- package/lib/subscription/requestSubscription.js +32 -6
- package/lib/util/RelayConcreteNode.js +3 -0
- package/lib/util/RelayFeatureFlags.js +5 -4
- package/lib/util/RelayProfiler.js +17 -187
- package/lib/util/RelayReplaySubject.js +22 -7
- package/lib/util/deepFreeze.js +1 -0
- package/lib/util/getPaginationMetadata.js +41 -0
- package/lib/util/getPaginationVariables.js +67 -0
- package/lib/util/getPendingOperationsForFragment.js +55 -0
- package/lib/util/getRefetchMetadata.js +36 -0
- package/lib/util/getRelayHandleKey.js +1 -1
- package/lib/util/getRequestIdentifier.js +1 -1
- package/lib/util/getValueAtPath.js +51 -0
- package/lib/util/isEmptyObject.js +1 -1
- package/lib/util/registerEnvironmentWithDevTools.js +26 -0
- package/lib/util/withDuration.js +31 -0
- package/multi-actor-environment/ActorIdentifier.js.flow +43 -0
- package/multi-actor-environment/ActorSpecificEnvironment.js.flow +217 -0
- package/multi-actor-environment/ActorUtils.js.flow +33 -0
- package/multi-actor-environment/MultiActorEnvironment.js.flow +485 -0
- package/multi-actor-environment/MultiActorEnvironmentTypes.js.flow +245 -0
- package/multi-actor-environment/index.js.flow +27 -0
- package/mutations/RelayRecordSourceSelectorProxy.js.flow +7 -2
- package/mutations/commitMutation.js.flow +3 -1
- package/mutations/validateMutation.js.flow +42 -16
- package/network/RelayNetworkTypes.js.flow +17 -8
- package/network/RelayObservable.js.flow +2 -0
- package/network/RelayQueryResponseCache.js.flow +31 -17
- package/network/wrapNetworkWithLogObserver.js.flow +99 -0
- package/package.json +3 -2
- package/relay-runtime.js +2 -2
- package/relay-runtime.min.js +2 -2
- package/store/ClientID.js.flow +5 -1
- package/store/DataChecker.js.flow +148 -44
- package/store/{RelayModernQueryExecutor.js.flow → OperationExecutor.js.flow} +578 -237
- package/store/RelayConcreteVariables.js.flow +31 -1
- package/store/RelayModernEnvironment.js.flow +132 -220
- package/store/RelayModernFragmentSpecResolver.js.flow +40 -14
- package/store/RelayModernOperationDescriptor.js.flow +9 -3
- package/store/RelayModernRecord.js.flow +49 -0
- package/store/RelayModernStore.js.flow +57 -17
- package/store/RelayOperationTracker.js.flow +56 -34
- package/store/RelayPublishQueue.js.flow +37 -11
- package/store/RelayReader.js.flow +186 -27
- package/store/RelayRecordSource.js.flow +72 -6
- package/store/RelayReferenceMarker.js.flow +51 -21
- package/store/RelayResponseNormalizer.js.flow +251 -67
- package/store/RelayStoreReactFlightUtils.js.flow +6 -9
- package/store/RelayStoreSubscriptions.js.flow +10 -3
- package/store/RelayStoreTypes.js.flow +144 -21
- package/store/RelayStoreUtils.js.flow +19 -4
- package/store/ResolverCache.js.flow +247 -0
- package/store/ResolverFragments.js.flow +128 -0
- package/store/createRelayContext.js.flow +1 -1
- package/store/defaultGetDataID.js.flow +3 -1
- package/subscription/requestSubscription.js.flow +43 -8
- package/util/NormalizationNode.js.flow +16 -3
- package/util/ReaderNode.js.flow +29 -2
- package/util/RelayConcreteNode.js.flow +3 -0
- package/util/RelayFeatureFlags.js.flow +10 -6
- package/util/RelayProfiler.js.flow +22 -194
- package/util/RelayReplaySubject.js.flow +7 -6
- package/util/RelayRuntimeTypes.js.flow +4 -2
- package/util/deepFreeze.js.flow +2 -1
- package/util/getPaginationMetadata.js.flow +74 -0
- package/util/getPaginationVariables.js.flow +112 -0
- package/util/getPendingOperationsForFragment.js.flow +62 -0
- package/util/getRefetchMetadata.js.flow +80 -0
- package/util/getValueAtPath.js.flow +46 -0
- package/util/isEmptyObject.js.flow +2 -1
- package/util/registerEnvironmentWithDevTools.js.flow +33 -0
- package/util/withDuration.js.flow +32 -0
- package/lib/store/RelayRecordSourceMapImpl.js +0 -107
- package/lib/store/RelayStoreSubscriptionsUsingMapByID.js +0 -318
- package/store/RelayRecordSourceMapImpl.js.flow +0 -91
- package/store/RelayStoreSubscriptionsUsingMapByID.js.flow +0 -283
|
@@ -14,14 +14,19 @@
|
|
|
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');
|
|
21
20
|
const warning = require('warning');
|
|
22
21
|
|
|
23
22
|
const {
|
|
23
|
+
ACTOR_IDENTIFIER_FIELD_NAME,
|
|
24
|
+
getActorIdentifierFromPayload,
|
|
25
|
+
} = require('../multi-actor-environment/ActorUtils');
|
|
26
|
+
const {
|
|
27
|
+
ACTOR_CHANGE,
|
|
24
28
|
CONDITION,
|
|
29
|
+
CLIENT_COMPONENT,
|
|
25
30
|
CLIENT_EXTENSION,
|
|
26
31
|
DEFER,
|
|
27
32
|
FLIGHT_FIELD,
|
|
@@ -36,10 +41,11 @@ const {
|
|
|
36
41
|
TYPE_DISCRIMINATOR,
|
|
37
42
|
} = require('../util/RelayConcreteNode');
|
|
38
43
|
const {generateClientID, isClientID} = require('./ClientID');
|
|
44
|
+
const {getLocalVariables} = require('./RelayConcreteVariables');
|
|
39
45
|
const {createNormalizationSelector} = require('./RelayModernSelector');
|
|
40
46
|
const {
|
|
41
47
|
refineToReactFlightPayloadData,
|
|
42
|
-
|
|
48
|
+
REACT_FLIGHT_EXECUTABLE_DEFINITIONS_STORAGE_KEY,
|
|
43
49
|
REACT_FLIGHT_TREE_STORAGE_KEY,
|
|
44
50
|
REACT_FLIGHT_TYPE_NAME,
|
|
45
51
|
} = require('./RelayStoreReactFlightUtils');
|
|
@@ -55,8 +61,10 @@ const {
|
|
|
55
61
|
} = require('./RelayStoreUtils');
|
|
56
62
|
const {generateTypeID, TYPE_SCHEMA_TYPE} = require('./TypeID');
|
|
57
63
|
|
|
64
|
+
import type {ActorIdentifier} from '../multi-actor-environment/ActorIdentifier';
|
|
58
65
|
import type {PayloadData} from '../network/RelayNetworkTypes';
|
|
59
66
|
import type {
|
|
67
|
+
NormalizationActorChange,
|
|
60
68
|
NormalizationDefer,
|
|
61
69
|
NormalizationFlightField,
|
|
62
70
|
NormalizationLinkedField,
|
|
@@ -67,20 +75,20 @@ import type {
|
|
|
67
75
|
} from '../util/NormalizationNode';
|
|
68
76
|
import type {DataID, Variables} from '../util/RelayRuntimeTypes';
|
|
69
77
|
import type {
|
|
78
|
+
FollowupPayload,
|
|
70
79
|
HandleFieldPayload,
|
|
71
80
|
IncrementalDataPlaceholder,
|
|
72
|
-
ModuleImportPayload,
|
|
73
81
|
MutableRecordSource,
|
|
74
82
|
NormalizationSelector,
|
|
75
|
-
ReactFlightReachableQuery,
|
|
76
83
|
ReactFlightPayloadDeserializer,
|
|
84
|
+
ReactFlightReachableExecutableDefinitions,
|
|
77
85
|
ReactFlightServerErrorHandler,
|
|
78
86
|
Record,
|
|
79
87
|
RelayResponsePayload,
|
|
80
88
|
} from './RelayStoreTypes';
|
|
81
89
|
|
|
82
90
|
export type GetDataID = (
|
|
83
|
-
fieldValue: {[string]: mixed
|
|
91
|
+
fieldValue: interface {[string]: mixed},
|
|
84
92
|
typeName: string,
|
|
85
93
|
) => mixed;
|
|
86
94
|
|
|
@@ -90,6 +98,8 @@ export type NormalizationOptions = {|
|
|
|
90
98
|
+path?: $ReadOnlyArray<string>,
|
|
91
99
|
+reactFlightPayloadDeserializer?: ?ReactFlightPayloadDeserializer,
|
|
92
100
|
+reactFlightServerErrorHandler?: ?ReactFlightServerErrorHandler,
|
|
101
|
+
+shouldProcessClientComponents?: ?boolean,
|
|
102
|
+
+actorIdentifier?: ?ActorIdentifier,
|
|
93
103
|
|};
|
|
94
104
|
|
|
95
105
|
/**
|
|
@@ -117,37 +127,41 @@ function normalize(
|
|
|
117
127
|
* Helper for handling payloads.
|
|
118
128
|
*/
|
|
119
129
|
class RelayResponseNormalizer {
|
|
130
|
+
_actorIdentifier: ?ActorIdentifier;
|
|
120
131
|
_getDataId: GetDataID;
|
|
121
132
|
_handleFieldPayloads: Array<HandleFieldPayload>;
|
|
122
133
|
_treatMissingFieldsAsNull: boolean;
|
|
123
134
|
_incrementalPlaceholders: Array<IncrementalDataPlaceholder>;
|
|
124
135
|
_isClientExtension: boolean;
|
|
125
136
|
_isUnmatchedAbstractType: boolean;
|
|
126
|
-
|
|
137
|
+
_followupPayloads: Array<FollowupPayload>;
|
|
127
138
|
_path: Array<string>;
|
|
128
139
|
_recordSource: MutableRecordSource;
|
|
129
140
|
_variables: Variables;
|
|
130
141
|
_reactFlightPayloadDeserializer: ?ReactFlightPayloadDeserializer;
|
|
131
142
|
_reactFlightServerErrorHandler: ?ReactFlightServerErrorHandler;
|
|
143
|
+
_shouldProcessClientComponents: ?boolean;
|
|
132
144
|
|
|
133
145
|
constructor(
|
|
134
146
|
recordSource: MutableRecordSource,
|
|
135
147
|
variables: Variables,
|
|
136
148
|
options: NormalizationOptions,
|
|
137
149
|
) {
|
|
150
|
+
this._actorIdentifier = options.actorIdentifier;
|
|
138
151
|
this._getDataId = options.getDataID;
|
|
139
152
|
this._handleFieldPayloads = [];
|
|
140
153
|
this._treatMissingFieldsAsNull = options.treatMissingFieldsAsNull;
|
|
141
154
|
this._incrementalPlaceholders = [];
|
|
142
155
|
this._isClientExtension = false;
|
|
143
156
|
this._isUnmatchedAbstractType = false;
|
|
144
|
-
this.
|
|
157
|
+
this._followupPayloads = [];
|
|
145
158
|
this._path = options.path ? [...options.path] : [];
|
|
146
159
|
this._recordSource = recordSource;
|
|
147
160
|
this._variables = variables;
|
|
148
161
|
this._reactFlightPayloadDeserializer =
|
|
149
162
|
options.reactFlightPayloadDeserializer;
|
|
150
163
|
this._reactFlightServerErrorHandler = options.reactFlightServerErrorHandler;
|
|
164
|
+
this._shouldProcessClientComponents = options.shouldProcessClientComponents;
|
|
151
165
|
}
|
|
152
166
|
|
|
153
167
|
normalizeResponse(
|
|
@@ -166,7 +180,7 @@ class RelayResponseNormalizer {
|
|
|
166
180
|
errors: null,
|
|
167
181
|
fieldPayloads: this._handleFieldPayloads,
|
|
168
182
|
incrementalPlaceholders: this._incrementalPlaceholders,
|
|
169
|
-
|
|
183
|
+
followupPayloads: this._followupPayloads,
|
|
170
184
|
source: this._recordSource,
|
|
171
185
|
isFinal: false,
|
|
172
186
|
};
|
|
@@ -178,6 +192,7 @@ class RelayResponseNormalizer {
|
|
|
178
192
|
'RelayResponseNormalizer(): Undefined variable `%s`.',
|
|
179
193
|
name,
|
|
180
194
|
);
|
|
195
|
+
// $FlowFixMe[cannot-write]
|
|
181
196
|
return this._variables[name];
|
|
182
197
|
}
|
|
183
198
|
|
|
@@ -204,13 +219,22 @@ class RelayResponseNormalizer {
|
|
|
204
219
|
this._normalizeField(node, selection, record, data);
|
|
205
220
|
break;
|
|
206
221
|
case CONDITION:
|
|
207
|
-
const conditionValue =
|
|
222
|
+
const conditionValue = Boolean(
|
|
223
|
+
this._getVariableValue(selection.condition),
|
|
224
|
+
);
|
|
208
225
|
if (conditionValue === selection.passingValue) {
|
|
209
226
|
this._traverseSelections(selection, record, data);
|
|
210
227
|
}
|
|
211
228
|
break;
|
|
212
229
|
case FRAGMENT_SPREAD: {
|
|
230
|
+
const prevVariables = this._variables;
|
|
231
|
+
this._variables = getLocalVariables(
|
|
232
|
+
this._variables,
|
|
233
|
+
selection.fragment.argumentDefinitions,
|
|
234
|
+
selection.args,
|
|
235
|
+
);
|
|
213
236
|
this._traverseSelections(selection.fragment, record, data);
|
|
237
|
+
this._variables = prevVariables;
|
|
214
238
|
break;
|
|
215
239
|
}
|
|
216
240
|
case INLINE_FRAGMENT: {
|
|
@@ -220,7 +244,7 @@ class RelayResponseNormalizer {
|
|
|
220
244
|
if (typeName === selection.type) {
|
|
221
245
|
this._traverseSelections(selection, record, data);
|
|
222
246
|
}
|
|
223
|
-
} else
|
|
247
|
+
} else {
|
|
224
248
|
const implementsInterface = data.hasOwnProperty(abstractKey);
|
|
225
249
|
const typeName = RelayModernRecord.getType(record);
|
|
226
250
|
const typeID = generateTypeID(typeName);
|
|
@@ -237,36 +261,24 @@ class RelayResponseNormalizer {
|
|
|
237
261
|
if (implementsInterface) {
|
|
238
262
|
this._traverseSelections(selection, record, data);
|
|
239
263
|
}
|
|
240
|
-
} else {
|
|
241
|
-
// legacy behavior for abstract refinements: always normalize even
|
|
242
|
-
// if the type doesn't conform, but track if the type matches or not
|
|
243
|
-
// for determining whether response fields are expected to be present
|
|
244
|
-
const implementsInterface = data.hasOwnProperty(abstractKey);
|
|
245
|
-
const parentIsUnmatchedAbstractType = this._isUnmatchedAbstractType;
|
|
246
|
-
this._isUnmatchedAbstractType =
|
|
247
|
-
this._isUnmatchedAbstractType || !implementsInterface;
|
|
248
|
-
this._traverseSelections(selection, record, data);
|
|
249
|
-
this._isUnmatchedAbstractType = parentIsUnmatchedAbstractType;
|
|
250
264
|
}
|
|
251
265
|
break;
|
|
252
266
|
}
|
|
253
267
|
case TYPE_DISCRIMINATOR: {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
this._recordSource.set(typeID, typeRecord);
|
|
263
|
-
}
|
|
264
|
-
RelayModernRecord.setValue(
|
|
265
|
-
typeRecord,
|
|
266
|
-
abstractKey,
|
|
267
|
-
implementsInterface,
|
|
268
|
-
);
|
|
268
|
+
const {abstractKey} = selection;
|
|
269
|
+
const implementsInterface = data.hasOwnProperty(abstractKey);
|
|
270
|
+
const typeName = RelayModernRecord.getType(record);
|
|
271
|
+
const typeID = generateTypeID(typeName);
|
|
272
|
+
let typeRecord = this._recordSource.get(typeID);
|
|
273
|
+
if (typeRecord == null) {
|
|
274
|
+
typeRecord = RelayModernRecord.create(typeID, TYPE_SCHEMA_TYPE);
|
|
275
|
+
this._recordSource.set(typeID, typeRecord);
|
|
269
276
|
}
|
|
277
|
+
RelayModernRecord.setValue(
|
|
278
|
+
typeRecord,
|
|
279
|
+
abstractKey,
|
|
280
|
+
implementsInterface,
|
|
281
|
+
);
|
|
270
282
|
break;
|
|
271
283
|
}
|
|
272
284
|
case LINKED_HANDLE:
|
|
@@ -277,13 +289,17 @@ class RelayResponseNormalizer {
|
|
|
277
289
|
const fieldKey = getStorageKey(selection, this._variables);
|
|
278
290
|
const handleKey = getHandleStorageKey(selection, this._variables);
|
|
279
291
|
this._handleFieldPayloads.push({
|
|
292
|
+
/* $FlowFixMe[class-object-subtyping] added when improving typing
|
|
293
|
+
* for this parameters */
|
|
280
294
|
args,
|
|
281
295
|
dataID: RelayModernRecord.getDataID(record),
|
|
282
296
|
fieldKey,
|
|
283
297
|
handle: selection.handle,
|
|
284
298
|
handleKey,
|
|
285
299
|
handleArgs: selection.handleArgs
|
|
286
|
-
?
|
|
300
|
+
? /* $FlowFixMe[class-object-subtyping] added when improving typing
|
|
301
|
+
* for this parameters */
|
|
302
|
+
getArgumentValues(selection.handleArgs, this._variables)
|
|
287
303
|
: {},
|
|
288
304
|
});
|
|
289
305
|
break;
|
|
@@ -302,6 +318,12 @@ class RelayResponseNormalizer {
|
|
|
302
318
|
this._traverseSelections(selection, record, data);
|
|
303
319
|
this._isClientExtension = isClientExtension;
|
|
304
320
|
break;
|
|
321
|
+
case CLIENT_COMPONENT:
|
|
322
|
+
if (this._shouldProcessClientComponents === false) {
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
this._traverseSelections(selection.fragment, record, data);
|
|
326
|
+
break;
|
|
305
327
|
case FLIGHT_FIELD:
|
|
306
328
|
if (RelayFeatureFlags.ENABLE_REACT_FLIGHT_COMPONENT_FIELD) {
|
|
307
329
|
this._normalizeFlightField(node, selection, record, data);
|
|
@@ -309,6 +331,9 @@ class RelayResponseNormalizer {
|
|
|
309
331
|
throw new Error('Flight fields are not yet supported.');
|
|
310
332
|
}
|
|
311
333
|
break;
|
|
334
|
+
case ACTOR_CHANGE:
|
|
335
|
+
this._normalizeActorChange(node, selection, record, data);
|
|
336
|
+
break;
|
|
312
337
|
default:
|
|
313
338
|
(selection: empty);
|
|
314
339
|
invariant(
|
|
@@ -352,6 +377,7 @@ class RelayResponseNormalizer {
|
|
|
352
377
|
this._variables,
|
|
353
378
|
),
|
|
354
379
|
typeName: RelayModernRecord.getType(record),
|
|
380
|
+
actorIdentifier: this._actorIdentifier,
|
|
355
381
|
});
|
|
356
382
|
}
|
|
357
383
|
}
|
|
@@ -384,6 +410,7 @@ class RelayResponseNormalizer {
|
|
|
384
410
|
parentID: RelayModernRecord.getDataID(record),
|
|
385
411
|
node: stream,
|
|
386
412
|
variables: this._variables,
|
|
413
|
+
actorIdentifier: this._actorIdentifier,
|
|
387
414
|
});
|
|
388
415
|
}
|
|
389
416
|
}
|
|
@@ -414,13 +441,16 @@ class RelayResponseNormalizer {
|
|
|
414
441
|
operationReference ?? null,
|
|
415
442
|
);
|
|
416
443
|
if (operationReference != null) {
|
|
417
|
-
this.
|
|
444
|
+
this._followupPayloads.push({
|
|
445
|
+
kind: 'ModuleImportPayload',
|
|
446
|
+
args: moduleImport.args,
|
|
418
447
|
data,
|
|
419
448
|
dataID: RelayModernRecord.getDataID(record),
|
|
420
449
|
operationReference,
|
|
421
450
|
path: [...this._path],
|
|
422
451
|
typeName,
|
|
423
452
|
variables: this._variables,
|
|
453
|
+
actorIdentifier: this._actorIdentifier,
|
|
424
454
|
});
|
|
425
455
|
}
|
|
426
456
|
}
|
|
@@ -513,6 +543,99 @@ class RelayResponseNormalizer {
|
|
|
513
543
|
}
|
|
514
544
|
}
|
|
515
545
|
|
|
546
|
+
_normalizeActorChange(
|
|
547
|
+
parent: NormalizationNode,
|
|
548
|
+
selection: NormalizationActorChange,
|
|
549
|
+
record: Record,
|
|
550
|
+
data: PayloadData,
|
|
551
|
+
) {
|
|
552
|
+
const field = selection.linkedField;
|
|
553
|
+
invariant(
|
|
554
|
+
typeof data === 'object' && data,
|
|
555
|
+
'_normalizeActorChange(): Expected data for field `%s` to be an object.',
|
|
556
|
+
field.name,
|
|
557
|
+
);
|
|
558
|
+
const responseKey = field.alias || field.name;
|
|
559
|
+
const storageKey = getStorageKey(field, this._variables);
|
|
560
|
+
const fieldValue = data[responseKey];
|
|
561
|
+
|
|
562
|
+
if (fieldValue == null) {
|
|
563
|
+
if (fieldValue === undefined) {
|
|
564
|
+
const isOptionalField =
|
|
565
|
+
this._isClientExtension || this._isUnmatchedAbstractType;
|
|
566
|
+
|
|
567
|
+
if (isOptionalField) {
|
|
568
|
+
return;
|
|
569
|
+
} else if (!this._treatMissingFieldsAsNull) {
|
|
570
|
+
if (__DEV__) {
|
|
571
|
+
warning(
|
|
572
|
+
false,
|
|
573
|
+
'RelayResponseNormalizer: Payload did not contain a value ' +
|
|
574
|
+
'for field `%s: %s`. Check that you are parsing with the same ' +
|
|
575
|
+
'query that was used to fetch the payload.',
|
|
576
|
+
responseKey,
|
|
577
|
+
storageKey,
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
RelayModernRecord.setValue(record, storageKey, null);
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
const actorIdentifier = getActorIdentifierFromPayload(fieldValue);
|
|
588
|
+
if (actorIdentifier == null) {
|
|
589
|
+
if (__DEV__) {
|
|
590
|
+
warning(
|
|
591
|
+
false,
|
|
592
|
+
'RelayResponseNormalizer: Payload did not contain a value ' +
|
|
593
|
+
'for field `%s`. Check that you are parsing with the same ' +
|
|
594
|
+
'query that was used to fetch the payload. Payload is `%s`.',
|
|
595
|
+
ACTOR_IDENTIFIER_FIELD_NAME,
|
|
596
|
+
JSON.stringify(fieldValue, null, 2),
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
RelayModernRecord.setValue(record, storageKey, null);
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// $FlowFixMe[incompatible-call]
|
|
604
|
+
const typeName = field.concreteType ?? this._getRecordType(fieldValue);
|
|
605
|
+
const nextID =
|
|
606
|
+
this._getDataId(
|
|
607
|
+
// $FlowFixMe[incompatible-call]
|
|
608
|
+
fieldValue,
|
|
609
|
+
typeName,
|
|
610
|
+
) ||
|
|
611
|
+
RelayModernRecord.getLinkedRecordID(record, storageKey) ||
|
|
612
|
+
generateClientID(RelayModernRecord.getDataID(record), storageKey);
|
|
613
|
+
|
|
614
|
+
invariant(
|
|
615
|
+
typeof nextID === 'string',
|
|
616
|
+
'RelayResponseNormalizer: Expected id on field `%s` to be a string.',
|
|
617
|
+
storageKey,
|
|
618
|
+
);
|
|
619
|
+
|
|
620
|
+
RelayModernRecord.setActorLinkedRecordID(
|
|
621
|
+
record,
|
|
622
|
+
storageKey,
|
|
623
|
+
actorIdentifier,
|
|
624
|
+
nextID,
|
|
625
|
+
);
|
|
626
|
+
|
|
627
|
+
this._followupPayloads.push({
|
|
628
|
+
kind: 'ActorPayload',
|
|
629
|
+
data: (fieldValue: $FlowFixMe),
|
|
630
|
+
dataID: nextID,
|
|
631
|
+
path: [...this._path, responseKey],
|
|
632
|
+
typeName,
|
|
633
|
+
variables: this._variables,
|
|
634
|
+
node: field,
|
|
635
|
+
actorIdentifier,
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
|
|
516
639
|
_normalizeFlightField(
|
|
517
640
|
parent: NormalizationNode,
|
|
518
641
|
selection: NormalizationFlightField,
|
|
@@ -524,11 +647,37 @@ class RelayResponseNormalizer {
|
|
|
524
647
|
const fieldValue = data[responseKey];
|
|
525
648
|
|
|
526
649
|
if (fieldValue == null) {
|
|
650
|
+
if (fieldValue === undefined) {
|
|
651
|
+
// Flight field may be missing in the response if:
|
|
652
|
+
// - It is inside an abstract type refinement where the concrete type does
|
|
653
|
+
// not conform to the interface/union.
|
|
654
|
+
// However an otherwise-required field may also be missing if the server
|
|
655
|
+
// is configured to skip fields with `null` values, in which case the
|
|
656
|
+
// client is assumed to be correctly configured with
|
|
657
|
+
// treatMissingFieldsAsNull=true.
|
|
658
|
+
if (this._isUnmatchedAbstractType) {
|
|
659
|
+
// Field not expected to exist regardless of whether the server is pruning null
|
|
660
|
+
// fields or not.
|
|
661
|
+
return;
|
|
662
|
+
} else {
|
|
663
|
+
// Not optional and the server is not pruning null fields: field is expected
|
|
664
|
+
// to be present
|
|
665
|
+
invariant(
|
|
666
|
+
this._treatMissingFieldsAsNull,
|
|
667
|
+
'RelayResponseNormalizer: Payload did not contain a value for ' +
|
|
668
|
+
'field `%s: %s`. Check that you are parsing with the same ' +
|
|
669
|
+
'query that was used to fetch the payload.',
|
|
670
|
+
responseKey,
|
|
671
|
+
storageKey,
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
527
675
|
RelayModernRecord.setValue(record, storageKey, null);
|
|
528
676
|
return;
|
|
529
677
|
}
|
|
530
678
|
|
|
531
679
|
const reactFlightPayload = refineToReactFlightPayloadData(fieldValue);
|
|
680
|
+
const reactFlightPayloadDeserializer = this._reactFlightPayloadDeserializer;
|
|
532
681
|
|
|
533
682
|
invariant(
|
|
534
683
|
reactFlightPayload != null,
|
|
@@ -538,10 +687,10 @@ class RelayResponseNormalizer {
|
|
|
538
687
|
fieldValue,
|
|
539
688
|
);
|
|
540
689
|
invariant(
|
|
541
|
-
typeof
|
|
690
|
+
typeof reactFlightPayloadDeserializer === 'function',
|
|
542
691
|
'RelayResponseNormalizer: Expected reactFlightPayloadDeserializer to ' +
|
|
543
692
|
'be a function, got `%s`.',
|
|
544
|
-
|
|
693
|
+
reactFlightPayloadDeserializer,
|
|
545
694
|
);
|
|
546
695
|
|
|
547
696
|
if (reactFlightPayload.errors.length > 0) {
|
|
@@ -562,65 +711,103 @@ class RelayResponseNormalizer {
|
|
|
562
711
|
}
|
|
563
712
|
}
|
|
564
713
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
714
|
+
const reactFlightID = generateClientID(
|
|
715
|
+
RelayModernRecord.getDataID(record),
|
|
716
|
+
getStorageKey(selection, this._variables),
|
|
717
|
+
);
|
|
718
|
+
let reactFlightClientResponseRecord = this._recordSource.get(reactFlightID);
|
|
719
|
+
if (reactFlightClientResponseRecord == null) {
|
|
720
|
+
reactFlightClientResponseRecord = RelayModernRecord.create(
|
|
721
|
+
reactFlightID,
|
|
722
|
+
REACT_FLIGHT_TYPE_NAME,
|
|
723
|
+
);
|
|
724
|
+
this._recordSource.set(reactFlightID, reactFlightClientResponseRecord);
|
|
725
|
+
}
|
|
726
|
+
|
|
570
727
|
if (reactFlightPayload.tree == null) {
|
|
728
|
+
// This typically indicates that a fatal server error prevented rows from
|
|
729
|
+
// being written. When this occurs, we should not continue normalization of
|
|
730
|
+
// the Flight field because the row response is malformed.
|
|
731
|
+
//
|
|
732
|
+
// Receiving empty rows is OK because it can indicate the start of a stream.
|
|
571
733
|
warning(
|
|
572
734
|
false,
|
|
573
735
|
'RelayResponseNormalizer: Expected `tree` not to be null. This ' +
|
|
574
736
|
'typically indicates that a fatal server error prevented any Server ' +
|
|
575
737
|
'Component rows from being written.',
|
|
576
738
|
);
|
|
739
|
+
// We create the flight record with a null value for the tree
|
|
740
|
+
// and empty reachable definitions
|
|
741
|
+
RelayModernRecord.setValue(
|
|
742
|
+
reactFlightClientResponseRecord,
|
|
743
|
+
REACT_FLIGHT_TREE_STORAGE_KEY,
|
|
744
|
+
null,
|
|
745
|
+
);
|
|
746
|
+
RelayModernRecord.setValue(
|
|
747
|
+
reactFlightClientResponseRecord,
|
|
748
|
+
REACT_FLIGHT_EXECUTABLE_DEFINITIONS_STORAGE_KEY,
|
|
749
|
+
[],
|
|
750
|
+
);
|
|
751
|
+
RelayModernRecord.setLinkedRecordID(record, storageKey, reactFlightID);
|
|
577
752
|
return;
|
|
578
753
|
}
|
|
579
754
|
|
|
580
755
|
// We store the deserialized reactFlightClientResponse in a separate
|
|
581
756
|
// record and link it to the parent record. This is so we can GC the Flight
|
|
582
757
|
// tree later even if the parent record is still reachable.
|
|
583
|
-
const reactFlightClientResponse =
|
|
758
|
+
const reactFlightClientResponse = reactFlightPayloadDeserializer(
|
|
584
759
|
reactFlightPayload.tree,
|
|
585
760
|
);
|
|
586
|
-
|
|
587
|
-
RelayModernRecord.getDataID(record),
|
|
588
|
-
getStorageKey(selection, this._variables),
|
|
589
|
-
);
|
|
590
|
-
let reactFlightClientResponseRecord = this._recordSource.get(reactFlightID);
|
|
591
|
-
if (reactFlightClientResponseRecord == null) {
|
|
592
|
-
reactFlightClientResponseRecord = RelayModernRecord.create(
|
|
593
|
-
reactFlightID,
|
|
594
|
-
REACT_FLIGHT_TYPE_NAME,
|
|
595
|
-
);
|
|
596
|
-
this._recordSource.set(reactFlightID, reactFlightClientResponseRecord);
|
|
597
|
-
}
|
|
761
|
+
|
|
598
762
|
RelayModernRecord.setValue(
|
|
599
763
|
reactFlightClientResponseRecord,
|
|
600
764
|
REACT_FLIGHT_TREE_STORAGE_KEY,
|
|
601
765
|
reactFlightClientResponse,
|
|
602
766
|
);
|
|
603
|
-
|
|
767
|
+
|
|
768
|
+
const reachableExecutableDefinitions: Array<ReactFlightReachableExecutableDefinitions> = [];
|
|
604
769
|
for (const query of reactFlightPayload.queries) {
|
|
605
770
|
if (query.response.data != null) {
|
|
606
|
-
this.
|
|
771
|
+
this._followupPayloads.push({
|
|
772
|
+
kind: 'ModuleImportPayload',
|
|
773
|
+
args: null,
|
|
607
774
|
data: query.response.data,
|
|
608
775
|
dataID: ROOT_ID,
|
|
609
776
|
operationReference: query.module,
|
|
610
777
|
path: [],
|
|
611
778
|
typeName: ROOT_TYPE,
|
|
612
779
|
variables: query.variables,
|
|
780
|
+
actorIdentifier: this._actorIdentifier,
|
|
613
781
|
});
|
|
614
782
|
}
|
|
615
|
-
|
|
783
|
+
reachableExecutableDefinitions.push({
|
|
616
784
|
module: query.module,
|
|
617
785
|
variables: query.variables,
|
|
618
786
|
});
|
|
619
787
|
}
|
|
788
|
+
for (const fragment of reactFlightPayload.fragments) {
|
|
789
|
+
if (fragment.response.data != null) {
|
|
790
|
+
this._followupPayloads.push({
|
|
791
|
+
kind: 'ModuleImportPayload',
|
|
792
|
+
args: null,
|
|
793
|
+
data: fragment.response.data,
|
|
794
|
+
dataID: fragment.__id,
|
|
795
|
+
operationReference: fragment.module,
|
|
796
|
+
path: [],
|
|
797
|
+
typeName: fragment.__typename,
|
|
798
|
+
variables: fragment.variables,
|
|
799
|
+
actorIdentifier: this._actorIdentifier,
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
reachableExecutableDefinitions.push({
|
|
803
|
+
module: fragment.module,
|
|
804
|
+
variables: fragment.variables,
|
|
805
|
+
});
|
|
806
|
+
}
|
|
620
807
|
RelayModernRecord.setValue(
|
|
621
808
|
reactFlightClientResponseRecord,
|
|
622
|
-
|
|
623
|
-
|
|
809
|
+
REACT_FLIGHT_EXECUTABLE_DEFINITIONS_STORAGE_KEY,
|
|
810
|
+
reachableExecutableDefinitions,
|
|
624
811
|
);
|
|
625
812
|
RelayModernRecord.setLinkedRecordID(record, storageKey, reactFlightID);
|
|
626
813
|
}
|
|
@@ -826,9 +1013,6 @@ class RelayResponseNormalizer {
|
|
|
826
1013
|
}
|
|
827
1014
|
}
|
|
828
1015
|
|
|
829
|
-
|
|
830
|
-
'RelayResponseNormalizer.normalize',
|
|
1016
|
+
module.exports = {
|
|
831
1017
|
normalize,
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
module.exports = {normalize: instrumentedNormalize};
|
|
1018
|
+
};
|
|
@@ -19,7 +19,9 @@ const {getType} = require('./RelayModernRecord');
|
|
|
19
19
|
import type {ReactFlightPayloadData} from '../network/RelayNetworkTypes';
|
|
20
20
|
import type {ReactFlightClientResponse, Record} from './RelayStoreTypes';
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
// Reachable (client) executable definitions encountered while server component
|
|
23
|
+
// rendering
|
|
24
|
+
const REACT_FLIGHT_EXECUTABLE_DEFINITIONS_STORAGE_KEY = 'executableDefinitions';
|
|
23
25
|
const REACT_FLIGHT_TREE_STORAGE_KEY = 'tree';
|
|
24
26
|
const REACT_FLIGHT_TYPE_NAME = 'ReactFlightComponent';
|
|
25
27
|
|
|
@@ -32,6 +34,7 @@ function refineToReactFlightPayloadData(
|
|
|
32
34
|
typeof payload.status !== 'string' ||
|
|
33
35
|
(!Array.isArray(payload.tree) && payload.tree !== null) ||
|
|
34
36
|
!Array.isArray(payload.queries) ||
|
|
37
|
+
!Array.isArray(payload.fragments) ||
|
|
35
38
|
!Array.isArray(payload.errors)
|
|
36
39
|
) {
|
|
37
40
|
return null;
|
|
@@ -48,17 +51,11 @@ function getReactFlightClientResponse(
|
|
|
48
51
|
'got %s.',
|
|
49
52
|
record,
|
|
50
53
|
);
|
|
51
|
-
|
|
52
|
-
REACT_FLIGHT_TREE_STORAGE_KEY
|
|
53
|
-
]: $FlowFixMe);
|
|
54
|
-
if (response != null) {
|
|
55
|
-
return response;
|
|
56
|
-
}
|
|
57
|
-
return null;
|
|
54
|
+
return (record[REACT_FLIGHT_TREE_STORAGE_KEY]: $FlowFixMe);
|
|
58
55
|
}
|
|
59
56
|
|
|
60
57
|
module.exports = {
|
|
61
|
-
|
|
58
|
+
REACT_FLIGHT_EXECUTABLE_DEFINITIONS_STORAGE_KEY,
|
|
62
59
|
REACT_FLIGHT_TREE_STORAGE_KEY,
|
|
63
60
|
REACT_FLIGHT_TYPE_NAME,
|
|
64
61
|
getReactFlightClientResponse,
|
|
@@ -29,6 +29,7 @@ import type {
|
|
|
29
29
|
Snapshot,
|
|
30
30
|
StoreSubscriptions,
|
|
31
31
|
} from './RelayStoreTypes';
|
|
32
|
+
import type {ResolverCache} from './ResolverCache';
|
|
32
33
|
|
|
33
34
|
type Subscription = {|
|
|
34
35
|
callback: (snapshot: Snapshot) => void,
|
|
@@ -40,10 +41,12 @@ type Subscription = {|
|
|
|
40
41
|
class RelayStoreSubscriptions implements StoreSubscriptions {
|
|
41
42
|
_subscriptions: Set<Subscription>;
|
|
42
43
|
__log: ?LogFunction;
|
|
44
|
+
_resolverCache: ResolverCache;
|
|
43
45
|
|
|
44
|
-
constructor(log?: ?LogFunction) {
|
|
46
|
+
constructor(log?: ?LogFunction, resolverCache: ResolverCache) {
|
|
45
47
|
this._subscriptions = new Set();
|
|
46
48
|
this.__log = log;
|
|
49
|
+
this._resolverCache = resolverCache;
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
subscribe(
|
|
@@ -77,7 +80,11 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
|
|
|
77
80
|
return;
|
|
78
81
|
}
|
|
79
82
|
const snapshot = subscription.snapshot;
|
|
80
|
-
const backup = RelayReader.read(
|
|
83
|
+
const backup = RelayReader.read(
|
|
84
|
+
source,
|
|
85
|
+
snapshot.selector,
|
|
86
|
+
this._resolverCache,
|
|
87
|
+
);
|
|
81
88
|
const nextData = recycleNodesInto(snapshot.data, backup.data);
|
|
82
89
|
(backup: $FlowFixMe).data = nextData; // backup owns the snapshot and can safely mutate
|
|
83
90
|
subscription.backup = backup;
|
|
@@ -150,7 +157,7 @@ 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 = ({
|