@apollo/federation-internals 2.12.0 → 2.12.1

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/src/federation.ts CHANGED
@@ -37,7 +37,7 @@ import {
37
37
  isWrapperType,
38
38
  possibleRuntimeTypes,
39
39
  isIntType,
40
- Type, isFieldDefinition,
40
+ Type, isFieldDefinition, isElementNamedType,
41
41
  } from "./definitions";
42
42
  import { assert, MultiMap, printHumanReadableList, OrderedMap, mapValues, assertUnreachable } from "./utils";
43
43
  import { SDLValidationRule } from "graphql/validation/ValidationContext";
@@ -1071,7 +1071,7 @@ function validateListSizeAppliedToList(
1071
1071
  ) {
1072
1072
  const { sizedFields = [] } = application.arguments();
1073
1073
  // @listSize must be applied to a list https://ibm.github.io/graphql-specs/cost-spec.html#sec-Valid-List-Size-Target
1074
- if (!sizedFields.length && parent.type && !isListType(parent.type)) {
1074
+ if (!sizedFields.length && parent.type && !isListType(parent.type) && !isNonNullListType(parent.type)) {
1075
1075
  errorCollector.push(ERRORS.LIST_SIZE_APPLIED_TO_NON_LIST.err(
1076
1076
  `"${parent.coordinate}" is not a list`,
1077
1077
  { nodes: sourceASTs(application, parent) },
@@ -1141,8 +1141,9 @@ function validateSizedFieldsAreValidLists(
1141
1141
  ) {
1142
1142
  const { sizedFields = [] } = application.arguments();
1143
1143
  // Validate sizedFields https://ibm.github.io/graphql-specs/cost-spec.html#sec-Valid-Sized-Fields-Target
1144
- if (sizedFields.length) {
1145
- if (!parent.type || !isCompositeType(parent.type)) {
1144
+ if (sizedFields.length && parent.type) {
1145
+ const baseParentType = baseType(parent.type);
1146
+ if (!isCompositeType(baseParentType)) {
1146
1147
  // The output type must have fields
1147
1148
  errorCollector.push(ERRORS.LIST_SIZE_INVALID_SIZED_FIELD.err(
1148
1149
  `Sized fields cannot be used because "${parent.type}" is not a composite type`,
@@ -1150,11 +1151,11 @@ function validateSizedFieldsAreValidLists(
1150
1151
  ));
1151
1152
  } else {
1152
1153
  for (const sizedFieldName of sizedFields) {
1153
- const sizedField = parent.type.field(sizedFieldName);
1154
+ const sizedField = baseParentType.field(sizedFieldName);
1154
1155
  if (!sizedField) {
1155
1156
  // Sized fields must be present on the output type
1156
1157
  errorCollector.push(ERRORS.LIST_SIZE_INVALID_SIZED_FIELD.err(
1157
- `Sized field "${sizedFieldName}" is not a field on type "${parent.type.coordinate}"`,
1158
+ `Sized field "${sizedFieldName}" is not a field on type "${baseParentType.coordinate}"`,
1158
1159
  { nodes: sourceASTs(application, parent) }
1159
1160
  ));
1160
1161
  } else if (!sizedField.type || !(isListType(sizedField.type) || isNonNullListType(sizedField.type))) {
@@ -1846,7 +1847,7 @@ export class FederationBlueprint extends SchemaBlueprint {
1846
1847
  validateSizedFieldsAreValidLists(application, parent, errorCollector);
1847
1848
  }
1848
1849
 
1849
- // Validate @authenticated, @requireScopes and @policy
1850
+ // Validate @authenticated, @requireScopes and @policy usage on interfaces and interface objects
1850
1851
  validateNoAuthenticationOnInterfaces(metadata, errorCollector);
1851
1852
 
1852
1853
  return errorCollector;
@@ -2907,15 +2908,15 @@ function validateNoAuthenticationOnInterfaces(metadata: FederationMetadata, erro
2907
2908
  const policyDirective = metadata.policyDirective();
2908
2909
  [authenticatedDirective, requiresScopesDirective, policyDirective].forEach((directive) => {
2909
2910
  for (const application of directive.applications()) {
2910
- const element = application.parent;
2911
- function isAppliedOnInterface(type: Type) {
2912
- return isInterfaceType(type) || isInterfaceObjectType(baseType(type));
2913
- }
2914
- function isAppliedOnInterfaceField(elem: SchemaElement<any, any>) {
2915
- return isFieldDefinition(elem) && isAppliedOnInterface(elem.parent);
2916
- }
2917
-
2918
- if (isAppliedOnInterface(element) || isAppliedOnInterfaceField(element)) {
2911
+ const element: SchemaElement<any, any> = application.parent;
2912
+ if (
2913
+ // Is it applied on interface or interface object types?
2914
+ (isElementNamedType(element) &&
2915
+ (isInterfaceType(element) || isInterfaceObjectType(element))
2916
+ ) ||
2917
+ // Is it applied on interface fields?
2918
+ (isFieldDefinition(element) && isInterfaceType(element.parent))
2919
+ ) {
2919
2920
  let kind = '';
2920
2921
  switch (element.kind) {
2921
2922
  case 'FieldDefinition':
@@ -2928,8 +2929,8 @@ function validateNoAuthenticationOnInterfaces(metadata: FederationMetadata, erro
2928
2929
  kind = 'interface object';
2929
2930
  break;
2930
2931
  }
2931
- errorCollector.push(ERRORS.AUTHENTICATION_APPLIED_ON_INTERFACE.err(
2932
- `Invalid use of @${directive.name} on ${kind} "${element.coordinate}": @${directive.name} cannot be applied on interfaces, interface objects or their fields`,
2932
+ errorCollector.push(ERRORS.AUTH_REQUIREMENTS_APPLIED_ON_INTERFACE.err(
2933
+ `Invalid use of @${directive.name} on ${kind} "${element.coordinate}": @${directive.name} cannot be applied on interfaces, interface fields and interface objects`,
2933
2934
  {nodes: sourceASTs(application, element.parent)},
2934
2935
  ));
2935
2936
  }
@@ -24,6 +24,10 @@ export class AuthenticatedSpecDefinition extends FeatureDefinition {
24
24
  minimumFederationVersion,
25
25
  );
26
26
 
27
+ // WARNING: we cannot declare staticArgumentTransform() as access control merge logic needs to propagate
28
+ // requirements upwards/downwards between types and interfaces. We hijack the merge process by providing
29
+ // implementations/interfaces as "additional sources". This means that we cannot apply staticArgumentTransform()
30
+ // as subgraph index index will be wrong/undefined.
27
31
  this.registerDirective(createDirectiveSpecification({
28
32
  name: AuthenticatedSpecDefinition.directiveName,
29
33
  locations: [
@@ -31,6 +31,10 @@ export class PolicySpecDefinition extends FeatureDefinition {
31
31
 
32
32
  this.registerType(createScalarTypeSpecification({ name: PolicyTypeName.POLICY }));
33
33
 
34
+ // WARNING: we cannot declare staticArgumentTransform() as access control merge logic needs to propagate
35
+ // requirements upwards/downwards between types and interfaces. We hijack the merge process by providing
36
+ // implementations/interfaces as "additional sources". This means that we cannot apply staticArgumentTransform()
37
+ // as subgraph index index will be wrong/undefined.
34
38
  this.registerDirective(createDirectiveSpecification({
35
39
  name: PolicySpecDefinition.directiveName,
36
40
  args: [{
@@ -32,6 +32,10 @@ export class RequiresScopesSpecDefinition extends FeatureDefinition {
32
32
 
33
33
  this.registerType(createScalarTypeSpecification({ name: RequiresScopesTypeName.SCOPE }));
34
34
 
35
+ // WARNING: we cannot declare staticArgumentTransform() as access control merge logic needs to propagate
36
+ // requirements upwards/downwards between types and interfaces. We hijack the merge process by providing
37
+ // implementations/interfaces as "additional sources". This means that we cannot apply staticArgumentTransform()
38
+ // as subgraph index index will be wrong/undefined.
35
39
  this.registerDirective(createDirectiveSpecification({
36
40
  name: RequiresScopesSpecDefinition.directiveName,
37
41
  args: [{