@apollo/federation-internals 2.9.0 → 2.10.0-alpha.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.
Files changed (46) hide show
  1. package/dist/error.d.ts +0 -19
  2. package/dist/error.d.ts.map +1 -1
  3. package/dist/error.js +0 -38
  4. package/dist/error.js.map +1 -1
  5. package/dist/federation.d.ts +2 -6
  6. package/dist/federation.d.ts.map +1 -1
  7. package/dist/federation.js +2 -24
  8. package/dist/federation.js.map +1 -1
  9. package/dist/index.d.ts +1 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +1 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/knownCoreFeatures.d.ts +0 -3
  14. package/dist/knownCoreFeatures.d.ts.map +1 -1
  15. package/dist/knownCoreFeatures.js +1 -12
  16. package/dist/knownCoreFeatures.js.map +1 -1
  17. package/dist/specs/connectSpec.d.ts +12 -0
  18. package/dist/specs/connectSpec.d.ts.map +1 -0
  19. package/dist/specs/connectSpec.js +83 -0
  20. package/dist/specs/connectSpec.js.map +1 -0
  21. package/dist/specs/coreSpec.d.ts +0 -1
  22. package/dist/specs/coreSpec.d.ts.map +1 -1
  23. package/dist/specs/coreSpec.js +2 -5
  24. package/dist/specs/coreSpec.js.map +1 -1
  25. package/dist/specs/federationSpec.d.ts +0 -3
  26. package/dist/specs/federationSpec.d.ts.map +1 -1
  27. package/dist/specs/federationSpec.js +3 -9
  28. package/dist/specs/federationSpec.js.map +1 -1
  29. package/dist/supergraphs.d.ts +1 -1
  30. package/dist/supergraphs.d.ts.map +1 -1
  31. package/dist/supergraphs.js +1 -0
  32. package/dist/supergraphs.js.map +1 -1
  33. package/package.json +1 -1
  34. package/src/error.ts +4 -137
  35. package/src/federation.ts +24 -59
  36. package/src/index.ts +1 -1
  37. package/src/knownCoreFeatures.ts +0 -15
  38. package/src/specs/connectSpec.ts +148 -0
  39. package/src/specs/coreSpec.ts +2 -7
  40. package/src/specs/federationSpec.ts +3 -10
  41. package/src/supergraphs.ts +2 -1
  42. package/dist/specs/sourceSpec.d.ts +0 -69
  43. package/dist/specs/sourceSpec.d.ts.map +0 -1
  44. package/dist/specs/sourceSpec.js +0 -345
  45. package/dist/specs/sourceSpec.js.map +0 -1
  46. package/src/specs/sourceSpec.ts +0 -607
