@apollo/federation-internals 2.7.8 → 2.8.0-alpha.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 (56) hide show
  1. package/dist/directiveAndTypeSpecification.d.ts +13 -1
  2. package/dist/directiveAndTypeSpecification.d.ts.map +1 -1
  3. package/dist/directiveAndTypeSpecification.js +2 -2
  4. package/dist/directiveAndTypeSpecification.js.map +1 -1
  5. package/dist/error.d.ts +6 -0
  6. package/dist/error.d.ts.map +1 -1
  7. package/dist/error.js +12 -0
  8. package/dist/error.js.map +1 -1
  9. package/dist/extractSubgraphsFromSupergraph.d.ts +1 -1
  10. package/dist/extractSubgraphsFromSupergraph.d.ts.map +1 -1
  11. package/dist/extractSubgraphsFromSupergraph.js +62 -7
  12. package/dist/extractSubgraphsFromSupergraph.js.map +1 -1
  13. package/dist/federation.d.ts +15 -2
  14. package/dist/federation.d.ts.map +1 -1
  15. package/dist/federation.js +394 -4
  16. package/dist/federation.js.map +1 -1
  17. package/dist/index.d.ts +1 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +1 -0
  20. package/dist/index.js.map +1 -1
  21. package/dist/operations.d.ts +10 -8
  22. package/dist/operations.d.ts.map +1 -1
  23. package/dist/operations.js +37 -14
  24. package/dist/operations.js.map +1 -1
  25. package/dist/specs/contextSpec.d.ts +20 -0
  26. package/dist/specs/contextSpec.d.ts.map +1 -0
  27. package/dist/specs/contextSpec.js +62 -0
  28. package/dist/specs/contextSpec.js.map +1 -0
  29. package/dist/specs/federationSpec.d.ts +5 -2
  30. package/dist/specs/federationSpec.d.ts.map +1 -1
  31. package/dist/specs/federationSpec.js +9 -1
  32. package/dist/specs/federationSpec.js.map +1 -1
  33. package/dist/specs/joinSpec.d.ts +6 -0
  34. package/dist/specs/joinSpec.d.ts.map +1 -1
  35. package/dist/specs/joinSpec.js +11 -1
  36. package/dist/specs/joinSpec.js.map +1 -1
  37. package/dist/supergraphs.d.ts +4 -0
  38. package/dist/supergraphs.d.ts.map +1 -1
  39. package/dist/supergraphs.js +35 -2
  40. package/dist/supergraphs.js.map +1 -1
  41. package/dist/utils.d.ts +3 -0
  42. package/dist/utils.d.ts.map +1 -1
  43. package/dist/utils.js +39 -1
  44. package/dist/utils.js.map +1 -1
  45. package/package.json +1 -1
  46. package/src/directiveAndTypeSpecification.ts +8 -1
  47. package/src/error.ts +42 -0
  48. package/src/extractSubgraphsFromSupergraph.ts +76 -14
  49. package/src/federation.ts +593 -10
  50. package/src/index.ts +1 -0
  51. package/src/operations.ts +48 -21
  52. package/src/specs/contextSpec.ts +87 -0
  53. package/src/specs/federationSpec.ts +10 -1
  54. package/src/specs/joinSpec.ts +27 -3
  55. package/src/supergraphs.ts +37 -1
  56. package/src/utils.ts +38 -0
@@ -40,7 +40,7 @@ import { parseSelectionSet } from "./operations";
40
40
  import fs from 'fs';
41
41
  import path from 'path';
42
42
  import { validateStringContainsBoolean } from "./utils";
43
- import { errorCauses, printErrors } from ".";
43
+ import { CONTEXT_VERSIONS, ContextSpecDefinition, DirectiveDefinition, errorCauses, isFederationDirectiveDefinedInSchema, printErrors } from ".";
44
44
 
