@theguild/federation-composition 0.20.2 → 0.21.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 (57) hide show
  1. package/cjs/subgraph/state.js +21 -32
  2. package/cjs/subgraph/validation/rules/elements/authenticated.js +23 -2
  3. package/cjs/subgraph/validation/rules/elements/cost.js +12 -2
  4. package/cjs/subgraph/validation/rules/elements/list-size.js +10 -8
  5. package/cjs/subgraph/validation/rules/elements/policy.js +25 -5
  6. package/cjs/subgraph/validation/rules/elements/requires-scopes.js +23 -2
  7. package/cjs/supergraph/composition/ast.js +5 -14
  8. package/cjs/supergraph/composition/enum-type.js +3 -2
  9. package/cjs/supergraph/composition/interface-type.js +32 -11
  10. package/cjs/supergraph/composition/object-type.js +46 -7
  11. package/cjs/supergraph/composition/scalar-type.js +3 -2
  12. package/cjs/supergraph/state.js +43 -6
  13. package/cjs/supergraph/validation/rules/auth-on-requires-rule.js +211 -0
  14. package/cjs/supergraph/validation/rules/external-missing-on-base-rule.js +26 -1
  15. package/cjs/supergraph/validation/rules/list-size-slicing-arguments-rule.js +69 -0
  16. package/cjs/supergraph/validation/validate-supergraph.js +5 -0
  17. package/cjs/utils/auth.js +34 -0
  18. package/esm/subgraph/state.js +21 -32
  19. package/esm/subgraph/validation/rules/elements/authenticated.js +24 -3
  20. package/esm/subgraph/validation/rules/elements/cost.js +12 -2
  21. package/esm/subgraph/validation/rules/elements/list-size.js +10 -8
  22. package/esm/subgraph/validation/rules/elements/policy.js +26 -6
  23. package/esm/subgraph/validation/rules/elements/requires-scopes.js +24 -3
  24. package/esm/supergraph/composition/ast.js +5 -14
  25. package/esm/supergraph/composition/enum-type.js +3 -2
  26. package/esm/supergraph/composition/interface-type.js +33 -12
  27. package/esm/supergraph/composition/object-type.js +46 -7
  28. package/esm/supergraph/composition/scalar-type.js +3 -2
  29. package/esm/supergraph/state.js +43 -6
  30. package/esm/supergraph/validation/rules/auth-on-requires-rule.js +208 -0
  31. package/esm/supergraph/validation/rules/external-missing-on-base-rule.js +26 -1
  32. package/esm/supergraph/validation/rules/list-size-slicing-arguments-rule.js +66 -0
  33. package/esm/supergraph/validation/validate-supergraph.js +5 -0
  34. package/esm/utils/auth.js +31 -0
  35. package/package.json +1 -1
  36. package/typings/subgraph/state.d.cts +1 -6
  37. package/typings/subgraph/state.d.ts +1 -6
  38. package/typings/subgraph/validation/validation-context.d.cts +0 -3
  39. package/typings/subgraph/validation/validation-context.d.ts +0 -3
  40. package/typings/supergraph/composition/ast.d.cts +1 -0
  41. package/typings/supergraph/composition/ast.d.ts +1 -0
  42. package/typings/supergraph/composition/common.d.cts +4 -0
  43. package/typings/supergraph/composition/common.d.ts +4 -0
  44. package/typings/supergraph/composition/interface-type.d.cts +3 -0
  45. package/typings/supergraph/composition/interface-type.d.ts +3 -0
  46. package/typings/supergraph/composition/object-type.d.cts +6 -0
  47. package/typings/supergraph/composition/object-type.d.ts +6 -0
  48. package/typings/supergraph/state.d.cts +1 -0
  49. package/typings/supergraph/state.d.ts +1 -0
  50. package/typings/supergraph/validation/rules/auth-on-requires-rule.d.cts +5 -0
  51. package/typings/supergraph/validation/rules/auth-on-requires-rule.d.ts +5 -0
  52. package/typings/supergraph/validation/rules/external-missing-on-base-rule.d.cts +2 -1
  53. package/typings/supergraph/validation/rules/external-missing-on-base-rule.d.ts +2 -1
  54. package/typings/supergraph/validation/rules/list-size-slicing-arguments-rule.d.cts +5 -0
  55. package/typings/supergraph/validation/rules/list-size-slicing-arguments-rule.d.ts +5 -0
  56. package/typings/utils/auth.d.cts +2 -0
  57. package/typings/utils/auth.d.ts +2 -0
@@ -9,6 +9,7 @@ const graphql_1 = require("graphql");
9
9
  const printer_js_1 = require("../graphql/printer.js");
10
10
  const federation_js_1 = require("../specifications/federation.js");
11
11
  const helpers_js_1 = require("./helpers.js");
12
+ const auth_js_1 = require("../utils/auth.js");
12
13
  var TypeKind;
