@wundergraph/composition 0.15.0 → 0.17.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.
Files changed (36) hide show
  1. package/dist/ast/utils.d.ts +9 -2
  2. package/dist/ast/utils.js.map +1 -1
  3. package/dist/errors/errors.js +1 -2
  4. package/dist/errors/errors.js.map +1 -1
  5. package/dist/federation/federation-factory.d.ts +18 -14
  6. package/dist/federation/federation-factory.js +246 -83
  7. package/dist/federation/federation-factory.js.map +1 -1
  8. package/dist/federation/utils.d.ts +7 -11
  9. package/dist/federation/utils.js.map +1 -1
  10. package/dist/index.d.ts +6 -6
  11. package/dist/index.js +6 -6
  12. package/dist/index.js.map +1 -1
  13. package/dist/normalization/normalization-factory.d.ts +24 -14
  14. package/dist/normalization/normalization-factory.js +236 -120
  15. package/dist/normalization/normalization-factory.js.map +1 -1
  16. package/dist/normalization/utils.d.ts +3 -2
  17. package/dist/normalization/utils.js +21 -11
  18. package/dist/normalization/utils.js.map +1 -1
  19. package/dist/{subgraph/field-configuration.d.ts → router-configuration/router-configuration.d.ts} +13 -10
  20. package/dist/{subgraph/field-configuration.js → router-configuration/router-configuration.js} +1 -1
  21. package/dist/router-configuration/router-configuration.js.map +1 -0
  22. package/dist/subgraph/subgraph.d.ts +8 -4
  23. package/dist/subgraph/subgraph.js +81 -78
  24. package/dist/subgraph/subgraph.js.map +1 -1
  25. package/dist/tsconfig.tsbuildinfo +1 -1
  26. package/dist/utils/constants.d.ts +2 -1
  27. package/dist/utils/constants.js +82 -27
  28. package/dist/utils/constants.js.map +1 -1
  29. package/dist/utils/string-constants.d.ts +8 -2
  30. package/dist/utils/string-constants.js +10 -4
  31. package/dist/utils/string-constants.js.map +1 -1
  32. package/dist/utils/utils.d.ts +42 -1
  33. package/dist/utils/utils.js +156 -1
  34. package/dist/utils/utils.js.map +1 -1
  35. package/package.json +2 -2
  36. package/dist/subgraph/field-configuration.js.map +0 -1
@@ -15,20 +15,23 @@ const merge_1 = require("@graphql-tools/merge");
15
15
  const constants_1 = require("../utils/constants");
16
16
  const normalization_factory_1 = require("../normalization/normalization-factory");
17
17
  const utils_4 = require("../normalization/utils");
