UNPKG

@graphql-tools/federation

Version:

Useful tools to create and manipulate GraphQL schemas.

1,291 lines (1,288 loc) • 65.6 kB
'use strict'; var delegate = require('@graphql-tools/delegate'); var utils = require('@graphql-tools/utils'); var disposablestack = require('@whatwg-node/disposablestack'); var events = require('@whatwg-node/events'); var fetch = require('@whatwg-node/fetch'); var executorHttp = require('@graphql-tools/executor-http'); var stitch = require('@graphql-tools/stitch'); var promiseHelpers = require('@whatwg-node/promise-helpers'); var graphql = require('graphql'); const getArgsFromKeysForFederation = utils.memoize1( function getArgsFromKeysForFederation2(representations) { return { representations }; } ); function projectDataSelectionSet(data, selectionSet) { if (data == null || selectionSet == null || !selectionSet?.selections?.length) { return data; } if (data instanceof Error) { return null; } if (Array.isArray(data)) { return data.map((entry) => projectDataSelectionSet(entry, selectionSet)); } const projectedData = { __typename: data.__typename }; for (const selection of selectionSet.selections) { if (selection.kind === graphql.Kind.FIELD) { const fieldName = selection.name.value; const responseKey = selection.alias?.value || selection.name.value; if (Object.prototype.hasOwnProperty.call(data, responseKey)) { const projectedKeyData = projectDataSelectionSet( data[responseKey], selection.selectionSet ); if (projectedData[fieldName]) { if (projectedKeyData != null && !(projectedKeyData instanceof Error)) { projectedData[fieldName] = utils.mergeDeep( [projectedData[fieldName], projectedKeyData], void 0, true, true ); } } else { projectedData[fieldName] = projectedKeyData; } } } else if (selection.kind === graphql.Kind.INLINE_FRAGMENT) { if (selection.typeCondition && projectedData["__typename"] != null && projectedData["__typename"] !== selection.typeCondition.name.value) { continue; } Object.assign( projectedData, utils.mergeDeep( [ projectedData, projectDataSelectionSet(data, selection.selectionSet) ], void 0, true, true ) ); } } return projectedData; } function getKeyFnForFederation(typeName, keys) { if (keys.some((key) => key.includes("{") || key.includes("("))) { const parsedSelectionSet = utils.parseSelectionSet(`{${keys.join(" ")}}`, { noLocation: true }); return function keyFn(root) { if (root == null) { return root; } return projectDataSelectionSet( { __typename: typeName, ...root }, parsedSelectionSet ); }; } const allKeyProps = keys.flatMap((key) => key.split(" ")).map((key) => key.trim()); if (allKeyProps.length > 1) { return function keyFn(root) { if (root == null) { return null; } return allKeyProps.reduce( (prev, key) => { if (key !== "__typename") { prev[key] = root[key]; } return prev; }, { __typename: typeName } ); }; } const keyProp = allKeyProps[0]; return utils.memoize1(function keyFn(root) { if (root == null) { return null; } const keyPropVal = root[keyProp]; if (keyPropVal == null) { return null; } return { __typename: typeName, [keyProp]: keyPropVal }; }); } function getCacheKeyFnFromKey(key) { if (key.includes("{") || key.includes("(")) { const parsedSelectionSet = utils.parseSelectionSet(`{${key}}`, { noLocation: true }); return function cacheKeyFn(root) { return JSON.stringify(projectDataSelectionSet(root, parsedSelectionSet)); }; } const keyTrimmed = key.trim(); const keys = keyTrimmed.split(" ").map((key2) => key2.trim()); if (keys.length > 1) { return function cacheKeyFn(root) { return keys.map((key2) => { const keyVal = root[key2]; if (keyVal == null) { return ""; } if (typeof keyVal === "object") { return JSON.stringify(keyVal); } return keyVal; }).join(" "); }; } return utils.memoize1(function cacheKeyFn(root) { const keyVal = root[keyTrimmed]; if (keyVal == null) { return ""; } if (typeof keyVal === "object") { return JSON.stringify(keyVal); } return keyVal; }); } function hasInaccessible(obj) { return utils.getDirectiveExtensions(obj)?.inaccessible?.length; } function filterInternalFieldsAndTypes(finalSchema) { const internalTypeNameRegexp = /^(?:_Entity|_Any|_FieldSet|_Service|link|inaccessible|(?:link__|join__|core__)[\w]*)$/; return utils.mapSchema(finalSchema, { [utils.MapperKind.DIRECTIVE]: (directive) => { if (internalTypeNameRegexp.test(directive.name)) { return null; } return directive; }, [utils.MapperKind.TYPE]: (type) => { if (internalTypeNameRegexp.test(type.name) || hasInaccessible(type)) { return null; } return type; }, [utils.MapperKind.FIELD]: (fieldConfig) => { if (hasInaccessible(fieldConfig)) { return null; } return fieldConfig; }, [utils.MapperKind.QUERY_ROOT_FIELD]: (fieldConfig, fieldName) => { if (fieldName === "_entities" || hasInaccessible(fieldConfig)) { return null; } return fieldConfig; }, [utils.MapperKind.ENUM_VALUE]: (valueConfig) => { if (hasInaccessible(valueConfig)) { return null; } return valueConfig; }, [utils.MapperKind.ARGUMENT]: (argConfig) => { if (hasInaccessible(argConfig)) { return null; } return argConfig; } }); } function getNamedTypeNode(typeNode) { if (typeNode.kind !== graphql.Kind.NAMED_TYPE) { return getNamedTypeNode(typeNode.type); } return typeNode; } function ensureSupergraphSDLAst(supergraphSdl) { return typeof supergraphSdl === "string" ? graphql.parse(supergraphSdl, { noLocation: true }) : supergraphSdl; } const rootTypeMap = /* @__PURE__ */ new Map([ ["Query", "query"], ["Mutation", "mutation"], ["Subscription", "subscription"] ]); const memoizedASTPrint = utils.memoize1(graphql.print); const memoizedTypePrint = utils.memoize1( (type) => type.toString() ); function getStitchingOptionsFromSupergraphSdl(opts) { const supergraphAst = ensureSupergraphSDLAst(opts.supergraphSdl); const subgraphEndpointMap = /* @__PURE__ */ new Map(); const subgraphTypesMap = /* @__PURE__ */ new Map(); const typeNameKeysBySubgraphMap = /* @__PURE__ */ new Map(); const typeNameFieldsKeyBySubgraphMap = /* @__PURE__ */ new Map(); const typeNameCanonicalMap = /* @__PURE__ */ new Map(); const subgraphTypeNameProvidedMap = /* @__PURE__ */ new Map(); const subgraphTypeNameFieldProvidedSelectionMap = /* @__PURE__ */ new Map(); const orphanTypeMap = /* @__PURE__ */ new Map(); const typeFieldASTMap = /* @__PURE__ */ new Map(); for (const definition of supergraphAst.definitions) { if ("fields" in definition) { const fieldMap = /* @__PURE__ */ new Map(); typeFieldASTMap.set(definition.name.value, fieldMap); for (const field of definition.fields || []) { fieldMap.set(field.name.value, field); } } } const subgraphExternalFieldMap = /* @__PURE__ */ new Map(); const subgraphNames = []; graphql.visit(supergraphAst, { EnumTypeDefinition(node) { if (node.name.value === "join__Graph") { node.values?.forEach((valueNode) => { subgraphNames.push(valueNode.name.value); }); } } }); function TypeWithFieldsVisitor(typeNode) { if (typeNode.name.value === "Query" || typeNode.name.value === "Mutation" && !typeNode.directives?.some( (directiveNode) => directiveNode.name.value === "join__type" )) { typeNode.directives = [ ...typeNode.directives || [], ...subgraphNames.map((subgraphName) => ({ kind: graphql.Kind.DIRECTIVE, name: { kind: graphql.Kind.NAME, value: "join__type" }, arguments: [ { kind: graphql.Kind.ARGUMENT, name: { kind: graphql.Kind.NAME, value: "graph" }, value: { kind: graphql.Kind.ENUM, value: subgraphName } } ] })) ]; } let isOrphan = true; const fieldDefinitionNodesByGraphName = /* @__PURE__ */ new Map(); typeNode.directives?.forEach((directiveNode) => { if (typeNode.kind === graphql.Kind.OBJECT_TYPE_DEFINITION) { if (directiveNode.name.value === "join__owner") { directiveNode.arguments?.forEach((argumentNode) => { if (argumentNode.name.value === "graph" && argumentNode.value?.kind === graphql.Kind.ENUM) { typeNameCanonicalMap.set( typeNode.name.value, argumentNode.value.value ); } }); } } if (directiveNode.name.value === "join__type") { isOrphan = false; const joinTypeGraphArgNode = directiveNode.arguments?.find( (argumentNode) => argumentNode.name.value === "graph" ); if (joinTypeGraphArgNode?.value?.kind === graphql.Kind.ENUM) { const graphName = joinTypeGraphArgNode.value.value; if (typeNode.kind === graphql.Kind.OBJECT_TYPE_DEFINITION || typeNode.kind === graphql.Kind.INTERFACE_TYPE_DEFINITION) { const keyArgumentNode = directiveNode.arguments?.find( (argumentNode) => argumentNode.name.value === "key" ); const isResolvable = !directiveNode.arguments?.some( (argumentNode) => argumentNode.name.value === "resolvable" && argumentNode.value?.kind === graphql.Kind.BOOLEAN && argumentNode.value.value === false ); if (isResolvable && keyArgumentNode?.value?.kind === graphql.Kind.STRING) { let typeNameKeysMap = typeNameKeysBySubgraphMap.get(graphName); if (!typeNameKeysMap) { typeNameKeysMap = /* @__PURE__ */ new Map(); typeNameKeysBySubgraphMap.set(graphName, typeNameKeysMap); } let keys = typeNameKeysMap.get(typeNode.name.value); if (!keys) { keys = []; typeNameKeysMap.set(typeNode.name.value, keys); } keys.push(keyArgumentNode.value.value); } } const fieldDefinitionNodesOfSubgraph = []; typeNode.fields?.forEach((fieldNode) => { const joinFieldDirectives = fieldNode.directives?.filter( (directiveNode2) => directiveNode2.name.value === "join__field" ); let notInSubgraph = true; joinFieldDirectives?.forEach((joinFieldDirectiveNode) => { const joinFieldGraphArgNode = joinFieldDirectiveNode.arguments?.find( (argumentNode) => argumentNode.name.value === "graph" ); if (joinFieldGraphArgNode?.value?.kind === graphql.Kind.ENUM && joinFieldGraphArgNode.value.value === graphName) { notInSubgraph = false; const isExternal = joinFieldDirectiveNode.arguments?.some( (argumentNode) => argumentNode.name.value === "external" && argumentNode.value?.kind === graphql.Kind.BOOLEAN && argumentNode.value.value === true ); const isOverridden = joinFieldDirectiveNode.arguments?.some( (argumentNode) => argumentNode.name.value === "usedOverridden" && argumentNode.value?.kind === graphql.Kind.BOOLEAN && argumentNode.value.value === true ); if (isExternal) { let externalFieldsByType = subgraphExternalFieldMap.get(graphName); if (!externalFieldsByType) { externalFieldsByType = /* @__PURE__ */ new Map(); subgraphExternalFieldMap.set( graphName, externalFieldsByType ); } let externalFields = externalFieldsByType.get( typeNode.name.value ); if (!externalFields) { externalFields = /* @__PURE__ */ new Set(); externalFieldsByType.set( typeNode.name.value, externalFields ); } externalFields.add(fieldNode.name.value); } if (!isExternal && !isOverridden) { const typeArg = joinFieldDirectiveNode.arguments?.find( (argumentNode) => argumentNode.name.value === "type" ); const typeNode2 = typeArg?.value.kind === graphql.Kind.STRING ? graphql.parseType(typeArg.value.value) : fieldNode.type; fieldDefinitionNodesOfSubgraph.push({ ...fieldNode, type: typeNode2, directives: fieldNode.directives?.filter( (directiveNode2) => directiveNode2.name.value !== "join__field" ) }); } const providedExtraField = joinFieldDirectiveNode.arguments?.find( (argumentNode) => argumentNode.name.value === "provides" ); if (providedExtraField?.value?.kind === graphql.Kind.STRING) { let handleSelection2 = function(fieldNodeTypeName2, selection) { switch (selection.kind) { case graphql.Kind.FIELD: { const extraFieldTypeNode = supergraphAst.definitions.find( (def) => "name" in def && def.name?.value === fieldNodeTypeName2 ); const extraFieldNodeInType = extraFieldTypeNode.fields?.find( (fieldNode2) => fieldNode2.name.value === selection.name.value ); if (extraFieldNodeInType) { let typeNameProvidedMap = subgraphTypeNameProvidedMap.get(graphName); if (!typeNameProvidedMap) { typeNameProvidedMap = /* @__PURE__ */ new Map(); subgraphTypeNameProvidedMap.set( graphName, typeNameProvidedMap ); } let providedFields = typeNameProvidedMap.get(fieldNodeTypeName2); if (!providedFields) { providedFields = /* @__PURE__ */ new Set(); typeNameProvidedMap.set( fieldNodeTypeName2, providedFields ); } providedFields.add(selection.name.value); if (selection.selectionSet) { const extraFieldNodeNamedType = getNamedTypeNode( extraFieldNodeInType.type ); const extraFieldNodeTypeName = extraFieldNodeNamedType.name.value; for (const subSelection of selection.selectionSet.selections) { handleSelection2( extraFieldNodeTypeName, subSelection ); } } } } break; case graphql.Kind.INLINE_FRAGMENT: { const fragmentType = selection.typeCondition?.name?.value || fieldNodeType.name.value; if (selection.selectionSet) { for (const subSelection of selection.selectionSet.selections) { handleSelection2(fragmentType, subSelection); } } } break; } }; const providesSelectionSet = utils.parseSelectionSet( /* GraphQL */ `{ ${providedExtraField.value.value} }` ); let typeNameFieldProvidedSelectionMap = subgraphTypeNameFieldProvidedSelectionMap.get(graphName); if (!typeNameFieldProvidedSelectionMap) { typeNameFieldProvidedSelectionMap = /* @__PURE__ */ new Map(); subgraphTypeNameFieldProvidedSelectionMap.set( graphName, typeNameFieldProvidedSelectionMap ); } let fieldProvidedSelectionMap = typeNameFieldProvidedSelectionMap.get(typeNode.name.value); if (!fieldProvidedSelectionMap) { fieldProvidedSelectionMap = /* @__PURE__ */ new Map(); typeNameFieldProvidedSelectionMap.set( typeNode.name.value, fieldProvidedSelectionMap ); } fieldProvidedSelectionMap.set( fieldNode.name.value, providesSelectionSet ); const fieldNodeType = getNamedTypeNode(fieldNode.type); const fieldNodeTypeName = fieldNodeType.name.value; for (const selection of providesSelectionSet.selections) { handleSelection2(fieldNodeTypeName, selection); } } const requiresArgumentNode = joinFieldDirectiveNode.arguments?.find( (argumentNode) => argumentNode.name.value === "requires" ); if (requiresArgumentNode?.value?.kind === graphql.Kind.STRING) { let typeNameFieldsKeyMap = typeNameFieldsKeyBySubgraphMap.get(graphName); if (!typeNameFieldsKeyMap) { typeNameFieldsKeyMap = /* @__PURE__ */ new Map(); typeNameFieldsKeyBySubgraphMap.set( graphName, typeNameFieldsKeyMap ); } let fieldsKeyMap = typeNameFieldsKeyMap.get( typeNode.name.value ); if (!fieldsKeyMap) { fieldsKeyMap = /* @__PURE__ */ new Map(); typeNameFieldsKeyMap.set(typeNode.name.value, fieldsKeyMap); } fieldsKeyMap.set( fieldNode.name.value, requiresArgumentNode.value.value ); } } }); if (!joinFieldDirectives?.length) { fieldDefinitionNodesOfSubgraph.push({ ...fieldNode, directives: fieldNode.directives?.filter( (directiveNode2) => directiveNode2.name.value !== "join__field" ) }); } else if (notInSubgraph && typeNameKeysBySubgraphMap.get(graphName)?.get(typeNode.name.value)?.some((key) => key.split(" ").includes(fieldNode.name.value))) { fieldDefinitionNodesOfSubgraph.push({ ...fieldNode, directives: fieldNode.directives?.filter( (directiveNode2) => directiveNode2.name.value !== "join__field" ) }); } }); fieldDefinitionNodesByGraphName.set( graphName, fieldDefinitionNodesOfSubgraph ); } } }); const joinImplementsDirectives = typeNode.directives?.filter( (directiveNode) => directiveNode.name.value === "join__implements" ); fieldDefinitionNodesByGraphName.forEach( (fieldDefinitionNodesOfSubgraph, graphName) => { const interfaces = []; typeNode.interfaces?.forEach((interfaceNode) => { const implementedSubgraphs = joinImplementsDirectives?.filter( (directiveNode) => { const argumentNode = directiveNode.arguments?.find( (argumentNode2) => argumentNode2.name.value === "interface" ); return argumentNode?.value?.kind === graphql.Kind.STRING && argumentNode.value.value === interfaceNode.name.value; } ); if (!implementedSubgraphs?.length || implementedSubgraphs.some((directiveNode) => { const argumentNode = directiveNode.arguments?.find( (argumentNode2) => argumentNode2.name.value === "graph" ); return argumentNode?.value?.kind === graphql.Kind.ENUM && argumentNode.value.value === graphName; })) { interfaces.push(interfaceNode); } }); if (typeNode.name.value === "Query") { fieldDefinitionNodesOfSubgraph.push(entitiesFieldDefinitionNode); } const objectTypedDefNodeForSubgraph = { ...typeNode, interfaces, fields: fieldDefinitionNodesOfSubgraph, directives: typeNode.directives?.filter( (directiveNode) => directiveNode.name.value !== "join__type" && directiveNode.name.value !== "join__owner" && directiveNode.name.value !== "join__implements" ) }; let subgraphTypes = subgraphTypesMap.get(graphName); if (!subgraphTypes) { subgraphTypes = []; subgraphTypesMap.set(graphName, subgraphTypes); } subgraphTypes.push(objectTypedDefNodeForSubgraph); } ); if (isOrphan) { orphanTypeMap.set(typeNode.name.value, typeNode); } } graphql.visit(supergraphAst, { ScalarTypeDefinition(node) { let isOrphan = !node.name.value.startsWith("link__") && !node.name.value.startsWith("join__"); node.directives?.forEach((directiveNode) => { if (directiveNode.name.value === "join__type") { directiveNode.arguments?.forEach((argumentNode) => { if (argumentNode.name.value === "graph" && argumentNode?.value?.kind === graphql.Kind.ENUM) { isOrphan = false; const graphName = argumentNode.value.value; let subgraphTypes = subgraphTypesMap.get(graphName); if (!subgraphTypes) { subgraphTypes = []; subgraphTypesMap.set(graphName, subgraphTypes); } subgraphTypes.push({ ...node, directives: node.directives?.filter( (directiveNode2) => directiveNode2.name.value !== "join__type" ) }); } }); } }); if (isOrphan) { orphanTypeMap.set(node.name.value, node); } }, InputObjectTypeDefinition(node) { let isOrphan = true; node.directives?.forEach((directiveNode) => { if (directiveNode.name.value === "join__type") { directiveNode.arguments?.forEach((argumentNode) => { if (argumentNode.name.value === "graph" && argumentNode?.value?.kind === graphql.Kind.ENUM) { isOrphan = false; const graphName = argumentNode.value.value; let subgraphTypes = subgraphTypesMap.get(graphName); if (!subgraphTypes) { subgraphTypes = []; subgraphTypesMap.set(graphName, subgraphTypes); } subgraphTypes.push({ ...node, directives: node.directives?.filter( (directiveNode2) => directiveNode2.name.value !== "join__type" ) }); } }); } }); if (isOrphan) { orphanTypeMap.set(node.name.value, node); } }, InterfaceTypeDefinition: TypeWithFieldsVisitor, UnionTypeDefinition(node) { let isOrphan = true; node.directives?.forEach((directiveNode) => { if (directiveNode.name.value === "join__type") { directiveNode.arguments?.forEach((argumentNode) => { if (argumentNode.name.value === "graph" && argumentNode?.value?.kind === graphql.Kind.ENUM) { isOrphan = false; const graphName = argumentNode.value.value; const unionMembers = []; node.directives?.forEach((directiveNode2) => { if (directiveNode2.name.value === "join__unionMember") { const graphArgumentNode = directiveNode2.arguments?.find( (argumentNode2) => argumentNode2.name.value === "graph" ); const memberArgumentNode = directiveNode2.arguments?.find( (argumentNode2) => argumentNode2.name.value === "member" ); if (graphArgumentNode?.value?.kind === graphql.Kind.ENUM && graphArgumentNode.value.value === graphName && memberArgumentNode?.value?.kind === graphql.Kind.STRING) { unionMembers.push({ kind: graphql.Kind.NAMED_TYPE, name: { kind: graphql.Kind.NAME, value: memberArgumentNode.value.value } }); } } }); if (unionMembers.length > 0) { let subgraphTypes = subgraphTypesMap.get(graphName); if (!subgraphTypes) { subgraphTypes = []; subgraphTypesMap.set(graphName, subgraphTypes); } subgraphTypes.push({ ...node, types: unionMembers, directives: node.directives?.filter( (directiveNode2) => directiveNode2.name.value !== "join__type" && directiveNode2.name.value !== "join__unionMember" ) }); } } }); } }); if (isOrphan && node.name.value !== "_Entity") { orphanTypeMap.set(node.name.value, node); } }, EnumTypeDefinition(node) { let isOrphan = true; if (node.name.value === "join__Graph") { node.values?.forEach((valueNode) => { isOrphan = false; valueNode.directives?.forEach((directiveNode) => { if (directiveNode.name.value === "join__graph") { directiveNode.arguments?.forEach((argumentNode) => { if (argumentNode.name.value === "url" && argumentNode.value?.kind === graphql.Kind.STRING) { subgraphEndpointMap.set( valueNode.name.value, argumentNode.value.value ); } }); } }); }); } node.directives?.forEach((directiveNode) => { if (directiveNode.name.value === "join__type") { isOrphan = false; directiveNode.arguments?.forEach((argumentNode) => { if (argumentNode.name.value === "graph" && argumentNode.value?.kind === graphql.Kind.ENUM) { const graphName = argumentNode.value.value; const enumValueNodes = []; node.values?.forEach((valueNode) => { const joinEnumValueDirectives = valueNode.directives?.filter( (directiveNode2) => directiveNode2.name.value === "join__enumValue" ); if (joinEnumValueDirectives?.length) { joinEnumValueDirectives.forEach( (joinEnumValueDirectiveNode) => { joinEnumValueDirectiveNode.arguments?.forEach( (argumentNode2) => { if (argumentNode2.name.value === "graph" && argumentNode2.value?.kind === graphql.Kind.ENUM && argumentNode2.value.value === graphName) { enumValueNodes.push({ ...valueNode, directives: valueNode.directives?.filter( (directiveNode2) => directiveNode2.name.value !== "join__enumValue" ) }); } } ); } ); } else { enumValueNodes.push(valueNode); } }); const enumTypedDefNodeForSubgraph = { ...node, directives: node.directives?.filter( (directiveNode2) => directiveNode2.name.value !== "join__type" ), values: enumValueNodes }; let subgraphTypes = subgraphTypesMap.get(graphName); if (!subgraphTypes) { subgraphTypes = []; subgraphTypesMap.set(graphName, subgraphTypes); } subgraphTypes.push(enumTypedDefNodeForSubgraph); } }); } }); if (isOrphan) { orphanTypeMap.set(node.name.value, node); } }, ObjectTypeDefinition: TypeWithFieldsVisitor }); const subschemas = []; for (const [subgraphName, endpoint] of subgraphEndpointMap) { let visitTypeDefinitionsForOrphanTypes2 = function(node) { function visitNamedTypeNode(namedTypeNode) { const typeName = namedTypeNode.name.value; if (specifiedTypeNames.includes(typeName)) { return node; } const orphanType = orphanTypeMap.get(typeName); if (orphanType) { if (!extraOrphanTypesForSubgraph.has(typeName)) { extraOrphanTypesForSubgraph.set(typeName, {}); const extraOrphanType = visitTypeDefinitionsForOrphanTypes2(orphanType); extraOrphanTypesForSubgraph.set(typeName, extraOrphanType); } } else if (!subgraphTypes.some((typeNode) => typeNode.name.value === typeName)) { return null; } return node; } function visitFieldDefs(nodeFields) { const fields = []; for (const field of nodeFields || []) { const isTypeNodeOk = visitNamedTypeNode( getNamedTypeNode(field.type) ); if (!isTypeNodeOk) { continue; } if (field.kind === graphql.Kind.FIELD_DEFINITION) { const args = visitFieldDefs( field.arguments ); fields.push({ ...field, arguments: args }); } else { fields.push(field); } } return fields; } function visitObjectAndInterfaceDefs(node2) { const fields = visitFieldDefs(node2.fields); const interfaces = []; for (const iface of node2.interfaces || []) { const isTypeNodeOk = visitNamedTypeNode(iface); if (!isTypeNodeOk) { continue; } interfaces.push(iface); } return { ...node2, fields, interfaces }; } return graphql.visit(node, { [graphql.Kind.OBJECT_TYPE_DEFINITION]: visitObjectAndInterfaceDefs, [graphql.Kind.OBJECT_TYPE_EXTENSION]: visitObjectAndInterfaceDefs, [graphql.Kind.INTERFACE_TYPE_DEFINITION]: visitObjectAndInterfaceDefs, [graphql.Kind.INTERFACE_TYPE_EXTENSION]: visitObjectAndInterfaceDefs, [graphql.Kind.UNION_TYPE_DEFINITION](node2) { const types = []; for (const type of node2.types || []) { const isTypeNodeOk = visitNamedTypeNode(type); if (!isTypeNodeOk) { continue; } types.push(type); } return { ...node2, types }; }, [graphql.Kind.UNION_TYPE_EXTENSION](node2) { const types = []; for (const type of node2.types || []) { const isTypeNodeOk = visitNamedTypeNode(type); if (!isTypeNodeOk) { continue; } types.push(type); } return { ...node2, types }; }, [graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION](node2) { const fields = visitFieldDefs(node2.fields); return { ...node2, fields }; }, [graphql.Kind.INPUT_OBJECT_TYPE_EXTENSION](node2) { const fields = visitFieldDefs(node2.fields); return { ...node2, fields }; } }); }; const mergeConfig = {}; const typeNameKeyMap = typeNameKeysBySubgraphMap.get(subgraphName); const unionTypeNodes = []; if (typeNameKeyMap) { const typeNameFieldsKeyMap = typeNameFieldsKeyBySubgraphMap.get(subgraphName); for (const [typeName, keys] of typeNameKeyMap) { let getMergedTypeConfigFromKey2 = function(key) { return { selectionSet: `{ ${key} }`, argsFromKeys: getArgsFromKeysForFederation, key: getKeyFnForFederation(typeName, [key, ...extraKeys]), fieldName: `_entities`, dataLoaderOptions: { cacheKeyFn: getCacheKeyFnFromKey(key), ...opts.batchDelegateOptions || {} } }; }; const mergedTypeConfig = mergeConfig[typeName] = {}; const fieldsKeyMap = typeNameFieldsKeyMap?.get(typeName); const extraKeys = /* @__PURE__ */ new Set(); if (fieldsKeyMap) { const fieldsConfig = mergedTypeConfig.fields = {}; for (const [fieldName, fieldNameKey] of fieldsKeyMap) { const aliasedFieldNameKey = fieldNameKey.includes("(") ? `_${fieldNameKey.split("(")[0]}: ${fieldNameKey}` : fieldNameKey; extraKeys.add(aliasedFieldNameKey); fieldsConfig[fieldName] = { selectionSet: `{ ${aliasedFieldNameKey} }`, computed: true }; } } if (typeNameCanonicalMap.get(typeName) === subgraphName) { mergedTypeConfig.canonical = true; } if (keys.length === 1 && keys[0]) { Object.assign(mergedTypeConfig, getMergedTypeConfigFromKey2(keys[0])); } if (keys.length > 1) { const entryPoints = keys.map( (key) => getMergedTypeConfigFromKey2(key) ); mergedTypeConfig.entryPoints = entryPoints; } unionTypeNodes.push({ kind: graphql.Kind.NAMED_TYPE, name: { kind: graphql.Kind.NAME, value: typeName } }); opts.onMergedTypeConfig?.(typeName, mergedTypeConfig); } } const typeNameProvidedSelectionMap = subgraphTypeNameFieldProvidedSelectionMap.get(subgraphName); if (typeNameProvidedSelectionMap) { for (const [ typeName, fieldSelectionMap ] of typeNameProvidedSelectionMap) { const mergedTypeConfig = mergeConfig[typeName] ||= {}; const fieldsConfig = mergedTypeConfig.fields ||= {}; for (const [fieldName, selectionSet] of fieldSelectionMap) { fieldsConfig[fieldName] = { provides: selectionSet }; } } } const entitiesUnionTypeDefinitionNode = { name: { kind: graphql.Kind.NAME, value: "_Entity" }, kind: graphql.Kind.UNION_TYPE_DEFINITION, types: unionTypeNodes }; const extraOrphanTypesForSubgraph = /* @__PURE__ */ new Map(); const subgraphTypes = subgraphTypesMap.get(subgraphName) || []; subgraphTypes.forEach((typeNode) => { visitTypeDefinitionsForOrphanTypes2(typeNode); }); const extendedSubgraphTypes = [ ...subgraphTypes, ...extraOrphanTypesForSubgraph.values() ]; for (const interfaceInSubgraph of extendedSubgraphTypes) { if (interfaceInSubgraph.kind === graphql.Kind.INTERFACE_TYPE_DEFINITION) { let isOrphan = true; for (const definitionNode of supergraphAst.definitions) { if (definitionNode.kind === graphql.Kind.OBJECT_TYPE_DEFINITION && definitionNode.interfaces?.some( (interfaceNode) => interfaceNode.name.value === interfaceInSubgraph.name.value )) { isOrphan = false; } } if (isOrphan) { interfaceInSubgraph.kind = graphql.Kind.OBJECT_TYPE_DEFINITION; } } } let schema; let schemaAst = { kind: graphql.Kind.DOCUMENT, definitions: [ ...extendedSubgraphTypes, entitiesUnionTypeDefinitionNode, anyTypeDefinitionNode ] }; if (opts.onSubgraphAST) { schemaAst = opts.onSubgraphAST(subgraphName, schemaAst); } try { schema = graphql.buildASTSchema(schemaAst, { assumeValidSDL: true, assumeValid: true }); } catch (e) { throw new Error( `Error building schema for subgraph ${subgraphName}: ${e?.stack || e?.message || e.toString()}` ); } let httpExecutorOpts; if (typeof opts.httpExecutorOpts === "function") { httpExecutorOpts = opts.httpExecutorOpts({ name: subgraphName, endpoint }); } else { httpExecutorOpts = opts.httpExecutorOpts || {}; } let executor = executorHttp.buildHTTPExecutor({ endpoint, ...httpExecutorOpts }); if (globalThis.process?.env?.["DEBUG"]) { const origExecutor = executor; executor = function debugExecutor(execReq) { const prefix = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${subgraphName}`; console.debug(`${prefix} - subgraph-execute-start`, { document: memoizedASTPrint(execReq.document), variables: JSON.stringify(execReq.variables) }); return promiseHelpers.handleMaybePromise( () => origExecutor(execReq), (res) => { console.debug( `[${(/* @__PURE__ */ new Date()).toISOString()}] ${subgraphName} - subgraph-execute-done`, JSON.stringify(res) ); return res; }, (err) => { console.error( `[${(/* @__PURE__ */ new Date()).toISOString()}] ${subgraphName} - subgraph-execute-error`, err ); return err; } ); }; } const typeNameProvidedMap = subgraphTypeNameProvidedMap.get(subgraphName); const externalFieldMap = subgraphExternalFieldMap.get(subgraphName); const transforms = []; if (externalFieldMap?.size && extendedSubgraphTypes.some( (t) => t.kind === graphql.Kind.INTERFACE_TYPE_DEFINITION )) { let createUnresolvableError2 = function(fieldName, fieldNode) { return utils.createGraphQLError( `Was not able to find any options for ${fieldName}: This shouldn't have happened.`, { extensions: { CRITICAL_ERROR: true }, nodes: [fieldNode] } ); }, createIfaceFieldChecker2 = function(parentType) { const providedInterfaceFields = typeNameProvidedMap?.get( parentType.name ); const implementations = schema.getPossibleTypes(parentType); const ifaceFieldCheckResult = /* @__PURE__ */ new Map(); return function ifaceFieldChecker(fieldName) { let result = ifaceFieldCheckResult.get(fieldName); if (result == null) { result = true; for (const implementation of implementations) { const externalFields = externalFieldMap?.get(implementation.name); const providedFields = typeNameProvidedMap?.get( implementation.name ); if (!providedInterfaceFields?.has(fieldName) && !providedFields?.has(fieldName) && externalFields?.has(fieldName)) { result = false; break; } } ifaceFieldCheckResult.set(fieldName, result); } return result; }; }; const typeInfo = delegate.getTypeInfo(schema); const visitorKeys = { Document: ["definitions"], OperationDefinition: ["selectionSet"], SelectionSet: ["selections"], Field: ["selectionSet"], InlineFragment: ["selectionSet"], FragmentDefinition: ["selectionSet"] }; const unresolvableIfaceFieldCheckerMap = /* @__PURE__ */ new Map(); transforms.push({ transformRequest(request) { return { ...request, document: graphql.visit( request.document, graphql.visitWithTypeInfo(typeInfo, { // To avoid resolving unresolvable interface fields [graphql.Kind.FIELD](fieldNode) { const fieldName = fieldNode.name.value; if (fieldName !== "__typename") { const parentType = typeInfo.getParentType(); if (graphql.isInterfaceType(parentType)) { let unresolvableIfaceFieldChecker = unresolvableIfaceFieldCheckerMap.get(parentType.name); if (unresolvableIfaceFieldChecker == null) { unresolvableIfaceFieldChecker = createIfaceFieldChecker2(parentType); unresolvableIfaceFieldCheckerMap.set( parentType.name, unresolvableIfaceFieldChecker ); } if (!unresolvableIfaceFieldChecker(fieldName)) { throw createUnresolvableError2(fieldName, fieldNode); } } } } }), visitorKeys ) }; } }); } const subschemaConfig = { name: subgraphName, endpoint, schema, executor, merge: mergeConfig, transforms, batch: opts.batch, batchingOptions: opts.batchingOptions }; subschemas.push(subschemaConfig); } const defaultMerger = stitch.getDefaultFieldConfigMerger(true); const fieldConfigMerger = function(candidates) { if (candidates.length === 1 || candidates.some((candidate) => candidate.fieldName === "_entities")) { if (candidates[0]) { return candidates[0].fieldConfig; } } let operationType; for (const candidate of candidates) { const candidateOperationType = rootTypeMap.get(candidate.type.name); if (candidateOperationType) { operationType = candidateOperationType; } } if (operationType) { const defaultMergedField = defaultMerger(candidates); const mergedResolver = function mergedResolver2(_root, _args, context, info) { const originalSelectionSet = { kind: graphql.Kind.SELECTION_SET, selections: info.fieldNodes }; const candidatesReversed = candidates.toReversed ? candidates.toReversed() : [...candidates].reverse(); let currentSubschema; let currentScore = Infinity; let currentUnavailableSelectionSet; let currentFriendSubschemas; let currentAvailableSelectionSet; for (const candidate of candidatesReversed) { if (candidate.transformedSubschema) { const unavailableFields = delegate.extractUnavailableFieldsFromSelectionSet( candidate.transformedSubschema.transformedSchema, candidate.type, originalSelectionSet, () => true, info.fragments ); const score = stitch.calculateSelectionScore( unavailableFields, info.fragments ); if (score < currentScore) { currentScore = score; currentSubschema = candidate.transformedSubschema; currentFriendSubschemas = /* @__PURE__ */ new Map(); currentUnavailableSelectionSet = { kind: graphql.Kind.SELECTION_SET, selections: unavailableFields }; currentAvailableSelectionSet = delegate.subtractSelectionSets( originalSelectionSet, currentUnavailableSelectionSet ); for (const friendCandidate of candidates) { if (friendCandidate === candidate || !friendCandidate.transformedSubschema || !currentUnavailableSelectionSet.selections.length) { continue; } const unavailableFieldsInFriend = delegate.extractUnavailableFieldsFromSelectionSet( friendCandidate.transformedSubschema.transformedSchema, friendCandidate.type, currentUnavailableSelectionSet, () => true, info.fragments ); const friendScore = stitch.calculateSelectionScore( unavailableFieldsInFriend, info.fragments ); if (friendScore < score) { const unavailableInFriendSelectionSet = { kind: graphql.Kind.SELECTION_SET, selections: unavailableFieldsInFriend }; const subschemaSelectionSet = delegate.subtractSelectionSets( currentUnavailableSelectionSet, unavailableInFriendSelectionSet ); currentFriendSubschemas.set( friendCandidate.transformedSubschema, subschemaSelectionSet ); currentUnavailableSelectionSet = unavailableInFriendSelectionSet; } } } } } if (!currentSubschema) { throw new Error("Could not determine subschema"); } const jobs = []; let hasPromise = false; const mainJob = delegate.delegateToSchema({ schema: currentSubschema, operation: rootTypeMap.get(info.parentType.name) || "query", context, info: currentFriendSubschemas?.size ? { ...info, fieldNodes: [ ...currentAvailableSelectionSet?.selections || [], ...currentUnavailableSelectionSet?.selections || [] ] } : info }); if (operationType !== "query") { return mainJob; } if (promiseHelpers.isPromise(mainJob)) { hasPromise = true; } jobs.push(mainJob); if (currentFriendSubschemas?.size) { for (const [ friendSubschema, friendSelectionSet ] of currentFriendSubschemas) { const friendJob = delegate.delegateToSchema({ schema: friendSubschema, operation: rootTypeMap.get(info.parentType.name) || "query", context, info: { ...info, fieldNodes: friendSelectionSet.selections }, skipTypeMerging: true }); if (promiseHelpers.isPromise(friendJob)) { hasPromise = true; } jobs.push(friendJob); } } if (jobs.length === 1) { return jobs[0]; } if (hasPromise) { return Promise.all(jobs).then((results) => mergeResults(results)); } return mergeResults(jobs); }; if (operationType === "subscription") { return { ...defaultMergedField, subscribe: mergedResolver, resolve: function identityFn(payload) { return payload; } }; } return { ...defaultMergedField, resolve: mergedResolver }; } const filteredCandidates = candidates.filter((candidate) => { const fieldASTMap = typeFieldASTMap.get(candidate.type.name); if (fieldASTMap) { const fieldAST = fieldASTMap.get(candidate.fieldName); if (fieldAST) { const typeNodeInAST = memoizedASTPrint(fieldAST.type); const typeNodeInCandidate = memoizedTypePrint( candidate.fieldConfig.type ); return typeNodeInAST === typeNodeInCandidate; } } return false; }); return defaultMerger( filteredCandidates.length ? filteredCandidates : candidates ); }; function doesFieldExistInSupergraph(typeName, fieldName) { for (const subschemaConfig of subschemas) { const type = subschemaConfig.schema.getType(typeName); if (type && "getFields" in type) { if (type.getFields()[fieldName]) { return true; } } } return false; } function getTypeInSup