@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.
- package/cjs/subgraph/state.js +21 -32
- package/cjs/subgraph/validation/rules/elements/authenticated.js +23 -2
- package/cjs/subgraph/validation/rules/elements/cost.js +12 -2
- package/cjs/subgraph/validation/rules/elements/list-size.js +10 -8
- package/cjs/subgraph/validation/rules/elements/policy.js +25 -5
- package/cjs/subgraph/validation/rules/elements/requires-scopes.js +23 -2
- package/cjs/supergraph/composition/ast.js +5 -14
- package/cjs/supergraph/composition/enum-type.js +3 -2
- package/cjs/supergraph/composition/interface-type.js +32 -11
- package/cjs/supergraph/composition/object-type.js +46 -7
- package/cjs/supergraph/composition/scalar-type.js +3 -2
- package/cjs/supergraph/state.js +43 -6
- package/cjs/supergraph/validation/rules/auth-on-requires-rule.js +211 -0
- package/cjs/supergraph/validation/rules/external-missing-on-base-rule.js +26 -1
- package/cjs/supergraph/validation/rules/list-size-slicing-arguments-rule.js +69 -0
- package/cjs/supergraph/validation/validate-supergraph.js +5 -0
- package/cjs/utils/auth.js +34 -0
- package/esm/subgraph/state.js +21 -32
- package/esm/subgraph/validation/rules/elements/authenticated.js +24 -3
- package/esm/subgraph/validation/rules/elements/cost.js +12 -2
- package/esm/subgraph/validation/rules/elements/list-size.js +10 -8
- package/esm/subgraph/validation/rules/elements/policy.js +26 -6
- package/esm/subgraph/validation/rules/elements/requires-scopes.js +24 -3
- package/esm/supergraph/composition/ast.js +5 -14
- package/esm/supergraph/composition/enum-type.js +3 -2
- package/esm/supergraph/composition/interface-type.js +33 -12
- package/esm/supergraph/composition/object-type.js +46 -7
- package/esm/supergraph/composition/scalar-type.js +3 -2
- package/esm/supergraph/state.js +43 -6
- package/esm/supergraph/validation/rules/auth-on-requires-rule.js +208 -0
- package/esm/supergraph/validation/rules/external-missing-on-base-rule.js +26 -1
- package/esm/supergraph/validation/rules/list-size-slicing-arguments-rule.js +66 -0
- package/esm/supergraph/validation/validate-supergraph.js +5 -0
- package/esm/utils/auth.js +31 -0
- package/package.json +1 -1
- package/typings/subgraph/state.d.cts +1 -6
- package/typings/subgraph/state.d.ts +1 -6
- package/typings/subgraph/validation/validation-context.d.cts +0 -3
- package/typings/subgraph/validation/validation-context.d.ts +0 -3
- package/typings/supergraph/composition/ast.d.cts +1 -0
- package/typings/supergraph/composition/ast.d.ts +1 -0
- package/typings/supergraph/composition/common.d.cts +4 -0
- package/typings/supergraph/composition/common.d.ts +4 -0
- package/typings/supergraph/composition/interface-type.d.cts +3 -0
- package/typings/supergraph/composition/interface-type.d.ts +3 -0
- package/typings/supergraph/composition/object-type.d.cts +6 -0
- package/typings/supergraph/composition/object-type.d.ts +6 -0
- package/typings/supergraph/state.d.cts +1 -0
- package/typings/supergraph/state.d.ts +1 -0
- package/typings/supergraph/validation/rules/auth-on-requires-rule.d.cts +5 -0
- package/typings/supergraph/validation/rules/auth-on-requires-rule.d.ts +5 -0
- package/typings/supergraph/validation/rules/external-missing-on-base-rule.d.cts +2 -1
- package/typings/supergraph/validation/rules/external-missing-on-base-rule.d.ts +2 -1
- package/typings/supergraph/validation/rules/list-size-slicing-arguments-rule.d.cts +5 -0
- package/typings/supergraph/validation/rules/list-size-slicing-arguments-rule.d.ts +5 -0
- package/typings/utils/auth.d.cts +2 -0
- package/typings/utils/auth.d.ts +2 -0
package/cjs/subgraph/state.js
CHANGED
|
@@ -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)
|
|
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)
|
|
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
|
-
|
|
730
|
-
|
|
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
|
-
|
|
736
|
-
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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.
|
|
49
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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 (!
|
|
187
|
-
|
|
186
|
+
else if (!isListType(targetField.type)) {
|
|
187
|
+
nonListFields.push(sizedField);
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
|
-
if (
|
|
191
|
-
|
|
192
|
-
context.reportError(new graphql_1.GraphQLError(`${coordinate} references "${fieldName}" field in @listSize(sizedFields:) argument that is not
|
|
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: "
|
|
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 (
|
|
59
|
-
typeDef.kind === graphql_1.Kind.
|
|
60
|
-
|
|
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.
|
|
72
|
-
|
|
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.
|
|
71
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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.
|
|
20
|
+
enumTypeState.policies = (0, auth_js_1.mergeScopePolicies)(enumTypeState.policies, type.policies);
|
|
20
21
|
}
|
|
21
22
|
if (type.scopes) {
|
|
22
|
-
enumTypeState.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.
|
|
57
|
+
fieldState.policies = (0, auth_js_1.mergeScopePolicies)(fieldState.policies, field.policies);
|
|
66
58
|
}
|
|
67
59
|
if (field.scopes) {
|
|
68
|
-
fieldState.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.
|
|
37
|
+
objectTypeState.policies = (0, auth_js_1.mergeScopePolicies)(objectTypeState.policies, type.policies);
|
|
37
38
|
}
|
|
38
39
|
if (type.scopes) {
|
|
39
|
-
objectTypeState.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.
|
|
107
|
+
fieldState.policies = (0, auth_js_1.mergeScopePolicies)(fieldState.policies, field.policies);
|
|
104
108
|
}
|
|
105
109
|
if (field.scopes) {
|
|
106
|
-
fieldState.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
|
|
581
|
-
policies
|
|
582
|
-
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.
|
|
20
|
+
scalarTypeState.policies = (0, auth_js_1.mergeScopePolicies)(scalarTypeState.policies, type.policies);
|
|
20
21
|
}
|
|
21
22
|
if (type.scopes) {
|
|
22
|
-
scalarTypeState.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);
|