relay-runtime 10.0.1 → 10.1.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/RelayDefaultHandlerProvider.js.flow +6 -0
- package/handlers/connection/MutationHandlers.js.flow +114 -3
- package/index.js +1 -1
- package/index.js.flow +16 -1
- package/lib/handlers/RelayDefaultHandlerProvider.js +9 -0
- package/lib/handlers/connection/MutationHandlers.js +138 -12
- package/lib/index.js +7 -0
- package/lib/mutations/RelayDeclarativeMutationConfig.js +2 -2
- package/lib/mutations/commitMutation.js +1 -4
- package/lib/mutations/validateMutation.js +27 -7
- package/lib/network/RelayQueryResponseCache.js +2 -2
- package/lib/query/GraphQLTag.js +2 -1
- package/lib/query/fetchQuery.js +2 -3
- package/lib/query/fetchQueryInternal.js +2 -3
- package/lib/store/DataChecker.js +82 -5
- package/lib/store/RelayModernEnvironment.js +18 -6
- package/lib/store/RelayModernFragmentSpecResolver.js +10 -1
- package/lib/store/RelayModernOperationDescriptor.js +6 -5
- package/lib/store/RelayModernQueryExecutor.js +44 -23
- package/lib/store/RelayModernStore.js +25 -14
- package/lib/store/RelayOperationTracker.js +2 -2
- package/lib/store/RelayPublishQueue.js +1 -1
- package/lib/store/RelayReader.js +196 -33
- package/lib/store/RelayRecordSourceMapImpl.js +2 -2
- package/lib/store/RelayReferenceMarker.js +89 -5
- package/lib/store/RelayResponseNormalizer.js +119 -19
- package/lib/store/RelayStoreReactFlightUtils.js +47 -0
- package/lib/store/defaultRequiredFieldLogger.js +18 -0
- package/lib/store/normalizeRelayPayload.js +1 -1
- package/lib/subscription/requestSubscription.js +2 -3
- package/lib/util/NormalizationNode.js +1 -5
- package/lib/util/RelayConcreteNode.js +2 -0
- package/lib/util/RelayFeatureFlags.js +5 -2
- package/lib/util/getFragmentIdentifier.js +12 -3
- package/lib/util/getOperation.js +33 -0
- package/lib/util/isEmptyObject.js +25 -0
- package/lib/util/recycleNodesInto.js +4 -1
- package/lib/util/reportMissingRequiredFields.js +48 -0
- package/mutations/commitMutation.js.flow +1 -2
- package/mutations/validateMutation.js.flow +34 -5
- package/network/RelayNetworkTypes.js.flow +22 -0
- package/package.json +2 -2
- package/query/GraphQLTag.js.flow +3 -1
- package/query/fetchQuery.js.flow +2 -2
- package/query/fetchQueryInternal.js.flow +0 -5
- package/relay-runtime.js +2 -2
- package/relay-runtime.min.js +2 -2
- package/store/DataChecker.js.flow +68 -2
- package/store/RelayModernEnvironment.js.flow +29 -9
- package/store/RelayModernFragmentSpecResolver.js.flow +13 -1
- package/store/RelayModernOperationDescriptor.js.flow +5 -1
- package/store/RelayModernQueryExecutor.js.flow +47 -23
- package/store/RelayModernStore.js.flow +31 -15
- package/store/RelayPublishQueue.js.flow +1 -1
- package/store/RelayReader.js.flow +180 -15
- package/store/RelayReferenceMarker.js.flow +72 -5
- package/store/RelayResponseNormalizer.js.flow +130 -19
- package/store/RelayStoreReactFlightUtils.js.flow +64 -0
- package/store/RelayStoreTypes.js.flow +90 -31
- package/store/defaultRequiredFieldLogger.js.flow +23 -0
- package/subscription/requestSubscription.js.flow +5 -2
- package/util/NormalizationNode.js.flow +17 -2
- package/util/ReaderNode.js.flow +20 -1
- package/util/RelayConcreteNode.js.flow +6 -0
- package/util/RelayFeatureFlags.js.flow +8 -1
- package/util/getFragmentIdentifier.js.flow +33 -9
- package/util/getOperation.js.flow +40 -0
- package/util/isEmptyObject.js.flow +25 -0
- package/util/recycleNodesInto.js.flow +11 -0
- package/util/reportMissingRequiredFields.js.flow +51 -0
|
@@ -16,6 +16,7 @@ const RelayFeatureFlags = require('../util/RelayFeatureFlags');
|
|
|
16
16
|
const RelayModernRecord = require('./RelayModernRecord');
|
|
17
17
|
const RelayProfiler = require('../util/RelayProfiler');
|
|
18
18
|
|
|
19
|
+
const areEqual = require('areEqual');
|
|
19
20
|
const invariant = require('invariant');
|
|
20
21
|
const warning = require('warning');
|
|
21
22
|
|
|
@@ -23,6 +24,7 @@ const {
|
|
|
23
24
|
CONDITION,
|
|
24
25
|
CLIENT_EXTENSION,
|
|
25
26
|
DEFER,
|
|
27
|
+
FLIGHT_FIELD,
|
|
26
28
|
INLINE_FRAGMENT,
|
|
27
29
|
LINKED_FIELD,
|
|
28
30
|
LINKED_HANDLE,
|
|
@@ -34,6 +36,12 @@ const {
|
|
|
34
36
|
} = require('../util/RelayConcreteNode');
|
|
35
37
|
const {generateClientID, isClientID} = require('./ClientID');
|
|
36
38
|
const {createNormalizationSelector} = require('./RelayModernSelector');
|
|
39
|
+
const {
|
|
40
|
+
refineToReactFlightPayloadData,
|
|
41
|
+
REACT_FLIGHT_QUERIES_STORAGE_KEY,
|
|
42
|
+
REACT_FLIGHT_TREE_STORAGE_KEY,
|
|
43
|
+
REACT_FLIGHT_TYPE_NAME,
|
|
44
|
+
} = require('./RelayStoreReactFlightUtils');
|
|
37
45
|
const {
|
|
38
46
|
getArgumentValues,
|
|
39
47
|
getHandleStorageKey,
|
|
@@ -42,12 +50,14 @@ const {
|
|
|
42
50
|
getStorageKey,
|
|
43
51
|
TYPENAME_KEY,
|
|
44
52
|
ROOT_ID,
|
|
53
|
+
ROOT_TYPE,
|
|
45
54
|
} = require('./RelayStoreUtils');
|
|
46
55
|
const {generateTypeID, TYPE_SCHEMA_TYPE} = require('./TypeID');
|
|
47
56
|
|
|
48
57
|
import type {PayloadData} from '../network/RelayNetworkTypes';
|
|
49
58
|
import type {
|
|
50
59
|
NormalizationDefer,
|
|
60
|
+
NormalizationFlightField,
|
|
51
61
|
NormalizationLinkedField,
|
|
52
62
|
NormalizationModuleImport,
|
|
53
63
|
NormalizationNode,
|
|
@@ -61,6 +71,8 @@ import type {
|
|
|
61
71
|
ModuleImportPayload,
|
|
62
72
|
MutableRecordSource,
|
|
63
73
|
NormalizationSelector,
|
|
74
|
+
ReactFlightReachableQuery,
|
|
75
|
+
ReactFlightPayloadDeserializer,
|
|
64
76
|
Record,
|
|
65
77
|
RelayResponsePayload,
|
|
66
78
|
} from './RelayStoreTypes';
|
|
@@ -74,6 +86,7 @@ export type NormalizationOptions = {|
|
|
|
74
86
|
+getDataID: GetDataID,
|
|
75
87
|
+treatMissingFieldsAsNull: boolean,
|
|
76
88
|
+path?: $ReadOnlyArray<string>,
|
|
89
|
+
+reactFlightPayloadDeserializer?: ?ReactFlightPayloadDeserializer,
|
|
77
90
|
|};
|
|
78
91
|
|
|
79
92
|
/**
|
|
@@ -111,6 +124,7 @@ class RelayResponseNormalizer {
|
|
|
111
124
|
_path: Array<string>;
|
|
112
125
|
_recordSource: MutableRecordSource;
|
|
113
126
|
_variables: Variables;
|
|
127
|
+
_reactFlightPayloadDeserializer: ?ReactFlightPayloadDeserializer;
|
|
114
128
|
|
|
115
129
|
constructor(
|
|
116
130
|
recordSource: MutableRecordSource,
|
|
@@ -127,6 +141,8 @@ class RelayResponseNormalizer {
|
|
|
127
141
|
this._path = options.path ? [...options.path] : [];
|
|
128
142
|
this._recordSource = recordSource;
|
|
129
143
|
this._variables = variables;
|
|
144
|
+
this._reactFlightPayloadDeserializer =
|
|
145
|
+
options.reactFlightPayloadDeserializer;
|
|
130
146
|
}
|
|
131
147
|
|
|
132
148
|
normalizeResponse(
|
|
@@ -277,6 +293,13 @@ class RelayResponseNormalizer {
|
|
|
277
293
|
this._traverseSelections(selection, record, data);
|
|
278
294
|
this._isClientExtension = isClientExtension;
|
|
279
295
|
break;
|
|
296
|
+
case FLIGHT_FIELD:
|
|
297
|
+
if (RelayFeatureFlags.ENABLE_REACT_FLIGHT_COMPONENT_FIELD) {
|
|
298
|
+
this._normalizeFlightField(node, selection, record, data);
|
|
299
|
+
} else {
|
|
300
|
+
throw new Error('Flight fields are not yet supported.');
|
|
301
|
+
}
|
|
302
|
+
break;
|
|
280
303
|
default:
|
|
281
304
|
(selection: empty);
|
|
282
305
|
invariant(
|
|
@@ -441,23 +464,27 @@ class RelayResponseNormalizer {
|
|
|
441
464
|
return;
|
|
442
465
|
}
|
|
443
466
|
}
|
|
444
|
-
if (
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
467
|
+
if (__DEV__) {
|
|
468
|
+
if (selection.kind === SCALAR_FIELD) {
|
|
469
|
+
this._validateConflictingFieldsWithIdenticalId(
|
|
470
|
+
record,
|
|
471
|
+
storageKey,
|
|
472
|
+
fieldValue,
|
|
473
|
+
);
|
|
474
|
+
}
|
|
450
475
|
}
|
|
451
476
|
RelayModernRecord.setValue(record, storageKey, null);
|
|
452
477
|
return;
|
|
453
478
|
}
|
|
454
479
|
|
|
455
480
|
if (selection.kind === SCALAR_FIELD) {
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
481
|
+
if (__DEV__) {
|
|
482
|
+
this._validateConflictingFieldsWithIdenticalId(
|
|
483
|
+
record,
|
|
484
|
+
storageKey,
|
|
485
|
+
fieldValue,
|
|
486
|
+
);
|
|
487
|
+
}
|
|
461
488
|
RelayModernRecord.setValue(record, storageKey, fieldValue);
|
|
462
489
|
} else if (selection.kind === LINKED_FIELD) {
|
|
463
490
|
this._path.push(responseKey);
|
|
@@ -477,6 +504,84 @@ class RelayResponseNormalizer {
|
|
|
477
504
|
}
|
|
478
505
|
}
|
|
479
506
|
|
|
507
|
+
_normalizeFlightField(
|
|
508
|
+
parent: NormalizationNode,
|
|
509
|
+
selection: NormalizationFlightField,
|
|
510
|
+
record: Record,
|
|
511
|
+
data: PayloadData,
|
|
512
|
+
) {
|
|
513
|
+
const responseKey = selection.alias || selection.name;
|
|
514
|
+
const storageKey = getStorageKey(selection, this._variables);
|
|
515
|
+
const fieldValue = data[responseKey];
|
|
516
|
+
|
|
517
|
+
if (fieldValue == null) {
|
|
518
|
+
RelayModernRecord.setValue(record, storageKey, null);
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
const reactFlightPayload = refineToReactFlightPayloadData(fieldValue);
|
|
523
|
+
|
|
524
|
+
invariant(
|
|
525
|
+
reactFlightPayload != null,
|
|
526
|
+
'RelayResponseNormalizer(): Expected React Flight payload data ' +
|
|
527
|
+
'to be an object with `tree` and `queries` properties, got `%s`.',
|
|
528
|
+
fieldValue,
|
|
529
|
+
);
|
|
530
|
+
invariant(
|
|
531
|
+
typeof this._reactFlightPayloadDeserializer === 'function',
|
|
532
|
+
'RelayResponseNormalizer: Expected reactFlightPayloadDeserializer to ' +
|
|
533
|
+
'be a function, got `%s`.',
|
|
534
|
+
this._reactFlightPayloadDeserializer,
|
|
535
|
+
);
|
|
536
|
+
|
|
537
|
+
// We store the deserialized reactFlightClientResponse in a separate
|
|
538
|
+
// record and link it to the parent record. This is so we can GC the Flight
|
|
539
|
+
// tree later even if the parent record is still reachable.
|
|
540
|
+
const reactFlightClientResponse = this._reactFlightPayloadDeserializer(
|
|
541
|
+
reactFlightPayload.tree,
|
|
542
|
+
);
|
|
543
|
+
const reactFlightID = generateClientID(
|
|
544
|
+
RelayModernRecord.getDataID(record),
|
|
545
|
+
getStorageKey(selection, this._variables),
|
|
546
|
+
);
|
|
547
|
+
let reactFlightClientResponseRecord = this._recordSource.get(reactFlightID);
|
|
548
|
+
if (reactFlightClientResponseRecord == null) {
|
|
549
|
+
reactFlightClientResponseRecord = RelayModernRecord.create(
|
|
550
|
+
reactFlightID,
|
|
551
|
+
REACT_FLIGHT_TYPE_NAME,
|
|
552
|
+
);
|
|
553
|
+
this._recordSource.set(reactFlightID, reactFlightClientResponseRecord);
|
|
554
|
+
}
|
|
555
|
+
RelayModernRecord.setValue(
|
|
556
|
+
reactFlightClientResponseRecord,
|
|
557
|
+
REACT_FLIGHT_TREE_STORAGE_KEY,
|
|
558
|
+
reactFlightClientResponse,
|
|
559
|
+
);
|
|
560
|
+
const reachableQueries: Array<ReactFlightReachableQuery> = [];
|
|
561
|
+
for (const query of reactFlightPayload.queries) {
|
|
562
|
+
if (query.response.data != null) {
|
|
563
|
+
this._moduleImportPayloads.push({
|
|
564
|
+
data: query.response.data,
|
|
565
|
+
dataID: ROOT_ID,
|
|
566
|
+
operationReference: query.module,
|
|
567
|
+
path: [],
|
|
568
|
+
typeName: ROOT_TYPE,
|
|
569
|
+
variables: query.variables,
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
reachableQueries.push({
|
|
573
|
+
module: query.module,
|
|
574
|
+
variables: query.variables,
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
RelayModernRecord.setValue(
|
|
578
|
+
reactFlightClientResponseRecord,
|
|
579
|
+
REACT_FLIGHT_QUERIES_STORAGE_KEY,
|
|
580
|
+
reachableQueries,
|
|
581
|
+
);
|
|
582
|
+
RelayModernRecord.setLinkedRecordID(record, storageKey, reactFlightID);
|
|
583
|
+
}
|
|
584
|
+
|
|
480
585
|
_normalizeLink(
|
|
481
586
|
field: NormalizationLinkedField,
|
|
482
587
|
record: Record,
|
|
@@ -582,13 +687,17 @@ class RelayResponseNormalizer {
|
|
|
582
687
|
} else if (__DEV__) {
|
|
583
688
|
this._validateRecordType(nextRecord, field, item);
|
|
584
689
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
690
|
+
// NOTE: the check to strip __DEV__ code only works for simple
|
|
691
|
+
// `if (__DEV__)`
|
|
692
|
+
if (__DEV__) {
|
|
693
|
+
if (prevIDs) {
|
|
694
|
+
this._validateConflictingLinkedFieldsWithIdenticalId(
|
|
695
|
+
record,
|
|
696
|
+
prevIDs[nextIndex],
|
|
697
|
+
nextID,
|
|
698
|
+
storageKey,
|
|
699
|
+
);
|
|
700
|
+
}
|
|
592
701
|
}
|
|
593
702
|
// $FlowFixMe[incompatible-variance]
|
|
594
703
|
this._traverseSelections(field, nextRecord, item);
|
|
@@ -629,13 +738,14 @@ class RelayResponseNormalizer {
|
|
|
629
738
|
storageKey: string,
|
|
630
739
|
fieldValue: mixed,
|
|
631
740
|
): void {
|
|
741
|
+
// NOTE: Only call this function in DEV
|
|
632
742
|
if (__DEV__) {
|
|
633
743
|
const dataID = RelayModernRecord.getDataID(record);
|
|
634
744
|
var previousValue = RelayModernRecord.getValue(record, storageKey);
|
|
635
745
|
warning(
|
|
636
746
|
storageKey === TYPENAME_KEY ||
|
|
637
747
|
previousValue === undefined ||
|
|
638
|
-
previousValue
|
|
748
|
+
areEqual(previousValue, fieldValue),
|
|
639
749
|
'RelayResponseNormalizer: Invalid record. The record contains two ' +
|
|
640
750
|
'instances of the same id: `%s` with conflicting field, %s and its values: %s and %s. ' +
|
|
641
751
|
'If two fields are different but share ' +
|
|
@@ -657,6 +767,7 @@ class RelayResponseNormalizer {
|
|
|
657
767
|
nextID: DataID,
|
|
658
768
|
storageKey: string,
|
|
659
769
|
): void {
|
|
770
|
+
// NOTE: Only call this function in DEV
|
|
660
771
|
if (__DEV__) {
|
|
661
772
|
warning(
|
|
662
773
|
prevID === undefined || prevID === nextID,
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// flowlint ambiguous-object-type:error
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
const invariant = require('invariant');
|
|
16
|
+
|
|
17
|
+
const {getType} = require('./RelayModernRecord');
|
|
18
|
+
|
|
19
|
+
import type {ReactFlightPayloadData} from '../network/RelayNetworkTypes';
|
|
20
|
+
import type {ReactFlightClientResponse, Record} from './RelayStoreTypes';
|
|
21
|
+
|
|
22
|
+
const REACT_FLIGHT_QUERIES_STORAGE_KEY = 'queries';
|
|
23
|
+
const REACT_FLIGHT_TREE_STORAGE_KEY = 'tree';
|
|
24
|
+
const REACT_FLIGHT_TYPE_NAME = 'ReactFlightComponent';
|
|
25
|
+
|
|
26
|
+
function refineToReactFlightPayloadData(
|
|
27
|
+
payload: mixed,
|
|
28
|
+
): ?ReactFlightPayloadData {
|
|
29
|
+
if (
|
|
30
|
+
payload == null ||
|
|
31
|
+
typeof payload !== 'object' ||
|
|
32
|
+
!Array.isArray(payload.tree) ||
|
|
33
|
+
!Array.isArray(payload.queries)
|
|
34
|
+
) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
return (payload: $FlowFixMe);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function getReactFlightClientResponse(
|
|
41
|
+
record: Record,
|
|
42
|
+
): ?ReactFlightClientResponse {
|
|
43
|
+
invariant(
|
|
44
|
+
getType(record) === REACT_FLIGHT_TYPE_NAME,
|
|
45
|
+
'getReactFlightClientResponse(): Expected a ReactFlightComponentRecord, ' +
|
|
46
|
+
'got %s.',
|
|
47
|
+
record,
|
|
48
|
+
);
|
|
49
|
+
const response: ?ReactFlightClientResponse = (record[
|
|
50
|
+
REACT_FLIGHT_TREE_STORAGE_KEY
|
|
51
|
+
]: $FlowFixMe);
|
|
52
|
+
if (response != null) {
|
|
53
|
+
return response;
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
module.exports = {
|
|
59
|
+
REACT_FLIGHT_QUERIES_STORAGE_KEY,
|
|
60
|
+
REACT_FLIGHT_TREE_STORAGE_KEY,
|
|
61
|
+
REACT_FLIGHT_TYPE_NAME,
|
|
62
|
+
getReactFlightClientResponse,
|
|
63
|
+
refineToReactFlightPayloadData,
|
|
64
|
+
};
|
|
@@ -17,14 +17,15 @@ import type {
|
|
|
17
17
|
INetwork,
|
|
18
18
|
PayloadData,
|
|
19
19
|
PayloadError,
|
|
20
|
+
ReactFlightServerTree,
|
|
20
21
|
UploadableMap,
|
|
21
22
|
} from '../network/RelayNetworkTypes';
|
|
22
23
|
import type RelayObservable from '../network/RelayObservable';
|
|
23
24
|
import type {
|
|
24
25
|
NormalizationLinkedField,
|
|
26
|
+
NormalizationRootNode,
|
|
25
27
|
NormalizationScalarField,
|
|
26
28
|
NormalizationSelectableNode,
|
|
27
|
-
NormalizationSplitOperation,
|
|
28
29
|
} from '../util/NormalizationNode';
|
|
29
30
|
import type {ReaderFragment} from '../util/ReaderNode';
|
|
30
31
|
import type {
|
|
@@ -83,6 +84,7 @@ export type RequestDescriptor = {|
|
|
|
83
84
|
+identifier: RequestIdentifier,
|
|
84
85
|
+node: ConcreteRequest,
|
|
85
86
|
+variables: Variables,
|
|
87
|
+
+cacheConfig: ?CacheConfig,
|
|
86
88
|
|};
|
|
87
89
|
|
|
88
90
|
/**
|
|
@@ -95,16 +97,25 @@ export type NormalizationSelector = {|
|
|
|
95
97
|
+variables: Variables,
|
|
96
98
|
|};
|
|
97
99
|
|
|
100
|
+
type MissingRequiredField = {|
|
|
101
|
+
path: string,
|
|
102
|
+
owner: string,
|
|
103
|
+
|};
|
|
104
|
+
|
|
105
|
+
export type MissingRequiredFields =
|
|
106
|
+
| {|action: 'THROW', field: MissingRequiredField|}
|
|
107
|
+
| {|action: 'LOG', fields: Array<MissingRequiredField>|};
|
|
108
|
+
|
|
98
109
|
/**
|
|
99
110
|
* A representation of a selector and its results at a particular point in time.
|
|
100
111
|
*/
|
|
101
|
-
export type
|
|
102
|
-
+data:
|
|
112
|
+
export type Snapshot = {|
|
|
113
|
+
+data: ?SelectorData,
|
|
103
114
|
+isMissingData: boolean,
|
|
104
115
|
+seenRecords: RecordMap,
|
|
105
116
|
+selector: SingularReaderSelector,
|
|
117
|
+
+missingRequiredFields: ?MissingRequiredFields,
|
|
106
118
|
|};
|
|
107
|
-
export type Snapshot = TypedSnapshot<?SelectorData>;
|
|
108
119
|
|
|
109
120
|
/**
|
|
110
121
|
* An operation selector describes a specific instance of a GraphQL operation
|
|
@@ -236,8 +247,6 @@ export interface Store {
|
|
|
236
247
|
|
|
237
248
|
/**
|
|
238
249
|
* Read the results of a selector from in-memory records in the store.
|
|
239
|
-
* Optionally takes an owner, corresponding to the operation that
|
|
240
|
-
* owns this selector (fragment).
|
|
241
250
|
*/
|
|
242
251
|
lookup(selector: SingularReaderSelector): Snapshot;
|
|
243
252
|
|
|
@@ -247,7 +256,7 @@ export interface Store {
|
|
|
247
256
|
* Optionally provide an OperationDescriptor indicating the source operation
|
|
248
257
|
* that was being processed to produce this run.
|
|
249
258
|
*
|
|
250
|
-
* This method should return an array of the affected fragment owners
|
|
259
|
+
* This method should return an array of the affected fragment owners.
|
|
251
260
|
*/
|
|
252
261
|
notify(
|
|
253
262
|
sourceOperation?: OperationDescriptor,
|
|
@@ -263,7 +272,7 @@ export interface Store {
|
|
|
263
272
|
|
|
264
273
|
/**
|
|
265
274
|
* Ensure that all the records necessary to fulfill the given selector are
|
|
266
|
-
* retained in
|
|
275
|
+
* retained in memory. The records will not be eligible for garbage collection
|
|
267
276
|
* until the returned reference is disposed.
|
|
268
277
|
*/
|
|
269
278
|
retain(operation: OperationDescriptor): Disposable;
|
|
@@ -472,7 +481,13 @@ export type LogEvent =
|
|
|
472
481
|
+name: 'store.notify.complete',
|
|
473
482
|
+updatedRecordIDs: UpdatedRecords,
|
|
474
483
|
+invalidatedRecordIDs: Set<DataID>,
|
|
484
|
+
|}
|
|
485
|
+
| {|
|
|
486
|
+
+name: 'entrypoint.root.consume',
|
|
487
|
+
+profilerContext: mixed,
|
|
488
|
+
+rootModuleID: string,
|
|
475
489
|
|};
|
|
490
|
+
|
|
476
491
|
export type LogFunction = LogEvent => void;
|
|
477
492
|
export type LogRequestInfoFunction = mixed => void;
|
|
478
493
|
|
|
@@ -563,14 +578,12 @@ export interface IEnvironment {
|
|
|
563
578
|
/**
|
|
564
579
|
* EXPERIMENTAL
|
|
565
580
|
* Returns the default render policy to use when rendering a query
|
|
566
|
-
* that uses Relay Hooks
|
|
581
|
+
* that uses Relay Hooks.
|
|
567
582
|
*/
|
|
568
583
|
UNSTABLE_getDefaultRenderPolicy(): RenderPolicy;
|
|
569
584
|
|
|
570
585
|
/**
|
|
571
586
|
* Read the results of a selector from in-memory records in the store.
|
|
572
|
-
* Optionally takes an owner, corresponding to the operation that
|
|
573
|
-
* owns this selector (fragment).
|
|
574
587
|
*/
|
|
575
588
|
lookup(selector: SingularReaderSelector): Snapshot;
|
|
576
589
|
|
|
@@ -587,7 +600,6 @@ export interface IEnvironment {
|
|
|
587
600
|
*/
|
|
588
601
|
execute(config: {|
|
|
589
602
|
operation: OperationDescriptor,
|
|
590
|
-
cacheConfig?: ?CacheConfig,
|
|
591
603
|
updater?: ?SelectorStoreUpdater,
|
|
592
604
|
|}): RelayObservable<GraphQLResponse>;
|
|
593
605
|
|
|
@@ -602,7 +614,6 @@ export interface IEnvironment {
|
|
|
602
614
|
* environment.executeMutation({...}).subscribe({...}).
|
|
603
615
|
*/
|
|
604
616
|
executeMutation({|
|
|
605
|
-
cacheConfig?: ?CacheConfig,
|
|
606
617
|
operation: OperationDescriptor,
|
|
607
618
|
optimisticUpdater?: ?SelectorStoreUpdater,
|
|
608
619
|
optimisticResponse?: ?Object,
|
|
@@ -639,18 +650,13 @@ export interface IEnvironment {
|
|
|
639
650
|
* whether we need to set up certain caches and timeout's.
|
|
640
651
|
*/
|
|
641
652
|
isServer(): boolean;
|
|
642
|
-
}
|
|
643
653
|
|
|
644
|
-
/**
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
__fragments: {[fragmentName: string]: Variables, ...},
|
|
651
|
-
__fragmentOwner: RequestDescriptor,
|
|
652
|
-
...
|
|
653
|
-
};
|
|
654
|
+
/**
|
|
655
|
+
* Called by Relay when it encounters a missing field that has been annotated
|
|
656
|
+
* with `@required(action: LOG)`.
|
|
657
|
+
*/
|
|
658
|
+
requiredFieldLogger: RequiredFieldLogger;
|
|
659
|
+
}
|
|
654
660
|
|
|
655
661
|
/**
|
|
656
662
|
* The partial shape of an object with a '...Fragment @module(name: "...")'
|
|
@@ -699,7 +705,9 @@ export type HandleFieldPayload = {|
|
|
|
699
705
|
|
|
700
706
|
/**
|
|
701
707
|
* A payload that represents data necessary to process the results of an object
|
|
702
|
-
* with a `@module` fragment spread:
|
|
708
|
+
* with a `@module` fragment spread, or a Flight field's:
|
|
709
|
+
*
|
|
710
|
+
* ## @module Fragment Spread
|
|
703
711
|
* - data: The GraphQL response value for the @match field.
|
|
704
712
|
* - dataID: The ID of the store object linked to by the @match field.
|
|
705
713
|
* - operationReference: A reference to a generated module containing the
|
|
@@ -710,6 +718,21 @@ export type HandleFieldPayload = {|
|
|
|
710
718
|
* The dataID, variables, and fragmentName can be used to create a Selector
|
|
711
719
|
* which can in turn be used to normalize and publish the data. The dataID and
|
|
712
720
|
* typeName can also be used to construct a root record for normalization.
|
|
721
|
+
*
|
|
722
|
+
* ## Flight fields
|
|
723
|
+
* In Flight, data for additional components rendered by the requested server
|
|
724
|
+
* component are included in the response returned by a Flight compliant server.
|
|
725
|
+
*
|
|
726
|
+
* - data: Data used by additional components rendered by the server component
|
|
727
|
+
* being requested.
|
|
728
|
+
* - dataID: For Flight fields, this should always be ROOT_ID. This is because
|
|
729
|
+
* the query data isn't relative to the parent record–it's root data.
|
|
730
|
+
* - operationReference: The query's module that will be later used by an
|
|
731
|
+
* operation loader.
|
|
732
|
+
* - variables: The query's variables.
|
|
733
|
+
* - typeName: For Flight fields, this should always be ROOT_TYPE. This is
|
|
734
|
+
* because the query data isn't relative to the parent record–it's
|
|
735
|
+
* root data.
|
|
713
736
|
*/
|
|
714
737
|
export type ModuleImportPayload = {|
|
|
715
738
|
+data: PayloadData,
|
|
@@ -744,22 +767,22 @@ export type StreamPlaceholder = {|
|
|
|
744
767
|
export type IncrementalDataPlaceholder = DeferPlaceholder | StreamPlaceholder;
|
|
745
768
|
|
|
746
769
|
/**
|
|
747
|
-
* A user-supplied object to load a generated operation (SplitOperation
|
|
748
|
-
* by a module reference. The exact format of a module
|
|
749
|
-
* the application, but it must be a plain JavaScript value
|
|
750
|
-
* or object/array of same).
|
|
770
|
+
* A user-supplied object to load a generated operation (SplitOperation or
|
|
771
|
+
* ConcreteRequest) AST by a module reference. The exact format of a module
|
|
772
|
+
* reference is left to the application, but it must be a plain JavaScript value
|
|
773
|
+
* (string, number, or object/array of same).
|
|
751
774
|
*/
|
|
752
775
|
export type OperationLoader = {|
|
|
753
776
|
/**
|
|
754
777
|
* Synchronously load an operation, returning either the node or null if it
|
|
755
778
|
* cannot be resolved synchronously.
|
|
756
779
|
*/
|
|
757
|
-
get(reference: mixed): ?
|
|
780
|
+
get(reference: mixed): ?NormalizationRootNode,
|
|
758
781
|
|
|
759
782
|
/**
|
|
760
783
|
* Asynchronously load an operation.
|
|
761
784
|
*/
|
|
762
|
-
load(reference: mixed): Promise<?
|
|
785
|
+
load(reference: mixed): Promise<?NormalizationRootNode>,
|
|
763
786
|
|};
|
|
764
787
|
|
|
765
788
|
/**
|
|
@@ -837,6 +860,23 @@ export type MissingFieldHandler =
|
|
|
837
860
|
) => ?Array<?DataID>,
|
|
838
861
|
|};
|
|
839
862
|
|
|
863
|
+
/**
|
|
864
|
+
* A handler for events related to @required fields. Currently reports missing
|
|
865
|
+
* fields with either `action: LOG` or `action: THROW`.
|
|
866
|
+
*/
|
|
867
|
+
export type RequiredFieldLogger = (
|
|
868
|
+
| {|
|
|
869
|
+
+kind: 'missing_field.log',
|
|
870
|
+
+owner: string,
|
|
871
|
+
+fieldPath: string,
|
|
872
|
+
|}
|
|
873
|
+
| {|
|
|
874
|
+
+kind: 'missing_field.throw',
|
|
875
|
+
+owner: string,
|
|
876
|
+
+fieldPath: string,
|
|
877
|
+
|},
|
|
878
|
+
) => void;
|
|
879
|
+
|
|
840
880
|
/**
|
|
841
881
|
* The results of normalizing a query.
|
|
842
882
|
*/
|
|
@@ -897,3 +937,22 @@ export interface PublishQueue {
|
|
|
897
937
|
*/
|
|
898
938
|
run(sourceOperation?: OperationDescriptor): $ReadOnlyArray<RequestDescriptor>;
|
|
899
939
|
}
|
|
940
|
+
|
|
941
|
+
/**
|
|
942
|
+
* ReactFlightDOMRelayClient processes a ReactFlightServerTree into a
|
|
943
|
+
* ReactFlightClientResponse object. readRoot() can suspend.
|
|
944
|
+
*/
|
|
945
|
+
export type ReactFlightClientResponse = {readRoot: () => mixed, ...};
|
|
946
|
+
|
|
947
|
+
export type ReactFlightReachableQuery = {|
|
|
948
|
+
+module: mixed,
|
|
949
|
+
+variables: Variables,
|
|
950
|
+
|};
|
|
951
|
+
|
|
952
|
+
/**
|
|
953
|
+
* A user-supplied function that takes a ReactFlightServerTree, and deserializes
|
|
954
|
+
* it into a ReactFlightClientResponse object.
|
|
955
|
+
*/
|
|
956
|
+
export type ReactFlightPayloadDeserializer = (
|
|
957
|
+
tree: ReactFlightServerTree,
|
|
958
|
+
) => ReactFlightClientResponse;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict-local
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
import type {RequiredFieldLogger} from './RelayStoreTypes';
|
|
14
|
+
|
|
15
|
+
const defaultRequiredFieldLogger: RequiredFieldLogger = event => {
|
|
16
|
+
if (__DEV__ && event.kind === 'missing_field.log') {
|
|
17
|
+
throw new Error(
|
|
18
|
+
'Relay Environment Configuration Error (dev only): `@required(action: LOG)` requires that the Relay Environment be configured with a `requiredFieldLogger`.',
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
module.exports = defaultRequiredFieldLogger;
|
|
@@ -60,7 +60,11 @@ function requestSubscription<TSubscriptionPayload>(
|
|
|
60
60
|
variables,
|
|
61
61
|
cacheConfig,
|
|
62
62
|
} = config;
|
|
63
|
-
const operation = createOperationDescriptor(
|
|
63
|
+
const operation = createOperationDescriptor(
|
|
64
|
+
subscription,
|
|
65
|
+
variables,
|
|
66
|
+
cacheConfig,
|
|
67
|
+
);
|
|
64
68
|
|
|
65
69
|
warning(
|
|
66
70
|
!(config.updater && configs),
|
|
@@ -80,7 +84,6 @@ function requestSubscription<TSubscriptionPayload>(
|
|
|
80
84
|
.execute({
|
|
81
85
|
operation,
|
|
82
86
|
updater,
|
|
83
|
-
cacheConfig,
|
|
84
87
|
})
|
|
85
88
|
.map(() => {
|
|
86
89
|
const data = environment.lookup(operation.fragment).data;
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
'use strict';
|
|
14
14
|
|
|
15
|
+
import type {ConcreteRequest} from './RelayConcreteNode';
|
|
16
|
+
|
|
15
17
|
/**
|
|
16
18
|
* Represents a single operation used to processing and normalize runtime
|
|
17
19
|
* request results.
|
|
@@ -34,7 +36,6 @@ export type NormalizationLinkedHandle = {|
|
|
|
34
36
|
+args: ?$ReadOnlyArray<NormalizationArgument>,
|
|
35
37
|
+handle: string,
|
|
36
38
|
+key: string,
|
|
37
|
-
// T45504512: new connection model
|
|
38
39
|
// NOTE: this property is optional because it's expected to be rarely used
|
|
39
40
|
+dynamicKey?: ?NormalizationArgument,
|
|
40
41
|
+filters: ?$ReadOnlyArray<string>,
|
|
@@ -48,10 +49,10 @@ export type NormalizationScalarHandle = {|
|
|
|
48
49
|
+args: ?$ReadOnlyArray<NormalizationArgument>,
|
|
49
50
|
+handle: string,
|
|
50
51
|
+key: string,
|
|
51
|
-
// T45504512: new connection model
|
|
52
52
|
// NOTE: this property is optional because it's expected to be rarely used
|
|
53
53
|
+dynamicKey?: ?NormalizationArgument,
|
|
54
54
|
+filters: ?$ReadOnlyArray<string>,
|
|
55
|
+
+handleArgs?: $ReadOnlyArray<NormalizationArgument>,
|
|
55
56
|
|};
|
|
56
57
|
|
|
57
58
|
export type NormalizationArgument =
|
|
@@ -73,6 +74,7 @@ export type NormalizationClientExtension = {|
|
|
|
73
74
|
|};
|
|
74
75
|
|
|
75
76
|
export type NormalizationField =
|
|
77
|
+
| NormalizationFlightField
|
|
76
78
|
| NormalizationScalarField
|
|
77
79
|
| NormalizationLinkedField;
|
|
78
80
|
|
|
@@ -138,6 +140,14 @@ export type NormalizationScalarField = {|
|
|
|
138
140
|
+storageKey: ?string,
|
|
139
141
|
|};
|
|
140
142
|
|
|
143
|
+
export type NormalizationFlightField = {|
|
|
144
|
+
+kind: 'FlightField',
|
|
145
|
+
+alias: ?string,
|
|
146
|
+
+name: string,
|
|
147
|
+
+args: ?$ReadOnlyArray<NormalizationArgument>,
|
|
148
|
+
+storageKey: ?string,
|
|
149
|
+
|};
|
|
150
|
+
|
|
141
151
|
export type NormalizationTypeDiscriminator = {|
|
|
142
152
|
+kind: 'TypeDiscriminator',
|
|
143
153
|
+abstractKey: string,
|
|
@@ -148,6 +158,7 @@ export type NormalizationSelection =
|
|
|
148
158
|
| NormalizationClientExtension
|
|
149
159
|
| NormalizationDefer
|
|
150
160
|
| NormalizationField
|
|
161
|
+
| NormalizationFlightField
|
|
151
162
|
| NormalizationHandle
|
|
152
163
|
| NormalizationInlineFragment
|
|
153
164
|
| NormalizationModuleImport
|
|
@@ -196,3 +207,7 @@ export type NormalizationSelectableNode =
|
|
|
196
207
|
| NormalizationOperation
|
|
197
208
|
| NormalizationSplitOperation
|
|
198
209
|
| NormalizationStream;
|
|
210
|
+
|
|
211
|
+
export type NormalizationRootNode =
|
|
212
|
+
| ConcreteRequest
|
|
213
|
+
| NormalizationSplitOperation;
|