@apollo/federation-internals 2.8.2 → 2.8.3-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/definitions.d.ts +4 -4
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +63 -51
- package/dist/definitions.js.map +1 -1
- package/dist/federation.d.ts +1 -1
- package/dist/federation.d.ts.map +1 -1
- package/dist/federation.js +2 -2
- package/dist/federation.js.map +1 -1
- package/dist/schemaUpgrader.js +1 -1
- package/dist/schemaUpgrader.js.map +1 -1
- package/package.json +1 -1
- package/src/definitions.ts +70 -53
- package/src/federation.ts +3 -3
- package/src/schemaUpgrader.ts +1 -1
package/src/definitions.ts
CHANGED
|
@@ -59,6 +59,8 @@ import { coreFeatureDefinitionIfKnown } from "./knownCoreFeatures";
|
|
|
59
59
|
const validationErrorCode = 'GraphQLValidationFailed';
|
|
60
60
|
const DEFAULT_VALIDATION_ERROR_MESSAGE = 'The schema is not a valid GraphQL schema.';
|
|
61
61
|
|
|
62
|
+
const EMPTY_SET = new Set<never>();
|
|
63
|
+
|
|
62
64
|
export const ErrGraphQLValidationFailed = (causes: GraphQLError[], message: string = DEFAULT_VALIDATION_ERROR_MESSAGE) =>
|
|
63
65
|
aggregateError(validationErrorCode, message, causes);
|
|
64
66
|
|
|
@@ -660,7 +662,7 @@ export abstract class NamedSchemaElement<TOwnType extends NamedSchemaElement<TOw
|
|
|
660
662
|
}
|
|
661
663
|
|
|
662
664
|
abstract class BaseNamedType<TReferencer, TOwnType extends NamedType & NamedSchemaElement<TOwnType, Schema, TReferencer>> extends NamedSchemaElement<TOwnType, Schema, TReferencer> {
|
|
663
|
-
protected _referencers?: TReferencer
|
|
665
|
+
protected _referencers?: Set<TReferencer>;
|
|
664
666
|
protected _extensions?: Extension<TOwnType>[];
|
|
665
667
|
public preserveEmptyDefinition: boolean = false;
|
|
666
668
|
|
|
@@ -669,19 +671,12 @@ abstract class BaseNamedType<TReferencer, TOwnType extends NamedType & NamedSche
|
|
|
669
671
|
}
|
|
670
672
|
|
|
671
673
|
private addReferencer(referencer: TReferencer) {
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
this._referencers.push(referencer);
|
|
675
|
-
}
|
|
676
|
-
} else {
|
|
677
|
-
this._referencers = [ referencer ];
|
|
678
|
-
}
|
|
674
|
+
this._referencers ??= new Set();
|
|
675
|
+
this._referencers.add(referencer);
|
|
679
676
|
}
|
|
680
677
|
|
|
681
678
|
private removeReferencer(referencer: TReferencer) {
|
|
682
|
-
|
|
683
|
-
removeArrayElement(referencer, this._referencers);
|
|
684
|
-
}
|
|
679
|
+
this._referencers?.delete(referencer)
|
|
685
680
|
}
|
|
686
681
|
|
|
687
682
|
get coordinate(): string {
|
|
@@ -789,10 +784,11 @@ abstract class BaseNamedType<TReferencer, TOwnType extends NamedType & NamedSche
|
|
|
789
784
|
this.removeAppliedDirectives();
|
|
790
785
|
this.removeInnerElements();
|
|
791
786
|
// Remove this type's references.
|
|
792
|
-
const toReturn =
|
|
787
|
+
const toReturn: TReferencer[] = [];
|
|
788
|
+
this._referencers?.forEach(r => {
|
|
793
789
|
SchemaElement.prototype['removeTypeReferenceInternal'].call(r, this);
|
|
794
|
-
|
|
795
|
-
})
|
|
790
|
+
toReturn.push(r);
|
|
791
|
+
});
|
|
796
792
|
this._referencers = undefined;
|
|
797
793
|
// Remove this type from its parent schema.
|
|
798
794
|
Schema.prototype['removeTypeInternal'].call(this._parent, this);
|
|
@@ -820,8 +816,8 @@ abstract class BaseNamedType<TReferencer, TOwnType extends NamedType & NamedSche
|
|
|
820
816
|
|
|
821
817
|
protected abstract removeReferenceRecursive(ref: TReferencer): void;
|
|
822
818
|
|
|
823
|
-
referencers():
|
|
824
|
-
return this._referencers ??
|
|
819
|
+
referencers(): ReadonlySet<TReferencer> {
|
|
820
|
+
return this._referencers ?? EMPTY_SET;
|
|
825
821
|
}
|
|
826
822
|
|
|
827
823
|
isReferenced(): boolean {
|
|
@@ -1261,7 +1257,7 @@ export class Schema {
|
|
|
1261
1257
|
if (!this.apiSchema) {
|
|
1262
1258
|
this.validate();
|
|
1263
1259
|
|
|
1264
|
-
const apiSchema = this.clone();
|
|
1260
|
+
const apiSchema = this.clone(undefined, false);
|
|
1265
1261
|
|
|
1266
1262
|
// As we compute the API schema of a supergraph, we want to ignore explicit definitions of `@defer` and `@stream` because
|
|
1267
1263
|
// those correspond to the merging of potential definitions from the subgraphs, but whether the supergraph API schema
|
|
@@ -1611,9 +1607,9 @@ export class Schema {
|
|
|
1611
1607
|
this.isValidated = true;
|
|
1612
1608
|
}
|
|
1613
1609
|
|
|
1614
|
-
clone(builtIns?: SchemaBlueprint): Schema {
|
|
1610
|
+
clone(builtIns?: SchemaBlueprint, cloneJoinDirectives: boolean = true): Schema {
|
|
1615
1611
|
const cloned = new Schema(builtIns ?? this.blueprint);
|
|
1616
|
-
copy(this, cloned);
|
|
1612
|
+
copy(this, cloned, cloneJoinDirectives);
|
|
1617
1613
|
if (this.isValidated) {
|
|
1618
1614
|
cloned.assumeValid();
|
|
1619
1615
|
}
|
|
@@ -2124,7 +2120,13 @@ export class ObjectType extends FieldBasedType<ObjectType, ObjectTypeReferencer>
|
|
|
2124
2120
|
}
|
|
2125
2121
|
|
|
2126
2122
|
unionsWhereMember(): readonly UnionType[] {
|
|
2127
|
-
|
|
2123
|
+
const unions: UnionType[] = [];
|
|
2124
|
+
this._referencers?.forEach((r) => {
|
|
2125
|
+
if (r instanceof BaseNamedType && isUnionType(r)) {
|
|
2126
|
+
unions.push(r);
|
|
2127
|
+
}
|
|
2128
|
+
});
|
|
2129
|
+
return unions;
|
|
2128
2130
|
}
|
|
2129
2131
|
}
|
|
2130
2132
|
|
|
@@ -2133,7 +2135,13 @@ export class InterfaceType extends FieldBasedType<InterfaceType, InterfaceTypeRe
|
|
|
2133
2135
|
readonly astDefinitionKind = Kind.INTERFACE_TYPE_DEFINITION;
|
|
2134
2136
|
|
|
2135
2137
|
allImplementations(): (ObjectType | InterfaceType)[] {
|
|
2136
|
-
|
|
2138
|
+
const implementations: (ObjectType | InterfaceType)[] = [];
|
|
2139
|
+
this.referencers().forEach(ref => {
|
|
2140
|
+
if (ref.kind === 'ObjectType' || ref.kind === 'InterfaceType') {
|
|
2141
|
+
implementations.push(ref);
|
|
2142
|
+
}
|
|
2143
|
+
});
|
|
2144
|
+
return implementations;
|
|
2137
2145
|
}
|
|
2138
2146
|
|
|
2139
2147
|
possibleRuntimeTypes(): readonly ObjectType[] {
|
|
@@ -2895,7 +2903,7 @@ export class DirectiveDefinition<TApplicationArgs extends {[key: string]: any} =
|
|
|
2895
2903
|
private _args?: MapWithCachedArrays<string, ArgumentDefinition<DirectiveDefinition>>;
|
|
2896
2904
|
repeatable: boolean = false;
|
|
2897
2905
|
private readonly _locations: DirectiveLocation[] = [];
|
|
2898
|
-
private _referencers?: Directive<SchemaElement<any, any>, TApplicationArgs
|
|
2906
|
+
private _referencers?: Set<Directive<SchemaElement<any, any>, TApplicationArgs>>;
|
|
2899
2907
|
|
|
2900
2908
|
constructor(name: string, readonly isBuiltIn: boolean = false) {
|
|
2901
2909
|
super(name);
|
|
@@ -2999,25 +3007,19 @@ export class DirectiveDefinition<TApplicationArgs extends {[key: string]: any} =
|
|
|
2999
3007
|
return this.locations.some((loc) => isTypeSystemDirectiveLocation(loc));
|
|
3000
3008
|
}
|
|
3001
3009
|
|
|
3002
|
-
applications():
|
|
3003
|
-
|
|
3010
|
+
applications(): ReadonlySet<Directive<SchemaElement<any, any>, TApplicationArgs>> {
|
|
3011
|
+
this._referencers ??= new Set();
|
|
3012
|
+
return this._referencers;
|
|
3004
3013
|
}
|
|
3005
3014
|
|
|
3006
3015
|
private addReferencer(referencer: Directive<SchemaElement<any, any>, TApplicationArgs>) {
|
|
3007
3016
|
assert(referencer, 'Referencer should exists');
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
this._referencers.push(referencer);
|
|
3011
|
-
}
|
|
3012
|
-
} else {
|
|
3013
|
-
this._referencers = [ referencer ];
|
|
3014
|
-
}
|
|
3017
|
+
this._referencers ??= new Set();
|
|
3018
|
+
this._referencers.add(referencer);
|
|
3015
3019
|
}
|
|
3016
3020
|
|
|
3017
3021
|
private removeReferencer(referencer: Directive<SchemaElement<any, any>, TApplicationArgs>) {
|
|
3018
|
-
|
|
3019
|
-
removeArrayElement(referencer, this._referencers);
|
|
3020
|
-
}
|
|
3022
|
+
this._referencers?.delete(referencer);
|
|
3021
3023
|
}
|
|
3022
3024
|
|
|
3023
3025
|
protected removeTypeReference(type: NamedType) {
|
|
@@ -3048,7 +3050,7 @@ export class DirectiveDefinition<TApplicationArgs extends {[key: string]: any} =
|
|
|
3048
3050
|
// doesn't store a link to that definition. Instead, we fetch the definition
|
|
3049
3051
|
// from the schema when requested. So we don't have to do anything on the
|
|
3050
3052
|
// referencers other than clear them (and return the pre-cleared set).
|
|
3051
|
-
const toReturn = this._referencers ?? [];
|
|
3053
|
+
const toReturn = Array.from(this._referencers ?? []);
|
|
3052
3054
|
this._referencers = undefined;
|
|
3053
3055
|
// Remove this directive definition from its parent schema.
|
|
3054
3056
|
Schema.prototype['removeDirectiveInternal'].call(this._parent, this);
|
|
@@ -3598,7 +3600,7 @@ export function copyDirectiveDefinitionToSchema({
|
|
|
3598
3600
|
);
|
|
3599
3601
|
}
|
|
3600
3602
|
|
|
3601
|
-
function copy(source: Schema, dest: Schema) {
|
|
3603
|
+
function copy(source: Schema, dest: Schema, cloneJoinDirectives: boolean) {
|
|
3602
3604
|
// We shallow copy types first so any future reference to any of them can be dereferenced.
|
|
3603
3605
|
for (const type of typesToCopy(source, dest)) {
|
|
3604
3606
|
dest.addType(newNamedType(type.kind, type.name));
|
|
@@ -3615,7 +3617,7 @@ function copy(source: Schema, dest: Schema) {
|
|
|
3615
3617
|
|
|
3616
3618
|
copySchemaDefinitionInner(source.schemaDefinition, dest.schemaDefinition);
|
|
3617
3619
|
for (const type of typesToCopy(source, dest)) {
|
|
3618
|
-
copyNamedTypeInner(type, dest.type(type.name)
|
|
3620
|
+
copyNamedTypeInner(type, dest.type(type.name)!, cloneJoinDirectives);
|
|
3619
3621
|
}
|
|
3620
3622
|
}
|
|
3621
3623
|
|
|
@@ -3655,7 +3657,7 @@ function copySchemaDefinitionInner(source: SchemaDefinition, dest: SchemaDefinit
|
|
|
3655
3657
|
dest.sourceAST = source.sourceAST;
|
|
3656
3658
|
}
|
|
3657
3659
|
|
|
3658
|
-
function copyNamedTypeInner(source: NamedType, dest: NamedType) {
|
|
3660
|
+
function copyNamedTypeInner(source: NamedType, dest: NamedType, cloneJoinDirectives: boolean) {
|
|
3659
3661
|
dest.preserveEmptyDefinition = source.preserveEmptyDefinition;
|
|
3660
3662
|
const extensionsMap = copyExtensions(source, dest);
|
|
3661
3663
|
// Same as copyAppliedDirectives, but as the directive applies to the type, we need to remember if the application
|
|
@@ -3672,7 +3674,7 @@ function copyNamedTypeInner(source: NamedType, dest: NamedType) {
|
|
|
3672
3674
|
for (const sourceField of source.fields()) {
|
|
3673
3675
|
const destField = destFieldBasedType.addField(new FieldDefinition(sourceField.name));
|
|
3674
3676
|
copyOfExtension(extensionsMap, sourceField, destField);
|
|
3675
|
-
copyFieldDefinitionInner(sourceField, destField);
|
|
3677
|
+
copyFieldDefinitionInner(sourceField, destField, cloneJoinDirectives);
|
|
3676
3678
|
}
|
|
3677
3679
|
for (const sourceImpl of source.interfaceImplementations()) {
|
|
3678
3680
|
const destImpl = destFieldBasedType.addImplementedInterface(sourceImpl.interface.name);
|
|
@@ -3692,7 +3694,7 @@ function copyNamedTypeInner(source: NamedType, dest: NamedType) {
|
|
|
3692
3694
|
const destValue = destEnumType.addValue(sourceValue.name);
|
|
3693
3695
|
destValue.description = sourceValue.description;
|
|
3694
3696
|
copyOfExtension(extensionsMap, sourceValue, destValue);
|
|
3695
|
-
copyAppliedDirectives(sourceValue, destValue);
|
|
3697
|
+
copyAppliedDirectives(sourceValue, destValue, cloneJoinDirectives);
|
|
3696
3698
|
}
|
|
3697
3699
|
break
|
|
3698
3700
|
case 'InputObjectType':
|
|
@@ -3700,13 +3702,13 @@ function copyNamedTypeInner(source: NamedType, dest: NamedType) {
|
|
|
3700
3702
|
for (const sourceField of source.fields()) {
|
|
3701
3703
|
const destField = destInputType.addField(new InputFieldDefinition(sourceField.name));
|
|
3702
3704
|
copyOfExtension(extensionsMap, sourceField, destField);
|
|
3703
|
-
copyInputFieldDefinitionInner(sourceField, destField);
|
|
3705
|
+
copyInputFieldDefinitionInner(sourceField, destField, cloneJoinDirectives);
|
|
3704
3706
|
}
|
|
3705
3707
|
}
|
|
3706
3708
|
}
|
|
3707
3709
|
|
|
3708
|
-
function copyAppliedDirectives(source: SchemaElement<any, any>, dest: SchemaElement<any, any
|
|
3709
|
-
source.appliedDirectives.forEach((d) => copyAppliedDirective(d, dest));
|
|
3710
|
+
function copyAppliedDirectives(source: SchemaElement<any, any>, dest: SchemaElement<any, any>, cloneJoinDirectives: boolean) {
|
|
3711
|
+
source.appliedDirectives.filter(d => cloneJoinDirectives || !d.name.startsWith('join__')).forEach((d) => copyAppliedDirective(d, dest));
|
|
3710
3712
|
}
|
|
3711
3713
|
|
|
3712
3714
|
function copyAppliedDirective(source: Directive<any, any>, dest: SchemaElement<any, any>): Directive<any, any> {
|
|
@@ -3715,23 +3717,27 @@ function copyAppliedDirective(source: Directive<any, any>, dest: SchemaElement<a
|
|
|
3715
3717
|
return res;
|
|
3716
3718
|
}
|
|
3717
3719
|
|
|
3718
|
-
function copyFieldDefinitionInner<P extends ObjectType | InterfaceType>(source: FieldDefinition<P>, dest: FieldDefinition<P
|
|
3720
|
+
function copyFieldDefinitionInner<P extends ObjectType | InterfaceType>(source: FieldDefinition<P>, dest: FieldDefinition<P>, cloneJoinDirectives: boolean) {
|
|
3719
3721
|
const type = copyWrapperTypeOrTypeRef(source.type, dest.schema()) as OutputType;
|
|
3720
3722
|
dest.type = type;
|
|
3721
3723
|
for (const arg of source.arguments()) {
|
|
3722
3724
|
const argType = copyWrapperTypeOrTypeRef(arg.type, dest.schema());
|
|
3723
|
-
copyArgumentDefinitionInner(
|
|
3725
|
+
copyArgumentDefinitionInner({
|
|
3726
|
+
source: arg,
|
|
3727
|
+
dest: dest.addArgument(arg.name, argType as InputType),
|
|
3728
|
+
cloneJoinDirectives,
|
|
3729
|
+
});
|
|
3724
3730
|
}
|
|
3725
|
-
copyAppliedDirectives(source, dest);
|
|
3731
|
+
copyAppliedDirectives(source, dest, cloneJoinDirectives);
|
|
3726
3732
|
dest.description = source.description;
|
|
3727
3733
|
dest.sourceAST = source.sourceAST;
|
|
3728
3734
|
}
|
|
3729
3735
|
|
|
3730
|
-
function copyInputFieldDefinitionInner(source: InputFieldDefinition, dest: InputFieldDefinition) {
|
|
3736
|
+
function copyInputFieldDefinitionInner(source: InputFieldDefinition, dest: InputFieldDefinition, cloneJoinDirectives: boolean) {
|
|
3731
3737
|
const type = copyWrapperTypeOrTypeRef(source.type, dest.schema()) as InputType;
|
|
3732
3738
|
dest.type = type;
|
|
3733
3739
|
dest.defaultValue = source.defaultValue;
|
|
3734
|
-
copyAppliedDirectives(source, dest);
|
|
3740
|
+
copyAppliedDirectives(source, dest, cloneJoinDirectives);
|
|
3735
3741
|
dest.description = source.description;
|
|
3736
3742
|
dest.sourceAST = source.sourceAST;
|
|
3737
3743
|
}
|
|
@@ -3750,16 +3756,22 @@ function copyWrapperTypeOrTypeRef(source: Type | undefined, destParent: Schema):
|
|
|
3750
3756
|
}
|
|
3751
3757
|
}
|
|
3752
3758
|
|
|
3753
|
-
function copyArgumentDefinitionInner<P extends FieldDefinition<any> | DirectiveDefinition>(
|
|
3759
|
+
function copyArgumentDefinitionInner<P extends FieldDefinition<any> | DirectiveDefinition>({
|
|
3760
|
+
source,
|
|
3761
|
+
dest,
|
|
3762
|
+
copyDirectiveApplications = true,
|
|
3763
|
+
cloneJoinDirectives,
|
|
3764
|
+
}: {
|
|
3754
3765
|
source: ArgumentDefinition<P>,
|
|
3755
3766
|
dest: ArgumentDefinition<P>,
|
|
3756
|
-
copyDirectiveApplications
|
|
3757
|
-
|
|
3767
|
+
copyDirectiveApplications?: boolean,
|
|
3768
|
+
cloneJoinDirectives: boolean,
|
|
3769
|
+
}) {
|
|
3758
3770
|
const type = copyWrapperTypeOrTypeRef(source.type, dest.schema()) as InputType;
|
|
3759
3771
|
dest.type = type;
|
|
3760
3772
|
dest.defaultValue = source.defaultValue;
|
|
3761
3773
|
if (copyDirectiveApplications) {
|
|
3762
|
-
copyAppliedDirectives(source, dest);
|
|
3774
|
+
copyAppliedDirectives(source, dest, cloneJoinDirectives);
|
|
3763
3775
|
}
|
|
3764
3776
|
dest.description = source.description;
|
|
3765
3777
|
dest.sourceAST = source.sourceAST;
|
|
@@ -3781,7 +3793,12 @@ function copyDirectiveDefinitionInner(
|
|
|
3781
3793
|
|
|
3782
3794
|
for (const arg of source.arguments()) {
|
|
3783
3795
|
const type = copyWrapperTypeOrTypeRef(arg.type, dest.schema());
|
|
3784
|
-
copyArgumentDefinitionInner(
|
|
3796
|
+
copyArgumentDefinitionInner({
|
|
3797
|
+
source: arg,
|
|
3798
|
+
dest: dest.addArgument(arg.name, type as InputType),
|
|
3799
|
+
copyDirectiveApplications: copyDirectiveApplicationsInArguments,
|
|
3800
|
+
cloneJoinDirectives: true,
|
|
3801
|
+
});
|
|
3785
3802
|
}
|
|
3786
3803
|
dest.repeatable = source.repeatable;
|
|
3787
3804
|
dest.addLocations(...locations);
|
package/src/federation.ts
CHANGED
|
@@ -1195,7 +1195,7 @@ export class FederationMetadata {
|
|
|
1195
1195
|
): Post20FederationDirectiveDefinition<TApplicationArgs> {
|
|
1196
1196
|
return this.getFederationDirective<TApplicationArgs>(name) ?? {
|
|
1197
1197
|
name,
|
|
1198
|
-
applications: () => new
|
|
1198
|
+
applications: () => new Set<Directive<any, TApplicationArgs>>(),
|
|
1199
1199
|
};
|
|
1200
1200
|
}
|
|
1201
1201
|
|
|
@@ -1391,7 +1391,7 @@ export class FederationMetadata {
|
|
|
1391
1391
|
|
|
1392
1392
|
export type FederationDirectiveNotDefinedInSchema<TApplicationArgs extends {[key: string]: any}> = {
|
|
1393
1393
|
name: string,
|
|
1394
|
-
applications: () =>
|
|
1394
|
+
applications: () => ReadonlySet<Directive<any, TApplicationArgs>>,
|
|
1395
1395
|
}
|
|
1396
1396
|
|
|
1397
1397
|
export type Post20FederationDirectiveDefinition<TApplicationArgs extends {[key: string]: any}> =
|
|
@@ -2040,7 +2040,7 @@ function completeFed1SubgraphSchema(schema: Schema): GraphQLError[] {
|
|
|
2040
2040
|
// definition to re-add the "correct" version, we'd have to re-attach existing applications (doable but not
|
|
2041
2041
|
// done). This assert is so we notice it quickly if that ever happens (again, unlikely, because fed1 schema
|
|
2042
2042
|
// is a backward compatibility thing and there is no reason to expand that too much in the future).
|
|
2043
|
-
assert(directive.applications().
|
|
2043
|
+
assert(directive.applications().size === 0, `${directive} shouldn't have had validation at that places`);
|
|
2044
2044
|
|
|
2045
2045
|
// The patterns we recognize and "correct" (by essentially ignoring the definition)
|
|
2046
2046
|
// are:
|
package/src/schemaUpgrader.ts
CHANGED
|
@@ -233,7 +233,7 @@ export function upgradeSubgraphsIfNecessary(inputs: Subgraphs): UpgradeResult {
|
|
|
233
233
|
for (const subgraph of inputs.values()) {
|
|
234
234
|
if (subgraph.isFed2Subgraph()) {
|
|
235
235
|
subgraphs.add(subgraph);
|
|
236
|
-
if (subgraph.metadata().interfaceObjectDirective().applications().
|
|
236
|
+
if (subgraph.metadata().interfaceObjectDirective().applications().size > 0) {
|
|
237
237
|
subgraphsUsingInterfaceObject.push(subgraph.name);
|
|
238
238
|
}
|
|
239
239
|
} else {
|