@apollo/federation-internals 2.1.0-alpha.2 → 2.1.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 (66) hide show
  1. package/CHANGELOG.md +5 -4
  2. package/dist/buildSchema.d.ts.map +1 -1
  3. package/dist/buildSchema.js +14 -4
  4. package/dist/buildSchema.js.map +1 -1
  5. package/dist/coreSpec.d.ts +1 -4
  6. package/dist/coreSpec.d.ts.map +1 -1
  7. package/dist/coreSpec.js +1 -5
  8. package/dist/coreSpec.js.map +1 -1
  9. package/dist/definitions.d.ts +66 -34
  10. package/dist/definitions.d.ts.map +1 -1
  11. package/dist/definitions.js +309 -165
  12. package/dist/definitions.js.map +1 -1
  13. package/dist/error.d.ts +5 -0
  14. package/dist/error.d.ts.map +1 -1
  15. package/dist/error.js +47 -1
  16. package/dist/error.js.map +1 -1
  17. package/dist/extractSubgraphsFromSupergraph.d.ts.map +1 -1
  18. package/dist/extractSubgraphsFromSupergraph.js +135 -5
  19. package/dist/extractSubgraphsFromSupergraph.js.map +1 -1
  20. package/dist/federation.d.ts +3 -2
  21. package/dist/federation.d.ts.map +1 -1
  22. package/dist/federation.js +12 -7
  23. package/dist/federation.js.map +1 -1
  24. package/dist/inaccessibleSpec.js +1 -2
  25. package/dist/inaccessibleSpec.js.map +1 -1
  26. package/dist/operations.d.ts +44 -20
  27. package/dist/operations.d.ts.map +1 -1
  28. package/dist/operations.js +287 -27
  29. package/dist/operations.js.map +1 -1
  30. package/dist/print.d.ts +1 -1
  31. package/dist/print.d.ts.map +1 -1
  32. package/dist/print.js +1 -1
  33. package/dist/print.js.map +1 -1
  34. package/dist/schemaUpgrader.d.ts.map +1 -1
  35. package/dist/schemaUpgrader.js +6 -6
  36. package/dist/schemaUpgrader.js.map +1 -1
  37. package/dist/supergraphs.d.ts +1 -3
  38. package/dist/supergraphs.d.ts.map +1 -1
  39. package/dist/supergraphs.js +9 -22
  40. package/dist/supergraphs.js.map +1 -1
  41. package/dist/utils.d.ts +10 -1
  42. package/dist/utils.d.ts.map +1 -1
  43. package/dist/utils.js +40 -1
  44. package/dist/utils.js.map +1 -1
  45. package/package.json +3 -4
  46. package/src/__tests__/coreSpec.test.ts +1 -1
  47. package/src/__tests__/definitions.test.ts +27 -0
  48. package/src/__tests__/extractSubgraphsFromSupergraph.test.ts +9 -5
  49. package/src/__tests__/operations.test.ts +36 -0
  50. package/src/__tests__/removeInaccessibleElements.test.ts +1 -3
  51. package/src/__tests__/schemaUpgrader.test.ts +0 -1
  52. package/src/__tests__/subgraphValidation.test.ts +1 -2
  53. package/src/buildSchema.ts +20 -7
  54. package/src/coreSpec.ts +2 -7
  55. package/src/definitions.ts +355 -155
  56. package/src/error.ts +62 -0
  57. package/src/extractSubgraphsFromSupergraph.ts +198 -7
  58. package/src/federation.ts +11 -4
  59. package/src/inaccessibleSpec.ts +2 -5
  60. package/src/operations.ts +428 -40
  61. package/src/print.ts +3 -3
  62. package/src/schemaUpgrader.ts +7 -6
  63. package/src/supergraphs.ts +16 -25
  64. package/src/utils.ts +49 -0
  65. package/tsconfig.test.tsbuildinfo +1 -1
  66. package/tsconfig.tsbuildinfo +1 -1
@@ -1,9 +1,12 @@
1
1
  import {
2
+ defaultRootName,
2
3
  Schema,
4
+ SchemaRootKind,
3
5
  } from '../../dist/definitions';
4
6
  import { buildSchema } from '../../dist/buildSchema';
