relay-runtime 0.0.0-main-563e04f2 → 0.0.0-main-cc054684
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/index.js +1 -1
- package/lib/store/RelayReader.js +16 -14
- package/lib/store/experimental-live-resolvers/LiveResolverCache.js +9 -0
- package/lib/util/RelayFeatureFlags.js +2 -1
- package/lib/util/handlePotentialSnapshotErrors.js +2 -5
- package/package.json +1 -1
- package/relay-runtime-experimental.js +1 -1
- package/relay-runtime-experimental.min.js +1 -1
- package/relay-runtime.js +2 -2
- package/relay-runtime.min.js +2 -2
- package/store/RelayReader.js.flow +50 -19
- package/store/experimental-live-resolvers/LiveResolverCache.js.flow +18 -1
- package/util/RelayFeatureFlags.js.flow +9 -3
- package/util/handlePotentialSnapshotErrors.js.flow +3 -3
|
@@ -840,12 +840,15 @@ class RelayReader {
|
|
|
840
840
|
if (field.linkedField.plural) {
|
|
841
841
|
invariant(
|
|
842
842
|
Array.isArray(clientEdgeResolverResponse),
|
|
843
|
-
'Expected plural Client Edge Relay Resolver to return an array containing IDs or objects with shape {id}.',
|
|
843
|
+
'Expected plural Client Edge Relay Resolver at `%s` in `%s` to return an array containing IDs or objects with shape {id}.',
|
|
844
|
+
backingField.path,
|
|
845
|
+
this._owner.identifier,
|
|
844
846
|
);
|
|
845
847
|
let storeIDs: $ReadOnlyArray<DataID>;
|
|
846
848
|
invariant(
|
|
847
849
|
field.kind === 'ClientEdgeToClientObject',
|
|
848
|
-
'Unexpected Client Edge to plural server type
|
|
850
|
+
'Unexpected Client Edge to plural server type `%s`. This should be prevented by the compiler.',
|
|
851
|
+
field.kind,
|
|
849
852
|
);
|
|
850
853
|
if (field.backingField.normalizationInfo == null) {
|
|
851
854
|
// @edgeTo case where we need to ensure that the record has `id` field
|
|
@@ -853,9 +856,15 @@ class RelayReader {
|
|
|
853
856
|
const concreteType = field.concreteType ?? itemResponse.__typename;
|
|
854
857
|
invariant(
|
|
855
858
|
typeof concreteType === 'string',
|
|
856
|
-
'Expected resolver modeling an edge to an abstract type to return an object with a `__typename` property.',
|
|
859
|
+
'Expected resolver for field at `%s` in `%s` modeling an edge to an abstract type to return an object with a `__typename` property.',
|
|
860
|
+
backingField.path,
|
|
861
|
+
this._owner.identifier,
|
|
862
|
+
);
|
|
863
|
+
const localId = extractIdFromResponse(
|
|
864
|
+
itemResponse,
|
|
865
|
+
backingField.path,
|
|
866
|
+
this._owner.identifier,
|
|
857
867
|
);
|
|
858
|
-
const localId = extractIdFromResponse(itemResponse);
|
|
859
868
|
const id = this._resolverCache.ensureClientRecord(
|
|
860
869
|
localId,
|
|
861
870
|
concreteType,
|
|
@@ -866,9 +875,11 @@ class RelayReader {
|
|
|
866
875
|
const modelResolver = modelResolvers[concreteType];
|
|
867
876
|
invariant(
|
|
868
877
|
modelResolver !== undefined,
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
878
|
+
'Invalid `__typename` returned by resolver at `%s` in `%s`. Expected one of %s but got `%s`.',
|
|
879
|
+
backingField.path,
|
|
880
|
+
this._owner.identifier,
|
|
881
|
+
Object.keys(modelResolvers).join(', '),
|
|
882
|
+
concreteType,
|
|
872
883
|
);
|
|
873
884
|
const model = this._readResolverFieldImpl(modelResolver, id);
|
|
874
885
|
return model != null ? id : null;
|
|
@@ -877,7 +888,9 @@ class RelayReader {
|
|
|
877
888
|
});
|
|
878
889
|
} else {
|
|
879
890
|
// The normalization process in LiveResolverCache should take care of generating the correct ID.
|
|
880
|
-
storeIDs = clientEdgeResolverResponse.map(
|
|
891
|
+
storeIDs = clientEdgeResolverResponse.map(obj =>
|
|
892
|
+
extractIdFromResponse(obj, backingField.path, this._owner.identifier),
|
|
893
|
+
);
|
|
881
894
|
}
|
|
882
895
|
this._clientEdgeTraversalPath.push(null);
|
|
883
896
|
const edgeValues = this._readLinkedIds(
|
|
@@ -890,7 +903,11 @@ class RelayReader {
|
|
|
890
903
|
data[fieldName] = edgeValues;
|
|
891
904
|
return edgeValues;
|
|
892
905
|
} else {
|
|
893
|
-
const id = extractIdFromResponse(
|
|
906
|
+
const id = extractIdFromResponse(
|
|
907
|
+
clientEdgeResolverResponse,
|
|
908
|
+
backingField.path,
|
|
909
|
+
this._owner.identifier,
|
|
910
|
+
);
|
|
894
911
|
let storeID: DataID;
|
|
895
912
|
const concreteType =
|
|
896
913
|
field.concreteType ?? clientEdgeResolverResponse.__typename;
|
|
@@ -899,7 +916,9 @@ class RelayReader {
|
|
|
899
916
|
if (field.backingField.normalizationInfo == null) {
|
|
900
917
|
invariant(
|
|
901
918
|
typeof concreteType === 'string',
|
|
902
|
-
'Expected resolver modeling an edge to an abstract type to return an object with a `__typename` property.',
|
|
919
|
+
'Expected resolver for field at `%s` in `%s` modeling an edge to an abstract type to return an object with a `__typename` property.',
|
|
920
|
+
backingField.path,
|
|
921
|
+
this._owner.identifier,
|
|
903
922
|
);
|
|
904
923
|
// @edgeTo case where we need to ensure that the record has `id` field
|
|
905
924
|
storeID = this._resolverCache.ensureClientRecord(id, concreteType);
|
|
@@ -921,14 +940,18 @@ class RelayReader {
|
|
|
921
940
|
if (modelResolvers != null) {
|
|
922
941
|
invariant(
|
|
923
942
|
typeof concreteType === 'string',
|
|
924
|
-
'Expected resolver modeling an edge to an abstract type to return an object with a `__typename` property.',
|
|
943
|
+
'Expected resolver for field at `%s` in `%s` modeling an edge to an abstract type to return an object with a `__typename` property.',
|
|
944
|
+
backingField.path,
|
|
945
|
+
this._owner.identifier,
|
|
925
946
|
);
|
|
926
947
|
const modelResolver = modelResolvers[concreteType];
|
|
927
948
|
invariant(
|
|
928
949
|
modelResolver !== undefined,
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
950
|
+
'Invalid `__typename` returned by resolver at `%s` in `%s`. Expected one of %s but got `%s`.',
|
|
951
|
+
backingField.path,
|
|
952
|
+
this._owner.identifier,
|
|
953
|
+
Object.keys(modelResolvers).join(', '),
|
|
954
|
+
concreteType,
|
|
932
955
|
);
|
|
933
956
|
const model = this._readResolverFieldImpl(modelResolver, storeID);
|
|
934
957
|
if (model == null) {
|
|
@@ -943,9 +966,10 @@ class RelayReader {
|
|
|
943
966
|
const prevData = data[fieldName];
|
|
944
967
|
invariant(
|
|
945
968
|
prevData == null || typeof prevData === 'object',
|
|
946
|
-
'RelayReader(): Expected data for field `%s` on record `%s` ' +
|
|
969
|
+
'RelayReader(): Expected data for field at `%s` in `%s` on record `%s` ' +
|
|
947
970
|
'to be an object, got `%s`.',
|
|
948
|
-
|
|
971
|
+
backingField.path,
|
|
972
|
+
this._owner.identifier,
|
|
949
973
|
RelayModernRecord.getDataID(record),
|
|
950
974
|
prevData,
|
|
951
975
|
);
|
|
@@ -999,9 +1023,10 @@ class RelayReader {
|
|
|
999
1023
|
const prevData = data[fieldName];
|
|
1000
1024
|
invariant(
|
|
1001
1025
|
prevData == null || typeof prevData === 'object',
|
|
1002
|
-
'RelayReader(): Expected data for field `%s` on record `%s` ' +
|
|
1026
|
+
'RelayReader(): Expected data for field `%s` at `%s` on record `%s` ' +
|
|
1003
1027
|
'to be an object, got `%s`.',
|
|
1004
1028
|
fieldName,
|
|
1029
|
+
this._owner.identifier,
|
|
1005
1030
|
RelayModernRecord.getDataID(record),
|
|
1006
1031
|
prevData,
|
|
1007
1032
|
);
|
|
@@ -1437,7 +1462,11 @@ function getResolverValue(
|
|
|
1437
1462
|
return [resolverResult, resolverError];
|
|
1438
1463
|
}
|
|
1439
1464
|
|
|
1440
|
-
function extractIdFromResponse(
|
|
1465
|
+
function extractIdFromResponse(
|
|
1466
|
+
individualResponse: mixed,
|
|
1467
|
+
path: string,
|
|
1468
|
+
owner: string,
|
|
1469
|
+
): string {
|
|
1441
1470
|
if (typeof individualResponse === 'string') {
|
|
1442
1471
|
return individualResponse;
|
|
1443
1472
|
} else if (
|
|
@@ -1449,7 +1478,9 @@ function extractIdFromResponse(individualResponse: mixed): string {
|
|
|
1449
1478
|
}
|
|
1450
1479
|
invariant(
|
|
1451
1480
|
false,
|
|
1452
|
-
'Expected object returned from
|
|
1481
|
+
'Expected object returned from edge resolver to be a string or an object with an `id` property at path %s in %s,',
|
|
1482
|
+
path,
|
|
1483
|
+
owner,
|
|
1453
1484
|
);
|
|
1454
1485
|
}
|
|
1455
1486
|
|
|
@@ -642,6 +642,11 @@ class LiveResolverCache implements ResolverCache {
|
|
|
642
642
|
return RelayModernRecord.getValue(resolverRecord, RELAY_RESOLVER_VALUE_KEY);
|
|
643
643
|
}
|
|
644
644
|
|
|
645
|
+
/**
|
|
646
|
+
* Takes a set of IDs whose records have just changed and are therefore about
|
|
647
|
+
* to be notified, and mutate the set, adding the IDs of resolvers that are
|
|
648
|
+
* transitively invalidated by this update.
|
|
649
|
+
*/
|
|
645
650
|
invalidateDataIDs(
|
|
646
651
|
updatedDataIDs: DataIDSet, // Mutated in place
|
|
647
652
|
): void {
|
|
@@ -649,7 +654,12 @@ class LiveResolverCache implements ResolverCache {
|
|
|
649
654
|
const visited: Set<string> = new Set();
|
|
650
655
|
const recordsToVisit = Array.from(updatedDataIDs);
|
|
651
656
|
while (recordsToVisit.length) {
|
|
652
|
-
|
|
657
|
+
// $FlowFixMe[incompatible-type] We just checked length so we know this is not undefined
|
|
658
|
+
const recordID: string = recordsToVisit.pop();
|
|
659
|
+
if (RelayFeatureFlags.AVOID_CYCLES_IN_RESOLVER_NOTIFICATION) {
|
|
660
|
+
visited.add(recordID);
|
|
661
|
+
}
|
|
662
|
+
|
|
653
663
|
// $FlowFixMe[incompatible-call]
|
|
654
664
|
updatedDataIDs.add(recordID);
|
|
655
665
|
// $FlowFixMe[incompatible-call]
|
|
@@ -659,6 +669,10 @@ class LiveResolverCache implements ResolverCache {
|
|
|
659
669
|
}
|
|
660
670
|
for (const fragment of fragmentSet) {
|
|
661
671
|
if (!visited.has(fragment)) {
|
|
672
|
+
if (RelayFeatureFlags.AVOID_CYCLES_IN_RESOLVER_NOTIFICATION) {
|
|
673
|
+
visited.add(fragment);
|
|
674
|
+
}
|
|
675
|
+
|
|
662
676
|
const recordSet = this._resolverIDToRecordIDs.get(fragment);
|
|
663
677
|
if (recordSet == null) {
|
|
664
678
|
continue;
|
|
@@ -666,6 +680,9 @@ class LiveResolverCache implements ResolverCache {
|
|
|
666
680
|
for (const anotherRecordID of recordSet) {
|
|
667
681
|
markInvalidatedResolverRecord(anotherRecordID, recordSource);
|
|
668
682
|
if (!visited.has(anotherRecordID)) {
|
|
683
|
+
if (RelayFeatureFlags.AVOID_CYCLES_IN_RESOLVER_NOTIFICATION) {
|
|
684
|
+
visited.add(anotherRecordID);
|
|
685
|
+
}
|
|
669
686
|
recordsToVisit.push(anotherRecordID);
|
|
670
687
|
}
|
|
671
688
|
}
|
|
@@ -51,8 +51,13 @@ export type FeatureFlags = {
|
|
|
51
51
|
|
|
52
52
|
ENABLE_CYLE_DETECTION_IN_VARIABLES: boolean,
|
|
53
53
|
|
|
54
|
-
// Temporary flag to experiment with
|
|
55
|
-
|
|
54
|
+
// Temporary flag to experiment to enable compatibility with React's unstable <Activity> API
|
|
55
|
+
ENABLE_ACTIVITY_COMPATIBILITY: boolean,
|
|
56
|
+
|
|
57
|
+
// Gating a fix to prevent infinite loops when invalidating Relay Resolvers.
|
|
58
|
+
// We believe the fix to be correct but don't yet have a test to validate it
|
|
59
|
+
// fixes the error, so we're gating it for now.
|
|
60
|
+
AVOID_CYCLES_IN_RESOLVER_NOTIFICATION: boolean,
|
|
56
61
|
};
|
|
57
62
|
|
|
58
63
|
const RelayFeatureFlags: FeatureFlags = {
|
|
@@ -75,7 +80,8 @@ const RelayFeatureFlags: FeatureFlags = {
|
|
|
75
80
|
PROCESS_OPTIMISTIC_UPDATE_BEFORE_SUBSCRIPTION: false,
|
|
76
81
|
MARK_RESOLVER_VALUES_AS_CLEAN_AFTER_FRAGMENT_REREAD: false,
|
|
77
82
|
ENABLE_CYLE_DETECTION_IN_VARIABLES: false,
|
|
78
|
-
|
|
83
|
+
ENABLE_ACTIVITY_COMPATIBILITY: false,
|
|
84
|
+
AVOID_CYCLES_IN_RESOLVER_NOTIFICATION: false,
|
|
79
85
|
};
|
|
80
86
|
|
|
81
87
|
module.exports = RelayFeatureFlags;
|
|
@@ -54,7 +54,7 @@ function handleFieldErrors(
|
|
|
54
54
|
for (const fieldError of errorResponseFields) {
|
|
55
55
|
const {path, owner, error} = fieldError;
|
|
56
56
|
if (fieldError.type === 'MISSING_DATA') {
|
|
57
|
-
|
|
57
|
+
// _logMissingData(environment, shouldThrow);
|
|
58
58
|
} else {
|
|
59
59
|
environment.relayFieldLogger({
|
|
60
60
|
kind: 'relay_field_payload.error',
|
|
@@ -74,7 +74,7 @@ function handleFieldErrors(
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
function
|
|
77
|
+
function _logMissingData(environment: IEnvironment, throwing: boolean) {
|
|
78
78
|
if (!throwing) {
|
|
79
79
|
environment.relayFieldLogger({
|
|
80
80
|
kind: 'missing_expected_data.log',
|
|
@@ -127,7 +127,7 @@ function handleMissingDataError(
|
|
|
127
127
|
environment: IEnvironment,
|
|
128
128
|
throwOnFieldErrorDirective: boolean,
|
|
129
129
|
) {
|
|
130
|
-
|
|
130
|
+
// _logMissingData(environment, throwOnFieldErrorDirective);
|
|
131
131
|
|
|
132
132
|
if (throwOnFieldErrorDirective) {
|
|
133
133
|
throw new RelayFieldError(`Relay: Missing data for one or more fields`);
|