@theguild/federation-composition 0.7.0 → 0.7.1-rc-20240104160136-52edd83

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.
@@ -138,7 +138,8 @@ function visitFields({ context, selectionSet, typeDefinition, interceptField, in
138
138
  }
139
139
  break;
140
140
  }
141
- if (interceptDirective && selection.directives?.length) {
141
+ const isTypename = selection.name.value === '__typename';
142
+ if (!isTypename && interceptDirective && selection.directives?.length) {
142
143
  for (const directive of selection.directives) {
143
144
  interceptDirective({
144
145
  directiveName: directive.name.value,
@@ -146,21 +147,23 @@ function visitFields({ context, selectionSet, typeDefinition, interceptField, in
146
147
  });
147
148
  }
148
149
  }
149
- context.markAsUsed('fields', typeDefinition.kind, typeDefinition.name.value, selectionFieldDef.name.value);
150
- if (interceptField) {
150
+ if (!isTypename) {
151
+ context.markAsUsed('fields', typeDefinition.kind, typeDefinition.name.value, selectionFieldDef.name.value);
152
+ }
153
+ if (!isTypename && interceptField) {
151
154
  interceptField({
152
155
  typeDefinition,
153
156
  fieldName: selection.name.value,
154
157
  });
155
158
  }
156
- if (selectionFieldDef.arguments?.length && interceptArguments) {
159
+ if (!isTypename && selectionFieldDef.arguments?.length && interceptArguments) {
157
160
  interceptArguments({
158
161
  typeDefinition,
159
162
  fieldName: selection.name.value,
160
163
  });
161
164
  continue;
162
165
  }
163
- if (interceptNonExternalField || interceptExternalField) {
166
+ if (!isTypename && (interceptNonExternalField || interceptExternalField)) {
164
167
  const isExternal = selectionFieldDef.directives?.some(d => context.isAvailableFederationDirective('external', d));
165
168
  const fieldName = selection.name.value;
166
169
  const fieldDef = typeDefinition.fields?.find(field => field.name.value === fieldName);
@@ -189,7 +192,8 @@ function visitFields({ context, selectionSet, typeDefinition, interceptField, in
189
192
  if (!innerTypeDef) {
190
193
  continue;
191
194
  }
192
- if (interceptInterfaceType &&
195
+ if (!isTypename &&
196
+ interceptInterfaceType &&
193
197
  (innerTypeDef.kind === graphql_1.Kind.INTERFACE_TYPE_DEFINITION ||
194
198
  innerTypeDef.kind === graphql_1.Kind.INTERFACE_TYPE_EXTENSION)) {
195
199
  interceptInterfaceType({
@@ -212,9 +216,13 @@ function visitFields({ context, selectionSet, typeDefinition, interceptField, in
212
216
  context,
213
217
  selectionSet: innerSelection,
214
218
  typeDefinition: innerTypeDef,
219
+ interceptField,
215
220
  interceptArguments,
216
221
  interceptUnknownField,
217
222
  interceptInterfaceType,
223
+ interceptDirective,
224
+ interceptExternalField,
225
+ interceptFieldWithMissingSelectionSet,
218
226
  });
219
227
  }
220
228
  }
@@ -154,7 +154,9 @@ function ProvidesRules(context) {
154
154
  }
155
155
  if (info.typeDefinition.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION ||
156
156
  info.typeDefinition.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
157
- context.stateBuilder.objectType.field.markAsProvided(info.typeDefinition.name.value, info.fieldName);
157
+ if (info.fieldName !== '__typename') {
158
+ context.stateBuilder.objectType.field.markAsProvided(info.typeDefinition.name.value, info.fieldName);
159
+ }
158
160
  }
159
161
  },
160
162
  });
@@ -81,7 +81,9 @@ function RequiresRules(context) {
81
81
  interceptField(info) {
82
82
  if (info.typeDefinition.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION ||
83
83
  info.typeDefinition.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
84
- context.stateBuilder.objectType.field.markedAsRequired(info.typeDefinition.name.value, info.fieldName);
84
+ if (info.fieldName !== '__typename') {
85
+ context.stateBuilder.objectType.field.markedAsRequired(info.typeDefinition.name.value, info.fieldName);
86
+ }
85
87
  }
86
88
  },
87
89
  interceptUnknownField(info) {
@@ -62,6 +62,33 @@ function validateSubgraphCore(subgraph) {
62
62
  exports.validateSubgraphCore = validateSubgraphCore;
63
63
  function validateSubgraph(subgraph, stateBuilder, federation, __internal) {
64
64
  subgraph.typeDefs = cleanSubgraphTypeDefsFromSubgraphSpec(subgraph.typeDefs);
65
+ const linkSpecDefinitions = (0, graphql_1.parse)(`
66
+ enum Purpose {
67
+ EXECUTION
68
+ SECURITY
69
+ }
70
+
71
+ directive @link(
72
+ url: String
73
+ as: String
74
+ for: link__Purpose
75
+ import: [link__Import]
76
+ ) repeatable on SCHEMA
77
+
78
+ scalar link__Import
79
+
80
+ enum link__Purpose {
81
+ """
82
+ \`SECURITY\` features provide metadata necessary to securely resolve fields.
83
+ """
84
+ SECURITY
85
+
86
+ """
87
+ \`EXECUTION\` features provide metadata necessary for operation execution.
88
+ """
89
+ EXECUTION
90
+ }
91
+ `).definitions;
65
92
  const rulesToSkip = __internal?.disableValidationRules ?? [];
66
93
  const typeNodeInfo = new type_node_info_js_1.TypeNodeInfo();
67
94
  const validationContext = (0, validation_context_js_1.createSubgraphValidationContext)(subgraph, federation, typeNodeInfo, stateBuilder);
@@ -111,6 +138,12 @@ function validateSubgraph(subgraph, stateBuilder, federation, __internal) {
111
138
  return rule(validationContext);
112
139
  })))));
113
140
  const federationDefinitionReplacements = validationContext.collectFederationDefinitionReplacements();
141
+ const linkSpecDefinitionsToInclude = linkSpecDefinitions.filter(def => {
142
+ if ('name' in def && typeof def.name?.value === 'string') {
143
+ return !stateBuilder.state.types.has(def.name.value);
144
+ }
145
+ return true;
146
+ });
114
147
  const fullTypeDefs = (0, graphql_1.concatAST)([
115
148
  {
116
149
  kind: graphql_1.Kind.DOCUMENT,
@@ -120,33 +153,12 @@ function validateSubgraph(subgraph, stateBuilder, federation, __internal) {
120
153
  },
121
154
  validationContext.satisfiesVersionRange('> v1.0') && !stateBuilder.state.specs.link
122
155
  ?
123
- (0, graphql_1.parse)(`
124
- enum Purpose {
125
- EXECUTION
126
- SECURITY
127
- }
128
-
129
- directive @link(
130
- url: String
131
- as: String
132
- for: link__Purpose
133
- import: [link__Import]
134
- ) repeatable on SCHEMA
135
-
136
- scalar link__Import
137
-
138
- enum link__Purpose {
139
- """
140
- \`SECURITY\` features provide metadata necessary to securely resolve fields.
141
- """
142
- SECURITY
143
-
144
- """
145
- \`EXECUTION\` features provide metadata necessary for operation execution.
146
- """
147
- EXECUTION
148
- }
149
- `)
156
+ linkSpecDefinitionsToInclude.length > 0
157
+ ? {
158
+ kind: graphql_1.Kind.DOCUMENT,
159
+ definitions: linkSpecDefinitionsToInclude,
160
+ }
161
+ : null
150
162
  : null,
151
163
  subgraph.typeDefs,
152
164
  ].filter(onlyDocumentNode));
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.stripFederation = exports.schemaCoordinate = exports.createJoinGraphEnumTypeNode = exports.createScalarTypeNode = exports.createEnumTypeNode = exports.createUnionTypeNode = exports.createInputObjectTypeNode = exports.createInterfaceTypeNode = exports.createObjectTypeNode = exports.createDirectiveNode = exports.createSchemaNode = void 0;
4
4
  const graphql_1 = require("graphql");
5
+ const printer_js_1 = require("../../graphql/printer.js");
5
6
  function createSchemaNode(schema) {
6
7
  return {
7
8
  kind: graphql_1.Kind.SCHEMA_DEFINITION,
@@ -740,7 +741,16 @@ function createNamedTypeNode(name) {
740
741
  };
741
742
  }
742
743
  function applyDirectives(common) {
743
- return [].concat(common.ast?.directives ?? [], common.join?.type?.map(createJoinTypeDirectiveNode) ?? [], common.join?.implements?.map(createJoinImplementsDirectiveNode) ?? [], common.join?.field?.map(createJoinFieldDirectiveNode) ?? [], common.join?.unionMember?.map(createJoinUnionMemberDirectiveNode) ?? [], common.join?.enumValue?.map(createJoinEnumValueDirectiveNode) ?? [], common.tags?.map(createTagDirectiveNode) ?? [], common.inaccessible ? [createInaccessibleDirectiveNode()] : [], common.authenticated ? [createAuthenticatedDirectiveNode()] : [], common.policies?.length ? [createPolicyDirectiveNode(common.policies)] : [], common.scopes?.length ? [createRequiresScopesDirectiveNode(common.scopes)] : [], common.deprecated ? [createDeprecatedDirectiveNode(common.deprecated)] : [], common.specifiedBy ? [createSpecifiedByDirectiveNode(common.specifiedBy)] : []);
744
+ const deduplicatedDirectives = (common.ast?.directives ?? [])
745
+ .map(directive => {
746
+ return {
747
+ ast: directive,
748
+ string: (0, printer_js_1.print)(directive),
749
+ };
750
+ })
751
+ .filter((directive, index, all) => all.findIndex(d => d.string === directive.string) === index)
752
+ .map(d => d.ast);
753
+ return [].concat(deduplicatedDirectives, common.join?.type?.map(createJoinTypeDirectiveNode) ?? [], common.join?.implements?.map(createJoinImplementsDirectiveNode) ?? [], common.join?.field?.map(createJoinFieldDirectiveNode) ?? [], common.join?.unionMember?.map(createJoinUnionMemberDirectiveNode) ?? [], common.join?.enumValue?.map(createJoinEnumValueDirectiveNode) ?? [], common.tags?.map(createTagDirectiveNode) ?? [], common.inaccessible ? [createInaccessibleDirectiveNode()] : [], common.authenticated ? [createAuthenticatedDirectiveNode()] : [], common.policies?.length ? [createPolicyDirectiveNode(common.policies)] : [], common.scopes?.length ? [createRequiresScopesDirectiveNode(common.scopes)] : [], common.deprecated ? [createDeprecatedDirectiveNode(common.deprecated)] : [], common.specifiedBy ? [createSpecifiedByDirectiveNode(common.specifiedBy)] : []);
744
754
  }
745
755
  function nonEmpty(value) {
746
756
  return value != null;
@@ -255,7 +255,8 @@ function objectTypeBuilder() {
255
255
  directives: (0, common_js_1.convertToConst)(objectType.ast.directives),
256
256
  },
257
257
  description: objectType.description,
258
- fields: Array.from(objectType.fields.values()).map(field => {
258
+ fields: Array.from(objectType.fields.values())
259
+ .map(field => {
259
260
  const fieldInGraphs = Array.from(field.byGraph.entries());
260
261
  const hasDifferentOutputType = fieldInGraphs.some(([_, meta]) => meta.type !== field.type);
261
262
  const isDefinedEverywhere = field.byGraph.size === (isQuery ? graphs.size : objectType.byGraph.size);
@@ -291,9 +292,26 @@ function objectTypeBuilder() {
291
292
  differencesBetweenGraphs.type = true;
292
293
  }
293
294
  }
295
+ if (!isQuery && field.byGraph.size === 1) {
296
+ const graphId = field.byGraph.keys().next().value;
297
+ const fieldInGraph = field.byGraph.get(graphId);
298
+ if (fieldInGraph.external &&
299
+ !fieldInGraph.usedAsKey &&
300
+ !fieldInGraph.required &&
301
+ !fieldInGraph.provided &&
302
+ !provideUsedOverriddenValue(field.name, overridesMap, fieldNamesOfImplementedInterfaces, graphId) &&
303
+ graphs.get(graphId).version === 'v1.0') {
304
+ return null;
305
+ }
306
+ }
294
307
  if (isQuery) {
295
308
  if (differencesBetweenGraphs.override) {
296
- const graphsWithOverride = fieldInGraphs.filter(([_, meta]) => meta.override !== null);
309
+ const graphsWithOverride = fieldInGraphs.filter(([_, meta]) => meta.override !== null &&
310
+ (objectType.byGraph.size > 1
311
+ ?
312
+ true
313
+ :
314
+ typeof graphNameToId(meta.override) === 'string'));
297
315
  joinFields = graphsWithOverride.map(([graphId, meta]) => ({
298
316
  graph: graphId,
299
317
  override: meta.override ?? undefined,
@@ -423,7 +441,8 @@ function objectTypeBuilder() {
423
441
  };
424
442
  }),
425
443
  };
426
- }),
444
+ })
445
+ .filter(helpers_js_1.isDefined),
427
446
  interfaces: Array.from(objectType.interfaces),
428
447
  tags: Array.from(objectType.tags),
429
448
  inaccessible: objectType.inaccessible,
@@ -134,7 +134,8 @@ export function visitFields({ context, selectionSet, typeDefinition, interceptFi
134
134
  }
135
135
  break;
136
136
  }
137
- if (interceptDirective && selection.directives?.length) {
137
+ const isTypename = selection.name.value === '__typename';
138
+ if (!isTypename && interceptDirective && selection.directives?.length) {
138
139
  for (const directive of selection.directives) {
139
140
  interceptDirective({
140
141
  directiveName: directive.name.value,
@@ -142,21 +143,23 @@ export function visitFields({ context, selectionSet, typeDefinition, interceptFi
142
143
  });
143
144
  }
144
145
  }
145
- context.markAsUsed('fields', typeDefinition.kind, typeDefinition.name.value, selectionFieldDef.name.value);
146
- if (interceptField) {
146
+ if (!isTypename) {
147
+ context.markAsUsed('fields', typeDefinition.kind, typeDefinition.name.value, selectionFieldDef.name.value);
148
+ }
149
+ if (!isTypename && interceptField) {
147
150
  interceptField({
148
151
  typeDefinition,
149
152
  fieldName: selection.name.value,
150
153
  });
151
154
  }
152
- if (selectionFieldDef.arguments?.length && interceptArguments) {
155
+ if (!isTypename && selectionFieldDef.arguments?.length && interceptArguments) {
153
156
  interceptArguments({
154
157
  typeDefinition,
155
158
  fieldName: selection.name.value,
156
159
  });
157
160
  continue;
158
161
  }
159
- if (interceptNonExternalField || interceptExternalField) {
162
+ if (!isTypename && (interceptNonExternalField || interceptExternalField)) {
160
163
  const isExternal = selectionFieldDef.directives?.some(d => context.isAvailableFederationDirective('external', d));
161
164
  const fieldName = selection.name.value;
162
165
  const fieldDef = typeDefinition.fields?.find(field => field.name.value === fieldName);
@@ -185,7 +188,8 @@ export function visitFields({ context, selectionSet, typeDefinition, interceptFi
185
188
  if (!innerTypeDef) {
186
189
  continue;
187
190
  }
188
- if (interceptInterfaceType &&
191
+ if (!isTypename &&
192
+ interceptInterfaceType &&
189
193
  (innerTypeDef.kind === Kind.INTERFACE_TYPE_DEFINITION ||
190
194
  innerTypeDef.kind === Kind.INTERFACE_TYPE_EXTENSION)) {
191
195
  interceptInterfaceType({
@@ -208,9 +212,13 @@ export function visitFields({ context, selectionSet, typeDefinition, interceptFi
208
212
  context,
209
213
  selectionSet: innerSelection,
210
214
  typeDefinition: innerTypeDef,
215
+ interceptField,
211
216
  interceptArguments,
212
217
  interceptUnknownField,
213
218
  interceptInterfaceType,
219
+ interceptDirective,
220
+ interceptExternalField,
221
+ interceptFieldWithMissingSelectionSet,
214
222
  });
215
223
  }
216
224
  }
@@ -151,7 +151,9 @@ export function ProvidesRules(context) {
151
151
  }
152
152
  if (info.typeDefinition.kind === Kind.OBJECT_TYPE_DEFINITION ||
153
153
  info.typeDefinition.kind === Kind.OBJECT_TYPE_EXTENSION) {
154
- context.stateBuilder.objectType.field.markAsProvided(info.typeDefinition.name.value, info.fieldName);
154
+ if (info.fieldName !== '__typename') {
155
+ context.stateBuilder.objectType.field.markAsProvided(info.typeDefinition.name.value, info.fieldName);
156
+ }
155
157
  }
156
158
  },
157
159
  });
@@ -78,7 +78,9 @@ export function RequiresRules(context) {
78
78
  interceptField(info) {
79
79
  if (info.typeDefinition.kind === Kind.OBJECT_TYPE_DEFINITION ||
80
80
  info.typeDefinition.kind === Kind.OBJECT_TYPE_EXTENSION) {
81
- context.stateBuilder.objectType.field.markedAsRequired(info.typeDefinition.name.value, info.fieldName);
81
+ if (info.fieldName !== '__typename') {
82
+ context.stateBuilder.objectType.field.markedAsRequired(info.typeDefinition.name.value, info.fieldName);
83
+ }
82
84
  }
83
85
  },
84
86
  interceptUnknownField(info) {
@@ -57,6 +57,33 @@ export function validateSubgraphCore(subgraph) {
57
57
  }
58
58
  export function validateSubgraph(subgraph, stateBuilder, federation, __internal) {
59
59
  subgraph.typeDefs = cleanSubgraphTypeDefsFromSubgraphSpec(subgraph.typeDefs);
60
+ const linkSpecDefinitions = parse(`
61
+ enum Purpose {
62
+ EXECUTION
63
+ SECURITY
64
+ }
65
+
66
+ directive @link(
67
+ url: String
68
+ as: String
69
+ for: link__Purpose
70
+ import: [link__Import]
71
+ ) repeatable on SCHEMA
72
+
73
+ scalar link__Import
74
+
75
+ enum link__Purpose {
76
+ """
77
+ \`SECURITY\` features provide metadata necessary to securely resolve fields.
78
+ """
79
+ SECURITY
80
+
81
+ """
82
+ \`EXECUTION\` features provide metadata necessary for operation execution.
83
+ """
84
+ EXECUTION
85
+ }
86
+ `).definitions;
60
87
  const rulesToSkip = __internal?.disableValidationRules ?? [];
61
88
  const typeNodeInfo = new TypeNodeInfo();
62
89
  const validationContext = createSubgraphValidationContext(subgraph, federation, typeNodeInfo, stateBuilder);
@@ -106,6 +133,12 @@ export function validateSubgraph(subgraph, stateBuilder, federation, __internal)
106
133
  return rule(validationContext);
107
134
  })))));
108
135
  const federationDefinitionReplacements = validationContext.collectFederationDefinitionReplacements();
136
+ const linkSpecDefinitionsToInclude = linkSpecDefinitions.filter(def => {
137
+ if ('name' in def && typeof def.name?.value === 'string') {
138
+ return !stateBuilder.state.types.has(def.name.value);
139
+ }
140
+ return true;
141
+ });
109
142
  const fullTypeDefs = concatAST([
110
143
  {
111
144
  kind: Kind.DOCUMENT,
@@ -115,33 +148,12 @@ export function validateSubgraph(subgraph, stateBuilder, federation, __internal)
115
148
  },
116
149
  validationContext.satisfiesVersionRange('> v1.0') && !stateBuilder.state.specs.link
117
150
  ?
118
- parse(`
119
- enum Purpose {
120
- EXECUTION
121
- SECURITY
122
- }
123
-
124
- directive @link(
125
- url: String
126
- as: String
127
- for: link__Purpose
128
- import: [link__Import]
129
- ) repeatable on SCHEMA
130
-
131
- scalar link__Import
132
-
133
- enum link__Purpose {
134
- """
135
- \`SECURITY\` features provide metadata necessary to securely resolve fields.
136
- """
137
- SECURITY
138
-
139
- """
140
- \`EXECUTION\` features provide metadata necessary for operation execution.
141
- """
142
- EXECUTION
143
- }
144
- `)
151
+ linkSpecDefinitionsToInclude.length > 0
152
+ ? {
153
+ kind: Kind.DOCUMENT,
154
+ definitions: linkSpecDefinitionsToInclude,
155
+ }
156
+ : null
145
157
  : null,
146
158
  subgraph.typeDefs,
147
159
  ].filter(onlyDocumentNode));
@@ -1,4 +1,5 @@
1
1
  import { Kind, OperationTypeNode, parseConstValue, parseType, specifiedDirectives, visit, visitInParallel, } from 'graphql';
2
+ import { print } from '../../graphql/printer.js';
2
3
  export function createSchemaNode(schema) {
3
4
  return {
4
5
  kind: Kind.SCHEMA_DEFINITION,
@@ -728,7 +729,16 @@ function createNamedTypeNode(name) {
728
729
  };
729
730
  }
730
731
  function applyDirectives(common) {
731
- return [].concat(common.ast?.directives ?? [], common.join?.type?.map(createJoinTypeDirectiveNode) ?? [], common.join?.implements?.map(createJoinImplementsDirectiveNode) ?? [], common.join?.field?.map(createJoinFieldDirectiveNode) ?? [], common.join?.unionMember?.map(createJoinUnionMemberDirectiveNode) ?? [], common.join?.enumValue?.map(createJoinEnumValueDirectiveNode) ?? [], common.tags?.map(createTagDirectiveNode) ?? [], common.inaccessible ? [createInaccessibleDirectiveNode()] : [], common.authenticated ? [createAuthenticatedDirectiveNode()] : [], common.policies?.length ? [createPolicyDirectiveNode(common.policies)] : [], common.scopes?.length ? [createRequiresScopesDirectiveNode(common.scopes)] : [], common.deprecated ? [createDeprecatedDirectiveNode(common.deprecated)] : [], common.specifiedBy ? [createSpecifiedByDirectiveNode(common.specifiedBy)] : []);
732
+ const deduplicatedDirectives = (common.ast?.directives ?? [])
733
+ .map(directive => {
734
+ return {
735
+ ast: directive,
736
+ string: print(directive),
737
+ };
738
+ })
739
+ .filter((directive, index, all) => all.findIndex(d => d.string === directive.string) === index)
740
+ .map(d => d.ast);
741
+ return [].concat(deduplicatedDirectives, common.join?.type?.map(createJoinTypeDirectiveNode) ?? [], common.join?.implements?.map(createJoinImplementsDirectiveNode) ?? [], common.join?.field?.map(createJoinFieldDirectiveNode) ?? [], common.join?.unionMember?.map(createJoinUnionMemberDirectiveNode) ?? [], common.join?.enumValue?.map(createJoinEnumValueDirectiveNode) ?? [], common.tags?.map(createTagDirectiveNode) ?? [], common.inaccessible ? [createInaccessibleDirectiveNode()] : [], common.authenticated ? [createAuthenticatedDirectiveNode()] : [], common.policies?.length ? [createPolicyDirectiveNode(common.policies)] : [], common.scopes?.length ? [createRequiresScopesDirectiveNode(common.scopes)] : [], common.deprecated ? [createDeprecatedDirectiveNode(common.deprecated)] : [], common.specifiedBy ? [createSpecifiedByDirectiveNode(common.specifiedBy)] : []);
732
742
  }
733
743
  function nonEmpty(value) {
734
744
  return value != null;
@@ -251,7 +251,8 @@ export function objectTypeBuilder() {
251
251
  directives: convertToConst(objectType.ast.directives),
252
252
  },
253
253
  description: objectType.description,
254
- fields: Array.from(objectType.fields.values()).map(field => {
254
+ fields: Array.from(objectType.fields.values())
255
+ .map(field => {
255
256
  const fieldInGraphs = Array.from(field.byGraph.entries());
256
257
  const hasDifferentOutputType = fieldInGraphs.some(([_, meta]) => meta.type !== field.type);
257
258
  const isDefinedEverywhere = field.byGraph.size === (isQuery ? graphs.size : objectType.byGraph.size);
@@ -287,9 +288,26 @@ export function objectTypeBuilder() {
287
288
  differencesBetweenGraphs.type = true;
288
289
  }
289
290
  }
291
+ if (!isQuery && field.byGraph.size === 1) {
292
+ const graphId = field.byGraph.keys().next().value;
293
+ const fieldInGraph = field.byGraph.get(graphId);
294
+ if (fieldInGraph.external &&
295
+ !fieldInGraph.usedAsKey &&
296
+ !fieldInGraph.required &&
297
+ !fieldInGraph.provided &&
298
+ !provideUsedOverriddenValue(field.name, overridesMap, fieldNamesOfImplementedInterfaces, graphId) &&
299
+ graphs.get(graphId).version === 'v1.0') {
300
+ return null;
301
+ }
302
+ }
290
303
  if (isQuery) {
291
304
  if (differencesBetweenGraphs.override) {
292
- const graphsWithOverride = fieldInGraphs.filter(([_, meta]) => meta.override !== null);
305
+ const graphsWithOverride = fieldInGraphs.filter(([_, meta]) => meta.override !== null &&
306
+ (objectType.byGraph.size > 1
307
+ ?
308
+ true
309
+ :
310
+ typeof graphNameToId(meta.override) === 'string'));
293
311
  joinFields = graphsWithOverride.map(([graphId, meta]) => ({
294
312
  graph: graphId,
295
313
  override: meta.override ?? undefined,
@@ -419,7 +437,8 @@ export function objectTypeBuilder() {
419
437
  };
420
438
  }),
421
439
  };
422
- }),
440
+ })
441
+ .filter(isDefined),
423
442
  interfaces: Array.from(objectType.interfaces),
424
443
  tags: Array.from(objectType.tags),
425
444
  inaccessible: objectType.inaccessible,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theguild/federation-composition",
3
- "version": "0.7.0",
3
+ "version": "0.7.1-rc-20240104160136-52edd83",
4
4
  "description": "Open Source Composition library for Apollo Federation",
5
5
  "peerDependencies": {
6
6
  "graphql": "^16.0.0"