5
7
  import { Field, FieldSelection, parseOperation, SelectionSet } from '../../dist/operations';
6
8
  import './matchers';
9
+ import { GraphQLError } from 'graphql';
7
10
 
8
11
  function parseSchema(schema: string): Schema {
9
12
  try {
@@ -341,3 +344,36 @@ describe('selection set freezing', () => {
341
344
  expect(s2.toString()).toBe('{ t { b } }');
342
345
  });
343
346
  });
347
+
348
+ describe('validations', () => {
349
+ test.each([
350
+ { directive: '@defer', rootKind: 'mutation' },
351
+ { directive: '@defer', rootKind: 'subscription' },
352
+ { directive: '@stream', rootKind: 'mutation' },
353
+ { directive: '@stream', rootKind: 'subscription' },
354
+ ])('reject $directive on $rootKind type', ({ directive, rootKind }) => {
355
+ const schema = parseSchema(`
356
+ type Query {
357
+ x: String
358
+ }
359
+
360
+ type Mutation {
361
+ x: String
362
+ }
363
+
364
+ type Subscription {
365
+ x: String
366
+ }
367
+ `);
368
+
369
+ expect(() => {
370
+ parseOperation(schema, `
371
+ ${rootKind} {
372
+ ... ${directive} {
373
+ x
374
+ }
375
+ }
376
+ `)
377
+ }).toThrowError(new GraphQLError(`The @defer and @stream directives cannot be used on ${rootKind} root type "${defaultRootName(rootKind as SchemaRootKind)}"`));
378
+ });
379
+ });
@@ -1,6 +1,5 @@
1
1
  import {
2
2
  ArgumentDefinition,
3
- errorCauses,
4
3
  FieldDefinition,
5
4
  InterfaceType,
6
5
  ObjectType,
@@ -8,8 +7,8 @@ import {
8
7
  } from "../definitions";
9
8
  import { buildSchema } from "../buildSchema";
10
9
  import { removeInaccessibleElements } from "../inaccessibleSpec";
11
- import { GraphQLErrorExt } from "@apollo/core-schema/dist/error";
12
10
  import { GraphQLError } from "graphql";
11
+ import { errorCauses } from "../error";
13
12
 
14
13
  describe("removeInaccessibleElements", () => {
15
14
  const INACCESSIBLE_V02_HEADER = `
@@ -31,7 +30,6 @@ describe("removeInaccessibleElements", () => {
31
30
  `;
32
31
 
33
32
  function getCauses(e: unknown): GraphQLError[] {
34
- expect(e instanceof GraphQLErrorExt).toBeTruthy();
35
33
  const causes = errorCauses(e as Error);
36
34
  expect(causes).toBeDefined();
37
35
  expect(Array.isArray(causes)).toBeTruthy();
@@ -167,7 +167,6 @@ test('update federation directive non-string arguments', () => {
167
167
  `);
168
168
  })
169
169
 
170
-
171
170
  test('remove tag on external field if found on definition', () => {
172
171
  const s1 = `
173
172
  type Query {
@@ -1,7 +1,6 @@
1
1
  import { DocumentNode } from 'graphql';
2
2
  import gql from 'graphql-tag';
3
- import { Subgraph } from '..';
4
- import { errorCauses } from '../definitions';
3
+ import { Subgraph, errorCauses } from '..';
5
4
  import { asFed2SubgraphDocument, buildSubgraph } from "../federation"
6
5
  import { defaultPrintOptions, printSchema } from '../print';
7
6
  import './matchers';
@@ -52,10 +52,9 @@ import {
52
52
  EnumType,
53
53
  Extension,
54
54
  ErrGraphQLValidationFailed,
55
- errorCauses,
56
55
  NamedSchemaElement,
57
56
  } from "./definitions";
58
- import { ERRORS, withModifiedErrorNodes } from "./error";
57
+ import { ERRORS, errorCauses, withModifiedErrorNodes } from "./error";
59
58
 
60
59
  function buildValue(value?: ValueNode): any {
61
60
  return value ? valueFromASTUntyped(value) : undefined;
@@ -100,7 +99,7 @@ export function buildSchemaFromAST(
100
99
  // is that:
101
100
  // 1. we can (enum values are self-contained and cannot reference anything that may need to be imported first; this
102
101
  // is also why we skip directive applications at that point, as those _may_ reference something that hasn't been imported yet)
103
- // 2. this allows the code to handle better the case where the `link__Purpose` enum is provided in the AST despite the `@link`
102
+ // 2. this allows the code to handle better the case where the `link__Purpose` enum is provided in the AST despite the `@link`
104
103
  // _definition_ not being provided. And the reason that is true is that as we later _add_ the `@link` definition, we
105
104
  // will need to check if `link_Purpose` needs to be added or not, but when it is already present, we check it's definition
106
105
  // is the expected, but that check will unexpected fail if we haven't finished "building" said type definition.
@@ -215,7 +214,7 @@ function buildNamedTypeAndDirectivesShallow(documentNode: DocumentNode, schema:
215
214
  let type = schema.type(definitionNode.name.value);
216
215
  // Note that the type may already exists due to an extension having been processed first, but we know we
217
216
  // have seen 2 definitions (which is invalid) if the definition has `preserverEmptyDefnition` already set
218
- // since it's only set for definitions, not extensions.
217
+ // since it's only set for definitions, not extensions.
219
218
  // Also note that we allow to redefine built-ins.
220
219
  if (!type || type.isBuiltIn) {
221
220
  type = schema.addType(newNamedType(withoutTrailingDefinition(definitionNode.kind), definitionNode.name.value));
@@ -332,9 +331,23 @@ function buildAppliedDirectives(
332
331
  for (const directive of elementNode.directives ?? []) {
333
332
  withNodeAttachedToError(
334
333
  () => {
335
- const d = element.applyDirective(directive.name.value, buildArgs(directive));
336
- d.setOfExtension(extension);
337
- d.sourceAST = directive;
334
+ /**
335
+ * If we are at the schemaDefinition level of a federation schema, it's possible that some directives
336
+ * will not be added until after the federation calls completeSchema. In that case, we want to wait
337
+ * until after completeSchema is called before we try to apply those directives.
338
+ */
339
+ if (element !== element.schema().schemaDefinition || directive.name.value === 'link' || !element.schema().blueprint.applyDirectivesAfterParsing()) {
340
+ const d = element.applyDirective(directive.name.value, buildArgs(directive));
341
+ d.setOfExtension(extension);
342
+ d.sourceAST = directive;
343
+ } else {
344
+ element.addUnappliedDirective({
345
+ extension,
346
+ directive,
347
+ args: buildArgs(directive),
348
+ nameOrDef: directive.name.value,
349
+ });
350
+ }
338
351
  },
339
352
  directive,
340
353
  errors,
package/src/coreSpec.ts CHANGED
@@ -2,9 +2,8 @@ import { ASTNode, DirectiveLocation, GraphQLError, StringValueNode } from "graph
2
2
  import { URL } from "url";
3
3
  import { CoreFeature, Directive, DirectiveDefinition, EnumType, ErrGraphQLAPISchemaValidationFailed, ErrGraphQLValidationFailed, InputType, ListType, NamedType, NonNullType, ScalarType, Schema, SchemaDefinition, SchemaElement, sourceASTs } from "./definitions";
4
4
  import { sameType } from "./types";
5
- import { err } from '@apollo/core-schema';
6
5
  import { assert, firstOf } from './utils';
7
- import { ERRORS } from "./error";
6
+ import { aggregateError, ERRORS } from "./error";
8
7
  import { valueToString } from "./values";
9
8
  import { coreFeatureDefinitionIfKnown, registerKnownFeature } from "./knownCoreFeatures";
10
9
  import { didYouMean, suggestionList } from "./suggestions";
@@ -15,11 +14,7 @@ export const linkIdentity = 'https://specs.apollo.dev/link';
15
14
 
16
15
  export const linkDirectiveDefaultName = 'link';
17
16
 
18
- export const ErrCoreCheckFailed = (causes: Error[]) =>
19
- err('CheckFailed', {
20
- message: 'one or more checks failed',
21
- causes
22
- })
17
+ export const ErrCoreCheckFailed = (causes: GraphQLError[]) => aggregateError('CheckFailed', 'one or more checks failed', causes);
23
18
 
24
19
  function buildError(message: string): Error {
25
20
  // Maybe not the right error for this?