relay-runtime 10.1.3 → 11.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/handlers/connection/ConnectionHandler.js.flow +60 -0
- package/handlers/connection/MutationHandlers.js.flow +28 -0
- package/index.js +1 -1
- package/index.js.flow +9 -3
- package/lib/handlers/RelayDefaultHandlerProvider.js +1 -1
- package/lib/handlers/connection/ConnectionHandler.js +68 -6
- package/lib/handlers/connection/MutationHandlers.js +67 -8
- package/lib/index.js +3 -0
- package/lib/multi-actor-environment/ActorIdentifier.js +23 -0
- package/lib/multi-actor-environment/ActorSpecificEnvironment.js +108 -0
- package/lib/multi-actor-environment/MultiActorEnvironment.js +156 -0
- package/lib/multi-actor-environment/MultiActorEnvironmentTypes.js +11 -0
- package/lib/multi-actor-environment/index.js +17 -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 +1 -1
- package/lib/mutations/applyOptimisticMutation.js +1 -1
- package/lib/mutations/commitMutation.js +1 -1
- package/lib/mutations/validateMutation.js +36 -15
- package/lib/network/RelayNetwork.js +1 -1
- package/lib/network/RelayQueryResponseCache.js +3 -2
- package/lib/query/GraphQLTag.js +1 -1
- package/lib/query/fetchQuery.js +129 -13
- package/lib/query/fetchQueryInternal.js +3 -4
- package/lib/query/fetchQuery_DEPRECATED.js +39 -0
- package/lib/store/DataChecker.js +26 -14
- package/lib/store/{RelayModernQueryExecutor.js → OperationExecutor.js} +117 -47
- package/lib/store/RelayConcreteVariables.js +8 -4
- package/lib/store/RelayModernEnvironment.js +105 -136
- package/lib/store/RelayModernFragmentSpecResolver.js +16 -9
- package/lib/store/RelayModernRecord.js +1 -1
- package/lib/store/RelayModernSelector.js +1 -1
- package/lib/store/RelayModernStore.js +19 -20
- package/lib/store/RelayOperationTracker.js +55 -49
- package/lib/store/RelayPublishQueue.js +9 -5
- package/lib/store/RelayReader.js +68 -14
- package/lib/store/RelayReferenceMarker.js +28 -14
- package/lib/store/RelayResponseNormalizer.js +109 -15
- package/lib/store/RelayStoreReactFlightUtils.js +6 -4
- package/lib/store/RelayStoreSubscriptions.js +18 -8
- package/lib/store/RelayStoreSubscriptionsUsingMapByID.js +90 -30
- package/lib/store/RelayStoreUtils.js +3 -2
- package/lib/store/ResolverFragments.js +57 -0
- package/lib/store/cloneRelayHandleSourceField.js +1 -1
- package/lib/store/cloneRelayScalarHandleSourceField.js +1 -1
- package/lib/store/createFragmentSpecResolver.js +2 -2
- package/lib/store/createRelayContext.js +1 -1
- package/lib/store/defaultGetDataID.js +3 -1
- package/lib/store/hasOverlappingIDs.js +11 -3
- package/lib/store/readInlineData.js +1 -1
- package/lib/subscription/requestSubscription.js +33 -5
- package/lib/util/RelayConcreteNode.js +2 -0
- package/lib/util/RelayFeatureFlags.js +8 -3
- package/lib/util/RelayProfiler.js +17 -187
- package/lib/util/RelayReplaySubject.js +1 -1
- package/lib/util/deepFreeze.js +1 -0
- package/lib/util/getRelayHandleKey.js +1 -1
- package/lib/util/getRequestIdentifier.js +1 -1
- package/multi-actor-environment/ActorIdentifier.js.flow +27 -0
- package/multi-actor-environment/ActorSpecificEnvironment.js.flow +189 -0
- package/multi-actor-environment/MultiActorEnvironment.js.flow +233 -0
- package/multi-actor-environment/MultiActorEnvironmentTypes.js.flow +196 -0
- package/multi-actor-environment/index.js.flow +24 -0
- package/mutations/RelayRecordSourceProxy.js.flow +3 -2
- package/mutations/commitMutation.js.flow +1 -1
- package/mutations/validateMutation.js.flow +40 -15
- package/network/RelayNetworkTypes.js.flow +31 -11
- package/network/RelayQueryResponseCache.js.flow +2 -1
- package/package.json +3 -2
- package/query/fetchQuery.js.flow +147 -20
- package/query/fetchQueryInternal.js.flow +2 -3
- package/query/fetchQuery_DEPRECATED.js.flow +47 -0
- package/relay-runtime.js +2 -2
- package/relay-runtime.min.js +2 -2
- package/store/DataChecker.js.flow +23 -15
- package/store/{RelayModernQueryExecutor.js.flow → OperationExecutor.js.flow} +128 -40
- package/store/RelayConcreteVariables.js.flow +5 -0
- package/store/RelayModernEnvironment.js.flow +100 -130
- package/store/RelayModernFragmentSpecResolver.js.flow +30 -8
- package/store/RelayModernStore.js.flow +28 -24
- package/store/RelayOperationTracker.js.flow +69 -56
- package/store/RelayPublishQueue.js.flow +7 -4
- package/store/RelayReader.js.flow +63 -11
- package/store/RelayRecordSource.js.flow +3 -3
- package/store/RelayRecordSourceMapImpl.js.flow +6 -2
- package/store/RelayReferenceMarker.js.flow +28 -18
- package/store/RelayResponseNormalizer.js.flow +134 -23
- package/store/RelayStoreReactFlightUtils.js.flow +9 -4
- package/store/RelayStoreSubscriptions.js.flow +22 -7
- package/store/RelayStoreSubscriptionsUsingMapByID.js.flow +36 -12
- package/store/RelayStoreTypes.js.flow +51 -22
- package/store/RelayStoreUtils.js.flow +2 -1
- package/store/ResolverFragments.js.flow +125 -0
- package/store/createFragmentSpecResolver.js.flow +2 -0
- package/store/defaultGetDataID.js.flow +3 -1
- package/store/hasOverlappingIDs.js.flow +11 -9
- package/subscription/requestSubscription.js.flow +25 -2
- package/util/NormalizationNode.js.flow +13 -0
- package/util/ReaderNode.js.flow +14 -1
- package/util/RelayConcreteNode.js.flow +2 -0
- package/util/RelayFeatureFlags.js.flow +12 -2
- package/util/RelayProfiler.js.flow +22 -194
- package/util/RelayRuntimeTypes.js.flow +4 -5
- package/util/deepFreeze.js.flow +2 -1
- package/util/isEmptyObject.js.flow +1 -1
|
@@ -46,7 +46,7 @@ import type {
|
|
|
46
46
|
MutableRecordSource,
|
|
47
47
|
NormalizationSelector,
|
|
48
48
|
OperationLoader,
|
|
49
|
-
|
|
49
|
+
ReactFlightReachableExecutableDefinitions,
|
|
50
50
|
Record,
|
|
51
51
|
RecordSource,
|
|
52
52
|
} from './RelayStoreTypes';
|
|
@@ -58,6 +58,7 @@ export type Availability = {|
|
|
|
58
58
|
|
|
59
59
|
const {
|
|
60
60
|
CONDITION,
|
|
61
|
+
CLIENT_COMPONENT,
|
|
61
62
|
CLIENT_EXTENSION,
|
|
62
63
|
DEFER,
|
|
63
64
|
FLIGHT_FIELD,
|
|
@@ -95,6 +96,7 @@ function check(
|
|
|
95
96
|
handlers: $ReadOnlyArray<MissingFieldHandler>,
|
|
96
97
|
operationLoader: ?OperationLoader,
|
|
97
98
|
getDataID: GetDataID,
|
|
99
|
+
shouldProcessClientComponents: ?boolean,
|
|
98
100
|
): Availability {
|
|
99
101
|
const {dataID, node, variables} = selector;
|
|
100
102
|
const checker = new DataChecker(
|
|
@@ -104,6 +106,7 @@ function check(
|
|
|
104
106
|
handlers,
|
|
105
107
|
operationLoader,
|
|
106
108
|
getDataID,
|
|
109
|
+
shouldProcessClientComponents,
|
|
107
110
|
);
|
|
108
111
|
return checker.check(node, dataID);
|
|
109
112
|
}
|
|
@@ -121,6 +124,7 @@ class DataChecker {
|
|
|
121
124
|
_recordWasMissing: boolean;
|
|
122
125
|
_source: RecordSource;
|
|
123
126
|
_variables: Variables;
|
|
127
|
+
_shouldProcessClientComponents: ?boolean;
|
|
124
128
|
|
|
125
129
|
constructor(
|
|
126
130
|
source: RecordSource,
|
|
@@ -129,6 +133,7 @@ class DataChecker {
|
|
|
129
133
|
handlers: $ReadOnlyArray<MissingFieldHandler>,
|
|
130
134
|
operationLoader: ?OperationLoader,
|
|
131
135
|
getDataID: GetDataID,
|
|
136
|
+
shouldProcessClientComponents: ?boolean,
|
|
132
137
|
) {
|
|
133
138
|
const mutator = new RelayRecordSourceMutator(source, target);
|
|
134
139
|
this._mostRecentlyInvalidatedAt = null;
|
|
@@ -139,6 +144,7 @@ class DataChecker {
|
|
|
139
144
|
this._recordWasMissing = false;
|
|
140
145
|
this._source = source;
|
|
141
146
|
this._variables = variables;
|
|
147
|
+
this._shouldProcessClientComponents = shouldProcessClientComponents;
|
|
142
148
|
}
|
|
143
149
|
|
|
144
150
|
check(node: NormalizationNode, dataID: DataID): Availability {
|
|
@@ -161,6 +167,7 @@ class DataChecker {
|
|
|
161
167
|
'RelayAsyncLoader(): Undefined variable `%s`.',
|
|
162
168
|
name,
|
|
163
169
|
);
|
|
170
|
+
// $FlowFixMe[cannot-write]
|
|
164
171
|
return this._variables[name];
|
|
165
172
|
}
|
|
166
173
|
|
|
@@ -383,12 +390,7 @@ class DataChecker {
|
|
|
383
390
|
break;
|
|
384
391
|
// $FlowFixMe[incompatible-type]
|
|
385
392
|
case FRAGMENT_SPREAD:
|
|
386
|
-
|
|
387
|
-
false,
|
|
388
|
-
'RelayAsyncLoader(): Unexpected ast kind `%s`.',
|
|
389
|
-
selection.kind,
|
|
390
|
-
);
|
|
391
|
-
// $FlowExpectedError[unreachable-code] - we need the break; for OSS linter
|
|
393
|
+
this._traverseSelections(selection.fragment.selections, dataID);
|
|
392
394
|
break;
|
|
393
395
|
case CLIENT_EXTENSION:
|
|
394
396
|
const recordWasMissing = this._recordWasMissing;
|
|
@@ -423,6 +425,12 @@ class DataChecker {
|
|
|
423
425
|
throw new Error('Flight fields are not yet supported.');
|
|
424
426
|
}
|
|
425
427
|
break;
|
|
428
|
+
case CLIENT_COMPONENT:
|
|
429
|
+
if (this._shouldProcessClientComponents === false) {
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
this._traverseSelections(selection.fragment.selections, dataID);
|
|
433
|
+
break;
|
|
426
434
|
default:
|
|
427
435
|
(selection: empty);
|
|
428
436
|
invariant(
|
|
@@ -527,12 +535,12 @@ class DataChecker {
|
|
|
527
535
|
linkedID,
|
|
528
536
|
RelayStoreReactFlightUtils.REACT_FLIGHT_TREE_STORAGE_KEY,
|
|
529
537
|
);
|
|
530
|
-
const
|
|
538
|
+
const reachableExecutableDefinitions = this._mutator.getValue(
|
|
531
539
|
linkedID,
|
|
532
|
-
RelayStoreReactFlightUtils.
|
|
540
|
+
RelayStoreReactFlightUtils.REACT_FLIGHT_EXECUTABLE_DEFINITIONS_STORAGE_KEY,
|
|
533
541
|
);
|
|
534
542
|
|
|
535
|
-
if (tree == null || !Array.isArray(
|
|
543
|
+
if (tree == null || !Array.isArray(reachableExecutableDefinitions)) {
|
|
536
544
|
this._handleMissing();
|
|
537
545
|
return;
|
|
538
546
|
}
|
|
@@ -543,13 +551,13 @@ class DataChecker {
|
|
|
543
551
|
'DataChecker: Expected an operationLoader to be configured when using ' +
|
|
544
552
|
'React Flight.',
|
|
545
553
|
);
|
|
546
|
-
// In Flight, the variables that are in scope for reachable
|
|
547
|
-
// the same as what's in scope for the outer query.
|
|
554
|
+
// In Flight, the variables that are in scope for reachable executable
|
|
555
|
+
// definitions aren't the same as what's in scope for the outer query.
|
|
548
556
|
const prevVariables = this._variables;
|
|
549
557
|
// $FlowFixMe[incompatible-cast]
|
|
550
|
-
for (const
|
|
551
|
-
this._variables =
|
|
552
|
-
const normalizationRootNode = operationLoader.get(
|
|
558
|
+
for (const definition of (reachableExecutableDefinitions: Array<ReactFlightReachableExecutableDefinitions>)) {
|
|
559
|
+
this._variables = definition.variables;
|
|
560
|
+
const normalizationRootNode = operationLoader.get(definition.module);
|
|
553
561
|
if (normalizationRootNode != null) {
|
|
554
562
|
const operation = getOperation(normalizationRootNode);
|
|
555
563
|
this._traverseSelections(operation.selections, ROOT_ID);
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
'use strict';
|
|
15
15
|
|
|
16
16
|
const RelayError = require('../util/RelayError');
|
|
17
|
+
const RelayFeatureFlags = require('../util/RelayFeatureFlags');
|
|
17
18
|
const RelayModernRecord = require('./RelayModernRecord');
|
|
18
19
|
const RelayObservable = require('../network/RelayObservable');
|
|
19
20
|
const RelayRecordSource = require('./RelayRecordSource');
|
|
@@ -24,8 +25,11 @@ const invariant = require('invariant');
|
|
|
24
25
|
const stableCopy = require('../util/stableCopy');
|
|
25
26
|
const warning = require('warning');
|
|
26
27
|
|
|
27
|
-
const {generateClientID} = require('./ClientID');
|
|
28
|
-
const {
|
|
28
|
+
const {generateClientID, generateUniqueClientID} = require('./ClientID');
|
|
29
|
+
const {
|
|
30
|
+
createNormalizationSelector,
|
|
31
|
+
createReaderSelector,
|
|
32
|
+
} = require('./RelayModernSelector');
|
|
29
33
|
const {ROOT_TYPE, TYPENAME_KEY, getStorageKey} = require('./RelayStoreUtils');
|
|
30
34
|
|
|
31
35
|
import type {
|
|
@@ -48,6 +52,7 @@ import type {
|
|
|
48
52
|
OptimisticUpdate,
|
|
49
53
|
PublishQueue,
|
|
50
54
|
ReactFlightPayloadDeserializer,
|
|
55
|
+
ReactFlightServerErrorHandler,
|
|
51
56
|
Record,
|
|
52
57
|
RelayResponsePayload,
|
|
53
58
|
SelectorStoreUpdater,
|
|
@@ -71,16 +76,18 @@ export type ExecuteConfig = {|
|
|
|
71
76
|
+operation: OperationDescriptor,
|
|
72
77
|
+operationExecutions: Map<string, ActiveState>,
|
|
73
78
|
+operationLoader: ?OperationLoader,
|
|
74
|
-
+operationTracker
|
|
79
|
+
+operationTracker: OperationTracker,
|
|
75
80
|
+optimisticConfig: ?OptimisticResponseConfig,
|
|
76
81
|
+publishQueue: PublishQueue,
|
|
77
82
|
+reactFlightPayloadDeserializer?: ?ReactFlightPayloadDeserializer,
|
|
83
|
+
+reactFlightServerErrorHandler?: ?ReactFlightServerErrorHandler,
|
|
78
84
|
+scheduler?: ?TaskScheduler,
|
|
79
85
|
+sink: Sink<GraphQLResponse>,
|
|
80
86
|
+source: RelayObservable<GraphQLResponse>,
|
|
81
87
|
+store: Store,
|
|
82
88
|
+updater?: ?SelectorStoreUpdater,
|
|
83
89
|
+isClientPayload?: boolean,
|
|
90
|
+
+shouldProcessClientComponents?: ?boolean,
|
|
84
91
|
|};
|
|
85
92
|
|
|
86
93
|
export type ActiveState = 'active' | 'inactive';
|
|
@@ -126,12 +133,14 @@ class Executor {
|
|
|
126
133
|
_operation: OperationDescriptor;
|
|
127
134
|
_operationExecutions: Map<string, ActiveState>;
|
|
128
135
|
_operationLoader: ?OperationLoader;
|
|
129
|
-
_operationTracker:
|
|
136
|
+
_operationTracker: OperationTracker;
|
|
130
137
|
_operationUpdateEpochs: Map<string, number>;
|
|
131
138
|
_optimisticUpdates: null | Array<OptimisticUpdate>;
|
|
132
139
|
_pendingModulePayloadsCount: number;
|
|
133
140
|
_publishQueue: PublishQueue;
|
|
134
141
|
_reactFlightPayloadDeserializer: ?ReactFlightPayloadDeserializer;
|
|
142
|
+
_reactFlightServerErrorHandler: ?ReactFlightServerErrorHandler;
|
|
143
|
+
_shouldProcessClientComponents: ?boolean;
|
|
135
144
|
_scheduler: ?TaskScheduler;
|
|
136
145
|
_sink: Sink<GraphQLResponse>;
|
|
137
146
|
_source: Map<
|
|
@@ -144,6 +153,7 @@ class Executor {
|
|
|
144
153
|
_updater: ?SelectorStoreUpdater;
|
|
145
154
|
_retainDisposable: ?Disposable;
|
|
146
155
|
+_isClientPayload: boolean;
|
|
156
|
+
+_isSubscriptionOperation: boolean;
|
|
147
157
|
|
|
148
158
|
constructor({
|
|
149
159
|
operation,
|
|
@@ -161,6 +171,8 @@ class Executor {
|
|
|
161
171
|
getDataID,
|
|
162
172
|
isClientPayload,
|
|
163
173
|
reactFlightPayloadDeserializer,
|
|
174
|
+
reactFlightServerErrorHandler,
|
|
175
|
+
shouldProcessClientComponents,
|
|
164
176
|
}: ExecuteConfig): void {
|
|
165
177
|
this._getDataID = getDataID;
|
|
166
178
|
this._treatMissingFieldsAsNull = treatMissingFieldsAsNull;
|
|
@@ -184,6 +196,10 @@ class Executor {
|
|
|
184
196
|
this._updater = updater;
|
|
185
197
|
this._isClientPayload = isClientPayload === true;
|
|
186
198
|
this._reactFlightPayloadDeserializer = reactFlightPayloadDeserializer;
|
|
199
|
+
this._reactFlightServerErrorHandler = reactFlightServerErrorHandler;
|
|
200
|
+
this._isSubscriptionOperation =
|
|
201
|
+
this._operation.request.node.params.operationKind === 'subscription';
|
|
202
|
+
this._shouldProcessClientComponents = shouldProcessClientComponents;
|
|
187
203
|
|
|
188
204
|
const id = this._nextSubscriptionId++;
|
|
189
205
|
source.subscribe({
|
|
@@ -228,6 +244,7 @@ class Executor {
|
|
|
228
244
|
optimisticUpdates.forEach(update =>
|
|
229
245
|
this._publishQueue.revertUpdate(update),
|
|
230
246
|
);
|
|
247
|
+
// OK: run revert on cancel
|
|
231
248
|
this._publishQueue.run();
|
|
232
249
|
}
|
|
233
250
|
this._incrementalResults.clear();
|
|
@@ -260,7 +277,7 @@ class Executor {
|
|
|
260
277
|
}
|
|
261
278
|
default:
|
|
262
279
|
(this._state: empty);
|
|
263
|
-
invariant(false, '
|
|
280
|
+
invariant(false, 'OperationExecutor: invalid executor state.');
|
|
264
281
|
}
|
|
265
282
|
this._operationExecutions.set(
|
|
266
283
|
this._operation.request.identifier,
|
|
@@ -387,7 +404,7 @@ class Executor {
|
|
|
387
404
|
if (isOptimistic && this._state !== 'started') {
|
|
388
405
|
invariant(
|
|
389
406
|
false,
|
|
390
|
-
'
|
|
407
|
+
'OperationExecutor: optimistic payload received after server payload.',
|
|
391
408
|
);
|
|
392
409
|
}
|
|
393
410
|
if (isOptimistic) {
|
|
@@ -433,6 +450,7 @@ class Executor {
|
|
|
433
450
|
nonIncrementalResponses,
|
|
434
451
|
incrementalResponses,
|
|
435
452
|
] = partitionGraphQLResponses(responsesWithData);
|
|
453
|
+
const hasNonIncrementalResponses = nonIncrementalResponses.length > 0;
|
|
436
454
|
|
|
437
455
|
// In theory this doesn't preserve the ordering of the batch.
|
|
438
456
|
// The idea is that a batch is always:
|
|
@@ -441,16 +459,20 @@ class Executor {
|
|
|
441
459
|
// The non-incremental payload can appear if the server sends a batch
|
|
442
460
|
// with the initial payload followed by some early-to-resolve incremental
|
|
443
461
|
// payloads (although, can that even happen?)
|
|
444
|
-
if (
|
|
462
|
+
if (hasNonIncrementalResponses) {
|
|
445
463
|
const payloadFollowups = this._processResponses(nonIncrementalResponses);
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
464
|
+
|
|
465
|
+
if (!RelayFeatureFlags.ENABLE_BATCHED_STORE_UPDATES) {
|
|
466
|
+
const updatedOwners = this._publishQueue.run(this._operation);
|
|
467
|
+
this._updateOperationTracker(updatedOwners);
|
|
468
|
+
}
|
|
469
|
+
|
|
451
470
|
this._processPayloadFollowups(payloadFollowups);
|
|
452
|
-
|
|
453
|
-
|
|
471
|
+
|
|
472
|
+
if (!RelayFeatureFlags.ENABLE_BATCHED_STORE_UPDATES) {
|
|
473
|
+
if (this._incrementalPayloadsPending && !this._retainDisposable) {
|
|
474
|
+
this._retainDisposable = this._store.retain(this._operation);
|
|
475
|
+
}
|
|
454
476
|
}
|
|
455
477
|
}
|
|
456
478
|
|
|
@@ -458,13 +480,46 @@ class Executor {
|
|
|
458
480
|
const payloadFollowups = this._processIncrementalResponses(
|
|
459
481
|
incrementalResponses,
|
|
460
482
|
);
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
483
|
+
if (!RelayFeatureFlags.ENABLE_BATCHED_STORE_UPDATES) {
|
|
484
|
+
// For the incremental case, we're only handling follow-up responses
|
|
485
|
+
// for already initiated operation (and we're not passing it to
|
|
486
|
+
// the run(...) call)
|
|
487
|
+
const updatedOwners = this._publishQueue.run();
|
|
488
|
+
this._updateOperationTracker(updatedOwners);
|
|
489
|
+
}
|
|
466
490
|
this._processPayloadFollowups(payloadFollowups);
|
|
467
491
|
}
|
|
492
|
+
if (
|
|
493
|
+
this._isSubscriptionOperation &&
|
|
494
|
+
RelayFeatureFlags.ENABLE_UNIQUE_SUBSCRIPTION_ROOT
|
|
495
|
+
) {
|
|
496
|
+
// We attach the id to allow the `requestSubscription` to read from the store using
|
|
497
|
+
// the current id in its `onNext` callback
|
|
498
|
+
if (responsesWithData[0].extensions == null) {
|
|
499
|
+
// $FlowFixMe[cannot-write]
|
|
500
|
+
responsesWithData[0].extensions = {
|
|
501
|
+
__relay_subscription_root_id: this._operation.fragment.dataID,
|
|
502
|
+
};
|
|
503
|
+
} else {
|
|
504
|
+
responsesWithData[0].extensions.__relay_subscription_root_id = this._operation.fragment.dataID;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if (RelayFeatureFlags.ENABLE_BATCHED_STORE_UPDATES) {
|
|
509
|
+
// OK: run once after each new payload
|
|
510
|
+
// If we have non-incremental responses, we passing `this._operation` to
|
|
511
|
+
// the publish queue here, which will later be passed to the store (via
|
|
512
|
+
// notify) to indicate that this operation caused the store to update
|
|
513
|
+
const updatedOwners = this._publishQueue.run(
|
|
514
|
+
hasNonIncrementalResponses ? this._operation : undefined,
|
|
515
|
+
);
|
|
516
|
+
if (hasNonIncrementalResponses) {
|
|
517
|
+
if (this._incrementalPayloadsPending && !this._retainDisposable) {
|
|
518
|
+
this._retainDisposable = this._store.retain(this._operation);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
this._updateOperationTracker(updatedOwners);
|
|
522
|
+
}
|
|
468
523
|
this._sink.next(response);
|
|
469
524
|
}
|
|
470
525
|
|
|
@@ -491,6 +546,8 @@ class Executor {
|
|
|
491
546
|
getDataID: this._getDataID,
|
|
492
547
|
path: [],
|
|
493
548
|
reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
|
|
549
|
+
reactFlightServerErrorHandler: this._reactFlightServerErrorHandler,
|
|
550
|
+
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
494
551
|
treatMissingFieldsAsNull,
|
|
495
552
|
},
|
|
496
553
|
);
|
|
@@ -517,6 +574,8 @@ class Executor {
|
|
|
517
574
|
}
|
|
518
575
|
this._optimisticUpdates = optimisticUpdates;
|
|
519
576
|
optimisticUpdates.forEach(update => this._publishQueue.applyUpdate(update));
|
|
577
|
+
// OK: only called on construction and when receiving an optimistic payload from network,
|
|
578
|
+
// which doesn't fall-through to the regular next() handling
|
|
520
579
|
this._publishQueue.run();
|
|
521
580
|
}
|
|
522
581
|
|
|
@@ -569,7 +628,9 @@ class Executor {
|
|
|
569
628
|
getDataID: this._getDataID,
|
|
570
629
|
path: moduleImportPayload.path,
|
|
571
630
|
reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
|
|
631
|
+
reactFlightServerErrorHandler: this._reactFlightServerErrorHandler,
|
|
572
632
|
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
633
|
+
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
573
634
|
},
|
|
574
635
|
);
|
|
575
636
|
}
|
|
@@ -614,12 +675,13 @@ class Executor {
|
|
|
614
675
|
if (this._optimisticUpdates == null) {
|
|
615
676
|
warning(
|
|
616
677
|
false,
|
|
617
|
-
'
|
|
678
|
+
'OperationExecutor: Unexpected ModuleImport optimistic ' +
|
|
618
679
|
'update in operation %s.' +
|
|
619
680
|
this._operation.request.node.params.name,
|
|
620
681
|
);
|
|
621
682
|
} else {
|
|
622
683
|
this._optimisticUpdates.push(...moduleImportOptimisticUpdates);
|
|
684
|
+
// OK: always have to run() after an module import resolves async
|
|
623
685
|
this._publishQueue.run();
|
|
624
686
|
}
|
|
625
687
|
});
|
|
@@ -645,7 +707,9 @@ class Executor {
|
|
|
645
707
|
getDataID: this._getDataID,
|
|
646
708
|
path: [],
|
|
647
709
|
reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
|
|
710
|
+
reactFlightServerErrorHandler: this._reactFlightServerErrorHandler,
|
|
648
711
|
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
712
|
+
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
649
713
|
},
|
|
650
714
|
);
|
|
651
715
|
this._publishQueue.commitPayload(
|
|
@@ -723,8 +787,10 @@ class Executor {
|
|
|
723
787
|
}
|
|
724
788
|
});
|
|
725
789
|
if (relayPayloads.length > 0) {
|
|
726
|
-
|
|
727
|
-
|
|
790
|
+
if (!RelayFeatureFlags.ENABLE_BATCHED_STORE_UPDATES) {
|
|
791
|
+
const updatedOwners = this._publishQueue.run();
|
|
792
|
+
this._updateOperationTracker(updatedOwners);
|
|
793
|
+
}
|
|
728
794
|
this._processPayloadFollowups(relayPayloads);
|
|
729
795
|
}
|
|
730
796
|
}
|
|
@@ -733,9 +799,7 @@ class Executor {
|
|
|
733
799
|
}
|
|
734
800
|
|
|
735
801
|
_maybeCompleteSubscriptionOperationTracking() {
|
|
736
|
-
|
|
737
|
-
this._operation.request.node.params.operationKind === 'subscription';
|
|
738
|
-
if (!isSubscriptionOperation) {
|
|
802
|
+
if (!this._isSubscriptionOperation) {
|
|
739
803
|
return;
|
|
740
804
|
}
|
|
741
805
|
if (
|
|
@@ -744,6 +808,23 @@ class Executor {
|
|
|
744
808
|
) {
|
|
745
809
|
this._completeOperationTracker();
|
|
746
810
|
}
|
|
811
|
+
if (RelayFeatureFlags.ENABLE_UNIQUE_SUBSCRIPTION_ROOT) {
|
|
812
|
+
const nextID = generateUniqueClientID();
|
|
813
|
+
this._operation = {
|
|
814
|
+
request: this._operation.request,
|
|
815
|
+
fragment: createReaderSelector(
|
|
816
|
+
this._operation.fragment.node,
|
|
817
|
+
nextID,
|
|
818
|
+
this._operation.fragment.variables,
|
|
819
|
+
this._operation.fragment.owner,
|
|
820
|
+
),
|
|
821
|
+
root: createNormalizationSelector(
|
|
822
|
+
this._operation.root.node,
|
|
823
|
+
nextID,
|
|
824
|
+
this._operation.root.variables,
|
|
825
|
+
),
|
|
826
|
+
};
|
|
827
|
+
}
|
|
747
828
|
}
|
|
748
829
|
|
|
749
830
|
/**
|
|
@@ -792,6 +873,9 @@ class Executor {
|
|
|
792
873
|
moduleImportPayload,
|
|
793
874
|
getOperation(operation),
|
|
794
875
|
);
|
|
876
|
+
// OK: always have to run after an async module import resolves
|
|
877
|
+
const updatedOwners = this._publishQueue.run();
|
|
878
|
+
this._updateOperationTracker(updatedOwners);
|
|
795
879
|
});
|
|
796
880
|
}
|
|
797
881
|
})
|
|
@@ -818,8 +902,10 @@ class Executor {
|
|
|
818
902
|
operation,
|
|
819
903
|
);
|
|
820
904
|
this._publishQueue.commitPayload(this._operation, relayPayload);
|
|
821
|
-
|
|
822
|
-
|
|
905
|
+
if (!RelayFeatureFlags.ENABLE_BATCHED_STORE_UPDATES) {
|
|
906
|
+
const updatedOwners = this._publishQueue.run();
|
|
907
|
+
this._updateOperationTracker(updatedOwners);
|
|
908
|
+
}
|
|
823
909
|
this._processPayloadFollowups([relayPayload]);
|
|
824
910
|
}
|
|
825
911
|
|
|
@@ -924,8 +1010,10 @@ class Executor {
|
|
|
924
1010
|
const payloadFollowups = this._processIncrementalResponses(
|
|
925
1011
|
pendingResponses,
|
|
926
1012
|
);
|
|
927
|
-
|
|
928
|
-
|
|
1013
|
+
if (!RelayFeatureFlags.ENABLE_BATCHED_STORE_UPDATES) {
|
|
1014
|
+
const updatedOwners = this._publishQueue.run();
|
|
1015
|
+
this._updateOperationTracker(updatedOwners);
|
|
1016
|
+
}
|
|
929
1017
|
this._processPayloadFollowups(payloadFollowups);
|
|
930
1018
|
}
|
|
931
1019
|
}
|
|
@@ -1020,7 +1108,9 @@ class Executor {
|
|
|
1020
1108
|
getDataID: this._getDataID,
|
|
1021
1109
|
path: placeholder.path,
|
|
1022
1110
|
reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
|
|
1111
|
+
reactFlightServerErrorHandler: this._reactFlightServerErrorHandler,
|
|
1023
1112
|
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
1113
|
+
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
1024
1114
|
},
|
|
1025
1115
|
);
|
|
1026
1116
|
this._publishQueue.commitPayload(this._operation, relayPayload);
|
|
@@ -1235,7 +1325,9 @@ class Executor {
|
|
|
1235
1325
|
getDataID: this._getDataID,
|
|
1236
1326
|
path: [...normalizationPath, responseKey, String(itemIndex)],
|
|
1237
1327
|
reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
|
|
1328
|
+
reactFlightServerErrorHandler: this._reactFlightServerErrorHandler,
|
|
1238
1329
|
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
1330
|
+
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
1239
1331
|
});
|
|
1240
1332
|
return {
|
|
1241
1333
|
fieldPayloads,
|
|
@@ -1250,11 +1342,7 @@ class Executor {
|
|
|
1250
1342
|
_updateOperationTracker(
|
|
1251
1343
|
updatedOwners: ?$ReadOnlyArray<RequestDescriptor>,
|
|
1252
1344
|
): void {
|
|
1253
|
-
if (
|
|
1254
|
-
this._operationTracker != null &&
|
|
1255
|
-
updatedOwners != null &&
|
|
1256
|
-
updatedOwners.length > 0
|
|
1257
|
-
) {
|
|
1345
|
+
if (updatedOwners != null && updatedOwners.length > 0) {
|
|
1258
1346
|
this._operationTracker.update(
|
|
1259
1347
|
this._operation.request,
|
|
1260
1348
|
new Set(updatedOwners),
|
|
@@ -1263,9 +1351,7 @@ class Executor {
|
|
|
1263
1351
|
}
|
|
1264
1352
|
|
|
1265
1353
|
_completeOperationTracker() {
|
|
1266
|
-
|
|
1267
|
-
this._operationTracker.complete(this._operation.request);
|
|
1268
|
-
}
|
|
1354
|
+
this._operationTracker.complete(this._operation.request);
|
|
1269
1355
|
}
|
|
1270
1356
|
}
|
|
1271
1357
|
|
|
@@ -1283,7 +1369,7 @@ function partitionGraphQLResponses(
|
|
|
1283
1369
|
if (label == null || path == null) {
|
|
1284
1370
|
invariant(
|
|
1285
1371
|
false,
|
|
1286
|
-
'
|
|
1372
|
+
'OperationExecutor: invalid incremental payload, expected ' +
|
|
1287
1373
|
'`path` and `label` to either both be null/undefined, or ' +
|
|
1288
1374
|
'`path` to be an `Array<string | number>` and `label` to be a ' +
|
|
1289
1375
|
'`string`.',
|
|
@@ -1335,11 +1421,13 @@ function validateOptimisticResponsePayload(
|
|
|
1335
1421
|
if (incrementalPlaceholders != null && incrementalPlaceholders.length !== 0) {
|
|
1336
1422
|
invariant(
|
|
1337
1423
|
false,
|
|
1338
|
-
'
|
|
1424
|
+
'OperationExecutor: optimistic responses cannot be returned ' +
|
|
1339
1425
|
'for operations that use incremental data delivery (@defer, ' +
|
|
1340
1426
|
'@stream, and @stream_connection).',
|
|
1341
1427
|
);
|
|
1342
1428
|
}
|
|
1343
1429
|
}
|
|
1344
1430
|
|
|
1345
|
-
module.exports = {
|
|
1431
|
+
module.exports = {
|
|
1432
|
+
execute,
|
|
1433
|
+
};
|
|
@@ -35,6 +35,7 @@ function getFragmentVariables(
|
|
|
35
35
|
if (argumentVariables.hasOwnProperty(definition.name)) {
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
|
+
// $FlowFixMe[cannot-spread-interface]
|
|
38
39
|
variables = variables || {...argumentVariables};
|
|
39
40
|
switch (definition.kind) {
|
|
40
41
|
case 'LocalArgument':
|
|
@@ -51,9 +52,12 @@ function getFragmentVariables(
|
|
|
51
52
|
* RelayStoreUtils.getStableVariableValue() that variable keys are all
|
|
52
53
|
* present.
|
|
53
54
|
*/
|
|
55
|
+
// $FlowFixMe[incompatible-use]
|
|
54
56
|
variables[definition.name] = undefined;
|
|
55
57
|
break;
|
|
56
58
|
}
|
|
59
|
+
// $FlowFixMe[incompatible-use]
|
|
60
|
+
// $FlowFixMe[cannot-write]
|
|
57
61
|
variables[definition.name] = rootVariables[definition.name];
|
|
58
62
|
break;
|
|
59
63
|
default:
|
|
@@ -82,6 +86,7 @@ function getOperationVariables(
|
|
|
82
86
|
const operationVariables = {};
|
|
83
87
|
operation.argumentDefinitions.forEach(def => {
|
|
84
88
|
let value = def.defaultValue;
|
|
89
|
+
// $FlowFixMe[cannot-write]
|
|
85
90
|
if (variables[def.name] != null) {
|
|
86
91
|
value = variables[def.name];
|
|
87
92
|
}
|