@apollo/federation-internals 2.4.9 → 2.5.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 (84) hide show
  1. package/dist/argumentCompositionStrategies.d.ts +12 -7
  2. package/dist/argumentCompositionStrategies.d.ts.map +1 -1
  3. package/dist/argumentCompositionStrategies.js +26 -7
  4. package/dist/argumentCompositionStrategies.js.map +1 -1
  5. package/dist/authenticatedSpec.d.ts +13 -0
  6. package/dist/authenticatedSpec.d.ts.map +1 -0
  7. package/dist/authenticatedSpec.js +36 -0
  8. package/dist/authenticatedSpec.js.map +1 -0
  9. package/dist/coreSpec.d.ts +6 -5
  10. package/dist/coreSpec.d.ts.map +1 -1
  11. package/dist/coreSpec.js +42 -32
  12. package/dist/coreSpec.js.map +1 -1
  13. package/dist/definitions.d.ts +2 -3
  14. package/dist/definitions.d.ts.map +1 -1
  15. package/dist/definitions.js +12 -7
  16. package/dist/definitions.js.map +1 -1
  17. package/dist/directiveAndTypeSpecification.d.ts +8 -8
  18. package/dist/directiveAndTypeSpecification.d.ts.map +1 -1
  19. package/dist/directiveAndTypeSpecification.js +21 -16
  20. package/dist/directiveAndTypeSpecification.js.map +1 -1
  21. package/dist/error.d.ts +1 -1
  22. package/dist/extractSubgraphsFromSupergraph.d.ts +1 -1
  23. package/dist/extractSubgraphsFromSupergraph.d.ts.map +1 -1
  24. package/dist/extractSubgraphsFromSupergraph.js +450 -295
  25. package/dist/extractSubgraphsFromSupergraph.js.map +1 -1
  26. package/dist/federation.d.ts +10 -5
  27. package/dist/federation.d.ts.map +1 -1
  28. package/dist/federation.js +58 -16
  29. package/dist/federation.js.map +1 -1
  30. package/dist/federationSpec.d.ts +3 -1
  31. package/dist/federationSpec.d.ts.map +1 -1
  32. package/dist/federationSpec.js +12 -3
  33. package/dist/federationSpec.js.map +1 -1
  34. package/dist/inaccessibleSpec.d.ts +1 -1
  35. package/dist/inaccessibleSpec.d.ts.map +1 -1
  36. package/dist/inaccessibleSpec.js +4 -4
  37. package/dist/inaccessibleSpec.js.map +1 -1
  38. package/dist/index.d.ts +2 -1
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +2 -1
  41. package/dist/index.js.map +1 -1
  42. package/dist/joinSpec.d.ts +19 -17
  43. package/dist/joinSpec.d.ts.map +1 -1
  44. package/dist/joinSpec.js +3 -3
  45. package/dist/joinSpec.js.map +1 -1
  46. package/dist/operations.d.ts +9 -43
  47. package/dist/operations.d.ts.map +1 -1
  48. package/dist/operations.js +44 -97
  49. package/dist/operations.js.map +1 -1
  50. package/dist/requiresScopesSpec.d.ts +16 -0
  51. package/dist/requiresScopesSpec.d.ts.map +1 -0
  52. package/dist/requiresScopesSpec.js +55 -0
  53. package/dist/requiresScopesSpec.js.map +1 -0
  54. package/dist/supergraphs.d.ts +19 -4
  55. package/dist/supergraphs.d.ts.map +1 -1
  56. package/dist/supergraphs.js +40 -14
  57. package/dist/supergraphs.js.map +1 -1
  58. package/dist/tagSpec.d.ts +1 -1
  59. package/dist/tagSpec.d.ts.map +1 -1
  60. package/dist/tagSpec.js +4 -4
  61. package/dist/tagSpec.js.map +1 -1
  62. package/dist/utils.d.ts +1 -0
  63. package/dist/utils.d.ts.map +1 -1
  64. package/dist/utils.js +11 -1
  65. package/dist/utils.js.map +1 -1
  66. package/package.json +1 -1
  67. package/src/argumentCompositionStrategies.ts +32 -9
  68. package/src/authenticatedSpec.ts +62 -0
  69. package/src/coreSpec.ts +57 -35
  70. package/src/definitions.ts +22 -9
  71. package/src/directiveAndTypeSpecification.ts +25 -24
  72. package/src/error.ts +2 -2
  73. package/src/extractSubgraphsFromSupergraph.ts +647 -393
  74. package/src/federation.ts +95 -16
  75. package/src/federationSpec.ts +13 -5
  76. package/src/inaccessibleSpec.ts +4 -4
  77. package/src/index.ts +2 -1
  78. package/src/joinSpec.ts +23 -13
  79. package/src/operations.ts +62 -182
  80. package/src/precompute.ts +1 -1
  81. package/src/requiresScopesSpec.ts +76 -0
  82. package/src/supergraphs.ts +64 -16
  83. package/src/tagSpec.ts +4 -4
  84. package/src/utils.ts +10 -0