45
45
  function filteredTypes(
46
46
  supergraph: Schema,
@@ -193,7 +193,7 @@ function typesUsedInFederationDirective(fieldSet: string | undefined, parentType
193
193
  return usedTypes;
194
194
  }
195
195
 
196
- export function extractSubgraphsFromSupergraph(supergraph: Schema, validateExtractedSubgraphs: boolean = true): Subgraphs {
196
+ export function extractSubgraphsFromSupergraph(supergraph: Schema, validateExtractedSubgraphs: boolean = true): [Subgraphs, Map<string, string>] {
197
197
  const [coreFeatures, joinSpec] = validateSupergraph(supergraph);
198
198
  const isFed1 = joinSpec.version.equals(new FeatureVersion(0, 1));
199
199
  try {
@@ -212,6 +212,17 @@ export function extractSubgraphsFromSupergraph(supergraph: Schema, validateExtra
212
212
  return subgraph;
213
213
  };
214
214
 
215
+ const subgraphNameToGraphEnumValue = new Map<string, string>();
216
+ for (const [k, v] of graphEnumNameToSubgraphName.entries()) {
217
+ subgraphNameToGraphEnumValue.set(v, k);
218
+ }
219
+
220
+ const getSubgraphEnumValue = (subgraphName: string): string => {
221
+ const enumValue = subgraphNameToGraphEnumValue.get(subgraphName);
222
+ assert(enumValue, () => `Invalid subgraph name ${subgraphName} found: does not match a subgraph defined in the @join__Graph enum`);
223
+ return enumValue;
224
+ }
225
+
215
226
  const types = filteredTypes(supergraph, joinSpec, coreFeatures.coreDefinition);
216
227
  const args: ExtractArguments = {
217
228
  supergraph,
@@ -219,6 +230,7 @@ export function extractSubgraphsFromSupergraph(supergraph: Schema, validateExtra
219
230
  joinSpec,
220
231
  filteredTypes: types,
221
232
  getSubgraph,
233
+ getSubgraphEnumValue,
222
234
  };
223
235
  if (isFed1) {
224
236
  extractSubgraphsFromFed1Supergraph(args);
@@ -241,7 +253,7 @@ export function extractSubgraphsFromSupergraph(supergraph: Schema, validateExtra
241
253
  }
242
254
  }
243
255
 
244
- return subgraphs;
256
+ return [subgraphs, subgraphNameToGraphEnumValue];
245
257
  } catch (e) {
246
258
  let error = e;
247
259
  let subgraph: Subgraph | undefined = undefined;
@@ -281,6 +293,7 @@ type ExtractArguments = {
281
293
  joinSpec: JoinSpecDefinition,
282
294
  filteredTypes: NamedType[],
283
295
  getSubgraph: (application: Directive<any, { graph?: string }>) => Subgraph | undefined,
296
+ getSubgraphEnumValue: (subgraphName: string) => string
284
297
  }
285
298
 
286
299
  type SubgraphTypeInfo<T extends NamedType> = Map<string, { type: T, subgraph: Subgraph }>;
@@ -297,12 +310,13 @@ type TypesInfo = {
297
310
  unionTypes: TypeInfo<UnionType>[],
298
311
  };
299
312
 
300
- function addAllEmptySubgraphTypes({
301
- supergraph,
302
- joinSpec,
303
- filteredTypes,
304
- getSubgraph,
305
- }: ExtractArguments): TypesInfo {
313
+ function addAllEmptySubgraphTypes(args: ExtractArguments): TypesInfo {
314
+ const {
315
+ supergraph,
316
+ joinSpec,
317
+ filteredTypes,
318
+ getSubgraph,
319
+ } = args;
306
320
  const typeDirective = joinSpec.typeDirective(supergraph);
307
321
 
308
322
  const objOrItfTypes: TypeInfo<ObjectType | InterfaceType>[] = [];
@@ -316,16 +330,16 @@ function addAllEmptySubgraphTypes({
316
330
  // (on top of it making sense code-wise since both type behave exactly the same for most of what we're doing here).
317
331
  case 'InterfaceType':
318
332
  case 'ObjectType':
319
- objOrItfTypes.push({ type, subgraphsInfo: addEmptyType(type, type.appliedDirectivesOf(typeDirective), getSubgraph) });
333
+ objOrItfTypes.push({ type, subgraphsInfo: addEmptyType(type, type.appliedDirectivesOf(typeDirective), args) });
320
334
  break;
321
335
  case 'InputObjectType':
322
- inputObjTypes.push({ type, subgraphsInfo: addEmptyType(type, type.appliedDirectivesOf(typeDirective), getSubgraph) });
336
+ inputObjTypes.push({ type, subgraphsInfo: addEmptyType(type, type.appliedDirectivesOf(typeDirective), args) });
323
337
  break;
324
338
  case 'EnumType':
325
- enumTypes.push({ type, subgraphsInfo: addEmptyType(type, type.appliedDirectivesOf(typeDirective), getSubgraph) });
339
+ enumTypes.push({ type, subgraphsInfo: addEmptyType(type, type.appliedDirectivesOf(typeDirective), args) });
326
340
  break;
327
341
  case 'UnionType':
328
- unionTypes.push({ type, subgraphsInfo: addEmptyType(type, type.appliedDirectivesOf(typeDirective), getSubgraph) });
342
+ unionTypes.push({ type, subgraphsInfo: addEmptyType(type, type.appliedDirectivesOf(typeDirective), args) });
329
343
  break;
330
344
  case 'ScalarType':
331
345
  // Scalar are a bit special in that they don't have any sub-component, so we don't track them beyond adding them to the
@@ -350,8 +364,9 @@ function addAllEmptySubgraphTypes({
350
364
  function addEmptyType<T extends NamedType>(
351
365
  type: T,
352
366
  typeApplications: Directive<T, JoinTypeDirectiveArguments>[],
353
- getSubgraph: (application: Directive<any, { graph?: string }>) => Subgraph | undefined,
367
+ args: ExtractArguments,
354
368
  ): SubgraphTypeInfo<T> {
369
+ const { supergraph, getSubgraph, getSubgraphEnumValue } = args;
355
370
  // In fed2, we always mark all types with `@join__type` but making sure.
356
371
  assert(typeApplications.length > 0, `Missing @join__type on ${type}`)
357
372
  const subgraphsInfo: SubgraphTypeInfo<T> = new Map<string, { type: T, subgraph: Subgraph }>();
@@ -382,6 +397,33 @@ function addEmptyType<T extends NamedType>(
382
397
  }
383
398
  }
384
399
  }
400
+
401
+ const coreFeatures = supergraph.coreFeatures;
402
+ assert(coreFeatures, 'Should have core features');
403
+ const contextFeature = coreFeatures.getByIdentity(ContextSpecDefinition.identity);
404
+ let supergraphContextDirective: DirectiveDefinition<{ name: string}> | undefined;
405
+ if (contextFeature) {
406
+ const contextSpec = CONTEXT_VERSIONS.find(contextFeature.url.version);
407
+ assert(contextSpec, 'Should have context spec');
408
+ supergraphContextDirective = contextSpec.contextDirective(supergraph);
409
+ }
410
+
411
+ if (supergraphContextDirective) {
412
+ const contextApplications = type.appliedDirectivesOf(supergraphContextDirective);
413
+ // for every application, apply the context directive to the correct subgraph
414
+ for (const application of contextApplications) {
415
+ const { name } = application.arguments();
416
+ const match = name.match(/^(.*)__([A-Za-z]\w*)$/);
417
+ const graph = match ? match[1] : undefined;
418
+ const context = match ? match[2] : undefined;
419
+ assert(graph, `Invalid context name ${name} found in ${application} on ${application.parent}: does not match the expected pattern`);
420
+ const subgraphInfo = subgraphsInfo.get(getSubgraphEnumValue(graph));
421
+ const contextDirective = subgraphInfo?.subgraph.metadata().contextDirective();
422
+ if (subgraphInfo && contextDirective && isFederationDirectiveDefinedInSchema(contextDirective)) {
423
+ subgraphInfo.type.applyDirective(contextDirective, {name: context});
424
+ }
425
+ }
426
+ }
385
427
  return subgraphsInfo;
386
428
  }
387
429
 
@@ -610,6 +652,26 @@ function addSubgraphField({
610
652
  if (joinFieldArgs?.provides) {
611
653
  subgraphField.applyDirective(subgraph.metadata().providesDirective(), {'fields': joinFieldArgs.provides});
612
654
  }
655
+ if (joinFieldArgs?.contextArguments) {
656
+ const fromContextDirective = subgraph.metadata().fromContextDirective();
657
+ if (!isFederationDirectiveDefinedInSchema(fromContextDirective)) {
658
+ throw new Error(`@fromContext directive is not defined in the subgraph schema: ${subgraph.name}`);
659
+ } else {
660
+ for (const arg of joinFieldArgs.contextArguments) {
661
+ // this code will remove the subgraph name from the context
662
+ const match = arg.context.match(/^.*__([A-Za-z]\w*)$/);
663
+ if (!match) {
664
+ throw new Error(`Invalid context argument: ${arg.context}`);
665
+ }
666
+
667
+ subgraphField.addArgument(arg.name, decodeType(arg.type, subgraph.schema, subgraph.name));
668
+ const argOnField = subgraphField.argument(arg.name);
669
+ argOnField?.applyDirective(fromContextDirective, {
670
+ field: `\$${match[1]} ${arg.selection}`,
671
+ });
672
+ }
673
+ }
674
+ }
613
675
  const external = !!joinFieldArgs?.external;
614
676
  if (external) {
615
677
  subgraphField.applyDirective(subgraph.metadata().externalDirective());