package/src/federation.ts CHANGED
@@ -93,13 +93,8 @@ import {
93
93
  import { defaultPrintOptions, PrintOptions as PrintOptions, printSchema } from "./print";
94
94
  import { createObjectTypeSpecification, createScalarTypeSpecification, createUnionTypeSpecification } from "./directiveAndTypeSpecification";
95
95
  import { didYouMean, suggestionList } from "./suggestions";
96
- import { coreFeatureDefinitionIfKnown, validateKnownFeatures } from "./knownCoreFeatures";
96
+ import { coreFeatureDefinitionIfKnown } from "./knownCoreFeatures";
97
97
  import { joinIdentity } from "./specs/joinSpec";
98
- import {
99
- SourceAPIDirectiveArgs,
100
- SourceFieldDirectiveArgs,
101
- SourceTypeDirectiveArgs,
102
- } from "./specs/sourceSpec";
103
98
  import { CostDirectiveArguments, ListSizeDirectiveArguments } from "./specs/costSpec";
104
99
 
105
100
  const linkSpec = LINK_VERSIONS.latest();
@@ -398,10 +393,10 @@ const validateFieldValueType = ({
398
393
  fromContextParent: ArgumentDefinition<FieldDefinition<ObjectType | InterfaceType | UnionType>>,
399
394
  }): { resolvedType: InputType | undefined } => {
400
395
  const selections = selectionSet.selections();
401
-
396
+
402
397
  // ensure that type is not an interfaceObject
403
398
  const interfaceObjectDirective = metadata.interfaceObjectDirective();
404
- if (currentType.kind === 'ObjectType' && isFederationDirectiveDefinedInSchema(interfaceObjectDirective) && (currentType.appliedDirectivesOf(interfaceObjectDirective).length > 0)) {
399
+ if (currentType.kind === 'ObjectType' && isFederationDirectiveDefinedInSchema(interfaceObjectDirective) && (currentType.appliedDirectivesOf(interfaceObjectDirective).length > 0)) {
405
400
  errorCollector.push(ERRORS.CONTEXT_INVALID_SELECTION.err(
406
401
  `Context "is used in "${fromContextParent.coordinate}" but the selection is invalid: One of the types in the selection is an interfaceObject: "${currentType.name}"`,
407
402
  { nodes: sourceASTs(fromContextParent) }
@@ -595,7 +590,7 @@ function validateFieldValue({
595
590
  if (selectionType === 'error') {
596
591
  return;
597
592
  }
598
-
593
+
599
594
  const usedTypeConditions = new Set<string>;
600
595
  for (const location of setContextLocations) {
601
596
  // for each location, we need to validate that the selection will result in exactly one field being selected
@@ -622,7 +617,7 @@ function validateFieldValue({
622
617
  { nodes: sourceASTs(fromContextParent) }
623
618
  ));
624
619
  }
625
-
620
+
626
621
  if (selectionType === 'field') {
627
622
  const { resolvedType } = validateFieldValueType({
628
623
  currentType: location,
@@ -795,13 +790,13 @@ export function collectUsedFields(metadata: FederationMetadata): Set<FieldDefini
795
790
  },
796
791
  usedFields,
797
792
  );
798
-
793
+
799
794
  // also for @fromContext
800
795
  collectUsedFieldsForFromContext<CompositeType>(
801
796
  metadata,
802
797
  usedFields,
803
798
  );
804
-
799
+
805
800
  // Collects all fields used to satisfy an interface constraint
806
801
  for (const itfType of metadata.schema.interfaceTypes()) {
807
802
  const runtimeTypes = itfType.possibleRuntimeTypes();
@@ -824,12 +819,12 @@ function collectUsedFieldsForFromContext<TParent extends SchemaElement<any, any>
824
819
  ) {
825
820
  const fromContextDirective = metadata.fromContextDirective();
826
821
  const contextDirective = metadata.contextDirective();
827
-
822
+
828
823
  // if one of the directives is not defined, there's nothing to validate
829
824
  if (!isFederationDirectiveDefinedInSchema(fromContextDirective) || !isFederationDirectiveDefinedInSchema(contextDirective)) {
830
- return;
825
+ return;
831
826
  }
832
-
827
+
833
828
  // build the list of context entry points
834
829
  const entryPoints = new Map<string, Set<CompositeType>>();
835
830
  for (const application of contextDirective.applications()) {
@@ -842,9 +837,9 @@ function collectUsedFieldsForFromContext<TParent extends SchemaElement<any, any>
842
837
  if (!entryPoints.has(context)) {
843
838
  entryPoints.set(context, new Set());
844
839
  }
845
- entryPoints.get(context)!.add(type as CompositeType);
840
+ entryPoints.get(context)!.add(type as CompositeType);
846
841
  }
847
-
842
+
848
843
  for (const application of fromContextDirective.applications()) {
849
844
  const type = application.parent as TParent;
850
845
  if (!type) {
@@ -854,20 +849,20 @@ function collectUsedFieldsForFromContext<TParent extends SchemaElement<any, any>
854
849
 
855
850
  const fieldValue = application.arguments().field;
856
851
  const { context, selection } = parseContext(fieldValue);
857
-
852
+
858
853
  if (!context) {
859
854
  continue;
860
855
  }
861
-
856
+
862
857
  // now we need to collect all the fields used for every type that they could be used for
863
858
  const contextTypes = entryPoints.get(context);
864
859
  if (!contextTypes) {
865
860
  continue;
866
861
  }
867
-
862
+
868
863
  for (const contextType of contextTypes) {
869
864
  try {
870
- // helper function
865
+ // helper function
871
866
  const fieldAccessor = (t: CompositeType, f: string) => {
872
867
  const field = t.field(f);
873
868
  if (field) {
@@ -883,7 +878,7 @@ function collectUsedFieldsForFromContext<TParent extends SchemaElement<any, any>
883
878
  }
884
879
  return field;
885
880
  };
886
-
881
+
887
882
  parseSelectionSet({ parentType: contextType, source: selection, fieldAccessor });
888
883
  } catch (e) {
889
884
  // ignore the error, it will be caught later
@@ -1256,18 +1251,6 @@ export class FederationMetadata {
1256
1251
  return this.getPost20FederationDirective(FederationDirectiveName.POLICY);
1257
1252
  }
1258
1253
 
1259
- sourceAPIDirective(): Post20FederationDirectiveDefinition<SourceAPIDirectiveArgs> {
1260
- return this.getPost20FederationDirective(FederationDirectiveName.SOURCE_API);
1261
- }
1262
-
1263
- sourceTypeDirective(): Post20FederationDirectiveDefinition<SourceTypeDirectiveArgs> {
1264
- return this.getPost20FederationDirective(FederationDirectiveName.SOURCE_TYPE);
1265
- }
1266
-
1267
- sourceFieldDirective(): Post20FederationDirectiveDefinition<SourceFieldDirectiveArgs> {
1268
- return this.getPost20FederationDirective(FederationDirectiveName.SOURCE_FIELD);
1269
- }
1270
-
1271
1254
  fromContextDirective(): Post20FederationDirectiveDefinition<{ field: string }> {
1272
1255
  return this.getPost20FederationDirective(FederationDirectiveName.FROM_CONTEXT);
1273
1256
  }
@@ -1324,19 +1307,6 @@ export class FederationMetadata {
1324
1307
  baseDirectives.push(policyDirective);
1325
1308
  }
1326
1309
 
1327
- const sourceAPIDirective = this.sourceAPIDirective();
1328
- if (isFederationDirectiveDefinedInSchema(sourceAPIDirective)) {
1329
- baseDirectives.push(sourceAPIDirective);
1330
- }
1331
- const sourceTypeDirective = this.sourceTypeDirective();
1332
- if (isFederationDirectiveDefinedInSchema(sourceTypeDirective)) {
1333
- baseDirectives.push(sourceTypeDirective);
1334
- }
1335
- const sourceFieldDirective = this.sourceFieldDirective();
1336
- if (isFederationDirectiveDefinedInSchema(sourceFieldDirective)) {
1337
- baseDirectives.push(sourceFieldDirective);
1338
- }
1339
-
1340
1310
  const contextDirective = this.contextDirective();
1341
1311
  if (isFederationDirectiveDefinedInSchema(contextDirective)) {
1342
1312
  baseDirectives.push(contextDirective);
@@ -1595,7 +1565,6 @@ export class FederationBlueprint extends SchemaBlueprint {
1595
1565
  for (const application of contextDirective.applications()) {
1596
1566
  const parent = application.parent;
1597
1567
  const name = application.arguments().name as string;
1598
-
1599
1568
  const match = name.match(/^([A-Za-z]\w*)$/);
1600
1569
  if (name.includes('_')) {
1601
1570
  errorCollector.push(ERRORS.CONTEXT_NAME_INVALID.err(
@@ -1621,7 +1590,7 @@ export class FederationBlueprint extends SchemaBlueprint {
1621
1590
  for (const application of fromContextDirective.applications()) {
1622
1591
  const { field } = application.arguments();
1623
1592
  const { context, selection } = parseContext(field);
1624
-
1593
+
1625
1594
  // error if parent's parent is a directive definition
1626
1595
  if (application.parent.parent.kind === 'DirectiveDefinition') {
1627
1596
  errorCollector.push(ERRORS.CONTEXT_NOT_SET.err(
@@ -1653,14 +1622,14 @@ export class FederationBlueprint extends SchemaBlueprint {
1653
1622
  ));
1654
1623
  }
1655
1624
  }
1656
-
1625
+
1657
1626
  if (parent.defaultValue !== undefined) {
1658
1627
  errorCollector.push(ERRORS.CONTEXT_NOT_SET.err(
1659
1628
  `@fromContext arguments may not have a default value: "${parent.coordinate}".`,
1660
1629
  { nodes: sourceASTs(application) }
1661
- ));
1630
+ ));
1662
1631
  }
1663
-
1632
+
1664
1633
  if (!context || !selection) {
1665
1634
  errorCollector.push(ERRORS.NO_CONTEXT_IN_SELECTION.err(
1666
1635
  `@fromContext argument does not reference a context "${field}".`,
@@ -1683,7 +1652,7 @@ export class FederationBlueprint extends SchemaBlueprint {
1683
1652
  metadata,
1684
1653
  });
1685
1654
  }
1686
-
1655
+
1687
1656
  // validate that there is at least one resolvable key on the type
1688
1657
  const keyDirective = metadata.keyDirective();
1689
1658
  const keyApplications = objectType.appliedDirectivesOf(keyDirective);
@@ -1701,10 +1670,6 @@ export class FederationBlueprint extends SchemaBlueprint {
1701
1670
  validateKeyOnInterfacesAreAlsoOnAllImplementations(metadata, errorCollector);
1702
1671
  validateInterfaceObjectsAreOnEntities(metadata, errorCollector);
1703
1672
 
1704
- // FeatureDefinition objects passed to registerKnownFeature can register
1705
- // validation functions for subgraph schemas by overriding the
1706
- // validateSubgraphSchema method.
1707
- validateKnownFeatures(schema, errorCollector);
1708
1673
  // If tag is redefined by the user, make sure the definition is compatible with what we expect
1709
1674
  const tagDirective = metadata.tagDirective();
1710
1675
  if (tagDirective) {
@@ -1850,9 +1815,9 @@ export function setSchemaAsFed2Subgraph(schema: Schema, useLatest: boolean = fal
1850
1815
 
1851
1816
  // This is the full @link declaration as added by `asFed2SubgraphDocument`. It's here primarily for uses by tests that print and match
1852
1817
  // subgraph schema to avoid having to update 20+ tests every time we use a new directive or the order of import changes ...
1853
- export const FEDERATION2_LINK_WITH_FULL_IMPORTS = '@link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject", "@authenticated", "@requiresScopes", "@policy", "@sourceAPI", "@sourceType", "@sourceField", "@context", "@fromContext", "@cost", "@listSize"])';
1818
+ export const FEDERATION2_LINK_WITH_FULL_IMPORTS = '@link(url: "https://specs.apollo.dev/federation/v2.10", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject", "@authenticated", "@requiresScopes", "@policy", "@context", "@fromContext", "@cost", "@listSize"])';
1854
1819
  // This is the full @link declaration that is added when upgrading fed v1 subgraphs to v2 version. It should only be used by tests.
1855
- export const FEDERATION2_LINK_WITH_AUTO_EXPANDED_IMPORTS = '@link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"])';
1820
+ export const FEDERATION2_LINK_WITH_AUTO_EXPANDED_IMPORTS = '@link(url: "https://specs.apollo.dev/federation/v2.10", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"])';
1856
1821
 
1857
1822
  // This is the federation @link for tests that go through the SchemaUpgrader.
1858
1823
  export const FEDERATION2_LINK_WITH_AUTO_EXPANDED_IMPORTS_UPGRADED = '@link(url: "https://specs.apollo.dev/federation/v2.4", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"])';
package/src/index.ts CHANGED
@@ -24,5 +24,5 @@ export * from './argumentCompositionStrategies';
24
24
  export * from './specs/authenticatedSpec';
25
25
  export * from './specs/requiresScopesSpec';
26
26
  export * from './specs/policySpec';
27
- export * from './specs/sourceSpec';
27
+ export * from './specs/connectSpec';
28
28
  export * from './specs/costSpec';
@@ -1,5 +1,3 @@
1
- import { GraphQLError } from "graphql";
2
- import { Schema } from "./definitions";
3
1
  import { FeatureDefinition, FeatureDefinitions, FeatureUrl } from "./specs/coreSpec";
4
2
 
5
3
  const registeredFeatures = new Map<string, FeatureDefinitions>();
@@ -14,19 +12,6 @@ export function coreFeatureDefinitionIfKnown(url: FeatureUrl): FeatureDefinition
14
12
  return registeredFeatures.get(url.identity)?.find(url.version);
15
13
  }
16
14
 
17
- export function validateKnownFeatures(
18
- schema: Schema,
19
- errorCollector: GraphQLError[] = [],
20
- ): GraphQLError[] {
21
- registeredFeatures.forEach(definitions => {
22
- const feature = definitions.latest();
23
- if (feature.validateSubgraphSchema !== FeatureDefinition.prototype.validateSubgraphSchema) {
24
- errorCollector.push(...feature.validateSubgraphSchema(schema));
25
- }
26
- });
27
- return errorCollector;
28
- }
29
-
30
15
  /**
31
16
  * Removes a feature from the set of known features.
32
17
  *
@@ -0,0 +1,148 @@
1
+ import {DirectiveLocation, GraphQLError} from 'graphql';
2
+ import { CorePurpose, FeatureDefinition, FeatureDefinitions, FeatureUrl, FeatureVersion } from "./coreSpec";
3
+ import {
4
+ Schema,
5
+ NonNullType,
6
+ InputObjectType,
7
+ InputFieldDefinition,
8
+ ListType,
9
+ } from '../definitions';
10
+ import { registerKnownFeature } from '../knownCoreFeatures';
11
+ import { createDirectiveSpecification, createScalarTypeSpecification } from '../directiveAndTypeSpecification';
12
+
13
+ export const connectIdentity = 'https://specs.apollo.dev/connect';
14
+
15
+ const CONNECT = "connect";
16
+ const SOURCE = "source";
17
+ const URL_PATH_TEMPLATE = "URLPathTemplate";
18
+ const JSON_SELECTION = "JSONSelection";
19
+ const CONNECT_HTTP = "ConnectHTTP";
20
+ const SOURCE_HTTP = "SourceHTTP";
21
+ const HTTP_HEADER_MAPPING = "HTTPHeaderMapping";
22
+
23
+ export class ConnectSpecDefinition extends FeatureDefinition {
24
+ constructor(version: FeatureVersion, readonly minimumFederationVersion: FeatureVersion) {
25
+ super(new FeatureUrl(connectIdentity, CONNECT, version), minimumFederationVersion);
26
+
27
+ this.registerDirective(createDirectiveSpecification({
28
+ name: CONNECT,
29
+ locations: [DirectiveLocation.FIELD_DEFINITION],
30
+ repeatable: true,
31
+ // We "compose" these directives using the `@join__directive` mechanism,
32
+ // so they do not need to be composed in the way passing `composes: true`
33
+ // here implies.
34
+ composes: false,
35
+ }));
36
+
37
+ this.registerDirective(createDirectiveSpecification({
38
+ name: SOURCE,
39
+ locations: [DirectiveLocation.SCHEMA],
40
+ repeatable: true,
41
+ composes: false,
42
+ }));
43
+
44
+ this.registerType(createScalarTypeSpecification({ name: URL_PATH_TEMPLATE }));
45
+ this.registerType(createScalarTypeSpecification({ name: JSON_SELECTION }));
46
+ this.registerType({ name: CONNECT_HTTP, checkOrAdd: () => [] });
47
+ this.registerType({ name: SOURCE_HTTP, checkOrAdd: () => [] });
48
+ this.registerType({ name: HTTP_HEADER_MAPPING, checkOrAdd: () => [] });
49
+ }
50
+
51
+ addElementsToSchema(schema: Schema): GraphQLError[] {
52
+ /* scalar URLPathTemplate */
53
+ const URLPathTemplate = this.addScalarType(schema, URL_PATH_TEMPLATE);
54
+
55
+ /* scalar JSONSelection */
56
+ const JSONSelection = this.addScalarType(schema, JSON_SELECTION);
57
+
58
+ /*
59
+ directive @connect(
60
+ source: String
61
+ http: ConnectHTTP
62
+ selection: JSONSelection!
63
+ entity: Boolean = false
64
+ ) repeatable on FIELD_DEFINITION
65
+ */
66
+ const connect = this.addDirective(schema, CONNECT).addLocations(DirectiveLocation.FIELD_DEFINITION);
67
+ connect.repeatable = true;
68
+
69
+ connect.addArgument(SOURCE, schema.stringType());
70
+
71
+ /*
72
+ input HTTPHeaderMapping {
73
+ name: String!
74
+ from: String
75
+ value: String
76
+ }
77
+ */
78
+ const HTTPHeaderMapping = schema.addType(new InputObjectType(this.typeNameInSchema(schema, HTTP_HEADER_MAPPING)!));
79
+ HTTPHeaderMapping.addField(new InputFieldDefinition('name')).type =
80
+ new NonNullType(schema.stringType());
81
+ HTTPHeaderMapping.addField(new InputFieldDefinition('from')).type =
82
+ schema.stringType();
83
+ HTTPHeaderMapping.addField(new InputFieldDefinition('value')).type =
84
+ schema.stringType();
85
+
86
+ /*
87
+ input ConnectHTTP {
88
+ GET: URLPathTemplate
89
+ POST: URLPathTemplate
90
+ PUT: URLPathTemplate
91
+ PATCH: URLPathTemplate
92
+ DELETE: URLPathTemplate
93
+ body: JSONSelection
94
+ headers: [HTTPHeaderMapping!]
95
+ }
96
+ */
97
+ const ConnectHTTP = schema.addType(new InputObjectType(this.typeNameInSchema(schema, CONNECT_HTTP)!));
98
+ ConnectHTTP.addField(new InputFieldDefinition('GET')).type = URLPathTemplate;
99
+ ConnectHTTP.addField(new InputFieldDefinition('POST')).type = URLPathTemplate;
100
+ ConnectHTTP.addField(new InputFieldDefinition('PUT')).type = URLPathTemplate;
101
+ ConnectHTTP.addField(new InputFieldDefinition('PATCH')).type = URLPathTemplate;
102
+ ConnectHTTP.addField(new InputFieldDefinition('DELETE')).type = URLPathTemplate;
103
+ ConnectHTTP.addField(new InputFieldDefinition('body')).type = JSONSelection;
104
+ ConnectHTTP.addField(new InputFieldDefinition('headers')).type =
105
+ new ListType(new NonNullType(HTTPHeaderMapping));
106
+ connect.addArgument('http', new NonNullType(ConnectHTTP));
107
+
108
+ connect.addArgument('selection', new NonNullType(JSONSelection));
109
+ connect.addArgument('entity', schema.booleanType(), false);
110
+
111
+ /*
112
+ directive @source(
113
+ name: String!
114
+ http: ConnectHTTP
115
+ ) repeatable on SCHEMA
116
+ */
117
+ const source = this.addDirective(schema, SOURCE).addLocations(
118
+ DirectiveLocation.SCHEMA,
119
+ );
120
+ source.repeatable = true;
121
+ source.addArgument('name', new NonNullType(schema.stringType()));
122
+
123
+ /*
124
+ input SourceHTTP {
125
+ baseURL: String!
126
+ headers: [HTTPHeaderMapping!]
127
+ }
128
+ */
129
+ const SourceHTTP = schema.addType(new InputObjectType(this.typeNameInSchema(schema, SOURCE_HTTP)!));
130
+ SourceHTTP.addField(new InputFieldDefinition('baseURL')).type =
131
+ new NonNullType(schema.stringType());
132
+ SourceHTTP.addField(new InputFieldDefinition('headers')).type =
133
+ new ListType(new NonNullType(HTTPHeaderMapping));
134
+
135
+ source.addArgument('http', new NonNullType(SourceHTTP));
136
+
137
+ return [];
138
+ }
139
+
140
+ get defaultCorePurpose(): CorePurpose {
141
+ return 'EXECUTION';
142
+ }
143
+ }
144
+
145
+ export const CONNECT_VERSIONS = new FeatureDefinitions<ConnectSpecDefinition>(connectIdentity)
146
+ .add(new ConnectSpecDefinition(new FeatureVersion(0, 1), new FeatureVersion(2, 10)));
147
+
148
+ registerKnownFeature(CONNECT_VERSIONS);
@@ -117,11 +117,6 @@ export abstract class FeatureDefinition {
117
117
  .concat(this.typeSpecs().map((spec) => spec.name));
118
118
  }
119
119
 
120
- // No-op implementation that can be overridden by subclasses.
121
- validateSubgraphSchema(_schema: Schema): GraphQLError[] {
122
- return [];
123
- }
124
-
125
120
  protected nameInSchema(schema: Schema): string | undefined {
126
121
  const feature = this.featureInSchema(schema);
127
122
  return feature?.nameInSchema;
@@ -623,7 +618,7 @@ export class FeatureDefinitions<T extends FeatureDefinition = FeatureDefinition>
623
618
  // this._definitions is already sorted with the most recent first
624
619
  // get the first definition that is compatible with the federation version
625
620
  // if the minimum version is not present, assume that we won't look for an older version
626
- const def = this._definitions.find(def => def.minimumFederationVersion ? fedVersion >= def.minimumFederationVersion : true);
621
+ const def = this._definitions.find(def => def.minimumFederationVersion ? fedVersion.gte(def.minimumFederationVersion) : true);
627
622
  assert(def, `No compatible definition exists for federation version ${fedVersion}`);
628
623
 
629
624
  // note that it's necessary that we can only get versions that have the same major version as the latest,
@@ -675,7 +670,7 @@ export class FeatureVersion {
675
670
  let max: FeatureVersion | undefined;
676
671
 
677
672
  for (const version of versions) {
678
- if (!max || version > max) {
673
+ if (!max || version.gt(max)) {
679
674
  max = version;
680
675
  }
681
676
  }
@@ -18,7 +18,6 @@ import { INACCESSIBLE_VERSIONS } from "./inaccessibleSpec";
18
18
  import { AUTHENTICATED_VERSIONS } from "./authenticatedSpec";
19
19
  import { REQUIRES_SCOPES_VERSIONS } from "./requiresScopesSpec";
20
20
  import { POLICY_VERSIONS } from './policySpec';
21
- import { SOURCE_VERSIONS } from './sourceSpec';
22
21
  import { CONTEXT_VERSIONS } from './contextSpec';
23
22
  import { COST_VERSIONS } from "./costSpec";
24
23
 
@@ -44,9 +43,6 @@ export enum FederationDirectiveName {
44
43
  AUTHENTICATED = 'authenticated',
45
44
  REQUIRES_SCOPES = 'requiresScopes',
46
45
  POLICY = 'policy',
47
- SOURCE_API = 'sourceAPI',
48
- SOURCE_TYPE = 'sourceType',
49
- SOURCE_FIELD = 'sourceField',
50
46
  CONTEXT = 'context',
51
47
  FROM_CONTEXT = 'fromContext',
52
48
  COST = 'cost',
@@ -135,7 +131,7 @@ export class FederationSpecDefinition extends FeatureDefinition {
135
131
 
136
132
  this.registerSubFeature(INACCESSIBLE_VERSIONS.getMinimumRequiredVersion(version));
137
133
 
138
- if (version >= (new FeatureVersion(2, 7))) {
134
+ if (version.gte(new FeatureVersion(2, 7))) {
139
135
  this.registerDirective(createDirectiveSpecification({
140
136
  name: FederationDirectiveName.OVERRIDE,
141
137
  locations: [DirectiveLocation.FIELD_DEFINITION],
@@ -178,10 +174,6 @@ export class FederationSpecDefinition extends FeatureDefinition {
178
174
  this.registerSubFeature(POLICY_VERSIONS.find(new FeatureVersion(0, 1))!);
179
175
  }
180
176
 
181
- if (version.gte(new FeatureVersion(2, 7))) {
182
- this.registerSubFeature(SOURCE_VERSIONS.find(new FeatureVersion(0, 1))!);
183
- }
184
-
185
177
  if (version.gte(new FeatureVersion(2, 8))) {
186
178
  this.registerSubFeature(CONTEXT_VERSIONS.find(new FeatureVersion(0, 1))!);
187
179
  }
@@ -202,6 +194,7 @@ export const FEDERATION_VERSIONS = new FeatureDefinitions<FederationSpecDefiniti
202
194
  .add(new FederationSpecDefinition(new FeatureVersion(2, 6)))
203
195
  .add(new FederationSpecDefinition(new FeatureVersion(2, 7)))
204
196
  .add(new FederationSpecDefinition(new FeatureVersion(2, 8)))
205
- .add(new FederationSpecDefinition(new FeatureVersion(2, 9)));
197
+ .add(new FederationSpecDefinition(new FeatureVersion(2, 9)))
198
+ .add(new FederationSpecDefinition(new FeatureVersion(2, 10)));
206
199
 
207
200
  registerKnownFeature(FEDERATION_VERSIONS);
@@ -41,6 +41,7 @@ export const ROUTER_SUPPORTED_SUPERGRAPH_FEATURES = new Set([
41
41
  'https://specs.apollo.dev/source/v0.1',
42
42
  'https://specs.apollo.dev/context/v0.1',
43
43
  'https://specs.apollo.dev/cost/v0.1',
44
+ 'https://specs.apollo.dev/connect/v0.1',
44
45
  ]);
45
46
 
46
47
  const coreVersionZeroDotOneUrl = FeatureUrl.parse('https://specs.apollo.dev/core/v0.1');
@@ -128,7 +129,7 @@ export class Supergraph {
128
129
  this.containedSubgraphs = extractSubgraphsNamesAndUrlsFromSupergraph(schema);
129
130
  }
130
131
 
131
- static build(supergraphSdl: string | DocumentNode, options?: { supportedFeatures?: Set<string>, validateSupergraph?: boolean }) {
132
+ static build(supergraphSdl: string | DocumentNode, options?: { supportedFeatures?: Set<string> | null, validateSupergraph?: boolean }) {
132
133
  // We delay validation because `checkFeatureSupport` in the constructor gives slightly more useful errors if, say, 'for' is used with core v0.1.
133
134
  const schema = typeof supergraphSdl === 'string'
134
135
  ? buildSchema(supergraphSdl, { validate: false })
@@ -1,69 +0,0 @@
1
- import { GraphQLError } from 'graphql';
2
- import { FeatureDefinition, FeatureDefinitions, FeatureVersion } from "./coreSpec";
3
- import { Schema, DirectiveDefinition } from '../definitions';
4
- export declare const sourceIdentity = "https://specs.apollo.dev/source";
5
- export declare class SourceSpecDefinition extends FeatureDefinition {
6
- readonly minimumFederationVersion: FeatureVersion;
7
- constructor(version: FeatureVersion, minimumFederationVersion: FeatureVersion);
8
- addElementsToSchema(schema: Schema): GraphQLError[];
9
- allElementNames(): string[];
10
- sourceAPIDirective(schema: Schema): DirectiveDefinition<SourceAPIDirectiveArgs>;
11
- sourceTypeDirective(schema: Schema): DirectiveDefinition<SourceTypeDirectiveArgs>;
12
- sourceFieldDirective(schema: Schema): DirectiveDefinition<SourceFieldDirectiveArgs>;
13
- private getSourceDirectives;
14
- validateSubgraphSchema(schema: Schema): GraphQLError[];
15
- private validateSourceAPI;
16
- private validateSourceType;
17
- private validateSourceField;
18
- }
19
- export type SourceAPIDirectiveArgs = {
20
- name: string;
21
- http?: HTTPSourceAPI;
22
- };
23
- export type HTTPSourceAPI = {
24
- baseURL: string;
25
- headers?: HTTPHeaderMapping[];
26
- };
27
- export type HTTPHeaderMapping = {
28
- name: string;
29
- as?: string;
30
- value?: string;
31
- };
32
- export type SourceTypeDirectiveArgs = {
33
- api: string;
34
- http?: HTTPSourceType;
35
- selection: JSONSelection;
36
- keyTypeMap?: KeyTypeMap;
37
- };
38
- export type HTTPSourceType = {
39
- GET?: URLPathTemplate;
40
- POST?: URLPathTemplate;
41
- headers?: HTTPHeaderMapping[];
42
- body?: JSONSelection;
43
- };
44
- type URLPathTemplate = string;
45
- type JSONSelection = string;
46
- type KeyTypeMap = {
47
- key: string;
48
- typeMap: {
49
- [__typename: string]: string;
50
- };
51
- };
52
- export type SourceFieldDirectiveArgs = {
53
- api: string;
54
- http?: HTTPSourceField;
55
- selection?: JSONSelection;
56
- keyTypeMap?: KeyTypeMap;
57
- };
58
- export type HTTPSourceField = {
59
- GET?: URLPathTemplate;
60
- POST?: URLPathTemplate;
61
- PUT?: URLPathTemplate;
62
- PATCH?: URLPathTemplate;
63
- DELETE?: URLPathTemplate;
64
- body?: JSONSelection;
65
- headers?: HTTPHeaderMapping[];
66
- };
67
- export declare const SOURCE_VERSIONS: FeatureDefinitions<SourceSpecDefinition>;
68
- export {};
69
- //# sourceMappingURL=sourceSpec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sourceSpec.d.ts","sourceRoot":"","sources":["../../src/specs/sourceSpec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,YAAY,EAAQ,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAc,cAAc,EAAqB,MAAM,YAAY,CAAC;AAClH,OAAO,EACL,MAAM,EAKN,mBAAmB,EAEpB,MAAM,gBAAgB,CAAC;AAKxB,eAAO,MAAM,cAAc,oCAAoC,CAAC;AAEhE,qBAAa,oBAAqB,SAAQ,iBAAiB;IACpB,QAAQ,CAAC,wBAAwB,EAAE,cAAc;gBAA1E,OAAO,EAAE,cAAc,EAAW,wBAAwB,EAAE,cAAc;IA4BtF,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE;IA2EnD,eAAe,IAAI,MAAM,EAAE;IAgB3B,kBAAkB,CAAC,MAAM,EAAE,MAAM;IAIjC,mBAAmB,CAAC,MAAM,EAAE,MAAM;IAIlC,oBAAoB,CAAC,MAAM,EAAE,MAAM;IAInC,OAAO,CAAC,mBAAmB;IA+BlB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE;IA+B/D,OAAO,CAAC,iBAAiB;IAkEzB,OAAO,CAAC,kBAAkB;IAiG1B,OAAO,CAAC,mBAAmB;CAiH5B;AA2DD,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,SAAS,EAAE,aAAa,CAAC;IACzB,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,GAAG,CAAC,EAAE,eAAe,CAAC;IACtB,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,OAAO,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAC9B,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB,CAAC;AAEF,KAAK,eAAe,GAAG,MAAM,CAAC;AAC9B,KAAK,aAAa,GAAG,MAAM,CAAC;AAE5B,KAAK,UAAU,GAAG;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE;QACP,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC;KAC9B,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,EAAE,eAAe,CAAC;IACtB,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,GAAG,CAAC,EAAE,eAAe,CAAC;IACtB,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,OAAO,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAC/B,CAAC;AAEF,eAAO,MAAM,eAAe,0CACwD,CAAC"}