relay-runtime 18.1.0 → 19.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 +22 -9
- package/handlers/connection/ConnectionHandler.js.flow +6 -1
- package/index.js +1 -1
- package/index.js.flow +4 -0
- package/lib/experimental.js +5 -2
- package/lib/handlers/connection/ConnectionHandler.js +1 -1
- package/lib/index.js +3 -0
- package/lib/multi-actor-environment/ActorSpecificEnvironment.js +1 -1
- package/lib/mutations/RelayRecordProxy.js +14 -3
- package/lib/mutations/RelayRecordSourceMutator.js +17 -0
- 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 +4 -5
- package/lib/store/OperationExecutor.js +11 -0
- package/lib/store/RelayModernEnvironment.js +13 -4
- package/lib/store/RelayModernFragmentSpecResolver.js +4 -4
- package/lib/store/RelayModernStore.js +43 -21
- package/lib/store/RelayPublishQueue.js +11 -15
- package/lib/store/RelayReader.js +244 -183
- package/lib/store/RelayReferenceMarker.js +3 -4
- package/lib/store/RelayResponseNormalizer.js +48 -26
- package/lib/store/RelayStoreSubscriptions.js +2 -2
- package/lib/store/RelayStoreUtils.js +8 -0
- package/lib/store/ResolverCache.js +1 -165
- 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 +5 -10
- package/lib/store/live-resolvers/resolverDataInjector.js +4 -4
- package/lib/store/observeFragmentExperimental.js +60 -13
- package/lib/store/observeQueryExperimental.js +21 -0
- package/lib/util/RelayFeatureFlags.js +7 -2
- package/lib/util/handlePotentialSnapshotErrors.js +12 -9
- package/multi-actor-environment/ActorSpecificEnvironment.js.flow +1 -0
- package/mutations/RelayRecordProxy.js.flow +30 -3
- package/mutations/RelayRecordSourceMutator.js.flow +27 -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 +5 -2
- package/store/OperationExecutor.js.flow +12 -1
- package/store/RelayExperimentalGraphResponseTransform.js.flow +4 -4
- package/store/RelayModernEnvironment.js.flow +22 -6
- package/store/RelayModernFragmentSpecResolver.js.flow +6 -6
- package/store/RelayModernRecord.js.flow +1 -1
- package/store/RelayModernSelector.js.flow +2 -0
- package/store/RelayModernStore.js.flow +74 -27
- package/store/RelayOptimisticRecordSource.js.flow +2 -0
- package/store/RelayPublishQueue.js.flow +32 -21
- package/store/RelayReader.js.flow +400 -145
- package/store/RelayRecordState.js.flow +1 -1
- package/store/RelayReferenceMarker.js.flow +3 -4
- package/store/RelayResponseNormalizer.js.flow +94 -62
- package/store/RelayStoreSubscriptions.js.flow +2 -2
- package/store/RelayStoreTypes.js.flow +45 -15
- package/store/RelayStoreUtils.js.flow +30 -1
- package/store/ResolverCache.js.flow +2 -271
- 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 +5 -10
- package/store/live-resolvers/resolverDataInjector.js.flow +10 -6
- 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 +10 -1
- package/util/ReaderNode.js.flow +9 -3
- package/util/RelayConcreteNode.js.flow +3 -1
- package/util/RelayError.js.flow +1 -0
- package/util/RelayFeatureFlags.js.flow +31 -7
- package/util/RelayRuntimeTypes.js.flow +17 -3
- package/util/getPaginationVariables.js.flow +2 -0
- package/util/handlePotentialSnapshotErrors.js.flow +24 -12
- 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
|
@@ -38,7 +38,8 @@ const RelayStoreUtils = require('./RelayStoreUtils');
|
|
|
38
38
|
const {generateTypeID} = require('./TypeID');
|
|
39
39
|
const invariant = require('invariant');
|
|
40
40
|
|
|
41
|
-
const {getStorageKey, getModuleOperationKey} =
|
|
41
|
+
const {getReadTimeResolverStorageKey, getStorageKey, getModuleOperationKey} =
|
|
42
|
+
RelayStoreUtils;
|
|
42
43
|
|
|
43
44
|
function mark(
|
|
44
45
|
recordSource: RecordSource,
|
|
@@ -216,8 +217,6 @@ class RelayReferenceMarker {
|
|
|
216
217
|
this._traverseSelections(selection.fragment.selections, record);
|
|
217
218
|
break;
|
|
218
219
|
case 'RelayResolver':
|
|
219
|
-
this._traverseResolverField(selection, record);
|
|
220
|
-
break;
|
|
221
220
|
case 'RelayLiveResolver':
|
|
222
221
|
this._traverseResolverField(selection, record);
|
|
223
222
|
break;
|
|
@@ -291,7 +290,7 @@ class RelayReferenceMarker {
|
|
|
291
290
|
field: NormalizationResolverField | NormalizationLiveResolverField,
|
|
292
291
|
record: Record,
|
|
293
292
|
): ?DataID {
|
|
294
|
-
const storageKey =
|
|
293
|
+
const storageKey = getReadTimeResolverStorageKey(field, this._variables);
|
|
295
294
|
const dataID = RelayModernRecord.getLinkedRecordID(record, storageKey);
|
|
296
295
|
|
|
297
296
|
// If the resolver value has been created, we should retain it.
|
|
@@ -29,7 +29,9 @@ import type {RelayErrorTrie} from './RelayErrorTrie';
|
|
|
29
29
|
import type {
|
|
30
30
|
FollowupPayload,
|
|
31
31
|
HandleFieldPayload,
|
|
32
|
+
IdCollisionTypenameLogEvent,
|
|
32
33
|
IncrementalDataPlaceholder,
|
|
34
|
+
LogFunction,
|
|
33
35
|
MutableRecordSource,
|
|
34
36
|
NormalizationSelector,
|
|
35
37
|
Record,
|
|
@@ -40,6 +42,7 @@ const {
|
|
|
40
42
|
ACTOR_IDENTIFIER_FIELD_NAME,
|
|
41
43
|
getActorIdentifierFromPayload,
|
|
42
44
|
} = require('../multi-actor-environment/ActorUtils');
|
|
45
|
+
const RelayFeatureFlags = require('../util/RelayFeatureFlags');
|
|
43
46
|
const {generateClientID, isClientID} = require('./ClientID');
|
|
44
47
|
const {getLocalVariables} = require('./RelayConcreteVariables');
|
|
45
48
|
const {
|
|
@@ -71,6 +74,7 @@ export type GetDataID = (
|
|
|
71
74
|
export type NormalizationOptions = {
|
|
72
75
|
+getDataID: GetDataID,
|
|
73
76
|
+treatMissingFieldsAsNull: boolean,
|
|
77
|
+
+log: ?LogFunction,
|
|
74
78
|
+path?: $ReadOnlyArray<string>,
|
|
75
79
|
+shouldProcessClientComponents?: ?boolean,
|
|
76
80
|
+actorIdentifier?: ?ActorIdentifier,
|
|
@@ -115,6 +119,7 @@ class RelayResponseNormalizer {
|
|
|
115
119
|
_variables: Variables;
|
|
116
120
|
_shouldProcessClientComponents: ?boolean;
|
|
117
121
|
_errorTrie: RelayErrorTrie | null;
|
|
122
|
+
_log: ?LogFunction;
|
|
118
123
|
|
|
119
124
|
constructor(
|
|
120
125
|
recordSource: MutableRecordSource,
|
|
@@ -133,6 +138,7 @@ class RelayResponseNormalizer {
|
|
|
133
138
|
this._recordSource = recordSource;
|
|
134
139
|
this._variables = variables;
|
|
135
140
|
this._shouldProcessClientComponents = options.shouldProcessClientComponents;
|
|
141
|
+
this._log = options.log;
|
|
136
142
|
}
|
|
137
143
|
|
|
138
144
|
normalizeResponse(
|
|
@@ -318,8 +324,6 @@ class RelayResponseNormalizer {
|
|
|
318
324
|
this._normalizeActorChange(selection, record, data);
|
|
319
325
|
break;
|
|
320
326
|
case 'RelayResolver':
|
|
321
|
-
this._normalizeResolver(selection, record, data);
|
|
322
|
-
break;
|
|
323
327
|
case 'RelayLiveResolver':
|
|
324
328
|
this._normalizeResolver(selection, record, data);
|
|
325
329
|
break;
|
|
@@ -471,7 +475,11 @@ class RelayResponseNormalizer {
|
|
|
471
475
|
const responseKey = selection.alias || selection.name;
|
|
472
476
|
const storageKey = getStorageKey(selection, this._variables);
|
|
473
477
|
const fieldValue = data[responseKey];
|
|
474
|
-
|
|
478
|
+
const isNoncompliantlyNullish =
|
|
479
|
+
RelayFeatureFlags.ENABLE_NONCOMPLIANT_ERROR_HANDLING_ON_LISTS &&
|
|
480
|
+
Array.isArray(fieldValue) &&
|
|
481
|
+
fieldValue.length === 0;
|
|
482
|
+
if (fieldValue == null || isNoncompliantlyNullish) {
|
|
475
483
|
if (fieldValue === undefined) {
|
|
476
484
|
// Fields may be missing in the response in two main cases:
|
|
477
485
|
// - Inside a client extension: the server will not generally return
|
|
@@ -505,20 +513,27 @@ class RelayResponseNormalizer {
|
|
|
505
513
|
return;
|
|
506
514
|
}
|
|
507
515
|
}
|
|
508
|
-
if (
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
516
|
+
if (selection.kind === 'ScalarField') {
|
|
517
|
+
this._validateConflictingFieldsWithIdenticalId(
|
|
518
|
+
record,
|
|
519
|
+
storageKey,
|
|
520
|
+
// When using `treatMissingFieldsAsNull` the conflicting validation raises a false positive
|
|
521
|
+
// because the value is set using `null` but validated using `fieldValue` which at this point
|
|
522
|
+
// will be `undefined`.
|
|
523
|
+
// Setting this to `null` matches the value that we actually set to the `fieldValue`.
|
|
524
|
+
null,
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
if (isNoncompliantlyNullish) {
|
|
528
|
+
// We need to preserve the fact that we received an empty list
|
|
529
|
+
if (selection.kind === 'LinkedField') {
|
|
530
|
+
RelayModernRecord.setLinkedRecordIDs(record, storageKey, []);
|
|
531
|
+
} else {
|
|
532
|
+
RelayModernRecord.setValue(record, storageKey, []);
|
|
519
533
|
}
|
|
534
|
+
} else {
|
|
535
|
+
RelayModernRecord.setValue(record, storageKey, null);
|
|
520
536
|
}
|
|
521
|
-
RelayModernRecord.setValue(record, storageKey, null);
|
|
522
537
|
const errorTrie = this._errorTrie;
|
|
523
538
|
if (errorTrie != null) {
|
|
524
539
|
const errors = getErrorsByKey(errorTrie, responseKey);
|
|
@@ -530,13 +545,11 @@ class RelayResponseNormalizer {
|
|
|
530
545
|
}
|
|
531
546
|
|
|
532
547
|
if (selection.kind === 'ScalarField') {
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
);
|
|
539
|
-
}
|
|
548
|
+
this._validateConflictingFieldsWithIdenticalId(
|
|
549
|
+
record,
|
|
550
|
+
storageKey,
|
|
551
|
+
fieldValue,
|
|
552
|
+
);
|
|
540
553
|
RelayModernRecord.setValue(record, storageKey, fieldValue);
|
|
541
554
|
} else if (selection.kind === 'LinkedField') {
|
|
542
555
|
this._path.push(responseKey);
|
|
@@ -680,13 +693,11 @@ class RelayResponseNormalizer {
|
|
|
680
693
|
'RelayResponseNormalizer: Expected id on field `%s` to be a string.',
|
|
681
694
|
storageKey,
|
|
682
695
|
);
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
);
|
|
689
|
-
}
|
|
696
|
+
this._validateConflictingLinkedFieldsWithIdenticalId(
|
|
697
|
+
RelayModernRecord.getLinkedRecordID(record, storageKey),
|
|
698
|
+
nextID,
|
|
699
|
+
storageKey,
|
|
700
|
+
);
|
|
690
701
|
RelayModernRecord.setLinkedRecordID(record, storageKey, nextID);
|
|
691
702
|
let nextRecord = this._recordSource.get(nextID);
|
|
692
703
|
if (!nextRecord) {
|
|
@@ -694,7 +705,7 @@ class RelayResponseNormalizer {
|
|
|
694
705
|
const typeName = field.concreteType || this._getRecordType(fieldValue);
|
|
695
706
|
nextRecord = RelayModernRecord.create(nextID, typeName);
|
|
696
707
|
this._recordSource.set(nextID, nextRecord);
|
|
697
|
-
} else
|
|
708
|
+
} else {
|
|
698
709
|
this._validateRecordType(nextRecord, field, fieldValue);
|
|
699
710
|
}
|
|
700
711
|
// $FlowFixMe[incompatible-variance]
|
|
@@ -760,19 +771,15 @@ class RelayResponseNormalizer {
|
|
|
760
771
|
const typeName = field.concreteType || this._getRecordType(item);
|
|
761
772
|
nextRecord = RelayModernRecord.create(nextID, typeName);
|
|
762
773
|
this._recordSource.set(nextID, nextRecord);
|
|
763
|
-
} else
|
|
774
|
+
} else {
|
|
764
775
|
this._validateRecordType(nextRecord, field, item);
|
|
765
776
|
}
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
nextID,
|
|
773
|
-
storageKey,
|
|
774
|
-
);
|
|
775
|
-
}
|
|
777
|
+
if (prevIDs) {
|
|
778
|
+
this._validateConflictingLinkedFieldsWithIdenticalId(
|
|
779
|
+
prevIDs[nextIndex],
|
|
780
|
+
nextID,
|
|
781
|
+
storageKey,
|
|
782
|
+
);
|
|
776
783
|
}
|
|
777
784
|
// $FlowFixMe[incompatible-variance]
|
|
778
785
|
this._traverseSelections(field, nextRecord, item);
|
|
@@ -790,20 +797,42 @@ class RelayResponseNormalizer {
|
|
|
790
797
|
field: NormalizationLinkedField,
|
|
791
798
|
payload: Object,
|
|
792
799
|
): void {
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
800
|
+
if (RelayFeatureFlags.ENABLE_STORE_ID_COLLISION_LOGGING) {
|
|
801
|
+
const typeName = field.concreteType ?? this._getRecordType(payload);
|
|
802
|
+
const dataID = RelayModernRecord.getDataID(record);
|
|
803
|
+
const expected =
|
|
804
|
+
(isClientID(dataID) && dataID !== ROOT_ID) ||
|
|
805
|
+
RelayModernRecord.getType(record) === typeName;
|
|
806
|
+
if (!expected) {
|
|
807
|
+
const logEvent: IdCollisionTypenameLogEvent = {
|
|
808
|
+
name: 'idCollision.typename',
|
|
809
|
+
previous_typename: RelayModernRecord.getType(record),
|
|
810
|
+
new_typename: typeName,
|
|
811
|
+
};
|
|
812
|
+
if (this._log != null) {
|
|
813
|
+
this._log(logEvent);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
// NOTE: Only emit a warning in DEV
|
|
818
|
+
if (__DEV__) {
|
|
819
|
+
const typeName = field.concreteType ?? this._getRecordType(payload);
|
|
820
|
+
const dataID = RelayModernRecord.getDataID(record);
|
|
821
|
+
const expected =
|
|
822
|
+
(isClientID(dataID) && dataID !== ROOT_ID) ||
|
|
823
|
+
RelayModernRecord.getType(record) === typeName;
|
|
824
|
+
warning(
|
|
825
|
+
expected,
|
|
826
|
+
'RelayResponseNormalizer: Invalid record `%s`. Expected %s to be ' +
|
|
827
|
+
'consistent, but the record was assigned conflicting types `%s` ' +
|
|
828
|
+
'and `%s`. The GraphQL server likely violated the globally unique ' +
|
|
829
|
+
'id requirement by returning the same id for different objects.',
|
|
830
|
+
dataID,
|
|
831
|
+
TYPENAME_KEY,
|
|
832
|
+
RelayModernRecord.getType(record),
|
|
833
|
+
typeName,
|
|
834
|
+
);
|
|
835
|
+
}
|
|
807
836
|
}
|
|
808
837
|
|
|
809
838
|
/**
|
|
@@ -814,14 +843,16 @@ class RelayResponseNormalizer {
|
|
|
814
843
|
storageKey: string,
|
|
815
844
|
fieldValue: mixed,
|
|
816
845
|
): void {
|
|
817
|
-
// NOTE: Only
|
|
846
|
+
// NOTE: Only emit a warning in DEV
|
|
818
847
|
if (__DEV__) {
|
|
848
|
+
const previousValue = RelayModernRecord.getValue(record, storageKey);
|
|
819
849
|
const dataID = RelayModernRecord.getDataID(record);
|
|
820
|
-
|
|
821
|
-
warning(
|
|
850
|
+
const expected =
|
|
822
851
|
storageKey === TYPENAME_KEY ||
|
|
823
|
-
|
|
824
|
-
|
|
852
|
+
previousValue === undefined ||
|
|
853
|
+
areEqual(previousValue, fieldValue);
|
|
854
|
+
warning(
|
|
855
|
+
expected,
|
|
825
856
|
'RelayResponseNormalizer: Invalid record. The record contains two ' +
|
|
826
857
|
'instances of the same id: `%s` with conflicting field, %s and its values: %s and %s. ' +
|
|
827
858
|
'If two fields are different but share ' +
|
|
@@ -842,10 +873,11 @@ class RelayResponseNormalizer {
|
|
|
842
873
|
nextID: DataID,
|
|
843
874
|
storageKey: string,
|
|
844
875
|
): void {
|
|
845
|
-
// NOTE: Only
|
|
876
|
+
// NOTE: Only emit a warning in DEV
|
|
846
877
|
if (__DEV__) {
|
|
878
|
+
const expected = prevID === undefined || prevID === nextID;
|
|
847
879
|
warning(
|
|
848
|
-
|
|
880
|
+
expected,
|
|
849
881
|
'RelayResponseNormalizer: Invalid record. The record contains ' +
|
|
850
882
|
'references to the conflicting field, %s and its id values: %s and %s. ' +
|
|
851
883
|
'We need to make sure that the record the field points ' +
|
|
@@ -115,7 +115,7 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
|
|
|
115
115
|
missingLiveResolverFields: backup.missingLiveResolverFields,
|
|
116
116
|
seenRecords: backup.seenRecords,
|
|
117
117
|
selector: backup.selector,
|
|
118
|
-
|
|
118
|
+
fieldErrors: backup.fieldErrors,
|
|
119
119
|
};
|
|
120
120
|
} else {
|
|
121
121
|
// This subscription was created during the optimisitic state. We should
|
|
@@ -185,7 +185,7 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
|
|
|
185
185
|
missingLiveResolverFields: nextSnapshot.missingLiveResolverFields,
|
|
186
186
|
seenRecords: nextSnapshot.seenRecords,
|
|
187
187
|
selector: nextSnapshot.selector,
|
|
188
|
-
|
|
188
|
+
fieldErrors: nextSnapshot.fieldErrors,
|
|
189
189
|
}: Snapshot);
|
|
190
190
|
if (__DEV__) {
|
|
191
191
|
deepFreeze(nextSnapshot);
|
|
@@ -116,7 +116,7 @@ export type NormalizationSelector = {
|
|
|
116
116
|
+variables: Variables,
|
|
117
117
|
};
|
|
118
118
|
|
|
119
|
-
export type
|
|
119
|
+
export type FieldError =
|
|
120
120
|
| RelayFieldPayloadErrorEvent
|
|
121
121
|
| MissingExpectedDataLogEvent
|
|
122
122
|
| MissingExpectedDataThrowEvent
|
|
@@ -124,7 +124,7 @@ export type ErrorResponseField =
|
|
|
124
124
|
| MissingRequiredFieldLogEvent
|
|
125
125
|
| MissingRequiredFieldThrowEvent;
|
|
126
126
|
|
|
127
|
-
export type
|
|
127
|
+
export type FieldErrors = Array<FieldError>;
|
|
128
128
|
|
|
129
129
|
export type ClientEdgeTraversalInfo = {
|
|
130
130
|
+readerClientEdge: ReaderClientEdgeToServerObject,
|
|
@@ -139,22 +139,17 @@ export type MissingClientEdgeRequestInfo = {
|
|
|
139
139
|
+clientEdgeDestinationID: DataID,
|
|
140
140
|
};
|
|
141
141
|
|
|
142
|
-
export type MissingLiveResolverField = {
|
|
143
|
-
+path: string,
|
|
144
|
-
+liveStateID: DataID,
|
|
145
|
-
};
|
|
146
|
-
|
|
147
142
|
/**
|
|
148
143
|
* A representation of a selector and its results at a particular point in time.
|
|
149
144
|
*/
|
|
150
145
|
export type Snapshot = {
|
|
151
146
|
+data: ?SelectorData,
|
|
152
147
|
+isMissingData: boolean,
|
|
153
|
-
+missingLiveResolverFields?: $ReadOnlyArray<
|
|
148
|
+
+missingLiveResolverFields?: $ReadOnlyArray<DataID>,
|
|
154
149
|
+missingClientEdges: null | $ReadOnlyArray<MissingClientEdgeRequestInfo>,
|
|
155
150
|
+seenRecords: DataIDSet,
|
|
156
151
|
+selector: SingularReaderSelector,
|
|
157
|
-
+
|
|
152
|
+
+fieldErrors: ?FieldErrors,
|
|
158
153
|
};
|
|
159
154
|
|
|
160
155
|
/**
|
|
@@ -467,6 +462,7 @@ export interface RecordProxy {
|
|
|
467
462
|
): RecordProxy;
|
|
468
463
|
getType(): string;
|
|
469
464
|
getValue(name: string, args?: ?Variables): mixed;
|
|
465
|
+
getErrors(name: string, args?: ?Variables): ?$ReadOnlyArray<TRelayFieldError>;
|
|
470
466
|
setLinkedRecord(
|
|
471
467
|
record: RecordProxy,
|
|
472
468
|
name: string,
|
|
@@ -477,7 +473,12 @@ export interface RecordProxy {
|
|
|
477
473
|
name: string,
|
|
478
474
|
args?: ?Variables,
|
|
479
475
|
): RecordProxy;
|
|
480
|
-
setValue(
|
|
476
|
+
setValue(
|
|
477
|
+
value: mixed,
|
|
478
|
+
name: string,
|
|
479
|
+
args?: ?Variables,
|
|
480
|
+
errors?: ?$ReadOnlyArray<TRelayFieldError>,
|
|
481
|
+
): RecordProxy;
|
|
481
482
|
invalidateRecord(): void;
|
|
482
483
|
}
|
|
483
484
|
|
|
@@ -683,6 +684,11 @@ export type ExecuteCompleteLogEvent = {
|
|
|
683
684
|
+executeId: number,
|
|
684
685
|
};
|
|
685
686
|
|
|
687
|
+
export type ExecuteUnsubscribeLogEvent = {
|
|
688
|
+
+name: 'execute.unsubscribe',
|
|
689
|
+
+executeId: number,
|
|
690
|
+
};
|
|
691
|
+
|
|
686
692
|
export type ExecuteNormalizeStart = {
|
|
687
693
|
+name: 'execute.normalize.start',
|
|
688
694
|
+operation: OperationDescriptor,
|
|
@@ -780,12 +786,23 @@ export type UseFragmentSubscriptionMissedUpdates = {
|
|
|
780
786
|
+hasDataChanges: boolean,
|
|
781
787
|
};
|
|
782
788
|
|
|
789
|
+
/**
|
|
790
|
+
* This event is logged when two strong objects share the same id,
|
|
791
|
+
* but have different types, resulting in an collision in the store.
|
|
792
|
+
*/
|
|
793
|
+
export type IdCollisionTypenameLogEvent = {
|
|
794
|
+
+name: 'idCollision.typename',
|
|
795
|
+
+previous_typename: string,
|
|
796
|
+
+new_typename: string,
|
|
797
|
+
};
|
|
798
|
+
|
|
783
799
|
export type LogEvent =
|
|
784
800
|
| SuspenseFragmentLogEvent
|
|
785
801
|
| SuspenseQueryLogEvent
|
|
786
802
|
| QueryResourceFetchLogEvent
|
|
787
803
|
| QueryResourceRetainLogEvent
|
|
788
804
|
| FragmentResourceMissingDataLogEvent
|
|
805
|
+
| IdCollisionTypenameLogEvent
|
|
789
806
|
| PendingOperationFoundLogEvent
|
|
790
807
|
| NetworkInfoLogEvent
|
|
791
808
|
| NetworkStartLogEvent
|
|
@@ -799,6 +816,7 @@ export type LogEvent =
|
|
|
799
816
|
| ExecuteAsyncModuleLogEvent
|
|
800
817
|
| ExecuteErrorLogEvent
|
|
801
818
|
| ExecuteCompleteLogEvent
|
|
819
|
+
| ExecuteUnsubscribeLogEvent
|
|
802
820
|
| ExecuteNormalizeStart
|
|
803
821
|
| ExecuteNormalizeEnd
|
|
804
822
|
| StoreDataCheckerStartEvent
|
|
@@ -1268,7 +1286,9 @@ export type MissingFieldHandler =
|
|
|
1268
1286
|
export type MissingExpectedDataLogEvent = {
|
|
1269
1287
|
+kind: 'missing_expected_data.log',
|
|
1270
1288
|
+owner: string,
|
|
1271
|
-
|
|
1289
|
+
fieldPath: string, // Purposefully mutable to allow lazy construction in RelayReader
|
|
1290
|
+
// To populate this, you should pass the value to a ReactRelayLoggingContext
|
|
1291
|
+
+uiContext: mixed | void,
|
|
1272
1292
|
};
|
|
1273
1293
|
|
|
1274
1294
|
/**
|
|
@@ -1294,8 +1314,10 @@ export type MissingExpectedDataLogEvent = {
|
|
|
1294
1314
|
export type MissingExpectedDataThrowEvent = {
|
|
1295
1315
|
+kind: 'missing_expected_data.throw',
|
|
1296
1316
|
+owner: string,
|
|
1297
|
-
|
|
1317
|
+
fieldPath: string, // Purposefully mutable to allow lazy construction in RelayReader
|
|
1298
1318
|
+handled: boolean,
|
|
1319
|
+
// To populate this, you should pass the value to a ReactRelayLoggingContext
|
|
1320
|
+
+uiContext: mixed | void,
|
|
1299
1321
|
};
|
|
1300
1322
|
|
|
1301
1323
|
/**
|
|
@@ -1305,7 +1327,9 @@ export type MissingExpectedDataThrowEvent = {
|
|
|
1305
1327
|
export type MissingRequiredFieldLogEvent = {
|
|
1306
1328
|
+kind: 'missing_required_field.log',
|
|
1307
1329
|
+owner: string,
|
|
1308
|
-
|
|
1330
|
+
fieldPath: string, // Purposefully mutable to allow lazy construction in RelayReader
|
|
1331
|
+
// To populate this, you should pass the value to a ReactRelayLoggingContext
|
|
1332
|
+
+uiContext: mixed | void,
|
|
1309
1333
|
};
|
|
1310
1334
|
|
|
1311
1335
|
/**
|
|
@@ -1322,8 +1346,10 @@ export type MissingRequiredFieldLogEvent = {
|
|
|
1322
1346
|
export type MissingRequiredFieldThrowEvent = {
|
|
1323
1347
|
+kind: 'missing_required_field.throw',
|
|
1324
1348
|
+owner: string,
|
|
1325
|
-
|
|
1349
|
+
fieldPath: string, // Purposefully mutable to allow lazy construction in RelayReader
|
|
1326
1350
|
+handled: boolean,
|
|
1351
|
+
// To populate this, you should pass the value to a ReactRelayLoggingContext
|
|
1352
|
+
+uiContext: mixed | void,
|
|
1327
1353
|
};
|
|
1328
1354
|
|
|
1329
1355
|
/**
|
|
@@ -1345,6 +1371,8 @@ export type RelayResolverErrorEvent = {
|
|
|
1345
1371
|
+error: Error,
|
|
1346
1372
|
+shouldThrow: boolean,
|
|
1347
1373
|
+handled: boolean,
|
|
1374
|
+
// To populate this, you should pass the value to a ReactRelayLoggingContext
|
|
1375
|
+
+uiContext: mixed | void,
|
|
1348
1376
|
};
|
|
1349
1377
|
|
|
1350
1378
|
/**
|
|
@@ -1371,6 +1399,8 @@ export type RelayFieldPayloadErrorEvent = {
|
|
|
1371
1399
|
+error: TRelayFieldError,
|
|
1372
1400
|
+shouldThrow: boolean,
|
|
1373
1401
|
+handled: boolean,
|
|
1402
|
+
// To populate this, you should pass the value to a ReactRelayLoggingContext
|
|
1403
|
+
+uiContext: mixed | void,
|
|
1374
1404
|
};
|
|
1375
1405
|
|
|
1376
1406
|
/**
|
|
@@ -1480,7 +1510,7 @@ export type ConcreteClientEdgeResolverReturnType<T = any> = {
|
|
|
1480
1510
|
* returns a callback which should be called when the value _may_ have changed.
|
|
1481
1511
|
*
|
|
1482
1512
|
* While over-notification (subscription notifications when the read value has
|
|
1483
|
-
* not actually changed) is
|
|
1513
|
+
* not actually changed) is supported, for performance reasons, it is recommended
|
|
1484
1514
|
* that the provider of the LiveState value confirms that the value has indeed
|
|
1485
1515
|
* change before notifying Relay of the change.
|
|
1486
1516
|
*/
|
|
@@ -15,6 +15,8 @@ import type {
|
|
|
15
15
|
NormalizationArgument,
|
|
16
16
|
NormalizationField,
|
|
17
17
|
NormalizationHandle,
|
|
18
|
+
NormalizationLiveResolverField,
|
|
19
|
+
NormalizationResolverField,
|
|
18
20
|
} from '../util/NormalizationNode';
|
|
19
21
|
import type {
|
|
20
22
|
ReaderActorChange,
|
|
@@ -28,6 +30,7 @@ import type {Variables} from '../util/RelayRuntimeTypes';
|
|
|
28
30
|
|
|
29
31
|
const getRelayHandleKey = require('../util/getRelayHandleKey');
|
|
30
32
|
const RelayConcreteNode = require('../util/RelayConcreteNode');
|
|
33
|
+
const RelayFeatureFlags = require('../util/RelayFeatureFlags');
|
|
31
34
|
const {stableCopy} = require('../util/stableCopy');
|
|
32
35
|
const invariant = require('invariant');
|
|
33
36
|
|
|
@@ -42,6 +45,8 @@ const ERRORS_KEY: '__errors' = '__errors';
|
|
|
42
45
|
const MODULE_COMPONENT_KEY_PREFIX = '__module_component_';
|
|
43
46
|
const MODULE_OPERATION_KEY_PREFIX = '__module_operation_';
|
|
44
47
|
|
|
48
|
+
const RELAY_READ_TIME_RESOLVER_KEY_PREFIX = '$r:';
|
|
49
|
+
|
|
45
50
|
function getArgumentValue(
|
|
46
51
|
arg: NormalizationArgument | ReaderArgument,
|
|
47
52
|
variables: Variables,
|
|
@@ -163,6 +168,28 @@ function getStorageKey(
|
|
|
163
168
|
: name;
|
|
164
169
|
}
|
|
165
170
|
|
|
171
|
+
/**
|
|
172
|
+
* This is a special case of getStorageKey that should be used when dealing with
|
|
173
|
+
* read time resolver fields. A resolver may be used at both exec time and at read
|
|
174
|
+
* time within the same project. However, the value of the read time resolver is
|
|
175
|
+
* wrapped while the value of the exec time resolver is a standard Relay object. To
|
|
176
|
+
* disambiguate in the case that both types may exist on the same record, the read
|
|
177
|
+
* time resolver storage keys are prefixed.
|
|
178
|
+
*/
|
|
179
|
+
function getReadTimeResolverStorageKey(
|
|
180
|
+
field:
|
|
181
|
+
| ReaderRelayResolver
|
|
182
|
+
| ReaderRelayLiveResolver
|
|
183
|
+
| NormalizationResolverField
|
|
184
|
+
| NormalizationLiveResolverField,
|
|
185
|
+
variables: Variables,
|
|
186
|
+
): string {
|
|
187
|
+
const storageKey = getStorageKey(field, variables);
|
|
188
|
+
return RelayFeatureFlags.ENABLE_READ_TIME_RESOLVER_STORAGE_KEY_PREFIX
|
|
189
|
+
? '$r:' + storageKey // Using inlined string to test the performance impact
|
|
190
|
+
: storageKey;
|
|
191
|
+
}
|
|
192
|
+
|
|
166
193
|
/**
|
|
167
194
|
* Given a field the method returns an array of arguments.
|
|
168
195
|
* For Relay resolver fields, we store arguments on the field and fragment
|
|
@@ -271,15 +298,17 @@ const RelayStoreUtils = {
|
|
|
271
298
|
RELAY_RESOLVER_SNAPSHOT_KEY: '__resolverSnapshot',
|
|
272
299
|
RELAY_RESOLVER_ERROR_KEY: '__resolverError',
|
|
273
300
|
RELAY_RESOLVER_OUTPUT_TYPE_RECORD_IDS: '__resolverOutputTypeRecordIDs',
|
|
301
|
+
RELAY_READ_TIME_RESOLVER_KEY_PREFIX,
|
|
274
302
|
|
|
275
303
|
formatStorageKey,
|
|
276
304
|
getArgumentValue,
|
|
277
305
|
getArgumentValues,
|
|
278
306
|
getHandleStorageKey,
|
|
279
307
|
getStorageKey,
|
|
308
|
+
getReadTimeResolverStorageKey,
|
|
280
309
|
getStableStorageKey,
|
|
281
310
|
getModuleComponentKey,
|
|
282
311
|
getModuleOperationKey,
|
|
283
|
-
};
|
|
312
|
+
} as const;
|
|
284
313
|
|
|
285
314
|
module.exports = RelayStoreUtils;
|