@apollo/federation-internals 2.8.4 → 2.9.0-beta.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/dist/argumentCompositionStrategies.d.ts +17 -0
- package/dist/argumentCompositionStrategies.d.ts.map +1 -1
- package/dist/argumentCompositionStrategies.js +38 -0
- package/dist/argumentCompositionStrategies.js.map +1 -1
- package/dist/extractSubgraphsFromSupergraph.d.ts.map +1 -1
- package/dist/extractSubgraphsFromSupergraph.js +59 -8
- package/dist/extractSubgraphsFromSupergraph.js.map +1 -1
- package/dist/federation.d.ts +5 -2
- package/dist/federation.d.ts.map +1 -1
- package/dist/federation.js +16 -2
- package/dist/federation.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/operations.d.ts +3 -1
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +26 -5
- package/dist/operations.js.map +1 -1
- package/dist/specs/coreSpec.d.ts +1 -0
- package/dist/specs/coreSpec.d.ts.map +1 -1
- package/dist/specs/coreSpec.js +18 -0
- package/dist/specs/coreSpec.js.map +1 -1
- package/dist/specs/costSpec.d.ts +17 -0
- package/dist/specs/costSpec.d.ts.map +1 -0
- package/dist/specs/costSpec.js +49 -0
- package/dist/specs/costSpec.js.map +1 -0
- package/dist/specs/federationSpec.d.ts +3 -1
- package/dist/specs/federationSpec.d.ts.map +1 -1
- package/dist/specs/federationSpec.js +8 -1
- package/dist/specs/federationSpec.js.map +1 -1
- package/dist/supergraphs.d.ts.map +1 -1
- package/dist/supergraphs.js +1 -0
- package/dist/supergraphs.js.map +1 -1
- package/package.json +1 -1
- package/src/argumentCompositionStrategies.ts +37 -0
- package/src/extractSubgraphsFromSupergraph.ts +94 -7
- package/src/federation.ts +21 -2
- package/src/index.ts +1 -0
- package/src/operations.ts +41 -4
- package/src/specs/coreSpec.ts +21 -0
- package/src/specs/costSpec.ts +60 -0
- package/src/specs/federationSpec.ts +9 -1
- package/src/supergraphs.ts +1 -0
package/src/federation.ts
CHANGED
|
@@ -100,6 +100,7 @@ import {
|
|
|
100
100
|
SourceFieldDirectiveArgs,
|
|
101
101
|
SourceTypeDirectiveArgs,
|
|
102
102
|
} from "./specs/sourceSpec";
|
|
103
|
+
import { CostDirectiveArguments, ListSizeDirectiveArguments } from "./specs/costSpec";
|
|
103
104
|
|
|
104
105
|
const linkSpec = LINK_VERSIONS.latest();
|
|
105
106
|
const tagSpec = TAG_VERSIONS.latest();
|
|
@@ -1275,6 +1276,14 @@ export class FederationMetadata {
|
|
|
1275
1276
|
return this.getPost20FederationDirective(FederationDirectiveName.CONTEXT);
|
|
1276
1277
|
}
|
|
1277
1278
|
|
|
1279
|
+
costDirective(): Post20FederationDirectiveDefinition<CostDirectiveArguments> {
|
|
1280
|
+
return this.getPost20FederationDirective(FederationDirectiveName.COST);
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
listSizeDirective(): Post20FederationDirectiveDefinition<ListSizeDirectiveArguments> {
|
|
1284
|
+
return this.getPost20FederationDirective(FederationDirectiveName.LIST_SIZE);
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1278
1287
|
allFederationDirectives(): DirectiveDefinition[] {
|
|
1279
1288
|
const baseDirectives: DirectiveDefinition[] = [
|
|
1280
1289
|
this.keyDirective(),
|
|
@@ -1338,6 +1347,16 @@ export class FederationMetadata {
|
|
|
1338
1347
|
baseDirectives.push(fromContextDirective);
|
|
1339
1348
|
}
|
|
1340
1349
|
|
|
1350
|
+
const costDirective = this.costDirective();
|
|
1351
|
+
if (isFederationDirectiveDefinedInSchema(costDirective)) {
|
|
1352
|
+
baseDirectives.push(costDirective);
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
const listSizeDirective = this.listSizeDirective();
|
|
1356
|
+
if (isFederationDirectiveDefinedInSchema(listSizeDirective)) {
|
|
1357
|
+
baseDirectives.push(listSizeDirective);
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1341
1360
|
return baseDirectives;
|
|
1342
1361
|
}
|
|
1343
1362
|
|
|
@@ -1831,9 +1850,9 @@ export function setSchemaAsFed2Subgraph(schema: Schema, useLatest: boolean = fal
|
|
|
1831
1850
|
|
|
1832
1851
|
// This is the full @link declaration as added by `asFed2SubgraphDocument`. It's here primarily for uses by tests that print and match
|
|
1833
1852
|
// subgraph schema to avoid having to update 20+ tests every time we use a new directive or the order of import changes ...
|
|
1834
|
-
export const FEDERATION2_LINK_WITH_FULL_IMPORTS = '@link(url: "https://specs.apollo.dev/federation/v2.
|
|
1853
|
+
export const FEDERATION2_LINK_WITH_FULL_IMPORTS = '@link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject", "@authenticated", "@requiresScopes", "@policy", "@sourceAPI", "@sourceType", "@sourceField", "@context", "@fromContext", "@cost", "@listSize"])';
|
|
1835
1854
|
// This is the full @link declaration that is added when upgrading fed v1 subgraphs to v2 version. It should only be used by tests.
|
|
1836
|
-
export const FEDERATION2_LINK_WITH_AUTO_EXPANDED_IMPORTS = '@link(url: "https://specs.apollo.dev/federation/v2.
|
|
1855
|
+
export const FEDERATION2_LINK_WITH_AUTO_EXPANDED_IMPORTS = '@link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"])';
|
|
1837
1856
|
|
|
1838
1857
|
// This is the federation @link for tests that go through the SchemaUpgrader.
|
|
1839
1858
|
export const FEDERATION2_LINK_WITH_AUTO_EXPANDED_IMPORTS_UPGRADED = '@link(url: "https://specs.apollo.dev/federation/v2.4", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"])';
|
package/src/index.ts
CHANGED
package/src/operations.ts
CHANGED
|
@@ -56,6 +56,8 @@ import { assert, mapKeys, mapValues, MapWithCachedArrays, MultiMap, SetMultiMap
|
|
|
56
56
|
import { argumentsEquals, argumentsFromAST, isValidValue, valueToAST, valueToString } from "./values";
|
|
57
57
|
import { v1 as uuidv1 } from 'uuid';
|
|
58
58
|
|
|
59
|
+
export const DEFAULT_MIN_USAGES_TO_OPTIMIZE = 2;
|
|
60
|
+
|
|
59
61
|
function validate(condition: any, message: () => string, sourceAST?: ASTNode): asserts condition {
|
|
60
62
|
if (!condition) {
|
|
61
63
|
throw ERRORS.INVALID_GRAPHQL.err(message(), { nodes: sourceAST });
|
|
@@ -934,25 +936,55 @@ export class Operation extends DirectiveTargetElement<Operation> {
|
|
|
934
936
|
this.appliedDirectives,
|
|
935
937
|
);
|
|
936
938
|
}
|
|
939
|
+
|
|
940
|
+
private collectUndefinedVariablesFromFragments(fragments: NamedFragments): Variable[] {
|
|
941
|
+
const collector = new VariableCollector();
|
|
942
|
+
for (const namedFragment of fragments.definitions()) {
|
|
943
|
+
namedFragment.selectionSet.usedVariables().forEach(v => {
|
|
944
|
+
if (!this.variableDefinitions.definition(v)) {
|
|
945
|
+
collector.add(v);
|
|
946
|
+
}
|
|
947
|
+
});
|
|
948
|
+
}
|
|
949
|
+
return collector.variables();
|
|
950
|
+
}
|
|
937
951
|
|
|
938
952
|
// Returns a copy of this operation with the provided updated selection set and fragments.
|
|
939
|
-
private withUpdatedSelectionSetAndFragments(
|
|
953
|
+
private withUpdatedSelectionSetAndFragments(
|
|
954
|
+
newSelectionSet: SelectionSet,
|
|
955
|
+
newFragments: NamedFragments | undefined,
|
|
956
|
+
allAvailableVariables?: VariableDefinitions,
|
|
957
|
+
): Operation {
|
|
940
958
|
if (this.selectionSet === newSelectionSet && newFragments === this.fragments) {
|
|
941
959
|
return this;
|
|
942
960
|
}
|
|
961
|
+
|
|
962
|
+
let newVariableDefinitions = this.variableDefinitions;
|
|
963
|
+
if (allAvailableVariables && newFragments) {
|
|
964
|
+
const undefinedVariables = this.collectUndefinedVariablesFromFragments(newFragments);
|
|
965
|
+
if (undefinedVariables.length > 0) {
|
|
966
|
+
newVariableDefinitions = new VariableDefinitions();
|
|
967
|
+
newVariableDefinitions.addAll(this.variableDefinitions);
|
|
968
|
+
newVariableDefinitions.addAll(allAvailableVariables.filter(undefinedVariables));
|
|
969
|
+
}
|
|
970
|
+
}
|
|
943
971
|
|
|
944
972
|
return new Operation(
|
|
945
973
|
this.schema(),
|
|
946
974
|
this.rootKind,
|
|
947
975
|
newSelectionSet,
|
|
948
|
-
|
|
976
|
+
newVariableDefinitions,
|
|
949
977
|
newFragments,
|
|
950
978
|
this.name,
|
|
951
979
|
this.appliedDirectives,
|
|
952
980
|
);
|
|
953
981
|
}
|
|
954
982
|
|
|
955
|
-
optimize(
|
|
983
|
+
optimize(
|
|
984
|
+
fragments?: NamedFragments,
|
|
985
|
+
minUsagesToOptimize: number = DEFAULT_MIN_USAGES_TO_OPTIMIZE,
|
|
986
|
+
allAvailableVariables?: VariableDefinitions,
|
|
987
|
+
): Operation {
|
|
956
988
|
assert(minUsagesToOptimize >= 1, `Expected 'minUsagesToOptimize' to be at least 1, but got ${minUsagesToOptimize}`)
|
|
957
989
|
if (!fragments || fragments.isEmpty()) {
|
|
958
990
|
return this;
|
|
@@ -1001,11 +1033,16 @@ export class Operation extends DirectiveTargetElement<Operation> {
|
|
|
1001
1033
|
}
|
|
1002
1034
|
}
|
|
1003
1035
|
|
|
1004
|
-
return this.withUpdatedSelectionSetAndFragments(
|
|
1036
|
+
return this.withUpdatedSelectionSetAndFragments(
|
|
1037
|
+
optimizedSelection,
|
|
1038
|
+
finalFragments ?? undefined,
|
|
1039
|
+
allAvailableVariables,
|
|
1040
|
+
);
|
|
1005
1041
|
}
|
|
1006
1042
|
|
|
1007
1043
|
generateQueryFragments(): Operation {
|
|
1008
1044
|
const [minimizedSelectionSet, fragments] = this.selectionSet.minimizeSelectionSet();
|
|
1045
|
+
|
|
1009
1046
|
return new Operation(
|
|
1010
1047
|
this.schema(),
|
|
1011
1048
|
this.rootKind,
|
package/src/specs/coreSpec.ts
CHANGED
|
@@ -552,6 +552,27 @@ export class CoreSpecDefinition extends FeatureDefinition {
|
|
|
552
552
|
return feature.addElementsToSchema(schema);
|
|
553
553
|
}
|
|
554
554
|
|
|
555
|
+
applyFeatureAsLink(schema: Schema, feature: FeatureDefinition, purpose?: CorePurpose, imports?: CoreImport[]): GraphQLError[] {
|
|
556
|
+
const existing = schema.schemaDefinition.appliedDirectivesOf(linkDirectiveDefaultName).find((link) => link.arguments().url === feature.toString());
|
|
557
|
+
if (existing) {
|
|
558
|
+
existing.remove();
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
const coreDirective = this.coreDirective(schema);
|
|
562
|
+
const args: LinkDirectiveArgs = {
|
|
563
|
+
url: feature.toString(),
|
|
564
|
+
import: (existing?.arguments().import ?? []).concat(imports?.map((i) => i.as ? { name: `@${i.name}`, as: `@${i.as}` } : `@${i.name}`)),
|
|
565
|
+
feature: undefined,
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
if (this.supportPurposes() && purpose) {
|
|
569
|
+
args.for = purpose;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
schema.schemaDefinition.applyDirective(coreDirective, args);
|
|
573
|
+
return feature.addElementsToSchema(schema);
|
|
574
|
+
}
|
|
575
|
+
|
|
555
576
|
extractFeatureUrl(args: CoreOrLinkDirectiveArgs): FeatureUrl {
|
|
556
577
|
return FeatureUrl.parse(args[this.urlArgName()]!);
|
|
557
578
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { DirectiveLocation } from 'graphql';
|
|
2
|
+
import { createDirectiveSpecification } from '../directiveAndTypeSpecification';
|
|
3
|
+
import { FeatureDefinition, FeatureDefinitions, FeatureUrl, FeatureVersion } from './coreSpec';
|
|
4
|
+
import { ListType, NonNullType } from '../definitions';
|
|
5
|
+
import { registerKnownFeature } from '../knownCoreFeatures';
|
|
6
|
+
import { ARGUMENT_COMPOSITION_STRATEGIES } from '../argumentCompositionStrategies';
|
|
7
|
+
|
|
8
|
+
export const costIdentity = 'https://specs.apollo.dev/cost';
|
|
9
|
+
|
|
10
|
+
export class CostSpecDefinition extends FeatureDefinition {
|
|
11
|
+
constructor(version: FeatureVersion, readonly minimumFederationVersion: FeatureVersion) {
|
|
12
|
+
super(new FeatureUrl(costIdentity, 'cost', version), minimumFederationVersion);
|
|
13
|
+
|
|
14
|
+
this.registerDirective(createDirectiveSpecification({
|
|
15
|
+
name: 'cost',
|
|
16
|
+
locations: [
|
|
17
|
+
DirectiveLocation.ARGUMENT_DEFINITION,
|
|
18
|
+
DirectiveLocation.ENUM,
|
|
19
|
+
DirectiveLocation.FIELD_DEFINITION,
|
|
20
|
+
DirectiveLocation.INPUT_FIELD_DEFINITION,
|
|
21
|
+
DirectiveLocation.OBJECT,
|
|
22
|
+
DirectiveLocation.SCALAR
|
|
23
|
+
],
|
|
24
|
+
args: [{ name: 'weight', type: (schema) => new NonNullType(schema.intType()), compositionStrategy: ARGUMENT_COMPOSITION_STRATEGIES.MAX }],
|
|
25
|
+
composes: true,
|
|
26
|
+
repeatable: false,
|
|
27
|
+
supergraphSpecification: (fedVersion) => COST_VERSIONS.getMinimumRequiredVersion(fedVersion),
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
this.registerDirective(createDirectiveSpecification({
|
|
31
|
+
name: 'listSize',
|
|
32
|
+
locations: [DirectiveLocation.FIELD_DEFINITION],
|
|
33
|
+
args: [
|
|
34
|
+
{ name: 'assumedSize', type: (schema) => schema.intType(), compositionStrategy: ARGUMENT_COMPOSITION_STRATEGIES.NULLABLE_MAX },
|
|
35
|
+
{ name: 'slicingArguments', type: (schema) => new ListType(new NonNullType(schema.stringType())), compositionStrategy: ARGUMENT_COMPOSITION_STRATEGIES.NULLABLE_UNION },
|
|
36
|
+
{ name: 'sizedFields', type: (schema) => new ListType(new NonNullType(schema.stringType())), compositionStrategy: ARGUMENT_COMPOSITION_STRATEGIES.NULLABLE_UNION },
|
|
37
|
+
{ name: 'requireOneSlicingArgument', type: (schema) => schema.booleanType(), defaultValue: true, compositionStrategy: ARGUMENT_COMPOSITION_STRATEGIES.NULLABLE_AND },
|
|
38
|
+
],
|
|
39
|
+
composes: true,
|
|
40
|
+
repeatable: false,
|
|
41
|
+
supergraphSpecification: (fedVersion) => COST_VERSIONS.getMinimumRequiredVersion(fedVersion)
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const COST_VERSIONS = new FeatureDefinitions<CostSpecDefinition>(costIdentity)
|
|
47
|
+
.add(new CostSpecDefinition(new FeatureVersion(0, 1), new FeatureVersion(2, 9)));
|
|
48
|
+
|
|
49
|
+
registerKnownFeature(COST_VERSIONS);
|
|
50
|
+
|
|
51
|
+
export interface CostDirectiveArguments {
|
|
52
|
+
weight: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface ListSizeDirectiveArguments {
|
|
56
|
+
assumedSize?: number;
|
|
57
|
+
slicingArguments?: string[];
|
|
58
|
+
sizedFields?: string[];
|
|
59
|
+
requireOneSlicingArgument?: boolean;
|
|
60
|
+
}
|
|
@@ -20,6 +20,7 @@ import { REQUIRES_SCOPES_VERSIONS } from "./requiresScopesSpec";
|
|
|
20
20
|
import { POLICY_VERSIONS } from './policySpec';
|
|
21
21
|
import { SOURCE_VERSIONS } from './sourceSpec';
|
|
22
22
|
import { CONTEXT_VERSIONS } from './contextSpec';
|
|
23
|
+
import { COST_VERSIONS } from "./costSpec";
|
|
23
24
|
|
|
24
25
|
export const federationIdentity = 'https://specs.apollo.dev/federation';
|
|
25
26
|
|
|
@@ -48,6 +49,8 @@ export enum FederationDirectiveName {
|
|
|
48
49
|
SOURCE_FIELD = 'sourceField',
|
|
49
50
|
CONTEXT = 'context',
|
|
50
51
|
FROM_CONTEXT = 'fromContext',
|
|
52
|
+
COST = 'cost',
|
|
53
|
+
LIST_SIZE = 'listSize',
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
const fieldSetTypeSpec = createScalarTypeSpecification({ name: FederationTypeName.FIELD_SET });
|
|
@@ -182,6 +185,10 @@ export class FederationSpecDefinition extends FeatureDefinition {
|
|
|
182
185
|
if (version.gte(new FeatureVersion(2, 8))) {
|
|
183
186
|
this.registerSubFeature(CONTEXT_VERSIONS.find(new FeatureVersion(0, 1))!);
|
|
184
187
|
}
|
|
188
|
+
|
|
189
|
+
if (version.gte(new FeatureVersion(2, 9))) {
|
|
190
|
+
this.registerSubFeature(COST_VERSIONS.find(new FeatureVersion(0, 1))!);
|
|
191
|
+
}
|
|
185
192
|
}
|
|
186
193
|
}
|
|
187
194
|
|
|
@@ -194,6 +201,7 @@ export const FEDERATION_VERSIONS = new FeatureDefinitions<FederationSpecDefiniti
|
|
|
194
201
|
.add(new FederationSpecDefinition(new FeatureVersion(2, 5)))
|
|
195
202
|
.add(new FederationSpecDefinition(new FeatureVersion(2, 6)))
|
|
196
203
|
.add(new FederationSpecDefinition(new FeatureVersion(2, 7)))
|
|
197
|
-
.add(new FederationSpecDefinition(new FeatureVersion(2, 8)))
|
|
204
|
+
.add(new FederationSpecDefinition(new FeatureVersion(2, 8)))
|
|
205
|
+
.add(new FederationSpecDefinition(new FeatureVersion(2, 9)));
|
|
198
206
|
|
|
199
207
|
registerKnownFeature(FEDERATION_VERSIONS);
|
package/src/supergraphs.ts
CHANGED
|
@@ -40,6 +40,7 @@ export const ROUTER_SUPPORTED_SUPERGRAPH_FEATURES = new Set([
|
|
|
40
40
|
'https://specs.apollo.dev/policy/v0.1',
|
|
41
41
|
'https://specs.apollo.dev/source/v0.1',
|
|
42
42
|
'https://specs.apollo.dev/context/v0.1',
|
|
43
|
+
'https://specs.apollo.dev/cost/v0.1',
|
|
43
44
|
]);
|
|
44
45
|
|
|
45
46
|
const coreVersionZeroDotOneUrl = FeatureUrl.parse('https://specs.apollo.dev/core/v0.1');
|