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.
@@ -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. This should be prevented by the compiler.',
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
- `Invalid \`__typename\` returned by resolver. Expected one of ${Object.keys(
870
- modelResolvers,
871
- ).join(', ')} but got \`${concreteType}\`.`,
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(extractIdFromResponse);
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(clientEdgeResolverResponse);
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
- `Invalid \`__typename\` returned by resolver. Expected one of ${Object.keys(
930
- modelResolvers,
931
- ).join(', ')} but got \`${concreteType}\`.`,
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
- fieldName,
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(individualResponse: mixed): string {
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 an edge resolver to be a string or an object with an `id` property',
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
- const recordID = recordsToVisit.pop();
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 new useFragmentInternal implementation
55
- ENABLE_USE_FRAGMENT_EXPERIMENTAL: boolean,
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
- ENABLE_USE_FRAGMENT_EXPERIMENTAL: false,
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
- logMissingData(environment, shouldThrow);
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 logMissingData(environment: IEnvironment, throwing: boolean) {
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
- logMissingData(environment, throwOnFieldErrorDirective);
130
+ // _logMissingData(environment, throwOnFieldErrorDirective);
131
131
 
132
132
  if (throwOnFieldErrorDirective) {
133
133
  throw new RelayFieldError(`Relay: Missing data for one or more fields`);