relay-runtime 18.2.0 → 20.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/experimental.js +1 -1
- package/experimental.js.flow +8 -6
- package/index.js +1 -1
- package/index.js.flow +3 -0
- package/lib/experimental.js +5 -2
- package/lib/index.js +3 -0
- package/lib/multi-actor-environment/ActorSpecificEnvironment.js +1 -1
- package/lib/mutations/RelayRecordSourceProxy.js +2 -1
- package/lib/mutations/createUpdatableProxy.js +1 -1
- package/lib/mutations/validateMutation.js +2 -2
- package/lib/network/RelayObservable.js +1 -3
- package/lib/network/wrapNetworkWithLogObserver.js +2 -2
- package/lib/query/fetchQuery.js +1 -1
- package/lib/store/DataChecker.js +12 -8
- package/lib/store/OperationExecutor.js +93 -43
- package/lib/store/RelayModernEnvironment.js +13 -4
- package/lib/store/RelayModernFragmentSpecResolver.js +4 -4
- package/lib/store/RelayModernStore.js +49 -24
- package/lib/store/RelayPublishQueue.js +11 -15
- package/lib/store/RelayReader.js +134 -151
- package/lib/store/RelayReferenceMarker.js +14 -7
- package/lib/store/RelayResponseNormalizer.js +57 -31
- package/lib/store/RelayStoreSubscriptions.js +2 -2
- package/lib/store/RelayStoreUtils.js +8 -0
- package/lib/store/ResolverFragments.js +2 -2
- package/lib/store/createRelayLoggingContext.js +17 -0
- package/lib/store/generateTypenamePrefixedDataID.js +9 -0
- package/lib/store/live-resolvers/LiveResolverCache.js +4 -2
- package/lib/store/live-resolvers/resolverDataInjector.js +4 -4
- package/lib/store/normalizeResponse.js +2 -2
- package/lib/store/observeFragmentExperimental.js +60 -13
- package/lib/store/observeQueryExperimental.js +21 -0
- package/lib/util/RelayFeatureFlags.js +7 -1
- package/lib/util/handlePotentialSnapshotErrors.js +11 -8
- package/multi-actor-environment/ActorSpecificEnvironment.js.flow +1 -0
- package/mutations/RelayRecordSourceProxy.js.flow +4 -0
- package/mutations/createUpdatableProxy.js.flow +1 -1
- package/mutations/validateMutation.js.flow +3 -3
- package/network/RelayNetworkTypes.js.flow +3 -0
- package/network/RelayObservable.js.flow +1 -5
- package/network/wrapNetworkWithLogObserver.js.flow +19 -1
- package/package.json +1 -1
- package/query/fetchQuery.js.flow +1 -1
- package/store/DataChecker.js.flow +16 -4
- package/store/OperationExecutor.js.flow +101 -15
- package/store/RelayExperimentalGraphResponseTransform.js.flow +4 -4
- package/store/RelayModernEnvironment.js.flow +22 -6
- package/store/RelayModernFragmentSpecResolver.js.flow +6 -6
- package/store/RelayModernSelector.js.flow +2 -0
- package/store/RelayModernStore.js.flow +86 -27
- package/store/RelayPublishQueue.js.flow +32 -21
- package/store/RelayReader.js.flow +168 -97
- package/store/RelayReferenceMarker.js.flow +15 -5
- package/store/RelayResponseNormalizer.js.flow +104 -69
- package/store/RelayStoreSubscriptions.js.flow +2 -2
- package/store/RelayStoreTypes.js.flow +34 -4
- package/store/RelayStoreUtils.js.flow +29 -0
- package/store/ResolverCache.js.flow +2 -2
- package/store/ResolverFragments.js.flow +5 -3
- package/store/StoreInspector.js.flow +5 -0
- package/store/createRelayContext.js.flow +3 -2
- package/store/createRelayLoggingContext.js.flow +46 -0
- package/store/generateTypenamePrefixedDataID.js.flow +25 -0
- package/store/live-resolvers/LiveResolverCache.js.flow +7 -2
- package/store/live-resolvers/resolverDataInjector.js.flow +10 -6
- package/store/normalizeResponse.js.flow +2 -0
- package/store/observeFragmentExperimental.js.flow +82 -28
- package/store/observeQueryExperimental.js.flow +61 -0
- package/store/waitForFragmentExperimental.js.flow +4 -3
- package/util/NormalizationNode.js.flow +2 -1
- package/util/RelayConcreteNode.js.flow +2 -0
- package/util/RelayError.js.flow +1 -0
- package/util/RelayFeatureFlags.js.flow +28 -0
- package/util/RelayRuntimeTypes.js.flow +6 -3
- package/util/getPaginationVariables.js.flow +2 -0
- package/util/handlePotentialSnapshotErrors.js.flow +23 -11
- package/util/registerEnvironmentWithDevTools.js.flow +4 -2
- package/util/withProvidedVariables.js.flow +1 -0
- package/util/withStartAndDuration.js.flow +3 -0
- package/relay-runtime-experimental.js +0 -4
- package/relay-runtime-experimental.min.js +0 -9
- package/relay-runtime.js +0 -4
- package/relay-runtime.min.js +0 -9
|
@@ -145,13 +145,13 @@ if (__DEV__) {
|
|
|
145
145
|
return validateModuleImport(context);
|
|
146
146
|
case 'TypeDiscriminator':
|
|
147
147
|
return validateAbstractKey(context, selection.abstractKey);
|
|
148
|
-
case 'RelayResolver':
|
|
149
|
-
case 'RelayLiveResolver':
|
|
150
148
|
case 'ClientEdgeToClientObject':
|
|
151
149
|
case 'LinkedHandle':
|
|
152
150
|
case 'ScalarHandle':
|
|
153
151
|
case 'Defer':
|
|
154
|
-
case 'Stream':
|
|
152
|
+
case 'Stream':
|
|
153
|
+
case 'RelayResolver':
|
|
154
|
+
case 'RelayLiveResolver': {
|
|
155
155
|
// TODO(T35864292) - Add missing validations for these types
|
|
156
156
|
return;
|
|
157
157
|
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
'use strict';
|
|
13
13
|
|
|
14
|
+
import type {OperationAvailability} from '../store/RelayStoreTypes';
|
|
14
15
|
import type {RequestParameters} from '../util/RelayConcreteNode';
|
|
15
16
|
import type {CacheConfig, Variables} from '../util/RelayRuntimeTypes';
|
|
16
17
|
import type RelayObservable, {ObservableFromValue} from './RelayObservable';
|
|
@@ -104,6 +105,8 @@ export type ExecuteFunction = (
|
|
|
104
105
|
logRequestInfo?: ?LogRequestInfoFunction,
|
|
105
106
|
encryptedVariables?: ?string,
|
|
106
107
|
preprocessResponse?: ?preprocessResponseFunction,
|
|
108
|
+
// Run datachecker on the current operation and returns the OperationAvailability
|
|
109
|
+
checkOperation?: () => OperationAvailability,
|
|
107
110
|
) => RelayObservable<GraphQLResponse>;
|
|
108
111
|
|
|
109
112
|
/**
|
|
@@ -614,11 +614,7 @@ if (__DEV__) {
|
|
|
614
614
|
// Default implementation of HostReportErrors() in development builds.
|
|
615
615
|
// Can be replaced by the host application environment.
|
|
616
616
|
RelayObservable.onUnhandledError((error, isUncaughtThrownError) => {
|
|
617
|
-
|
|
618
|
-
if (typeof fail === 'function') {
|
|
619
|
-
// In test environments (Jest), fail() immediately fails the current test.
|
|
620
|
-
fail(String(error));
|
|
621
|
-
} else if (isUncaughtThrownError) {
|
|
617
|
+
if (isUncaughtThrownError) {
|
|
622
618
|
// Rethrow uncaught thrown errors on the next frame to avoid breaking
|
|
623
619
|
// current logic.
|
|
624
620
|
setTimeout(() => {
|
|
@@ -12,12 +12,17 @@
|
|
|
12
12
|
'use strict';
|
|
13
13
|
import type ActorSpecificEnvironment from '../multi-actor-environment/ActorSpecificEnvironment';
|
|
14
14
|
import type RelayModernEnvironment from '../store/RelayModernEnvironment';
|
|
15
|
+
import type {
|
|
16
|
+
LogRequestInfoFunction,
|
|
17
|
+
OperationAvailability,
|
|
18
|
+
} from '../store/RelayStoreTypes';
|
|
15
19
|
import type {RequestParameters} from '../util/RelayConcreteNode';
|
|
16
20
|
import type {CacheConfig, Variables} from '../util/RelayRuntimeTypes';
|
|
17
21
|
import type {
|
|
18
22
|
GraphQLResponse,
|
|
19
23
|
INetwork,
|
|
20
24
|
UploadableMap,
|
|
25
|
+
preprocessResponseFunction,
|
|
21
26
|
} from './RelayNetworkTypes';
|
|
22
27
|
import type RelayObservable from './RelayObservable';
|
|
23
28
|
import type {Subscription} from './RelayObservable';
|
|
@@ -42,6 +47,10 @@ function wrapNetworkWithLogObserver(
|
|
|
42
47
|
variables: Variables,
|
|
43
48
|
cacheConfig: CacheConfig,
|
|
44
49
|
uploadables?: ?UploadableMap,
|
|
50
|
+
_?: ?LogRequestInfoFunction,
|
|
51
|
+
encryptedVariables?: ?string,
|
|
52
|
+
preprocessResponse?: ?preprocessResponseFunction,
|
|
53
|
+
checkOperation?: () => OperationAvailability,
|
|
45
54
|
): RelayObservable<GraphQLResponse> {
|
|
46
55
|
const networkRequestId = generateID();
|
|
47
56
|
const logObserver = {
|
|
@@ -89,7 +98,16 @@ function wrapNetworkWithLogObserver(
|
|
|
89
98
|
});
|
|
90
99
|
};
|
|
91
100
|
return network
|
|
92
|
-
.execute(
|
|
101
|
+
.execute(
|
|
102
|
+
params,
|
|
103
|
+
variables,
|
|
104
|
+
cacheConfig,
|
|
105
|
+
uploadables,
|
|
106
|
+
logRequestInfo,
|
|
107
|
+
encryptedVariables,
|
|
108
|
+
preprocessResponse,
|
|
109
|
+
checkOperation,
|
|
110
|
+
)
|
|
93
111
|
.do(logObserver);
|
|
94
112
|
},
|
|
95
113
|
};
|
package/package.json
CHANGED
package/query/fetchQuery.js.flow
CHANGED
|
@@ -138,7 +138,7 @@ function fetchQuery<TVariables: Variables, TData, TRawResponse>(
|
|
|
138
138
|
const fetchPolicy = options?.fetchPolicy ?? 'network-only';
|
|
139
139
|
|
|
140
140
|
function readData(snapshot: Snapshot): TData {
|
|
141
|
-
handlePotentialSnapshotErrors(environment, snapshot.
|
|
141
|
+
handlePotentialSnapshotErrors(environment, snapshot.fieldErrors);
|
|
142
142
|
/* $FlowFixMe[incompatible-return] we assume readData returns the right
|
|
143
143
|
* data just having written it from network or checked availability. */
|
|
144
144
|
return snapshot.data;
|
|
@@ -73,6 +73,7 @@ function check(
|
|
|
73
73
|
getDataID: GetDataID,
|
|
74
74
|
shouldProcessClientComponents: ?boolean,
|
|
75
75
|
log: ?LogFunction,
|
|
76
|
+
useExecTimeResolvers: ?boolean,
|
|
76
77
|
): Availability {
|
|
77
78
|
if (log != null) {
|
|
78
79
|
log({
|
|
@@ -90,6 +91,8 @@ function check(
|
|
|
90
91
|
operationLoader,
|
|
91
92
|
getDataID,
|
|
92
93
|
shouldProcessClientComponents,
|
|
94
|
+
log,
|
|
95
|
+
useExecTimeResolvers,
|
|
93
96
|
);
|
|
94
97
|
const result = checker.check(node, dataID);
|
|
95
98
|
if (log != null) {
|
|
@@ -112,6 +115,7 @@ class DataChecker {
|
|
|
112
115
|
_recordSourceProxy: RelayRecordSourceProxy;
|
|
113
116
|
_recordWasMissing: boolean;
|
|
114
117
|
_source: RecordSource;
|
|
118
|
+
_useExecTimeResolvers: boolean;
|
|
115
119
|
_variables: Variables;
|
|
116
120
|
_shouldProcessClientComponents: ?boolean;
|
|
117
121
|
+_getSourceForActor: (actorIdentifier: ActorIdentifier) => RecordSource;
|
|
@@ -123,6 +127,7 @@ class DataChecker {
|
|
|
123
127
|
ActorIdentifier,
|
|
124
128
|
[RelayRecordSourceMutator, RelayRecordSourceProxy],
|
|
125
129
|
>;
|
|
130
|
+
_log: ?LogFunction;
|
|
126
131
|
|
|
127
132
|
constructor(
|
|
128
133
|
getSourceForActor: (actorIdentifier: ActorIdentifier) => RecordSource,
|
|
@@ -135,6 +140,8 @@ class DataChecker {
|
|
|
135
140
|
operationLoader: ?OperationLoader,
|
|
136
141
|
getDataID: GetDataID,
|
|
137
142
|
shouldProcessClientComponents: ?boolean,
|
|
143
|
+
log: ?LogFunction,
|
|
144
|
+
useExecTimeResolvers: ?boolean,
|
|
138
145
|
) {
|
|
139
146
|
this._getSourceForActor = getSourceForActor;
|
|
140
147
|
this._getTargetForActor = getTargetForActor;
|
|
@@ -144,6 +151,7 @@ class DataChecker {
|
|
|
144
151
|
const [mutator, recordSourceProxy] = this._getMutatorAndRecordProxyForActor(
|
|
145
152
|
defaultActorIdentifier,
|
|
146
153
|
);
|
|
154
|
+
this._useExecTimeResolvers = useExecTimeResolvers ?? false;
|
|
147
155
|
this._mostRecentlyInvalidatedAt = null;
|
|
148
156
|
this._handlers = handlers;
|
|
149
157
|
this._mutator = mutator;
|
|
@@ -152,6 +160,7 @@ class DataChecker {
|
|
|
152
160
|
this._recordWasMissing = false;
|
|
153
161
|
this._variables = variables;
|
|
154
162
|
this._shouldProcessClientComponents = shouldProcessClientComponents;
|
|
163
|
+
this._log = log;
|
|
155
164
|
}
|
|
156
165
|
|
|
157
166
|
_getMutatorAndRecordProxyForActor(
|
|
@@ -170,6 +179,7 @@ class DataChecker {
|
|
|
170
179
|
this._getDataID,
|
|
171
180
|
undefined,
|
|
172
181
|
this._handlers,
|
|
182
|
+
this._log,
|
|
173
183
|
);
|
|
174
184
|
tuple = [mutator, recordSourceProxy];
|
|
175
185
|
this._mutatorRecordSourceProxyCache.set(actorIdentifier, tuple);
|
|
@@ -449,13 +459,15 @@ class DataChecker {
|
|
|
449
459
|
this._traverseSelections(selection.fragment.selections, dataID);
|
|
450
460
|
break;
|
|
451
461
|
case 'RelayResolver':
|
|
452
|
-
this._checkResolver(selection, dataID);
|
|
453
|
-
break;
|
|
454
462
|
case 'RelayLiveResolver':
|
|
455
|
-
this.
|
|
463
|
+
if (!this._useExecTimeResolvers) {
|
|
464
|
+
this._checkResolver(selection, dataID);
|
|
465
|
+
}
|
|
456
466
|
break;
|
|
457
467
|
case 'ClientEdgeToClientObject':
|
|
458
|
-
this.
|
|
468
|
+
if (!this._useExecTimeResolvers) {
|
|
469
|
+
this._checkResolver(selection.backingField, dataID);
|
|
470
|
+
}
|
|
459
471
|
break;
|
|
460
472
|
default:
|
|
461
473
|
(selection: empty);
|
|
@@ -138,6 +138,7 @@ class Executor<TMutation: MutationParameters> {
|
|
|
138
138
|
_operationTracker: OperationTracker;
|
|
139
139
|
_operationUpdateEpochs: Map<string, number>;
|
|
140
140
|
_optimisticUpdates: null | Array<OptimisticUpdate<TMutation>>;
|
|
141
|
+
_useExecTimeResolvers: boolean;
|
|
141
142
|
_pendingModulePayloadsCount: number;
|
|
142
143
|
+_getPublishQueue: (actorIdentifier: ActorIdentifier) => PublishQueue;
|
|
143
144
|
_shouldProcessClientComponents: ?boolean;
|
|
@@ -158,6 +159,7 @@ class Executor<TMutation: MutationParameters> {
|
|
|
158
159
|
+_isSubscriptionOperation: boolean;
|
|
159
160
|
+_seenActors: Set<ActorIdentifier>;
|
|
160
161
|
_normalizeResponse: NormalizeResponseFunction;
|
|
162
|
+
_execTimeResolverResponseComplete: boolean;
|
|
161
163
|
|
|
162
164
|
constructor({
|
|
163
165
|
actorIdentifier,
|
|
@@ -193,6 +195,12 @@ class Executor<TMutation: MutationParameters> {
|
|
|
193
195
|
this._operationTracker = operationTracker;
|
|
194
196
|
this._operationUpdateEpochs = new Map();
|
|
195
197
|
this._optimisticUpdates = null;
|
|
198
|
+
this._useExecTimeResolvers =
|
|
199
|
+
this._operation.request.node.operation.use_exec_time_resolvers ??
|
|
200
|
+
this._operation.request.node.operation.exec_time_resolvers_enabled_provider?.get() ===
|
|
201
|
+
true ??
|
|
202
|
+
false;
|
|
203
|
+
this._execTimeResolverResponseComplete = false;
|
|
196
204
|
this._pendingModulePayloadsCount = 0;
|
|
197
205
|
this._getPublishQueue = getPublishQueue;
|
|
198
206
|
this._scheduler = scheduler;
|
|
@@ -245,6 +253,12 @@ class Executor<TMutation: MutationParameters> {
|
|
|
245
253
|
cacheConfig: this._operation.request.cacheConfig ?? {},
|
|
246
254
|
});
|
|
247
255
|
},
|
|
256
|
+
unsubscribe: () => {
|
|
257
|
+
this._log({
|
|
258
|
+
name: 'execute.unsubscribe',
|
|
259
|
+
executeId: this._executeId,
|
|
260
|
+
});
|
|
261
|
+
},
|
|
248
262
|
});
|
|
249
263
|
|
|
250
264
|
if (
|
|
@@ -293,7 +307,7 @@ class Executor<TMutation: MutationParameters> {
|
|
|
293
307
|
}
|
|
294
308
|
|
|
295
309
|
_updateActiveState(): void {
|
|
296
|
-
let activeState;
|
|
310
|
+
let activeState: ActiveState;
|
|
297
311
|
switch (this._state) {
|
|
298
312
|
case 'started': {
|
|
299
313
|
activeState = 'active';
|
|
@@ -309,7 +323,11 @@ class Executor<TMutation: MutationParameters> {
|
|
|
309
323
|
}
|
|
310
324
|
case 'loading_final': {
|
|
311
325
|
activeState =
|
|
312
|
-
this._pendingModulePayloadsCount > 0
|
|
326
|
+
this._pendingModulePayloadsCount > 0 ||
|
|
327
|
+
(this._useExecTimeResolvers &&
|
|
328
|
+
!this._execTimeResolverResponseComplete)
|
|
329
|
+
? 'active'
|
|
330
|
+
: 'inactive';
|
|
313
331
|
break;
|
|
314
332
|
}
|
|
315
333
|
default:
|
|
@@ -510,9 +528,10 @@ class Executor<TMutation: MutationParameters> {
|
|
|
510
528
|
return;
|
|
511
529
|
}
|
|
512
530
|
|
|
513
|
-
const [nonIncrementalResponses, incrementalResponses] =
|
|
531
|
+
const [nonIncrementalResponses, incrementalResponses, normalizedResponses] =
|
|
514
532
|
partitionGraphQLResponses(responsesWithData);
|
|
515
533
|
const hasNonIncrementalResponses = nonIncrementalResponses.length > 0;
|
|
534
|
+
const hasNormalizedResponses = normalizedResponses.length > 0;
|
|
516
535
|
|
|
517
536
|
// In theory this doesn't preserve the ordering of the batch.
|
|
518
537
|
// The idea is that a batch is always:
|
|
@@ -547,6 +566,37 @@ class Executor<TMutation: MutationParameters> {
|
|
|
547
566
|
this._processPayloadFollowups(payloadFollowups);
|
|
548
567
|
}
|
|
549
568
|
|
|
569
|
+
if (hasNormalizedResponses) {
|
|
570
|
+
const payloadFollowups = [];
|
|
571
|
+
for (let i = 0; i < normalizedResponses.length; i++) {
|
|
572
|
+
const response = normalizedResponses[i];
|
|
573
|
+
const source = new RelayRecordSource(
|
|
574
|
+
response.data as $FlowExpectedError,
|
|
575
|
+
);
|
|
576
|
+
const isFinal = response.extensions?.is_final === true;
|
|
577
|
+
const payload: RelayResponsePayload = {
|
|
578
|
+
errors: [],
|
|
579
|
+
fieldPayloads: [],
|
|
580
|
+
followupPayloads: [],
|
|
581
|
+
incrementalPlaceholders: [],
|
|
582
|
+
isFinal,
|
|
583
|
+
source,
|
|
584
|
+
};
|
|
585
|
+
this._getPublishQueueAndSaveActor().commitPayload(
|
|
586
|
+
this._operation,
|
|
587
|
+
payload,
|
|
588
|
+
this._updater,
|
|
589
|
+
);
|
|
590
|
+
payloadFollowups.push(payload);
|
|
591
|
+
this._execTimeResolverResponseComplete = isFinal;
|
|
592
|
+
if (isFinal) {
|
|
593
|
+
// Need to update the active state to mark the query as inactive,
|
|
594
|
+
// incase server payloads have completed
|
|
595
|
+
this._updateActiveState();
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
550
600
|
if (incrementalResponses.length > 0) {
|
|
551
601
|
const payloadFollowups =
|
|
552
602
|
this._processIncrementalResponses(incrementalResponses);
|
|
@@ -572,7 +622,9 @@ class Executor<TMutation: MutationParameters> {
|
|
|
572
622
|
// the publish queue here, which will later be passed to the store (via
|
|
573
623
|
// notify) to indicate that this operation caused the store to update
|
|
574
624
|
const updatedOwners = this._runPublishQueue(
|
|
575
|
-
hasNonIncrementalResponses
|
|
625
|
+
hasNonIncrementalResponses || hasNormalizedResponses
|
|
626
|
+
? this._operation
|
|
627
|
+
: undefined,
|
|
576
628
|
);
|
|
577
629
|
|
|
578
630
|
if (hasNonIncrementalResponses) {
|
|
@@ -606,10 +658,12 @@ class Executor<TMutation: MutationParameters> {
|
|
|
606
658
|
{
|
|
607
659
|
actorIdentifier: this._actorIdentifier,
|
|
608
660
|
getDataID: this._getDataID,
|
|
661
|
+
log: this._log,
|
|
609
662
|
path: [],
|
|
610
663
|
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
611
664
|
treatMissingFieldsAsNull,
|
|
612
665
|
},
|
|
666
|
+
this._useExecTimeResolvers,
|
|
613
667
|
);
|
|
614
668
|
validateOptimisticResponsePayload(payload);
|
|
615
669
|
optimisticUpdates.push({
|
|
@@ -708,17 +762,26 @@ class Executor<TMutation: MutationParameters> {
|
|
|
708
762
|
followupPayload.dataID,
|
|
709
763
|
variables,
|
|
710
764
|
);
|
|
765
|
+
const nextResponse: GraphQLResponseWithData = {
|
|
766
|
+
data: followupPayload.data,
|
|
767
|
+
// `is_final` flag needs to be set for processing nested defer and 3D
|
|
768
|
+
// when the server doesn't support streaming
|
|
769
|
+
extensions:
|
|
770
|
+
this._state === 'loading_final' ? {is_final: true} : undefined,
|
|
771
|
+
};
|
|
711
772
|
return this._normalizeResponse(
|
|
712
|
-
|
|
773
|
+
nextResponse,
|
|
713
774
|
selector,
|
|
714
775
|
followupPayload.typeName,
|
|
715
776
|
{
|
|
716
777
|
actorIdentifier: this._actorIdentifier,
|
|
717
778
|
getDataID: this._getDataID,
|
|
779
|
+
log: this._log,
|
|
718
780
|
path: followupPayload.path,
|
|
719
781
|
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
720
782
|
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
721
783
|
},
|
|
784
|
+
this._useExecTimeResolvers,
|
|
722
785
|
);
|
|
723
786
|
}
|
|
724
787
|
|
|
@@ -797,10 +860,12 @@ class Executor<TMutation: MutationParameters> {
|
|
|
797
860
|
{
|
|
798
861
|
actorIdentifier: this._actorIdentifier,
|
|
799
862
|
getDataID: this._getDataID,
|
|
863
|
+
log: this._log,
|
|
800
864
|
path: [],
|
|
801
865
|
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
802
866
|
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
803
867
|
},
|
|
868
|
+
this._useExecTimeResolvers,
|
|
804
869
|
);
|
|
805
870
|
this._getPublishQueueAndSaveActor().commitPayload(
|
|
806
871
|
this._operation,
|
|
@@ -875,7 +940,8 @@ class Executor<TMutation: MutationParameters> {
|
|
|
875
940
|
placeholder.label,
|
|
876
941
|
placeholder.path,
|
|
877
942
|
placeholder,
|
|
878
|
-
|
|
943
|
+
// `is_final` flag needs to be set for processing nested defer payloads
|
|
944
|
+
{data: placeholder.data, extensions: {is_final: true}},
|
|
879
945
|
),
|
|
880
946
|
);
|
|
881
947
|
}
|
|
@@ -889,7 +955,14 @@ class Executor<TMutation: MutationParameters> {
|
|
|
889
955
|
}
|
|
890
956
|
|
|
891
957
|
_maybeCompleteSubscriptionOperationTracking() {
|
|
892
|
-
if (
|
|
958
|
+
if (
|
|
959
|
+
!this._isSubscriptionOperation &&
|
|
960
|
+
!(
|
|
961
|
+
this._useExecTimeResolvers &&
|
|
962
|
+
this._execTimeResolverResponseComplete &&
|
|
963
|
+
this._state === 'loading_final'
|
|
964
|
+
)
|
|
965
|
+
) {
|
|
893
966
|
return;
|
|
894
967
|
}
|
|
895
968
|
if (
|
|
@@ -1253,10 +1326,12 @@ class Executor<TMutation: MutationParameters> {
|
|
|
1253
1326
|
{
|
|
1254
1327
|
actorIdentifier: this._actorIdentifier,
|
|
1255
1328
|
getDataID: this._getDataID,
|
|
1329
|
+
log: this._log,
|
|
1256
1330
|
path: placeholder.path,
|
|
1257
1331
|
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
1258
1332
|
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
1259
1333
|
},
|
|
1334
|
+
this._useExecTimeResolvers,
|
|
1260
1335
|
);
|
|
1261
1336
|
this._getPublishQueueAndSaveActor().commitPayload(
|
|
1262
1337
|
this._operation,
|
|
@@ -1477,13 +1552,20 @@ class Executor<TMutation: MutationParameters> {
|
|
|
1477
1552
|
record: nextParentRecord,
|
|
1478
1553
|
fieldPayloads,
|
|
1479
1554
|
});
|
|
1480
|
-
const relayPayload = this._normalizeResponse(
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1555
|
+
const relayPayload = this._normalizeResponse(
|
|
1556
|
+
response,
|
|
1557
|
+
selector,
|
|
1558
|
+
typeName,
|
|
1559
|
+
{
|
|
1560
|
+
actorIdentifier: this._actorIdentifier,
|
|
1561
|
+
getDataID: this._getDataID,
|
|
1562
|
+
log: this._log,
|
|
1563
|
+
path: [...normalizationPath, responseKey, String(itemIndex)],
|
|
1564
|
+
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
1565
|
+
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
1566
|
+
},
|
|
1567
|
+
this._useExecTimeResolvers,
|
|
1568
|
+
);
|
|
1487
1569
|
return {
|
|
1488
1570
|
fieldPayloads,
|
|
1489
1571
|
itemID,
|
|
@@ -1586,9 +1668,11 @@ function partitionGraphQLResponses(
|
|
|
1586
1668
|
): [
|
|
1587
1669
|
$ReadOnlyArray<GraphQLResponseWithData>,
|
|
1588
1670
|
$ReadOnlyArray<IncrementalGraphQLResponse>,
|
|
1671
|
+
$ReadOnlyArray<GraphQLResponseWithData>,
|
|
1589
1672
|
] {
|
|
1590
1673
|
const nonIncrementalResponses: Array<GraphQLResponseWithData> = [];
|
|
1591
1674
|
const incrementalResponses: Array<IncrementalGraphQLResponse> = [];
|
|
1675
|
+
const normalizedResponses: Array<GraphQLResponseWithData> = [];
|
|
1592
1676
|
responses.forEach(response => {
|
|
1593
1677
|
if (response.path != null || response.label != null) {
|
|
1594
1678
|
const {label, path} = response;
|
|
@@ -1606,11 +1690,13 @@ function partitionGraphQLResponses(
|
|
|
1606
1690
|
path,
|
|
1607
1691
|
response,
|
|
1608
1692
|
});
|
|
1693
|
+
} else if (response.extensions?.is_normalized === true) {
|
|
1694
|
+
normalizedResponses.push(response);
|
|
1609
1695
|
} else {
|
|
1610
1696
|
nonIncrementalResponses.push(response);
|
|
1611
1697
|
}
|
|
1612
1698
|
});
|
|
1613
|
-
return [nonIncrementalResponses, incrementalResponses];
|
|
1699
|
+
return [nonIncrementalResponses, incrementalResponses, normalizedResponses];
|
|
1614
1700
|
}
|
|
1615
1701
|
|
|
1616
1702
|
function stableStringify(value: mixed): string {
|
|
@@ -222,10 +222,10 @@ export class GraphModeNormalizer {
|
|
|
222
222
|
$streamID,
|
|
223
223
|
__id: dataID,
|
|
224
224
|
__typename: ROOT_TYPE,
|
|
225
|
-
};
|
|
225
|
+
} as RecordChunk;
|
|
226
226
|
yield {
|
|
227
227
|
$kind: 'Complete',
|
|
228
|
-
};
|
|
228
|
+
} as CompleteChunk;
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
*_flushFields(
|
|
@@ -247,9 +247,9 @@ export class GraphModeNormalizer {
|
|
|
247
247
|
__typename: typename,
|
|
248
248
|
__id: cacheKey,
|
|
249
249
|
$streamID,
|
|
250
|
-
};
|
|
250
|
+
} as RecordChunk;
|
|
251
251
|
} else if (Object.keys(fields).length > 0) {
|
|
252
|
-
yield {...fields, $kind: 'Extend', $streamID};
|
|
252
|
+
yield {...fields, $kind: 'Extend', $streamID} as ExtendChunk;
|
|
253
253
|
}
|
|
254
254
|
return $streamID;
|
|
255
255
|
}
|
|
@@ -58,6 +58,7 @@ const defaultGetDataID = require('./defaultGetDataID');
|
|
|
58
58
|
const defaultRelayFieldLogger = require('./defaultRelayFieldLogger');
|
|
59
59
|
const normalizeResponse = require('./normalizeResponse');
|
|
60
60
|
const OperationExecutor = require('./OperationExecutor');
|
|
61
|
+
const RelayModernStore = require('./RelayModernStore');
|
|
61
62
|
const RelayPublishQueue = require('./RelayPublishQueue');
|
|
62
63
|
const RelayRecordSource = require('./RelayRecordSource');
|
|
63
64
|
const invariant = require('invariant');
|
|
@@ -71,7 +72,7 @@ export type EnvironmentConfig = {
|
|
|
71
72
|
+network: INetwork,
|
|
72
73
|
+normalizeResponse?: ?NormalizeResponseFunction,
|
|
73
74
|
+scheduler?: ?TaskScheduler,
|
|
74
|
-
+store
|
|
75
|
+
+store?: Store,
|
|
75
76
|
+missingFieldHandlers?: ?$ReadOnlyArray<MissingFieldHandler>,
|
|
76
77
|
+operationTracker?: ?OperationTracker,
|
|
77
78
|
+getDataID?: ?GetDataID,
|
|
@@ -118,6 +119,15 @@ class RelayModernEnvironment implements IEnvironment {
|
|
|
118
119
|
);
|
|
119
120
|
}
|
|
120
121
|
}
|
|
122
|
+
const store =
|
|
123
|
+
config.store ??
|
|
124
|
+
new RelayModernStore(new RelayRecordSource(), {
|
|
125
|
+
log: config.log,
|
|
126
|
+
operationLoader: config.operationLoader,
|
|
127
|
+
getDataID: config.getDataID,
|
|
128
|
+
shouldProcessClientComponents: config.shouldProcessClientComponents,
|
|
129
|
+
});
|
|
130
|
+
|
|
121
131
|
this.__log = config.log ?? emptyFunction;
|
|
122
132
|
this.relayFieldLogger = config.relayFieldLogger ?? defaultRelayFieldLogger;
|
|
123
133
|
this._defaultRenderPolicy =
|
|
@@ -128,13 +138,14 @@ class RelayModernEnvironment implements IEnvironment {
|
|
|
128
138
|
this._getDataID = config.getDataID ?? defaultGetDataID;
|
|
129
139
|
this._missingFieldHandlers = config.missingFieldHandlers ?? [];
|
|
130
140
|
this._publishQueue = new RelayPublishQueue(
|
|
131
|
-
|
|
141
|
+
store,
|
|
132
142
|
config.handlerProvider ?? RelayDefaultHandlerProvider,
|
|
133
143
|
this._getDataID,
|
|
134
144
|
this._missingFieldHandlers,
|
|
145
|
+
this.__log,
|
|
135
146
|
);
|
|
136
147
|
this._scheduler = config.scheduler ?? null;
|
|
137
|
-
this._store =
|
|
148
|
+
this._store = store;
|
|
138
149
|
this.options = config.options;
|
|
139
150
|
this._isServer = config.isServer ?? false;
|
|
140
151
|
this._normalizeResponse = config.normalizeResponse ?? normalizeResponse;
|
|
@@ -327,13 +338,18 @@ class RelayModernEnvironment implements IEnvironment {
|
|
|
327
338
|
operation: OperationDescriptor,
|
|
328
339
|
}): RelayObservable<GraphQLResponse> {
|
|
329
340
|
return this._execute({
|
|
330
|
-
createSource: () =>
|
|
331
|
-
this.getNetwork().execute(
|
|
341
|
+
createSource: () => {
|
|
342
|
+
return this.getNetwork().execute(
|
|
332
343
|
operation.request.node.params,
|
|
333
344
|
operation.request.variables,
|
|
334
345
|
operation.request.cacheConfig || {},
|
|
335
346
|
null,
|
|
336
|
-
|
|
347
|
+
undefined,
|
|
348
|
+
undefined,
|
|
349
|
+
undefined,
|
|
350
|
+
() => this.check(operation),
|
|
351
|
+
);
|
|
352
|
+
},
|
|
337
353
|
isClientPayload: false,
|
|
338
354
|
operation,
|
|
339
355
|
optimisticConfig: null,
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import type {ConcreteRequest} from '../util/RelayConcreteNode';
|
|
15
15
|
import type {Disposable, Variables} from '../util/RelayRuntimeTypes';
|
|
16
16
|
import type {
|
|
17
|
-
|
|
17
|
+
FieldErrors,
|
|
18
18
|
FragmentMap,
|
|
19
19
|
FragmentSpecResolver,
|
|
20
20
|
FragmentSpecResults,
|
|
@@ -228,7 +228,7 @@ class SelectorResolver {
|
|
|
228
228
|
_data: ?SelectorData;
|
|
229
229
|
_environment: IEnvironment;
|
|
230
230
|
_isMissingData: boolean;
|
|
231
|
-
|
|
231
|
+
_fieldErrors: ?FieldErrors;
|
|
232
232
|
_rootIsQueryRenderer: boolean;
|
|
233
233
|
_selector: SingularReaderSelector;
|
|
234
234
|
_subscription: ?Disposable;
|
|
@@ -244,7 +244,7 @@ class SelectorResolver {
|
|
|
244
244
|
this._callback = callback;
|
|
245
245
|
this._data = snapshot.data;
|
|
246
246
|
this._isMissingData = snapshot.isMissingData;
|
|
247
|
-
this.
|
|
247
|
+
this._fieldErrors = snapshot.fieldErrors;
|
|
248
248
|
this._environment = environment;
|
|
249
249
|
this._rootIsQueryRenderer = rootIsQueryRenderer;
|
|
250
250
|
this._selector = selector;
|
|
@@ -325,7 +325,7 @@ class SelectorResolver {
|
|
|
325
325
|
}
|
|
326
326
|
}
|
|
327
327
|
}
|
|
328
|
-
handlePotentialSnapshotErrors(this._environment, this.
|
|
328
|
+
handlePotentialSnapshotErrors(this._environment, this._fieldErrors);
|
|
329
329
|
return this._data;
|
|
330
330
|
}
|
|
331
331
|
|
|
@@ -340,7 +340,7 @@ class SelectorResolver {
|
|
|
340
340
|
const snapshot = this._environment.lookup(selector);
|
|
341
341
|
this._data = recycleNodesInto(this._data, snapshot.data);
|
|
342
342
|
this._isMissingData = snapshot.isMissingData;
|
|
343
|
-
this.
|
|
343
|
+
this._fieldErrors = snapshot.fieldErrors;
|
|
344
344
|
this._selector = selector;
|
|
345
345
|
this._subscription = this._environment.subscribe(snapshot, this._onChange);
|
|
346
346
|
}
|
|
@@ -376,7 +376,7 @@ class SelectorResolver {
|
|
|
376
376
|
_onChange = (snapshot: Snapshot): void => {
|
|
377
377
|
this._data = snapshot.data;
|
|
378
378
|
this._isMissingData = snapshot.isMissingData;
|
|
379
|
-
this.
|
|
379
|
+
this._fieldErrors = snapshot.fieldErrors;
|
|
380
380
|
this._callback();
|
|
381
381
|
};
|
|
382
382
|
}
|
|
@@ -340,6 +340,7 @@ function getVariablesFromObject(
|
|
|
340
340
|
const fragment = fragments[key];
|
|
341
341
|
const item = object[key];
|
|
342
342
|
const itemVariables = getVariablesFromFragment(fragment, item);
|
|
343
|
+
// $FlowFixMe[unsafe-object-assign]
|
|
343
344
|
Object.assign(variables, itemVariables);
|
|
344
345
|
}
|
|
345
346
|
}
|
|
@@ -397,6 +398,7 @@ function getVariablesFromPluralFragment(
|
|
|
397
398
|
if (value != null) {
|
|
398
399
|
const itemVariables = getVariablesFromSingularFragment(fragment, value);
|
|
399
400
|
if (itemVariables != null) {
|
|
401
|
+
// $FlowFixMe[unsafe-object-assign]
|
|
400
402
|
Object.assign(variables, itemVariables);
|
|
401
403
|
}
|
|
402
404
|
}
|