13
14
  (function (TypeKind) {
14
15
  TypeKind["OBJECT"] = "OBJECT";
@@ -637,10 +638,12 @@ function scalarTypeFactory(state) {
637
638
  getOrCreateScalarType(state, typeName).authenticated = true;
638
639
  },
639
640
  setPolicies(typeName, policies) {
640
- getOrCreateScalarType(state, typeName).policies.push(...policies);
641
+ const existing = getOrCreateScalarType(state, typeName);
642
+ existing.policies = (0, auth_js_1.mergeScopePolicies)(existing.policies, policies);
641
643
  },
642
644
  setScopes(typeName, scopes) {
643
- getOrCreateScalarType(state, typeName).scopes.push(...scopes);
645
+ const existing = getOrCreateScalarType(state, typeName);
646
+ existing.scopes = (0, auth_js_1.mergeScopePolicies)(existing.scopes, scopes);
644
647
  },
645
648
  setCost(typeName, cost) {
646
649
  getOrCreateScalarType(state, typeName).cost = cost;
@@ -719,23 +722,16 @@ function objectTypeFactory(state, renameObject, interfaceTypeBuilder, isInterfac
719
722
  objectType.inaccessible = true;
720
723
  },
721
724
  setAuthenticated(typeName) {
722
- if (isInterfaceObject(typeName)) {
723
- return interfaceTypeBuilder.setAuthenticated(typeName);
724
- }
725
725
  const objectType = getOrCreateObjectType(state, renameObject, typeName);
726
726
  objectType.authenticated = true;
727
727
  },
728
728
  setPolicies(typeName, policies) {
729
- if (isInterfaceObject(typeName)) {
730
- return interfaceTypeBuilder.setPolicies(typeName, policies);
731
- }
732
- getOrCreateObjectType(state, renameObject, typeName).policies.push(...policies);
729
+ const existing = getOrCreateObjectType(state, renameObject, typeName);
730
+ existing.policies = (0, auth_js_1.mergeScopePolicies)(existing.policies, policies);
733
731
  },
734
732
  setScopes(typeName, scopes) {
735
- if (isInterfaceObject(typeName)) {
736
- return interfaceTypeBuilder.setScopes(typeName, scopes);
737
- }
738
- getOrCreateObjectType(state, renameObject, typeName).scopes.push(...scopes);
733
+ const existing = getOrCreateObjectType(state, renameObject, typeName);
734
+ existing.scopes = (0, auth_js_1.mergeScopePolicies)(existing.scopes, scopes);
739
735
  },
740
736
  setCost(typeName, cost) {
741
737
  if (isInterfaceObject(typeName)) {
@@ -812,13 +808,15 @@ function objectTypeFactory(state, renameObject, interfaceTypeBuilder, isInterfac
812
808
  if (isInterfaceObject(typeName)) {
813
809
  return interfaceTypeBuilder.field.setPolicies(typeName, fieldName, policies);
814
810
  }
815
- getOrCreateObjectField(state, renameObject, typeName, fieldName).policies.push(...policies);
811
+ let existing = getOrCreateObjectField(state, renameObject, typeName, fieldName);
812
+ existing.policies = (0, auth_js_1.mergeScopePolicies)(existing.policies, policies);
816
813
  },
817
814
  setScopes(typeName, fieldName, scopes) {
818
815
  if (isInterfaceObject(typeName)) {
819
816
  return interfaceTypeBuilder.field.setScopes(typeName, fieldName, scopes);
820
817
  }
821
- getOrCreateObjectField(state, renameObject, typeName, fieldName).scopes.push(...scopes);
818
+ let existing = getOrCreateObjectField(state, renameObject, typeName, fieldName);
819
+ existing.scopes = (0, auth_js_1.mergeScopePolicies)(existing.scopes, scopes);
822
820
  },
823
821
  setCost(typeName, fieldName, cost) {
824
822
  if (isInterfaceObject(typeName)) {
@@ -983,16 +981,6 @@ function interfaceTypeFactory(state) {
983
981
  const objectType = getOrCreateInterfaceType(state, typeName);
984
982
  objectType.inaccessible = true;
985
983
  },
986
- setAuthenticated(typeName) {
987
- const t = getOrCreateInterfaceType(state, typeName);
988
- t.authenticated = true;
989
- },
990
- setPolicies(typeName, policies) {
991
- getOrCreateInterfaceType(state, typeName).policies.push(...policies);
992
- },
993
- setScopes(typeName, scopes) {
994
- getOrCreateInterfaceType(state, typeName).scopes.push(...scopes);
995
- },
996
984
  setTag(typeName, tag) {
997
985
  getOrCreateInterfaceType(state, typeName).tags.add(tag);
998
986
  },
@@ -1021,10 +1009,12 @@ function interfaceTypeFactory(state) {
1021
1009
  true;
1022
1010
  },
1023
1011
  setPolicies(typeName, fieldName, policies) {
1024
- getOrCreateInterfaceField(state, typeName, fieldName).policies.push(...policies);
1012
+ const existing = getOrCreateInterfaceField(state, typeName, fieldName);
1013
+ existing.policies = (0, auth_js_1.mergeScopePolicies)(existing.policies, policies);
1025
1014
  },
1026
1015
  setScopes(typeName, fieldName, scopes) {
1027
- getOrCreateInterfaceField(state, typeName, fieldName).scopes.push(...scopes);
1016
+ const existing = getOrCreateInterfaceField(state, typeName, fieldName);
1017
+ existing.scopes = (0, auth_js_1.mergeScopePolicies)(existing.scopes, scopes);
1028
1018
  },
1029
1019
  setCost(typeName, fieldName, cost) {
1030
1020
  getOrCreateInterfaceField(state, typeName, fieldName).cost = cost;
@@ -1196,10 +1186,12 @@ function enumTypeFactory(state) {
1196
1186
  getOrCreateEnumType(state, typeName).authenticated = true;
1197
1187
  },
1198
1188
  setPolicies(typeName, policies) {
1199
- getOrCreateEnumType(state, typeName).policies.push(...policies);
1189
+ const existing = getOrCreateEnumType(state, typeName);
1190
+ existing.policies = (0, auth_js_1.mergeScopePolicies)(existing.policies, policies);
1200
1191
  },
1201
1192
  setScopes(typeName, scopes) {
1202
- getOrCreateEnumType(state, typeName).scopes.push(...scopes);
1193
+ const existing = getOrCreateEnumType(state, typeName);
1194
+ existing.scopes = (0, auth_js_1.mergeScopePolicies)(existing.scopes, scopes);
1203
1195
  },
1204
1196
  setCost(typeName, cost) {
1205
1197
  getOrCreateEnumType(state, typeName).cost = cost;
@@ -1375,9 +1367,6 @@ function getOrCreateInterfaceType(state, typeName) {
1375
1367
  extension: false,
1376
1368
  keys: [],
1377
1369
  inaccessible: false,
1378
- authenticated: false,
1379
- policies: [],
1380
- scopes: [],
1381
1370
  tags: new Set(),
1382
1371
  interfaces: new Set(),
1383
1372
  implementedBy: new Set(),
@@ -33,6 +33,15 @@ function AuthenticatedRule(context) {
33
33
  if (!typeDef) {
34
34
  throw new Error("Could not find the parent type of the field annotated with @authenticated");
35
35
  }
36
+ if (typeDef.kind === graphql_1.Kind.INTERFACE_TYPE_DEFINITION ||
37
+ typeDef.kind === graphql_1.Kind.INTERFACE_TYPE_EXTENSION) {
38
+ context.reportError(new graphql_1.GraphQLError(`Invalid use of @authenticated on field "${typeDef.name.value}.${parent.name.value}": @authenticated cannot be applied on interfaces, interface fields and interface objects`, {
39
+ extensions: {
40
+ code: "AUTH_REQUIREMENTS_APPLIED_ON_INTERFACE",
41
+ },
42
+ }));
43
+ return;
44
+ }
36
45
  if (typeDef.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION ||
37
46
  typeDef.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
38
47
  context.stateBuilder.objectType.field.setAuthenticated(typeDef.name.value, parent.name.value);
@@ -41,12 +50,24 @@ function AuthenticatedRule(context) {
41
50
  }
42
51
  case graphql_1.Kind.OBJECT_TYPE_DEFINITION:
43
52
  case graphql_1.Kind.OBJECT_TYPE_EXTENSION:
53
+ if (context.stateBuilder.isInterfaceObject(parent.name.value)) {
54
+ context.reportError(new graphql_1.GraphQLError(`Invalid use of @authenticated on interface object "${parent.name.value}": @authenticated cannot be applied on interfaces, interface fields and interface objects`, {
55
+ extensions: {
56
+ code: "AUTH_REQUIREMENTS_APPLIED_ON_INTERFACE",
57
+ },
58
+ }));
59
+ return;
60
+ }
44
61
  context.stateBuilder.objectType.setAuthenticated(parent.name.value);
45
62
  break;
46
63
  case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
47
64
  case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
48
- context.stateBuilder.interfaceType.setAuthenticated(parent.name.value);
49
- break;
65
+ context.reportError(new graphql_1.GraphQLError(`Invalid use of @authenticated on interface "${parent.name.value}": @authenticated cannot be applied on interfaces, interface fields and interface objects`, {
66
+ extensions: {
67
+ code: "AUTH_REQUIREMENTS_APPLIED_ON_INTERFACE",
68
+ },
69
+ }));
70
+ return;
50
71
  case graphql_1.Kind.SCALAR_TYPE_DEFINITION:
51
72
  case graphql_1.Kind.SCALAR_TYPE_EXTENSION:
52
73
  context.stateBuilder.scalarType.setAuthenticated(parent.name.value);
@@ -58,7 +58,12 @@ function CostRule(context) {
58
58
  }
59
59
  if (typeDef.kind === graphql_1.Kind.INTERFACE_TYPE_DEFINITION ||
60
60
  typeDef.kind === graphql_1.Kind.INTERFACE_TYPE_EXTENSION) {
61
- context.stateBuilder.interfaceType.field.setCost(typeDef.name.value, parent.name.value, weight);
61
+ context.reportError(new graphql_1.GraphQLError(`@cost cannot be applied to interface "${typeDef.name.value}.${parent.name.value}"`, {
62
+ extensions: {
63
+ code: "COST_APPLIED_TO_INTERFACE_FIELD",
64
+ },
65
+ }));
66
+ return;
62
67
  }
63
68
  break;
64
69
  }
@@ -89,7 +94,12 @@ function CostRule(context) {
89
94
  if (!argDef) {
90
95
  throw new Error("Could not find the argument annotated with @cost");
91
96
  }
92
- context.stateBuilder.interfaceType.field.arg.setCost(typeDef.name.value, fieldDef.name.value, argDef.name.value, weight);
97
+ context.reportError(new graphql_1.GraphQLError(`@cost cannot be applied to interface "${typeDef.name.value}.${fieldDef.name.value}" argument "${argDef.name.value}"`, {
98
+ extensions: {
99
+ code: "COST_APPLIED_TO_INTERFACE_FIELD",
100
+ },
101
+ }));
102
+ return;
93
103
  }
94
104
  break;
95
105
  case graphql_1.Kind.OBJECT_TYPE_DEFINITION:
@@ -169,29 +169,29 @@ function ListSizeRule(context) {
169
169
  const outputType = (0, helpers_js_1.namedTypeFromTypeNode)(fieldDef.type);
170
170
  const targetType = knownObjectsAndInterfaces.get(outputType.name.value);
171
171
  if (!targetType) {
172
- context.reportError(new graphql_1.GraphQLError(`${coordinate} has @listSize(sizedFields:) applied, but the output type is not an object`, {
172
+ context.reportError(new graphql_1.GraphQLError(`${coordinate} has @listSize(sizedFields:) applied, but the output type is not a composite type`, {
173
173
  extensions: {
174
174
  code: "LIST_SIZE_INVALID_SIZED_FIELD",
175
175
  },
176
176
  }));
177
177
  return;
178
178
  }
179
- const nonIntFields = [];
179
+ const nonListFields = [];
180
180
  const nonExistingFields = [];
181
181
  for (const sizedField of sizedFields) {
182
182
  const targetField = targetType.fields?.find((f) => f.name.value === sizedField);
183
183
  if (!targetField) {
184
184
  nonExistingFields.push(sizedField);
185
185
  }
186
- else if (!isIntTypeOrNullableIntType(targetField.type)) {
187
- nonIntFields.push(sizedField);
186
+ else if (!isListType(targetField.type)) {
187
+ nonListFields.push(sizedField);
188
188
  }
189
189
  }
190
- if (nonIntFields.length || nonExistingFields.length) {
191
- nonIntFields.forEach((fieldName) => {
192
- context.reportError(new graphql_1.GraphQLError(`${coordinate} references "${fieldName}" field in @listSize(sizedFields:) argument that is not an integer.`, {
190
+ if (nonListFields.length || nonExistingFields.length) {
191
+ nonListFields.forEach((fieldName) => {
192
+ context.reportError(new graphql_1.GraphQLError(`${coordinate} references "${fieldName}" field in @listSize(sizedFields:) argument that is not a list.`, {
193
193
  extensions: {
194
- code: "LIST_SIZE_INVALID_SIZED_FIELD",
194
+ code: "LIST_SIZE_APPLIED_TO_NON_LIST",
195
195
  },
196
196
  }));
197
197
  });
@@ -238,6 +238,7 @@ function ListSizeRule(context) {
238
238
  if (typeDef.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION ||
239
239
  typeDef.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
240
240
  context.stateBuilder.objectType.field.setListSize(typeDef.name.value, parent.name.value, {
241
+ printRequireOneSlicingArgument: false,
241
242
  assumedSize,
242
243
  slicingArguments,
243
244
  sizedFields,
@@ -247,6 +248,7 @@ function ListSizeRule(context) {
247
248
  if (typeDef.kind === graphql_1.Kind.INTERFACE_TYPE_DEFINITION ||
248
249
  typeDef.kind === graphql_1.Kind.INTERFACE_TYPE_EXTENSION) {
249
250
  context.stateBuilder.interfaceType.field.setListSize(typeDef.name.value, parent.name.value, {
251
+ printRequireOneSlicingArgument: false,
250
252
  assumedSize,
251
253
  slicingArguments,
252
254
  sizedFields,
@@ -55,21 +55,41 @@ function PolicyRule(context) {
55
55
  if (!typeDef) {
56
56
  throw new Error("Could not find the parent type of the field annotated with @policy");
57
57
  }
58
- if ((typeDef.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION ||
59
- typeDef.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION) &&
60
- !context.stateBuilder.isInterfaceObject(typeDef.name.value)) {
58
+ if (typeDef.kind === graphql_1.Kind.INTERFACE_TYPE_DEFINITION ||
59
+ typeDef.kind === graphql_1.Kind.INTERFACE_TYPE_EXTENSION) {
60
+ context.reportError(new graphql_1.GraphQLError(`Invalid use of @policy on field "${typeDef.name.value}.${parent.name.value}": @policy cannot be applied on interfaces, interface fields and interface objects`, {
61
+ extensions: {
62
+ code: "AUTH_REQUIREMENTS_APPLIED_ON_INTERFACE",
63
+ },
64
+ }));
65
+ return;
66
+ }
67
+ if (typeDef.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION ||
68
+ typeDef.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
61
69
  context.stateBuilder.objectType.field.setPolicies(typeDef.name.value, parent.name.value, policies);
62
70
  }
63
71
  break;
64
72
  }
65
73
  case graphql_1.Kind.OBJECT_TYPE_DEFINITION:
66
74
  case graphql_1.Kind.OBJECT_TYPE_EXTENSION:
75
+ if (context.stateBuilder.isInterfaceObject(parent.name.value)) {
76
+ context.reportError(new graphql_1.GraphQLError(`Invalid use of @policy on interface object "${parent.name.value}": @policy cannot be applied on interfaces, interface fields and interface objects`, {
77
+ extensions: {
78
+ code: "AUTH_REQUIREMENTS_APPLIED_ON_INTERFACE",
79
+ },
80
+ }));
81
+ return;
82
+ }
67
83
  context.stateBuilder.objectType.setPolicies(parent.name.value, policies);
68
84
  break;
69
85
  case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
70
86
  case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
71
- context.stateBuilder.interfaceType.setPolicies(parent.name.value, policies);
72
- break;
87
+ context.reportError(new graphql_1.GraphQLError(`Invalid use of @policy on interface "${parent.name.value}": @policy cannot be applied on interfaces, interface fields and interface objects`, {
88
+ extensions: {
89
+ code: "AUTH_REQUIREMENTS_APPLIED_ON_INTERFACE",
90
+ },
91
+ }));
92
+ return;
73
93
  case graphql_1.Kind.SCALAR_TYPE_DEFINITION:
74
94
  case graphql_1.Kind.SCALAR_TYPE_EXTENSION:
75
95
  context.stateBuilder.scalarType.setPolicies(parent.name.value, policies);
@@ -55,6 +55,15 @@ function RequiresScopesRule(context) {
55
55
  if (!typeDef) {
56
56
  throw new Error("Could not find the parent type of the field annotated with @requiresScopes");
57
57
  }
58
+ if (typeDef.kind === graphql_1.Kind.INTERFACE_TYPE_DEFINITION ||
59
+ typeDef.kind === graphql_1.Kind.INTERFACE_TYPE_EXTENSION) {
60
+ context.reportError(new graphql_1.GraphQLError(`Invalid use of @requiresScopes on field "${typeDef.name.value}.${parent.name.value}": @requiresScopes cannot be applied on interfaces, interface fields and interface objects`, {
61
+ extensions: {
62
+ code: "AUTH_REQUIREMENTS_APPLIED_ON_INTERFACE",
63
+ },
64
+ }));
65
+ return;
66
+ }
58
67
  if (typeDef.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION ||
59
68
  typeDef.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
60
69
  context.stateBuilder.objectType.field.setScopes(typeDef.name.value, parent.name.value, scopes);
@@ -63,12 +72,24 @@ function RequiresScopesRule(context) {
63
72
  }
64
73
  case graphql_1.Kind.OBJECT_TYPE_DEFINITION:
65
74
  case graphql_1.Kind.OBJECT_TYPE_EXTENSION:
75
+ if (context.stateBuilder.isInterfaceObject(parent.name.value)) {
76
+ context.reportError(new graphql_1.GraphQLError(`Invalid use of @requiresScopes on interface object "${parent.name.value}": @requiresScopes cannot be applied on interfaces, interface fields and interface objects`, {
77
+ extensions: {
78
+ code: "AUTH_REQUIREMENTS_APPLIED_ON_INTERFACE",
79
+ },
80
+ }));
81
+ return;
82
+ }
66
83
  context.stateBuilder.objectType.setScopes(parent.name.value, scopes);
67
84
  break;
68
85
  case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
69
86
  case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
70
- context.stateBuilder.interfaceType.setScopes(parent.name.value, scopes);
71
- break;
87
+ context.reportError(new graphql_1.GraphQLError(`Invalid use of @requiresScopes on interface "${parent.name.value}": @requiresScopes cannot be applied on interfaces, interface fields and interface objects`, {
88
+ extensions: {
89
+ code: "AUTH_REQUIREMENTS_APPLIED_ON_INTERFACE",
90
+ },
91
+ }));
92
+ return;
72
93
  case graphql_1.Kind.SCALAR_TYPE_DEFINITION:
73
94
  case graphql_1.Kind.SCALAR_TYPE_EXTENSION:
74
95
  context.stateBuilder.scalarType.setScopes(parent.name.value, scopes);
@@ -528,16 +528,6 @@ function createAuthenticatedDirectiveNode() {
528
528
  arguments: [],
529
529
  };
530
530
  }
531
- function deduplicatePoliciesOrScopes(items) {
532
- const stringified = items.map((group) => group.sort().join("ɵ"));
533
- const indexesToRemove = [];
534
- for (let index = 0; index < stringified.length; index++) {
535
- if (stringified.indexOf(stringified[index]) !== index) {
536
- indexesToRemove.push(index);
537
- }
538
- }
539
- return items.filter((_, index) => !indexesToRemove.includes(index));
540
- }
541
531
  function createPolicyDirectiveNode(policies) {
542
532
  return {
543
533
  kind: graphql_1.Kind.DIRECTIVE,
@@ -554,7 +544,7 @@ function createPolicyDirectiveNode(policies) {
554
544
  },
555
545
  value: {
556
546
  kind: graphql_1.Kind.LIST,
557
- values: deduplicatePoliciesOrScopes(policies).map((group) => ({
547
+ values: policies.map((group) => ({
558
548
  kind: graphql_1.Kind.LIST,
559
549
  values: group.map((policy) => ({
560
550
  kind: graphql_1.Kind.STRING,
@@ -582,7 +572,7 @@ function createRequiresScopesDirectiveNode(scopes) {
582
572
  },
583
573
  value: {
584
574
  kind: graphql_1.Kind.LIST,
585
- values: deduplicatePoliciesOrScopes(scopes).map((group) => ({
575
+ values: scopes.map((group) => ({
586
576
  kind: graphql_1.Kind.LIST,
587
577
  values: group.map((scope) => ({
588
578
  kind: graphql_1.Kind.STRING,
@@ -726,7 +716,8 @@ function createCostDirectiveNode(input) {
726
716
  }
727
717
  function createListSizeDirectiveNode(input) {
728
718
  const args = [];
729
- if (input.requireOneSlicingArgument === false) {
719
+ if (input.requireOneSlicingArgument === false ||
720
+ input.printRequireOneSlicingArgument === true) {
730
721
  args.push({
731
722
  kind: graphql_1.Kind.ARGUMENT,
732
723
  name: {
@@ -735,7 +726,7 @@ function createListSizeDirectiveNode(input) {
735
726
  },
736
727
  value: {
737
728
  kind: graphql_1.Kind.BOOLEAN,
738
- value: false,
729
+ value: input.requireOneSlicingArgument === true,
739
730
  },
740
731
  });
741
732
  }
@@ -4,6 +4,7 @@ exports.enumTypeBuilder = enumTypeBuilder;
4
4
  const helpers_js_1 = require("../../utils/helpers.js");
5
5
  const ast_js_1 = require("./ast.js");
6
6
  const common_js_1 = require("./common.js");
7
+ const auth_js_1 = require("../../utils/auth.js");
7
8
  function enumTypeBuilder() {
8
9
  return {
9
10
  visitSubgraphState(graph, state, typeName, type) {
@@ -16,10 +17,10 @@ function enumTypeBuilder() {
16
17
  enumTypeState.authenticated = true;
17
18
  }
18
19
  if (type.policies) {
19
- enumTypeState.policies.push(...type.policies);
20
+ enumTypeState.policies = (0, auth_js_1.mergeScopePolicies)(enumTypeState.policies, type.policies);
20
21
  }
21
22
  if (type.scopes) {
22
- enumTypeState.scopes.push(...type.scopes);
23
+ enumTypeState.scopes = (0, auth_js_1.mergeScopePolicies)(enumTypeState.scopes, type.scopes);
23
24
  }
24
25
  if (type.cost !== null) {
25
26
  enumTypeState.cost = (0, helpers_js_1.mathMax)(type.cost, enumTypeState.cost);
@@ -4,6 +4,7 @@ exports.interfaceTypeBuilder = interfaceTypeBuilder;
4
4
  const helpers_js_1 = require("../../utils/helpers.js");
5
5
  const ast_js_1 = require("./ast.js");
6
6
  const common_js_1 = require("./common.js");
7
+ const auth_js_1 = require("../../utils/auth.js");
7
8
  function interfaceTypeBuilder() {
8
9
  return {
9
10
  visitSubgraphState(graph, state, typeName, type) {
@@ -12,15 +13,6 @@ function interfaceTypeBuilder() {
12
13
  if (type.inaccessible) {
13
14
  interfaceTypeState.inaccessible = true;
14
15
  }
15
- if (type.authenticated) {
16
- interfaceTypeState.authenticated = true;
17
- }
18
- if (type.policies) {
19
- interfaceTypeState.policies.push(...type.policies);
20
- }
21
- if (type.scopes) {
22
- interfaceTypeState.scopes.push(...type.scopes);
23
- }
24
16
  if (type.isDefinition) {
25
17
  interfaceTypeState.hasDefinition = true;
26
18
  }
@@ -62,16 +54,17 @@ function interfaceTypeBuilder() {
62
54
  fieldState.authenticated = true;
63
55
  }
64
56
  if (field.policies) {
65
- fieldState.policies.push(...field.policies);
57
+ fieldState.policies = (0, auth_js_1.mergeScopePolicies)(fieldState.policies, field.policies);
66
58
  }
67
59
  if (field.scopes) {
68
- fieldState.scopes.push(...field.scopes);
60
+ fieldState.scopes = (0, auth_js_1.mergeScopePolicies)(fieldState.scopes, field.scopes);
69
61
  }
70
62
  if (field.cost !== null) {
71
63
  fieldState.cost = (0, helpers_js_1.mathMax)(field.cost, fieldState.cost);
72
64
  }
73
65
  if (field.listSize !== null) {
74
66
  fieldState.listSize = {
67
+ printRequireOneSlicingArgument: false,
75
68
  assumedSize: (0, helpers_js_1.mathMaxNullable)(fieldState.listSize?.assumedSize, field.listSize.assumedSize),
76
69
  requireOneSlicingArgument: (fieldState.listSize?.requireOneSlicingArgument ?? true) &&
77
70
  field.listSize.requireOneSlicingArgument,
@@ -101,6 +94,9 @@ function interfaceTypeBuilder() {
101
94
  version: graph.version,
102
95
  external: field.external,
103
96
  shareable: field.shareable,
97
+ authenticated: field.authenticated,
98
+ policies: field.policies,
99
+ scopes: field.scopes,
104
100
  usedAsKey,
105
101
  });
106
102
  for (const arg of field.args.values()) {
@@ -134,6 +130,31 @@ function interfaceTypeBuilder() {
134
130
  }
135
131
  }
136
132
  },
133
+ composeSupergraphState(interfaceType, graphs, { supergraphState }) {
134
+ const implementors = Array.from(interfaceType.implementedBy)
135
+ .map((typeName) => supergraphState.objectTypes.get(typeName))
136
+ .filter(helpers_js_1.isDefined);
137
+ for (const implementor of implementors) {
138
+ interfaceType.scopes = (0, auth_js_1.mergeScopePolicies)(interfaceType.scopes, implementor.scopes);
139
+ interfaceType.policies = (0, auth_js_1.mergeScopePolicies)(interfaceType.policies, implementor.policies);
140
+ if (implementor.authenticated) {
141
+ interfaceType.authenticated = true;
142
+ }
143
+ }
144
+ for (const field of interfaceType.fields.values()) {
145
+ for (const implementor of implementors) {
146
+ let implementorField = implementor.fields.get(field.name);
147
+ if (!implementorField) {
148
+ continue;
149
+ }
150
+ field.scopes = (0, auth_js_1.mergeScopePolicies)(field.scopes, implementorField.scopes);
151
+ field.policies = (0, auth_js_1.mergeScopePolicies)(field.policies, implementorField.policies);
152
+ if (implementorField.authenticated) {
153
+ field.authenticated = true;
154
+ }
155
+ }
156
+ }
157
+ },
137
158
  composeSupergraphNode(interfaceType, graphs, { supergraphState }) {
138
159
  return (0, ast_js_1.createInterfaceTypeNode)({
139
160
  name: interfaceType.name,
@@ -5,6 +5,7 @@ exports.objectTypeBuilder = objectTypeBuilder;
5
5
  const helpers_js_1 = require("../../utils/helpers.js");
6
6
  const ast_js_1 = require("./ast.js");
7
7
  const common_js_1 = require("./common.js");
8
+ const auth_js_1 = require("../../utils/auth.js");
8
9
  function isRealExtension(meta, version) {
9
10
  const hasExtendsDirective = meta.extensionType === "@extends";
10
11
  if (meta.extension) {
@@ -33,10 +34,10 @@ function objectTypeBuilder() {
33
34
  objectTypeState.authenticated = true;
34
35
  }
35
36
  if (type.policies) {
36
- objectTypeState.policies.push(...type.policies);
37
+ objectTypeState.policies = (0, auth_js_1.mergeScopePolicies)(objectTypeState.policies, type.policies);
37
38
  }
38
39
  if (type.scopes) {
39
- objectTypeState.scopes.push(...type.scopes);
40
+ objectTypeState.scopes = (0, auth_js_1.mergeScopePolicies)(objectTypeState.scopes, type.scopes);
40
41
  }
41
42
  if (type.cost !== null) {
42
43
  objectTypeState.cost = (0, helpers_js_1.mathMax)(type.cost, objectTypeState.cost);
@@ -68,6 +69,9 @@ function objectTypeBuilder() {
68
69
  shareable: type.shareable,
69
70
  interfaces: type.interfaces,
70
71
  version: graph.version,
72
+ authenticated: type.authenticated,
73
+ policies: type.policies.slice(),
74
+ scopes: type.scopes.slice(),
71
75
  });
72
76
  const typeInGraph = objectTypeState.byGraph.get(graph.id);
73
77
  for (const field of type.fields.values()) {
@@ -100,16 +104,17 @@ function objectTypeBuilder() {
100
104
  fieldState.authenticated = true;
101
105
  }
102
106
  if (field.policies) {
103
- fieldState.policies.push(...field.policies);
107
+ fieldState.policies = (0, auth_js_1.mergeScopePolicies)(fieldState.policies, field.policies);
104
108
  }
105
109
  if (field.scopes) {
106
- fieldState.scopes.push(...field.scopes);
110
+ fieldState.scopes = (0, auth_js_1.mergeScopePolicies)(fieldState.scopes, field.scopes);
107
111
  }
108
112
  if (field.cost !== null) {
109
113
  fieldState.cost = (0, helpers_js_1.mathMax)(field.cost, fieldState.cost);
110
114
  }
111
115
  if (field.listSize !== null) {
112
116
  fieldState.listSize = {
117
+ printRequireOneSlicingArgument: false,
113
118
  assumedSize: (0, helpers_js_1.mathMaxNullable)(fieldState.listSize?.assumedSize, field.listSize.assumedSize),
114
119
  requireOneSlicingArgument: (fieldState.listSize?.requireOneSlicingArgument ?? true) &&
115
120
  field.listSize.requireOneSlicingArgument,
@@ -145,6 +150,9 @@ function objectTypeBuilder() {
145
150
  required: field.required,
146
151
  shareable: field.shareable,
147
152
  extension: field.extension,
153
+ authenticated: field.authenticated,
154
+ policies: field.policies,
155
+ scopes: field.scopes,
148
156
  used: field.used,
149
157
  usedAsKey,
150
158
  version: graph.version,
@@ -184,6 +192,27 @@ function objectTypeBuilder() {
184
192
  }
185
193
  }
186
194
  },
195
+ composeSupergraphState(objectType, _graphs, { supergraphState }) {
196
+ for (const interfaceName of objectType.interfaces) {
197
+ const interfaceState = supergraphState.interfaceTypes.get(interfaceName);
198
+ if (!interfaceState) {
199
+ throw new Error(`Interface "${interfaceName}" not found in Supergraph state`);
200
+ }
201
+ for (const [interfaceFieldName, interfaceField,] of interfaceState.fields) {
202
+ if (!interfaceState.hasInterfaceObject) {
203
+ continue;
204
+ }
205
+ const fieldState = objectType.fields.get(interfaceFieldName);
206
+ if (fieldState) {
207
+ fieldState.scopes = (0, auth_js_1.mergeScopePolicies)(fieldState.scopes, interfaceField.scopes);
208
+ fieldState.policies = (0, auth_js_1.mergeScopePolicies)(fieldState.policies, interfaceField.policies);
209
+ if (interfaceField.authenticated) {
210
+ fieldState.authenticated = true;
211
+ }
212
+ }
213
+ }
214
+ }
215
+ },
187
216
  composeSupergraphNode(objectType, graphs, { graphNameToId, supergraphState }) {
188
217
  const isQuery = objectType.name === "Query";
189
218
  const joinTypes = isQuery
@@ -573,13 +602,23 @@ function objectTypeBuilder() {
573
602
  .concat(resolvableFieldsFromInterfaceObjects
574
603
  .filter((f) => !objectType.fields.has(f.name))
575
604
  .map((field) => {
605
+ let scopes = [];
606
+ let policies = [];
607
+ let authenticated = false;
608
+ for (const fieldInGraph of field.byGraph.values()) {
609
+ scopes = (0, auth_js_1.mergeScopePolicies)(scopes, fieldInGraph.scopes);
610
+ policies = (0, auth_js_1.mergeScopePolicies)(policies, fieldInGraph.policies);
611
+ if (fieldInGraph.authenticated) {
612
+ authenticated = true;
613
+ }
614
+ }
576
615
  return {
577
616
  name: field.name,
578
617
  type: field.type,
579
618
  inaccessible: field.inaccessible,
580
- authenticated: field.authenticated,
581
- policies: field.policies,
582
- scopes: field.scopes,
619
+ authenticated,
620
+ policies,
621
+ scopes,
583
622
  cost: field.cost !== null
584
623
  ? {
585
624
  cost: field.cost,
@@ -4,6 +4,7 @@ exports.scalarTypeBuilder = scalarTypeBuilder;
4
4
  const helpers_js_1 = require("../../utils/helpers.js");
5
5
  const ast_js_1 = require("./ast.js");
6
6
  const common_js_1 = require("./common.js");
7
+ const auth_js_1 = require("../../utils/auth.js");
7
8
  function scalarTypeBuilder() {
8
9
  return {
9
10
  visitSubgraphState(graph, state, typeName, type) {
@@ -16,10 +17,10 @@ function scalarTypeBuilder() {
16
17
  scalarTypeState.authenticated = true;
17
18
  }
18
19
  if (type.policies) {
19
- scalarTypeState.policies.push(...type.policies);
20
+ scalarTypeState.policies = (0, auth_js_1.mergeScopePolicies)(scalarTypeState.policies, type.policies);
20
21
  }
21
22
  if (type.scopes) {
22
- scalarTypeState.scopes.push(...type.scopes);
23
+ scalarTypeState.scopes = (0, auth_js_1.mergeScopePolicies)(scalarTypeState.scopes, type.scopes);
23
24
  }
24
25
  if (type.cost !== null) {
25
26
  scalarTypeState.cost = (0, helpers_js_1.mathMax)(type.cost, scalarTypeState.cost);