18
+ const index_1 = require("graphql/index");
18
19
  class FederationFactory {
20
+ authorizationDataByParentTypeName;
19
21
  abstractToConcreteTypeNames = new Map();
20
22
  areFieldsExternal = false;
21
23
  areFieldsShareable = false;
22
24
  argumentTypeNameSet = new Set();
23
- argumentConfigurations = [];
25
+ fieldConfigurationByFieldPath = new Map();
24
26
  entityInterfaceFederationDataByTypeName;
25
27
  executableDirectives = new Set();
26
28
  parentTypeName = '';
27
29
  persistedDirectives = new Set([string_constants_1.DEPRECATED, string_constants_1.INACCESSIBLE, string_constants_1.TAG]);
30
+ persistedDirectiveDefinitions = new Set([string_constants_1.AUTHENTICATED, string_constants_1.DEPRECATED, string_constants_1.INACCESSIBLE, string_constants_1.TAG, string_constants_1.REQUIRES_SCOPES]);
28
31
  currentSubgraphName = '';
29
32
  childName = '';
30
33
  directiveDefinitions = new Map();
31
- entities = new Map();
34
+ entityContainersByTypeName;
32
35
  errors = [];
33
36
  evaluatedObjectLikesBySubgraph = new Map();
34
37
  extensions = new Map();
@@ -46,36 +49,24 @@ class FederationFactory {
46
49
  outputFieldTypeNameSet = new Set();
47
50
  parents = new Map();
48
51
  rootTypeNames = new Set([string_constants_1.DEFAULT_MUTATION, string_constants_1.DEFAULT_QUERY, string_constants_1.DEFAULT_SUBSCRIPTION]);
49
- subgraphs = [];
52
+ internalSubgraphBySubgraphName;
50
53
  shareableErrorTypeNames = new Map();
51
- subgraphConfigBySubgraphName;
54
+ renamedTypeNameByOriginalTypeName = new Map();
52
55
  warnings;
53
- constructor(subgraphs, subgraphConfigBySubgraphName, entityInterfaceFederationDataByTypeName, warnings) {
54
- this.subgraphs = subgraphs;
55
- this.subgraphConfigBySubgraphName = subgraphConfigBySubgraphName;
56
+ constructor(authorizationDataByParentTypeName, entityContainersByTypeName, entityInterfaceFederationDataByTypeName, internalSubgraphBySubgraphName, warnings) {
57
+ this.authorizationDataByParentTypeName = authorizationDataByParentTypeName;
58
+ this.entityContainersByTypeName = entityContainersByTypeName;
56
59
  this.entityInterfaceFederationDataByTypeName = entityInterfaceFederationDataByTypeName;
60
+ this.internalSubgraphBySubgraphName = internalSubgraphBySubgraphName;
57
61
  this.warnings = warnings || [];
58
62
  }
59
63
  isObjectRootType(node) {
60
64
  return this.rootTypeNames.has(node.name.value);
61
65
  }
62
- upsertEntity(node) {
63
- const typeName = node.name.value;
64
- const entity = this.entities.get(typeName);
65
- if (entity) {
66
- entity.subgraphs.add(this.currentSubgraphName);
67
- return;
68
- }
69
- this.entities.set(typeName, {
70
- fields: new Set(),
71
- subgraphs: new Set([this.currentSubgraphName]),
72
- });
73
- }
74
66
  populateMultiGraphAndRenameOperations(subgraphs) {
75
- for (const subgraph of subgraphs) {
67
+ for (const subgraph of subgraphs.values()) {
76
68
  this.currentSubgraphName = subgraph.name;
77
69
  (0, subgraph_1.walkSubgraphToCollectObjectLikesAndDirectiveDefinitions)(this, subgraph);
78
- (0, subgraph_1.walkSubgraphToCollectFields)(this, subgraph);
79
70
  }
80
71
  }
81
72
  getEnumMergeMethod(enumName) {
@@ -238,7 +229,7 @@ class FederationFactory {
238
229
  isFieldExternal(node) {
239
230
  return this.areFieldsExternal || (0, utils_1.isNodeExternal)(node);
240
231
  }
241
- isFieldShareable(node, parent) {
232
+ isFieldShareable(node) {
242
233
  return (!this.isCurrentSubgraphVersionTwo || this.areFieldsShareable || this.isFieldEntityKey() || (0, utils_1.isNodeShareable)(node));
243
234
  }
244
235
  getOverrideTargetSubgraphName(node) {
@@ -275,7 +266,7 @@ class FederationFactory {
275
266
  this.upsertArguments(node, directiveDefinition.arguments);
276
267
  (0, utils_1.setLongestDescriptionForNode)(directiveDefinition.node, node.description);
277
268
  directiveDefinition.node.repeatable = directiveDefinition.node.repeatable && node.repeatable;
278
- directiveDefinition.subgraphs.add(this.currentSubgraphName);
269
+ directiveDefinition.subgraphNames.add(this.currentSubgraphName);
279
270
  return;
280
271
  }
281
272
  const executableLocations = (0, utils_1.extractExecutableDirectiveLocations)(node.locations, new Set());
@@ -283,7 +274,7 @@ class FederationFactory {
283
274
  arguments: this.upsertArguments(node, new Map()),
284
275
  executableLocations,
285
276
  node: (0, ast_1.directiveDefinitionNodeToMutable)(node),
286
- subgraphs: new Set([this.currentSubgraphName]),
277
+ subgraphNames: new Set([this.currentSubgraphName]),
287
278
  });
288
279
  if (executableLocations.size > 0) {
289
280
  this.executableDirectives.add(directiveName);
@@ -309,8 +300,8 @@ class FederationFactory {
309
300
  }
310
301
  // shareability doesn't matter if:
311
302
  // the field has only been seen exactly twice—the target override and the source override
312
- if (fieldContainer.subgraphs.size === 2 &&
313
- fieldContainer.subgraphs.has(fieldContainer.overrideTargetSubgraphName)) {
303
+ if (fieldContainer.subgraphNames.size === 2 &&
304
+ fieldContainer.subgraphNames.has(fieldContainer.overrideTargetSubgraphName)) {
314
305
  continue;
315
306
  }
316
307
  unshareableFields += 1;
@@ -331,7 +322,7 @@ class FederationFactory {
331
322
  }
332
323
  const fieldMap = parent.fields;
333
324
  const isFieldExternal = this.isFieldExternal(node);
334
- const isFieldShareable = this.isFieldShareable(node, parent);
325
+ const isFieldShareable = this.isFieldShareable(node);
335
326
  const fieldPath = `${this.parentTypeName}.${this.childName}`;
336
327
  const fieldRootTypeName = (0, type_merging_1.getNamedTypeForChild)(fieldPath, node.type);
337
328
  const existingFieldContainer = fieldMap.get(this.childName);
@@ -339,7 +330,7 @@ class FederationFactory {
339
330
  if (existingFieldContainer) {
340
331
  this.extractPersistedDirectives(node.directives || [], existingFieldContainer.directives);
341
332
  (0, utils_1.setLongestDescriptionForNode)(existingFieldContainer.node, node.description);
342
- existingFieldContainer.subgraphs.add(this.currentSubgraphName);
333
+ existingFieldContainer.subgraphNames.add(this.currentSubgraphName);
343
334
  existingFieldContainer.overrideTargetSubgraphName = targetSubgraph;
344
335
  existingFieldContainer.subgraphsByShareable.set(this.currentSubgraphName, isFieldShareable);
345
336
  existingFieldContainer.subgraphsByExternal.set(this.currentSubgraphName, isFieldExternal);
@@ -385,7 +376,7 @@ class FederationFactory {
385
376
  node: (0, ast_1.fieldDefinitionNodeToMutable)(node, this.parentTypeName),
386
377
  namedTypeName: fieldRootTypeName,
387
378
  overrideTargetSubgraphName: targetSubgraph,
388
- subgraphs: new Set([this.currentSubgraphName]),
379
+ subgraphNames: new Set([this.currentSubgraphName]),
389
380
  subgraphsByShareable: new Map([[this.currentSubgraphName, isFieldShareable]]),
390
381
  subgraphsByExternal: new Map([[this.currentSubgraphName, isFieldExternal]]),
391
382
  });
@@ -465,7 +456,7 @@ class FederationFactory {
465
456
  (0, utils_1.setLongestDescriptionForNode)(parent.node, node.description);
466
457
  this.extractPersistedDirectives(node.directives || [], parent.directives);
467
458
  (0, utils_1.extractInterfaces)(node, parent.interfaces);
468
- parent.subgraphs.add(this.currentSubgraphName);
459
+ parent.subgraphNames.add(this.currentSubgraphName);
469
460
  return;
470
461
  }
471
462
  this.parents.set(parentTypeName, {
@@ -477,7 +468,7 @@ class FederationFactory {
477
468
  ...node,
478
469
  kind: graphql_1.Kind.INTERFACE_TYPE_DEFINITION,
479
470
  }),
480
- subgraphs: new Set([this.currentSubgraphName]),
471
+ subgraphNames: new Set([this.currentSubgraphName]),
481
472
  });
482
473
  }
483
474
  upsertParentNode(node) {
@@ -526,7 +517,7 @@ class FederationFactory {
526
517
  throw (0, errors_1.incompatibleParentKindFatalError)(parentTypeName, node.kind, parent.kind);
527
518
  }
528
519
  (0, utils_1.extractInterfaces)(node, parent.interfaces);
529
- parent.subgraphs.add(this.currentSubgraphName);
520
+ parent.subgraphNames.add(this.currentSubgraphName);
530
521
  return;
531
522
  }
532
523
  this.parents.set(parentTypeName, {
@@ -535,7 +526,7 @@ class FederationFactory {
535
526
  interfaces: (0, utils_1.extractInterfaces)(node, new Set()),
536
527
  kind: node.kind,
537
528
  node: (0, ast_1.interfaceTypeDefinitionNodeToMutable)(node),
538
- subgraphs: new Set([this.currentSubgraphName]),
529
+ subgraphNames: new Set([this.currentSubgraphName]),
539
530
  });
540
531
  return;
541
532
  case graphql_1.Kind.SCALAR_TYPE_DEFINITION:
@@ -557,7 +548,7 @@ class FederationFactory {
557
548
  throw (0, errors_1.incompatibleParentKindFatalError)(parentTypeName, node.kind, parent.kind);
558
549
  }
559
550
  (0, utils_1.extractInterfaces)(node, parent.interfaces);
560
- parent.subgraphs.add(this.currentSubgraphName);
551
+ parent.subgraphNames.add(this.currentSubgraphName);
561
552
  return;
562
553
  }
563
554
  this.parents.set(parentTypeName, {
@@ -567,7 +558,7 @@ class FederationFactory {
567
558
  isRootType: this.isParentRootType,
568
559
  kind: node.kind,
569
560
  node: (0, ast_1.objectTypeDefinitionNodeToMutable)(node),
570
- subgraphs: new Set([this.currentSubgraphName]),
561
+ subgraphNames: new Set([this.currentSubgraphName]),
571
562
  });
572
563
  return;
573
564
  case graphql_1.Kind.UNION_TYPE_DEFINITION:
@@ -597,7 +588,7 @@ class FederationFactory {
597
588
  if (extension.kind !== graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
598
589
  throw (0, errors_1.incompatibleParentKindFatalError)(this.parentTypeName, graphql_1.Kind.OBJECT_TYPE_EXTENSION, extension.kind);
599
590
  }
600
- extension.subgraphs.add(this.currentSubgraphName);
591
+ extension.subgraphNames.add(this.currentSubgraphName);
601
592
  (0, utils_1.extractInterfaces)(node, extension.interfaces);
602
593
  this.extractPersistedDirectives(node.directives || [], extension.directives);
603
594
  return;
@@ -611,7 +602,7 @@ class FederationFactory {
611
602
  isRootType: this.isParentRootType,
612
603
  kind: graphql_1.Kind.OBJECT_TYPE_EXTENSION,
613
604
  node: (0, ast_1.objectTypeExtensionNodeToMutable)(node),
614
- subgraphs: new Set([this.currentSubgraphName]),
605
+ subgraphNames: new Set([this.currentSubgraphName]),
615
606
  });
616
607
  }
617
608
  isTypeValidImplementation(originalType, implementationType) {
@@ -736,7 +727,7 @@ class FederationFactory {
736
727
  }
737
728
  mergeArguments(container, args, errors, argumentNames) {
738
729
  for (const argumentContainer of container.arguments.values()) {
739
- const missingSubgraphs = (0, utils_3.getEntriesNotInHashSet)(container.subgraphs, argumentContainer.subgraphs);
730
+ const missingSubgraphs = (0, utils_3.getEntriesNotInHashSet)(container.subgraphNames, argumentContainer.subgraphs);
740
731
  const argumentName = argumentContainer.node.name.value;
741
732
  if (missingSubgraphs.length > 0) {
742
733
  // Required arguments must be defined in all subgraphs that define the field
@@ -764,7 +755,7 @@ class FederationFactory {
764
755
  if (!this.executableDirectives.has(directiveName)) {
765
756
  return;
766
757
  }
767
- if (this.subgraphs.length !== directiveContainer.subgraphs.size) {
758
+ if (this.internalSubgraphBySubgraphName.size !== directiveContainer.subgraphNames.size) {
768
759
  return;
769
760
  }
770
761
  directiveContainer.node.locations = (0, utils_1.setToNameNodeArray)(directiveContainer.executableLocations);
@@ -782,11 +773,30 @@ class FederationFactory {
782
773
  directiveContainer.node.arguments = args;
783
774
  definitions.push(directiveContainer.node);
784
775
  }
776
+ pushAuthorizationDirectives(fieldContainer, parentTypeName) {
777
+ const authorizationData = this.authorizationDataByParentTypeName.get(parentTypeName);
778
+ if (!authorizationData) {
779
+ return;
780
+ }
781
+ const fieldAuthorizationData = authorizationData.fieldAuthorizationDataByFieldName.get(fieldContainer.node.name.value);
782
+ if (!fieldAuthorizationData) {
783
+ return;
784
+ }
785
+ if (fieldAuthorizationData.requiresAuthentication) {
786
+ fieldContainer.directives.directives.set(string_constants_1.AUTHENTICATED, [(0, utils_3.generateAuthenticatedDirective)()]);
787
+ }
788
+ if (fieldAuthorizationData.requiredScopes.length > 0) {
789
+ fieldContainer.directives.directives.set(string_constants_1.REQUIRES_SCOPES, [
790
+ (0, utils_3.generateRequiresScopesDirective)(fieldAuthorizationData.requiredScopes),
791
+ ]);
792
+ }
793
+ }
785
794
  getMergedFieldDefinitionNode(fieldContainer, parentTypeName) {
786
- if (!fieldContainer.arguments) {
795
+ this.pushAuthorizationDirectives(fieldContainer, parentTypeName);
796
+ (0, utils_1.pushPersistedDirectivesAndGetNode)(fieldContainer);
797
+ if (fieldContainer.arguments.size < 1) {
787
798
  return fieldContainer.node;
788
799
  }
789
- (0, utils_1.pushPersistedDirectivesAndGetNode)(fieldContainer);
790
800
  const fieldName = fieldContainer.node.name.value;
791
801
  const fieldPath = `${parentTypeName}.${fieldName}`;
792
802
  const args = [];
@@ -797,7 +807,7 @@ class FederationFactory {
797
807
  this.errors.push((0, errors_1.invalidRequiredArgumentsError)(string_constants_1.FIELD, fieldPath, errors));
798
808
  }
799
809
  else if (argumentNames.length > 0) {
800
- this.argumentConfigurations.push({
810
+ this.fieldConfigurationByFieldPath.set(`${parentTypeName}.${fieldName}`, {
801
811
  argumentNames,
802
812
  fieldName,
803
813
  typeName: parentTypeName,
@@ -883,7 +893,7 @@ class FederationFactory {
883
893
  return true;
884
894
  }
885
895
  if (entityAncestorName === parentTypeName) {
886
- const hasOverlap = (0, utils_3.doSetsHaveAnyOverlap)(fieldSubgraphs, (0, utils_3.getOrThrowError)(this.entities, entityAncestorName, string_constants_1.ENTITIES).subgraphs);
896
+ const hasOverlap = (0, utils_3.doSetsHaveAnyOverlap)(fieldSubgraphs, (0, utils_3.getOrThrowError)(this.entityContainersByTypeName, entityAncestorName, string_constants_1.ENTITIES).subgraphNames);
887
897
  this.graphPaths.set(path, hasOverlap);
888
898
  return hasOverlap;
889
899
  }
@@ -906,7 +916,7 @@ class FederationFactory {
906
916
  return false;
907
917
  }
908
918
  isFieldExternalInAllMutualSubgraphs(subgraphs, fieldContainer) {
909
- const mutualSubgraphs = (0, utils_3.getAllMutualEntries)(subgraphs, fieldContainer.subgraphs);
919
+ const mutualSubgraphs = (0, utils_3.getAllMutualEntries)(subgraphs, fieldContainer.subgraphNames);
910
920
  if (mutualSubgraphs.size < 1) {
911
921
  return false;
912
922
  }
@@ -934,7 +944,7 @@ class FederationFactory {
934
944
  }
935
945
  for (const entityAncestor of entityAncestors) {
936
946
  const entityContainer = (0, utils_3.getOrThrowError)(this.parents, entityAncestor, string_constants_1.PARENTS);
937
- const mutualEntityAncestorRootTypeFieldSubgraphs = (0, utils_3.getAllMutualEntries)(rootTypeFieldSubgraphs, entityContainer.subgraphs);
947
+ const mutualEntityAncestorRootTypeFieldSubgraphs = (0, utils_3.getAllMutualEntries)(rootTypeFieldSubgraphs, entityContainer.subgraphNames);
938
948
  const mutualEntityAncestorSubgraphs = (0, utils_3.getAllMutualEntries)(mutualEntityAncestorRootTypeFieldSubgraphs, objectSubgraphs);
939
949
  for (const mutualSubgraph of mutualEntityAncestorSubgraphs) {
940
950
  const objects = this.evaluatedObjectLikesBySubgraph.get(mutualSubgraph);
@@ -968,12 +978,12 @@ class FederationFactory {
968
978
  if (this.isFieldExternalInAllMutualSubgraphs(rootTypeFieldData.subgraphs, fieldContainer)) {
969
979
  continue;
970
980
  }
971
- this.updateEvaluatedSubgraphOccurrences(rootTypeFieldData.subgraphs, parentContainer.subgraphs, entityAncestors, parentTypeName);
981
+ this.updateEvaluatedSubgraphOccurrences(rootTypeFieldData.subgraphs, parentContainer.subgraphNames, entityAncestors, parentTypeName);
972
982
  evaluatedObjectLikes.add(parentTypeName);
973
- const isFieldResolvable = (0, utils_3.doSetsHaveAnyOverlap)(rootTypeFieldData.subgraphs, fieldContainer.subgraphs) ||
974
- this.isFieldResolvableByEntityAncestor(entityAncestors, fieldContainer.subgraphs, parentTypeName);
983
+ const isFieldResolvable = (0, utils_3.doSetsHaveAnyOverlap)(rootTypeFieldData.subgraphs, fieldContainer.subgraphNames) ||
984
+ this.isFieldResolvableByEntityAncestor(entityAncestors, fieldContainer.subgraphNames, parentTypeName);
975
985
  const newCurrentFieldPath = currentFieldPath + (isParentAbstract ? ' ' : '.') + fieldName;
976
- const entity = this.entities.get(fieldNamedTypeName);
986
+ const entity = this.entityContainersByTypeName.get(fieldNamedTypeName);
977
987
  if (isFieldResolvable) {
978
988
  // The base scalars are not in this.parentMap
979
989
  if (constants_1.BASE_SCALARS.has(fieldNamedTypeName)) {
@@ -991,7 +1001,7 @@ class FederationFactory {
991
1001
  case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
992
1002
  // intentional fallthrough
993
1003
  case graphql_1.Kind.UNION_TYPE_DEFINITION:
994
- this.evaluateResolvabilityOfAbstractType(fieldNamedTypeName, childContainer.kind, rootTypeFieldData, newCurrentFieldPath, evaluatedObjectLikes, entity ? [...entityAncestors, fieldNamedTypeName] : [...entityAncestors], fieldContainer.subgraphs);
1004
+ this.evaluateResolvabilityOfAbstractType(fieldNamedTypeName, childContainer.kind, rootTypeFieldData, newCurrentFieldPath, evaluatedObjectLikes, entity ? [...entityAncestors, fieldNamedTypeName] : [...entityAncestors]);
995
1005
  continue;
996
1006
  default:
997
1007
  this.errors.push((0, errors_1.unexpectedObjectResponseType)(newCurrentFieldPath, (0, utils_3.kindToTypeString)(childContainer.kind)));
@@ -999,7 +1009,7 @@ class FederationFactory {
999
1009
  }
1000
1010
  }
1001
1011
  if (constants_1.BASE_SCALARS.has(fieldNamedTypeName)) {
1002
- this.errors.push((0, errors_1.unresolvableFieldError)(rootTypeFieldData, fieldName, [...fieldContainer.subgraphs], newCurrentFieldPath, parentTypeName));
1012
+ this.errors.push((0, errors_1.unresolvableFieldError)(rootTypeFieldData, fieldName, [...fieldContainer.subgraphNames], newCurrentFieldPath, parentTypeName));
1003
1013
  continue;
1004
1014
  }
1005
1015
  const childContainer = (0, utils_3.getOrThrowError)(this.parents, fieldNamedTypeName, string_constants_1.PARENTS);
@@ -1007,21 +1017,21 @@ class FederationFactory {
1007
1017
  case graphql_1.Kind.ENUM_TYPE_DEFINITION:
1008
1018
  // intentional fallthrough
1009
1019
  case graphql_1.Kind.SCALAR_TYPE_DEFINITION:
1010
- this.errors.push((0, errors_1.unresolvableFieldError)(rootTypeFieldData, fieldName, [...fieldContainer.subgraphs], newCurrentFieldPath, parentTypeName));
1020
+ this.errors.push((0, errors_1.unresolvableFieldError)(rootTypeFieldData, fieldName, [...fieldContainer.subgraphNames], newCurrentFieldPath, parentTypeName));
1011
1021
  continue;
1012
1022
  case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
1013
1023
  // intentional fallthrough
1014
1024
  case graphql_1.Kind.UNION_TYPE_DEFINITION:
1015
1025
  // intentional fallthrough
1016
1026
  case graphql_1.Kind.OBJECT_TYPE_DEFINITION:
1017
- this.errors.push((0, errors_1.unresolvableFieldError)(rootTypeFieldData, fieldName, [...fieldContainer.subgraphs], newCurrentFieldPath + string_constants_1.SELECTION_REPRESENTATION, parentTypeName));
1027
+ this.errors.push((0, errors_1.unresolvableFieldError)(rootTypeFieldData, fieldName, [...fieldContainer.subgraphNames], newCurrentFieldPath + string_constants_1.SELECTION_REPRESENTATION, parentTypeName));
1018
1028
  continue;
1019
1029
  default:
1020
1030
  this.errors.push((0, errors_1.unexpectedObjectResponseType)(newCurrentFieldPath, (0, utils_3.kindToTypeString)(childContainer.kind)));
1021
1031
  }
1022
1032
  }
1023
1033
  }
1024
- evaluateResolvabilityOfAbstractType(abstractTypeName, abstractKind, rootTypeFieldData, currentFieldPath, evaluatedObjectLikes, entityAncestors, parentSubgraphs) {
1034
+ evaluateResolvabilityOfAbstractType(abstractTypeName, abstractKind, rootTypeFieldData, currentFieldPath, evaluatedObjectLikes, entityAncestors) {
1025
1035
  if (evaluatedObjectLikes.has(abstractTypeName)) {
1026
1036
  return;
1027
1037
  }
@@ -1040,22 +1050,171 @@ class FederationFactory {
1040
1050
  throw (0, errors_1.unexpectedParentKindErrorMessage)(concreteTypeName, 'Object', (0, utils_3.kindToTypeString)(concreteParentContainer.kind));
1041
1051
  }
1042
1052
  // If the concrete type is unreachable through an inline fragment, it is not an error
1043
- if (!(0, utils_3.doSetsHaveAnyOverlap)(concreteParentContainer.subgraphs, rootTypeFieldData.subgraphs)) {
1053
+ if (!(0, utils_3.doSetsHaveAnyOverlap)(concreteParentContainer.subgraphNames, rootTypeFieldData.subgraphs)) {
1044
1054
  continue;
1045
1055
  }
1046
- const entity = this.entities.get(concreteTypeName);
1056
+ const entity = this.entityContainersByTypeName.get(concreteTypeName);
1047
1057
  this.evaluateResolvabilityOfObject(concreteParentContainer, rootTypeFieldData, currentFieldPath + ` ... on ` + concreteTypeName, evaluatedObjectLikes, entity ? [...entityAncestors, concreteTypeName] : [...entityAncestors], true);
1048
1058
  }
1049
1059
  }
1060
+ validateKeyFieldSetsForImplicitEntity(entityContainer) {
1061
+ const internalSubgraph = (0, utils_3.getOrThrowError)(this.internalSubgraphBySubgraphName, this.currentSubgraphName, 'internalSubgraphBySubgraphName');
1062
+ const parentContainerByTypeName = internalSubgraph.parentContainerByTypeName;
1063
+ const extensionContainerByTypeName = internalSubgraph.extensionContainerByTypeName;
1064
+ const implicitEntityContainer = parentContainerByTypeName.get(entityContainer.typeName) ||
1065
+ extensionContainerByTypeName.get(entityContainer.typeName);
1066
+ if (!implicitEntityContainer ||
1067
+ (implicitEntityContainer.kind !== graphql_1.Kind.OBJECT_TYPE_DEFINITION &&
1068
+ implicitEntityContainer.kind !== graphql_1.Kind.OBJECT_TYPE_EXTENSION)) {
1069
+ throw (0, errors_1.incompatibleParentKindFatalError)(entityContainer.typeName, graphql_1.Kind.OBJECT_TYPE_DEFINITION, implicitEntityContainer?.kind || graphql_1.Kind.NULL);
1070
+ }
1071
+ const configurationData = (0, utils_3.getOrThrowError)(internalSubgraph.configurationDataMap, entityContainer.typeName, 'internalSubgraph.configurationDataMap');
1072
+ const keyFieldNames = new Set();
1073
+ const keys = [];
1074
+ // Any errors in the field sets would be caught when evaluating the explicit entities, so they are ignored here
1075
+ for (const fieldSet of entityContainer.keyFieldSets) {
1076
+ // Create a new selection set so that the value can be parsed as a new DocumentNode
1077
+ const { error, documentNode } = (0, utils_1.safeParse)('{' + fieldSet + '}');
1078
+ if (error || !documentNode) {
1079
+ // This would be caught as an error elsewhere
1080
+ continue;
1081
+ }
1082
+ const parentContainers = [implicitEntityContainer];
1083
+ const definedFields = [];
1084
+ let currentDepth = -1;
1085
+ let shouldDefineSelectionSet = true;
1086
+ let shouldAddKeyFieldSet = true;
1087
+ (0, index_1.visit)(documentNode, {
1088
+ Argument: {
1089
+ enter() {
1090
+ // Fields that define arguments are never allowed in a key FieldSet
1091
+ // However, at this stage, it actually means the argument is undefined on the field
1092
+ shouldAddKeyFieldSet = false;
1093
+ return index_1.BREAK;
1094
+ },
1095
+ },
1096
+ Field: {
1097
+ enter(node) {
1098
+ const parentContainer = parentContainers[currentDepth];
1099
+ const parentTypeName = parentContainer.name.value;
1100
+ // If an object-like was just visited, a selection set should have been entered
1101
+ if (shouldDefineSelectionSet) {
1102
+ shouldAddKeyFieldSet = false;
1103
+ return index_1.BREAK;
1104
+ }
1105
+ const fieldName = node.name.value;
1106
+ const fieldPath = `${parentTypeName}.${fieldName}`;
1107
+ const fieldContainer = parentContainer.fields.get(fieldName);
1108
+ // undefined if the field does not exist on the parent
1109
+ if (!fieldContainer || fieldContainer.arguments.size || definedFields[currentDepth].has(fieldName)) {
1110
+ shouldAddKeyFieldSet = false;
1111
+ return index_1.BREAK;
1112
+ }
1113
+ definedFields[currentDepth].add(fieldName);
1114
+ // Depth 0 is the original parent type
1115
+ // If a field is external, but it's part of a key FieldSet, it will be included in the root configuration
1116
+ if (currentDepth === 0) {
1117
+ keyFieldNames.add(fieldName);
1118
+ }
1119
+ const namedTypeName = (0, type_merging_1.getNamedTypeForChild)(fieldPath, fieldContainer.node.type);
1120
+ // The base scalars are not in the parents map
1121
+ if (constants_1.BASE_SCALARS.has(namedTypeName)) {
1122
+ return;
1123
+ }
1124
+ // The child could itself be a parent and could exist as an object extension
1125
+ const childContainer = parentContainerByTypeName.get(namedTypeName) || extensionContainerByTypeName.get(namedTypeName);
1126
+ if (!childContainer) {
1127
+ shouldAddKeyFieldSet = false;
1128
+ return index_1.BREAK;
1129
+ }
1130
+ if (childContainer.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION ||
1131
+ childContainer.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
1132
+ shouldDefineSelectionSet = true;
1133
+ parentContainers.push(childContainer);
1134
+ return;
1135
+ }
1136
+ // interfaces and unions are invalid in a key directive
1137
+ if ((0, utils_1.isKindAbstract)(childContainer.kind)) {
1138
+ shouldAddKeyFieldSet = false;
1139
+ return index_1.BREAK;
1140
+ }
1141
+ },
1142
+ },
1143
+ InlineFragment: {
1144
+ enter() {
1145
+ shouldAddKeyFieldSet = false;
1146
+ return index_1.BREAK;
1147
+ },
1148
+ },
1149
+ SelectionSet: {
1150
+ enter() {
1151
+ if (!shouldDefineSelectionSet) {
1152
+ shouldAddKeyFieldSet = false;
1153
+ return index_1.BREAK;
1154
+ }
1155
+ currentDepth += 1;
1156
+ shouldDefineSelectionSet = false;
1157
+ if (currentDepth < 0 || currentDepth >= parentContainers.length) {
1158
+ shouldAddKeyFieldSet = false;
1159
+ return index_1.BREAK;
1160
+ }
1161
+ definedFields.push(new Set());
1162
+ },
1163
+ leave() {
1164
+ if (shouldDefineSelectionSet) {
1165
+ shouldAddKeyFieldSet = false;
1166
+ return index_1.BREAK;
1167
+ }
1168
+ // Empty selection sets would be a parse error, so it is unnecessary to handle them
1169
+ currentDepth -= 1;
1170
+ parentContainers.pop();
1171
+ definedFields.pop();
1172
+ },
1173
+ },
1174
+ });
1175
+ if (!shouldAddKeyFieldSet) {
1176
+ continue;
1177
+ }
1178
+ // Add any top-level fields that compose the key in case they are external
1179
+ (0, utils_3.addIterableValuesToSet)(keyFieldNames, configurationData.fieldNames);
1180
+ keys.push({
1181
+ fieldName: '',
1182
+ selectionSet: (0, utils_4.getNormalizedFieldSet)(documentNode),
1183
+ disableEntityResolver: true,
1184
+ });
1185
+ }
1186
+ if (keys.length > 0) {
1187
+ configurationData.isRootNode = true;
1188
+ configurationData.keys = keys;
1189
+ }
1190
+ }
1191
+ handleAuthorizationDataForRenamedTypes() {
1192
+ for (const [originalTypeName, renamedTypeName] of this.renamedTypeNameByOriginalTypeName) {
1193
+ const originalAuthorizationData = this.authorizationDataByParentTypeName.get(originalTypeName);
1194
+ if (!originalAuthorizationData) {
1195
+ continue;
1196
+ }
1197
+ originalAuthorizationData.typeName = renamedTypeName;
1198
+ const renamedAuthorizationData = this.authorizationDataByParentTypeName.get(renamedTypeName);
1199
+ if (!renamedAuthorizationData) {
1200
+ this.authorizationDataByParentTypeName.set(renamedTypeName, originalAuthorizationData);
1201
+ }
1202
+ else {
1203
+ (0, utils_3.addAuthorizationDataProperties)(originalAuthorizationData, renamedAuthorizationData);
1204
+ }
1205
+ this.authorizationDataByParentTypeName.delete(originalTypeName);
1206
+ }
1207
+ }
1050
1208
  federate() {
1051
- this.populateMultiGraphAndRenameOperations(this.subgraphs);
1209
+ this.populateMultiGraphAndRenameOperations(this.internalSubgraphBySubgraphName);
1052
1210
  const factory = this;
1053
- for (const subgraph of this.subgraphs) {
1211
+ for (const subgraph of this.internalSubgraphBySubgraphName.values()) {
1054
1212
  this.isCurrentSubgraphVersionTwo = subgraph.isVersionTwo;
1055
1213
  this.currentSubgraphName = subgraph.name;
1056
1214
  this.keyFieldNamesByParentTypeName = subgraph.keyFieldNamesByParentTypeName;
1057
1215
  (0, subgraph_1.walkSubgraphToFederate)(subgraph.definitions, subgraph.overriddenFieldNamesByParentTypeName, factory);
1058
1216
  }
1217
+ this.handleAuthorizationDataForRenamedTypes();
1059
1218
  for (const [typeName, entityInterfaceData] of this.entityInterfaceFederationDataByTypeName) {
1060
1219
  (0, utils_3.subtractSourceSetFromTargetSet)(entityInterfaceData.interfaceFieldNames, entityInterfaceData.interfaceObjectFieldNames);
1061
1220
  const entityInterface = (0, utils_3.getOrThrowError)(this.parents, typeName, 'parents');
@@ -1064,7 +1223,7 @@ class FederationFactory {
1064
1223
  continue;
1065
1224
  }
1066
1225
  for (const subgraphName of entityInterfaceData.interfaceObjectSubgraphs) {
1067
- const configurationDataMap = (0, utils_3.getOrThrowError)(this.subgraphConfigBySubgraphName, subgraphName, 'subgraphConfigBySubgraphName').configurationDataMap;
1226
+ const configurationDataMap = (0, utils_3.getOrThrowError)(this.internalSubgraphBySubgraphName, subgraphName, 'internalSubgraphBySubgraphName').configurationDataMap;
1068
1227
  const concreteTypeNames = this.abstractToConcreteTypeNames.get(typeName);
1069
1228
  if (!concreteTypeNames) {
1070
1229
  continue;
@@ -1087,10 +1246,10 @@ class FederationFactory {
1087
1246
  continue;
1088
1247
  }
1089
1248
  // The subgraph locations of the interface object must be added to the concrete types that implement it
1090
- const entity = this.entities.get(concreteTypeName);
1249
+ const entity = this.entityContainersByTypeName.get(concreteTypeName);
1091
1250
  if (entity) {
1092
1251
  // TODO error if not an entity
1093
- entity.subgraphs.add(subgraphName);
1252
+ entity.subgraphNames.add(subgraphName);
1094
1253
  }
1095
1254
  const configurationData = {
1096
1255
  fieldNames,
@@ -1113,13 +1272,16 @@ class FederationFactory {
1113
1272
  }
1114
1273
  const definitions = [];
1115
1274
  for (const [directiveName, directiveContainer] of this.directiveDefinitions) {
1116
- if (this.persistedDirectives.has(directiveName)) {
1275
+ if (this.persistedDirectiveDefinitions.has(directiveName)) {
1117
1276
  definitions.push(directiveContainer.node);
1118
1277
  continue;
1119
1278
  }
1120
- // The definitions must be present in all subgraphs to kept in the federated graph
1279
+ // The definitions must be present in all subgraphs to be kept in the federated graph
1121
1280
  this.addValidExecutableDirectiveDefinition(directiveName, directiveContainer, definitions);
1122
1281
  }
1282
+ if (this.directiveDefinitions.has(string_constants_1.REQUIRES_SCOPES)) {
1283
+ definitions.push(constants_1.SCOPE_SCALAR_DEFINITION);
1284
+ }
1123
1285
  for (const [typeName, extension] of this.extensions) {
1124
1286
  this.parentTypeName = typeName;
1125
1287
  if (extension.isRootType && !this.parents.has(typeName)) {
@@ -1144,7 +1306,7 @@ class FederationFactory {
1144
1306
  this.childName = extensionFieldName;
1145
1307
  this.upsertExtensionFieldArguments(extensionFieldContainer.arguments, baseFieldContainer.arguments);
1146
1308
  (0, utils_1.setLongestDescriptionForNode)(baseFieldContainer.node, extensionFieldContainer.node.description);
1147
- (0, utils_3.addIterableValuesToSet)(extensionFieldContainer.subgraphs, baseFieldContainer.subgraphs);
1309
+ (0, utils_3.addIterableValuesToSet)(extensionFieldContainer.subgraphNames, baseFieldContainer.subgraphNames);
1148
1310
  continue;
1149
1311
  }
1150
1312
  const parent = this.shareableErrorTypeNames.get(typeName);
@@ -1166,8 +1328,7 @@ class FederationFactory {
1166
1328
  this.errors.push((0, errors_1.shareableFieldDefinitionsError)(parent, children));
1167
1329
  }
1168
1330
  const objectLikeContainersWithInterfaces = [];
1169
- for (const parentContainer of this.parents.values()) {
1170
- const parentTypeName = parentContainer.node.name.value;
1331
+ for (const [parentTypeName, parentContainer] of this.parents) {
1171
1332
  switch (parentContainer.kind) {
1172
1333
  case graphql_1.Kind.ENUM_TYPE_DEFINITION:
1173
1334
  const values = [];
@@ -1299,7 +1460,7 @@ class FederationFactory {
1299
1460
  if (evaluatedRootScalarsAndEnums.has(rootTypeFieldNamedTypeName)) {
1300
1461
  continue;
1301
1462
  }
1302
- if (!this.shouldEvaluateObjectLike(rootTypeFieldContainer.subgraphs, rootTypeFieldNamedTypeName)) {
1463
+ if (!this.shouldEvaluateObjectLike(rootTypeFieldContainer.subgraphNames, rootTypeFieldNamedTypeName)) {
1303
1464
  continue;
1304
1465
  }
1305
1466
  const childContainer = (0, utils_3.getOrThrowError)(this.parents, rootTypeFieldNamedTypeName, string_constants_1.PARENTS);
@@ -1309,7 +1470,7 @@ class FederationFactory {
1309
1470
  fieldTypeNodeString: (0, merge_1.printTypeNode)(rootTypeFieldContainer.node.type),
1310
1471
  path: fieldPath,
1311
1472
  typeName: rootTypeName,
1312
- subgraphs: rootTypeFieldContainer.subgraphs,
1473
+ subgraphs: rootTypeFieldContainer.subgraphNames,
1313
1474
  };
1314
1475
  switch (childContainer.kind) {
1315
1476
  case graphql_1.Kind.ENUM_TYPE_DEFINITION:
@@ -1320,12 +1481,12 @@ class FederationFactory {
1320
1481
  evaluatedRootScalarsAndEnums.add(rootTypeFieldNamedTypeName);
1321
1482
  continue;
1322
1483
  case graphql_1.Kind.OBJECT_TYPE_DEFINITION:
1323
- this.evaluateResolvabilityOfObject(childContainer, rootTypeFieldData, fieldPath, new Set(), this.entities.has(rootTypeFieldNamedTypeName) ? [rootTypeFieldNamedTypeName] : []);
1484
+ this.evaluateResolvabilityOfObject(childContainer, rootTypeFieldData, fieldPath, new Set(), this.entityContainersByTypeName.has(rootTypeFieldNamedTypeName) ? [rootTypeFieldNamedTypeName] : []);
1324
1485
  continue;
1325
1486
  case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
1326
1487
  // intentional fallthrough
1327
1488
  case graphql_1.Kind.UNION_TYPE_DEFINITION:
1328
- this.evaluateResolvabilityOfAbstractType(rootTypeFieldNamedTypeName, childContainer.kind, rootTypeFieldData, fieldPath, new Set(), this.entities.has(rootTypeFieldNamedTypeName) ? [rootTypeFieldNamedTypeName] : [], rootTypeFieldContainer.subgraphs);
1489
+ this.evaluateResolvabilityOfAbstractType(rootTypeFieldNamedTypeName, childContainer.kind, rootTypeFieldData, fieldPath, new Set(), this.entityContainersByTypeName.has(rootTypeFieldNamedTypeName) ? [rootTypeFieldNamedTypeName] : []);
1329
1490
  continue;
1330
1491
  default:
1331
1492
  this.errors.push((0, errors_1.unexpectedObjectResponseType)(fieldPath, (0, utils_3.kindToTypeString)(childContainer.kind)));
@@ -1340,10 +1501,20 @@ class FederationFactory {
1340
1501
  kind: graphql_1.Kind.DOCUMENT,
1341
1502
  definitions,
1342
1503
  };
1504
+ const subgraphConfigBySubgraphName = new Map();
1505
+ for (const subgraph of this.internalSubgraphBySubgraphName.values()) {
1506
+ subgraphConfigBySubgraphName.set(subgraph.name, {
1507
+ configurationDataMap: subgraph.configurationDataMap,
1508
+ schema: subgraph.schema,
1509
+ });
1510
+ }
1511
+ for (const authorizationData of this.authorizationDataByParentTypeName.values()) {
1512
+ (0, utils_3.upsertAuthorizationConfiguration)(this.fieldConfigurationByFieldPath, authorizationData);
1513
+ }
1343
1514
  return {
1344
1515
  federationResult: {
1345
- argumentConfigurations: this.argumentConfigurations,
1346
- subgraphConfigBySubgraphName: this.subgraphConfigBySubgraphName,
1516
+ fieldConfigurations: Array.from(this.fieldConfigurationByFieldPath.values()),
1517
+ subgraphConfigBySubgraphName,
1347
1518
  federatedGraphAST: newAst,
1348
1519
  federatedGraphSchema: (0, graphql_1.buildASTSchema)(newAst),
1349
1520
  },
@@ -1356,21 +1527,14 @@ function federateSubgraphs(subgraphs) {
1356
1527
  if (subgraphs.length < 1) {
1357
1528
  return { errors: [errors_1.minimumSubgraphRequirementError] };
1358
1529
  }
1359
- const { errors, internalSubgraphsBySubgraphName, warnings } = (0, normalization_factory_1.batchNormalize)(subgraphs);
1530
+ const { authorizationDataByParentTypeName, entityContainerByTypeName, errors, internalSubgraphBySubgraphName, warnings, } = (0, normalization_factory_1.batchNormalize)(subgraphs);
1360
1531
  if (errors) {
1361
1532
  return { errors };
1362
1533
  }
1363
- const internalSubgraphs = [];
1364
- const subgraphConfigBySubgraphName = new Map();
1365
1534
  const entityInterfaceFederationDataByTypeName = new Map();
1366
1535
  const invalidEntityInterfacesByTypeName = new Map();
1367
1536
  const validEntityInterfaceTypeNames = new Set();
1368
- for (const [subgraphName, internalSubgraph] of internalSubgraphsBySubgraphName) {
1369
- internalSubgraphs.push(internalSubgraph);
1370
- subgraphConfigBySubgraphName.set(subgraphName, {
1371
- configurationDataMap: internalSubgraph.configurationDataMap,
1372
- schema: internalSubgraph.schema,
1373
- });
1537
+ for (const [subgraphName, internalSubgraph] of internalSubgraphBySubgraphName) {
1374
1538
  for (const [typeName, entityInterfaceData] of internalSubgraph.entityInterfaces) {
1375
1539
  // Always add each entity interface to the invalid entity interfaces map
1376
1540
  // If not, earlier checks would not account for implementations not yet seen
@@ -1402,8 +1566,7 @@ function federateSubgraphs(subgraphs) {
1402
1566
  ],
1403
1567
  };
1404
1568
  }
1405
- const federationFactory = new FederationFactory(internalSubgraphs, subgraphConfigBySubgraphName, entityInterfaceFederationDataByTypeName, warnings);
1406
- return federationFactory.federate();
1569
+ return new FederationFactory(authorizationDataByParentTypeName, entityContainerByTypeName, entityInterfaceFederationDataByTypeName, internalSubgraphBySubgraphName, warnings).federate();
1407
1570
  }
1408
1571
  exports.federateSubgraphs = federateSubgraphs;
1409
1572
  //# sourceMappingURL=federation-factory.js.map