@@ -561,10 +561,11 @@ export abstract class SchemaElement<TOwnType extends SchemaElement<any, TParent>
561
561
  args?: TApplicationArgs,
562
562
  asFirstDirective: boolean = false,
563
563
  ): Directive<TOwnType, TApplicationArgs> {
564
- let name: string;
564
+ let toAdd: Directive<TOwnType, TApplicationArgs>;
565
565
  if (typeof nameOrDef === 'string') {
566
566
  this.checkUpdate();
567
- const def = this.schema().directive(nameOrDef) ?? this.schema().blueprint.onMissingDirectiveDefinition(this.schema(), nameOrDef, args);
567
+ toAdd = new Directive<TOwnType, TApplicationArgs>(nameOrDef, args ?? Object.create(null));
568
+ const def = this.schema().directive(nameOrDef) ?? this.schema().blueprint.onMissingDirectiveDefinition(this.schema(), toAdd);
568
569
  if (!def) {
569
570
  throw this.schema().blueprint.onGraphQLJSValidationError(
570
571
  this.schema(),
@@ -574,12 +575,10 @@ export abstract class SchemaElement<TOwnType extends SchemaElement<any, TParent>
574
575
  if (Array.isArray(def)) {
575
576
  throw ErrGraphQLValidationFailed(def);
576
577
  }
577
- name = nameOrDef;
578
578
  } else {
579
579
  this.checkUpdate(nameOrDef);
580
- name = nameOrDef.name;
580
+ toAdd = new Directive<TOwnType, TApplicationArgs>(nameOrDef.name, args ?? Object.create(null));
581
581
  }
582
- const toAdd = new Directive<TOwnType, TApplicationArgs>(name, args ?? Object.create(null));
583
582
  Element.prototype['setParent'].call(toAdd, this);
584
583
  // TODO: we should typecheck arguments or our TApplicationArgs business is just a lie.
585
584
  if (this._appliedDirectives) {
@@ -907,7 +906,7 @@ abstract class BaseExtensionMember<TExtended extends ExtendableElement> extends
907
906
  }
908
907
 
909
908
  export class SchemaBlueprint {
910
- onMissingDirectiveDefinition(_schema: Schema, _name: string, _args?: {[key: string]: any}): DirectiveDefinition | GraphQLError[] | undefined {
909
+ onMissingDirectiveDefinition(_schema: Schema, _directive: Directive): DirectiveDefinition | GraphQLError[] | undefined {
911
910
  // No-op by default, but used for federation.
912
911
  return undefined;
913
912
  }
@@ -1576,6 +1575,22 @@ export class Schema {
1576
1575
  this.isValidated = false;
1577
1576
  }
1578
1577
 
1578
+ /**
1579
+ * Marks the schema as validated _without running actual validation_.
1580
+ * Should obviously only be called when we know the built schema must be valid.
1581
+ *
1582
+ * Note that if `validate` is called after this, then it will exit immediately without validation as
1583
+ * the schema will have been marked as validated. However, if this schema is further modified, then
1584
+ * `invalidate` will be called, after which `validate` would run validation again.
1585
+ */
1586
+ assumeValid() {
1587
+ this.runWithBuiltInModificationAllowed(() => {
1588
+ addIntrospectionFields(this);
1589
+ });
1590
+
1591
+ this.isValidated = true;
1592
+ }
1593
+
1579
1594
  validate() {
1580
1595
  if (this.isValidated) {
1581
1596
  return;
@@ -1609,9 +1624,7 @@ export class Schema {
1609
1624
  const cloned = new Schema(builtIns ?? this.blueprint);
1610
1625
  copy(this, cloned);
1611
1626
  if (this.isValidated) {
1612
- // TODO: when we do actual validation, no point in redoing it, but we should
1613
- // at least call builtIns.onValidation() and set the proper isConstructed/isValidated flags.
1614
- cloned.validate();
1627
+ cloned.assumeValid();
1615
1628
  }
1616
1629
  return cloned;
1617
1630
  }
@@ -1,6 +1,7 @@
1
1
  import { ASTNode, DirectiveLocation, GraphQLError } from "graphql";
2
2
  import {
3
3
  ArgumentDefinition,
4
+ CoreFeature,
4
5
  DirectiveDefinition,
5
6
  EnumType,
6
7
  InputType,
@@ -22,17 +23,17 @@ import { valueEquals, valueToString } from "./values";
22
23
  import { sameType } from "./types";
23
24
  import { arrayEquals, assert } from "./utils";
24
25
  import { ArgumentCompositionStrategy } from "./argumentCompositionStrategies";
25
- import { FeatureDefinition } from "./coreSpec";
26
+ import { FeatureDefinition, FeatureVersion } from "./coreSpec";
26
27
 
27
28
  export type DirectiveSpecification = {
28
29
  name: string,
29
- checkOrAdd: (schema: Schema, nameInSchema?: string, asBuiltIn?: boolean) => GraphQLError[],
30
+ checkOrAdd: (schema: Schema, feature?: CoreFeature, asBuiltIn?: boolean) => GraphQLError[],
30
31
  composition?: DirectiveCompositionSpecification,
31
32
  }
32
33
 
33
34
  export type DirectiveCompositionSpecification = {
34
- supergraphSpecification: () => FeatureDefinition,
35
- argumentsMerger?: (schema: Schema) => ArgumentMerger | GraphQLError,
35
+ supergraphSpecification: (federationVersion: FeatureVersion) => FeatureDefinition,
36
+ argumentsMerger?: (schema: Schema, feature: CoreFeature) => ArgumentMerger | GraphQLError,
36
37
  }
37
38
 
38
39
  export type ArgumentMerger = {
@@ -42,12 +43,12 @@ export type ArgumentMerger = {
42
43
 
43
44
  export type TypeSpecification = {
44
45
  name: string,
45
- checkOrAdd: (schema: Schema, nameInSchema?: string, asBuiltIn?: boolean) => GraphQLError[],
46
+ checkOrAdd: (schema: Schema, feature?: CoreFeature, asBuiltIn?: boolean) => GraphQLError[],
46
47
  }
47
48
 
48
49
  export type ArgumentSpecification = {
49
50
  name: string,
50
- type: (schema: Schema, nameInSchema?: string) => InputType | GraphQLError[],
51
+ type: (schema: Schema, feature?: CoreFeature) => InputType | GraphQLError[],
51
52
  defaultValue?: any,
52
53
  }
53
54
 
@@ -80,17 +81,17 @@ export function createDirectiveSpecification({
80
81
  repeatable?: boolean,
81
82
  args?: DirectiveArgumentSpecification[],
82
83
  composes?: boolean,
83
- supergraphSpecification?: () => FeatureDefinition,
84
+ supergraphSpecification?: (fedVersion: FeatureVersion) => FeatureDefinition,
84
85
  }): DirectiveSpecification {
85
86
  let composition: DirectiveCompositionSpecification | undefined = undefined;
86
87
  if (composes) {
87
88
  assert(supergraphSpecification, `Should provide a @link specification to use in supergraph for directive @${name} if it composes`);
88
89
  const argStrategies = new Map(args.filter((arg) => arg.compositionStrategy).map((arg) => [arg.name, arg.compositionStrategy!]));
89
- let argumentsMerger: ((schema: Schema) => ArgumentMerger | GraphQLError) | undefined = undefined;
90
+ let argumentsMerger: ((schema: Schema, feature: CoreFeature) => ArgumentMerger | GraphQLError) | undefined = undefined;
90
91
  if (argStrategies.size > 0) {
91
92
  assert(!repeatable, () => `Invalid directive specification for @${name}: @${name} is repeatable and should not define composition strategy for its arguments`);
92
93
  assert(argStrategies.size === args.length, () => `Invalid directive specification for @${name}: not all arguments define a composition strategy`);
93
- argumentsMerger = (schema) => {
94
+ argumentsMerger = (schema, feature) => {
94
95
  // Validate that the arguments have compatible types with the declared strategies (a bit unfortunate that we can't do this until
95
96
  // we have a schema but well, not a huge deal either).
96
97
  for (const { name: argName, type } of args) {
@@ -98,14 +99,14 @@ export function createDirectiveSpecification({
98
99
  // Note that we've built `argStrategies` from the declared args and checked that all argument had a strategy, so it would be
99
100
  // a bug in the code if we didn't get a strategy (not an issue in the directive declaration).
100
101
  assert(strategy, () => `Should have a strategy for ${argName}`);
101
- const argType = type(schema);
102
+ const argType = type(schema, feature);
102
103
  // By the time we call this, the directive should have been added to the schema and so getting the type should not raise errors.
103
104
  assert(!Array.isArray(argType), () => `Should have gotten error getting type for @${name}(${argName}:), but got ${argType}`)
104
- const strategyTypes = strategy.supportedTypes(schema);
105
- if (!strategyTypes.some((t) => sameType(t, argType))) {
105
+ const { valid, supportedMsg } = strategy.isTypeSupported(schema, argType);
106
+ if (!valid) {
106
107
  return new GraphQLError(
107
108
  `Invalid composition strategy ${strategy.name} for argument @${name}(${argName}:) of type ${argType}; `
108
- + `${strategy.name} only supports type(s) ${strategyTypes.join(', ')}`
109
+ + `${strategy.name} only supports ${supportedMsg}`
109
110
  );
110
111
  }
111
112
  };
@@ -133,11 +134,11 @@ export function createDirectiveSpecification({
133
134
  return {
134
135
  name,
135
136
  composition,
136
- checkOrAdd: (schema: Schema, nameInSchema?: string, asBuiltIn?: boolean) => {
137
- const actualName = nameInSchema ?? name;
137
+ checkOrAdd: (schema: Schema, feature?: CoreFeature, asBuiltIn?: boolean) => {
138
+ const actualName = feature?.directiveNameInSchema(name) ?? name;
138
139
  const { resolvedArgs, errors } = args.reduce<{ resolvedArgs: (ResolvedArgumentSpecification & { compositionStrategy?: ArgumentCompositionStrategy })[], errors: GraphQLError[] }>(
139
140
  ({ resolvedArgs, errors }, arg) => {
140
- const typeOrErrors = arg.type(schema, actualName);
141
+ const typeOrErrors = arg.type(schema, feature);
141
142
  if (Array.isArray(typeOrErrors)) {
142
143
  errors.push(...typeOrErrors);
143
144
  } else {
@@ -169,8 +170,8 @@ export function createDirectiveSpecification({
169
170
  export function createScalarTypeSpecification({ name }: { name: string }): TypeSpecification {
170
171
  return {
171
172
  name,
172
- checkOrAdd: (schema: Schema, nameInSchema?: string, asBuiltIn?: boolean) => {
173
- const actualName = nameInSchema ?? name;
173
+ checkOrAdd: (schema: Schema, feature?: CoreFeature, asBuiltIn?: boolean) => {
174
+ const actualName = feature?.typeNameInSchema(name) ?? name;
174
175
  const existing = schema.type(actualName);
175
176
  if (existing) {
176
177
  return ensureSameTypeKind('ScalarType', existing);
@@ -191,8 +192,8 @@ export function createObjectTypeSpecification({
191
192
  }): TypeSpecification {
192
193
  return {
193
194
  name,
194
- checkOrAdd: (schema: Schema, nameInSchema?: string, asBuiltIn?: boolean) => {
195
- const actualName = nameInSchema ?? name;
195
+ checkOrAdd: (schema: Schema, feature?: CoreFeature, asBuiltIn?: boolean) => {
196
+ const actualName = feature?.typeNameInSchema(name) ?? name;
196
197
  const expectedFields = fieldsFct(schema);
197
198
  const existing = schema.type(actualName);
198
199
  if (existing) {
@@ -252,8 +253,8 @@ export function createUnionTypeSpecification({
252
253
  }): TypeSpecification {
253
254
  return {
254
255
  name,
255
- checkOrAdd: (schema: Schema, nameInSchema?: string, asBuiltIn?: boolean) => {
256
- const actualName = nameInSchema ?? name;
256
+ checkOrAdd: (schema: Schema, feature?: CoreFeature, asBuiltIn?: boolean) => {
257
+ const actualName = feature?.typeNameInSchema(name) ?? name;
257
258
  const existing = schema.type(actualName);
258
259
  const expectedMembers = membersFct(schema).sort((n1, n2) => n1.localeCompare(n2));
259
260
  if (expectedMembers.length === 0) {
@@ -301,8 +302,8 @@ export function createEnumTypeSpecification({
301
302
  }): TypeSpecification {
302
303
  return {
303
304
  name,
304
- checkOrAdd: (schema: Schema, nameInSchema?: string, asBuiltIn?: boolean) => {
305
- const actualName = nameInSchema ?? name;
305
+ checkOrAdd: (schema: Schema, feature?: CoreFeature, asBuiltIn?: boolean) => {
306
+ const actualName = feature?.typeNameInSchema(name) ?? name;
306
307
  const existing = schema.type(actualName);
307
308
  const expectedValueNames = values.map((v) => v.name).sort((n1, n2) => n1.localeCompare(n2));
308
309
  if (existing) {
package/src/error.ts CHANGED
@@ -58,7 +58,7 @@ export function extractGraphQLErrorOptions(e: GraphQLError): GraphQLErrorOptions
58
58
 
59
59
  class AggregateGraphQLError extends GraphQLError {
60
60
  constructor(
61
- code: String,
61
+ code: string,
62
62
  message: string,
63
63
  readonly causes: GraphQLError[],
64
64
  options?: GraphQLErrorOptions,
@@ -83,7 +83,7 @@ class AggregateGraphQLError extends GraphQLError {
83
83
  }
84
84
  }
85
85
 
86
- export function aggregateError(code: String, message: string, causes: GraphQLError[]): GraphQLError {
86
+ export function aggregateError(code: string, message: string, causes: GraphQLError[]): GraphQLError {
87
87
  return new AggregateGraphQLError(code, message, causes);
88
88
  }
89
89