UNPKG

@graphql-tools/federation

Version:

Useful tools to create and manipulate GraphQL schemas.

1,853 lines • 66 kB
import { getTypeInfo, extractUnavailableFieldsFromSelectionSet, subtractSelectionSets, delegateToSchema, isExternalObject, UNPATHED_ERRORS_SYMBOL, createDefaultExecutor } from '@graphql-tools/delegate';
import { memoize1, mergeDeep, parseSelectionSet, mapSchema, MapperKind, getDirectiveExtensions, createGraphQLError, fakePromise } from '@graphql-tools/utils';
import { DisposableSymbols } from '@whatwg-node/disposablestack';
import { CustomEvent } from '@whatwg-node/events';
import { fetch } from '@whatwg-node/fetch';
import { CRITICAL_ERROR } from '@graphql-tools/executor';
import { buildHTTPExecutor } from '@graphql-tools/executor-http';
import { getDefaultFieldConfigMerger, ValidationLevel, stitchSchemas, calculateSelectionScore } from '@graphql-tools/stitch';
import { isPromise, handleMaybePromise } from '@whatwg-node/promise-helpers';
import { Kind, parse, visit, buildASTSchema, isObjectType, isInterfaceType, isInputObjectType, parseType, print, visitWithTypeInfo } from 'graphql';

const getArgsFromKeysForFederation = 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 === 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] = mergeDeep(
              [projectedData[fieldName], projectedKeyData],
              void 0,
              true,
              true
            );
          }
        } else {
          projectedData[fieldName] = projectedKeyData;
        }
      }
    } else if (selection.kind === Kind.INLINE_FRAGMENT) {
      if (selection.typeCondition && projectedData["__typename"] != null && projectedData["__typename"] !== selection.typeCondition.name.value) {
        continue;
      }
      Object.assign(
        projectedData,
        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 = 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 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 = 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 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 getDirectiveExtensions(obj)?.inaccessible?.length;
}
function filterInternalFieldsAndTypes(finalSchema) {
  const internalTypeNameRegexp = /^(?:_Entity|_Any|_FieldSet|_Service|link|inaccessible|(?:link__|join__|core__)[\w]*)$/;
  return mapSchema(finalSchema, {
    [MapperKind.DIRECTIVE]: (directive) => {
      if (internalTypeNameRegexp.test(directive.name)) {
        return null;
      }
      return directive;
    },
    [MapperKind.TYPE]: (type) => {
      if (internalTypeNameRegexp.test(type.name) || hasInaccessible(type)) {
        return null;
      }
      return type;
    },
    [MapperKind.FIELD]: (fieldConfig) => {
      if (hasInaccessible(fieldConfig)) {
        return null;
      }
      return fieldConfig;
    },
    [MapperKind.QUERY_ROOT_FIELD]: (fieldConfig, fieldName) => {
      if (fieldName === "_entities" || hasInaccessible(fieldConfig)) {
        return null;
      }
      return fieldConfig;
    },
    [MapperKind.ENUM_VALUE]: (valueConfig) => {
      if (hasInaccessible(valueConfig)) {
        return null;
      }
      return valueConfig;
    },
    [MapperKind.ARGUMENT]: (argConfig) => {
      if (hasInaccessible(argConfig)) {
        return null;
      }
      return argConfig;
    }
  });
}
function getNamedTypeNode(typeNode) {
  if (typeNode.kind !== Kind.NAMED_TYPE) {
    return getNamedTypeNode(typeNode.type);
  }
  return typeNode;
}

function ensureSupergraphSDLAst(supergraphSdl) {
  return typeof supergraphSdl === "string" ? parse(supergraphSdl, { noLocation: true }) : supergraphSdl;
}
const rootTypeMap = /* @__PURE__ */ new Map([
  ["Query", "query"],
  ["Mutation", "mutation"],
  ["Subscription", "subscription"]
]);
const memoizedASTPrint = memoize1(print);
const memoizedTypePrint = 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 = [];
  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: Kind.DIRECTIVE,
          name: {
            kind: Kind.NAME,
            value: "join__type"
          },
          arguments: [
            {
              kind: Kind.ARGUMENT,
              name: {
                kind: Kind.NAME,
                value: "graph"
              },
              value: {
                kind: Kind.ENUM,
                value: subgraphName
              }
            }
          ]
        }))
      ];
    }
    let isOrphan = true;
    const fieldDefinitionNodesByGraphName = /* @__PURE__ */ new Map();
    typeNode.directives?.forEach((directiveNode) => {
      if (typeNode.kind === Kind.OBJECT_TYPE_DEFINITION) {
        if (directiveNode.name.value === "join__owner") {
          directiveNode.arguments?.forEach((argumentNode) => {
            if (argumentNode.name.value === "graph" && argumentNode.value?.kind === 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 === Kind.ENUM) {
          const graphName = joinTypeGraphArgNode.value.value;
          if (typeNode.kind === Kind.OBJECT_TYPE_DEFINITION || typeNode.kind === 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 === Kind.BOOLEAN && argumentNode.value.value === false
            );
            if (isResolvable && keyArgumentNode?.value?.kind === 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 === Kind.ENUM && joinFieldGraphArgNode.value.value === graphName) {
                notInSubgraph = false;
                const isExternal = joinFieldDirectiveNode.arguments?.some(
                  (argumentNode) => argumentNode.name.value === "external" && argumentNode.value?.kind === Kind.BOOLEAN && argumentNode.value.value === true
                );
                const isOverridden = joinFieldDirectiveNode.arguments?.some(
                  (argumentNode) => argumentNode.name.value === "usedOverridden" && argumentNode.value?.kind === 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 === Kind.STRING ? 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 === Kind.STRING) {
                  let handleSelection2 = function(fieldNodeTypeName2, selection) {
                    switch (selection.kind) {
                      case 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 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 = 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 === 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 === 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 === 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);
    }
  }
  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 === 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 === 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 === 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 === Kind.ENUM && graphArgumentNode.value.value === graphName && memberArgumentNode?.value?.kind === Kind.STRING) {
                    unionMembers.push({
                      kind: Kind.NAMED_TYPE,
                      name: {
                        kind: 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 === 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 === 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 === 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 === 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 visit(node, {
        [Kind.OBJECT_TYPE_DEFINITION]: visitObjectAndInterfaceDefs,
        [Kind.OBJECT_TYPE_EXTENSION]: visitObjectAndInterfaceDefs,
        [Kind.INTERFACE_TYPE_DEFINITION]: visitObjectAndInterfaceDefs,
        [Kind.INTERFACE_TYPE_EXTENSION]: visitObjectAndInterfaceDefs,
        [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
          };
        },
        [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
          };
        },
        [Kind.INPUT_OBJECT_TYPE_DEFINITION](node2) {
          const fields = visitFieldDefs(node2.fields);
          return {
            ...node2,
            fields
          };
        },
        [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: Kind.NAMED_TYPE,
          name: {
            kind: 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: Kind.NAME,
        value: "_Entity"
      },
      kind: 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 === Kind.INTERFACE_TYPE_DEFINITION) {
        let isOrphan = true;
        for (const definitionNode of supergraphAst.definitions) {
          if (definitionNode.kind === Kind.OBJECT_TYPE_DEFINITION && definitionNode.interfaces?.some(
            (interfaceNode) => interfaceNode.name.value === interfaceInSubgraph.name.value
          )) {
            isOrphan = false;
          }
        }
        if (isOrphan) {
          interfaceInSubgraph.kind = Kind.OBJECT_TYPE_DEFINITION;
        }
      }
    }
    let schema;
    let schemaAst = {
      kind: Kind.DOCUMENT,
      definitions: [
        ...extendedSubgraphTypes,
        entitiesUnionTypeDefinitionNode,
        anyTypeDefinitionNode
      ]
    };
    if (opts.onSubgraphAST) {
      schemaAst = opts.onSubgraphAST(subgraphName, schemaAst);
    }
    try {
      schema = 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 = 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 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 === Kind.INTERFACE_TYPE_DEFINITION
    )) {
      let createUnresolvableError2 = function(fieldName, fieldNode) {
        return 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 = 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: visit(
              request.document,
              visitWithTypeInfo(typeInfo, {
                // To avoid resolving unresolvable interface fields
                [Kind.FIELD](fieldNode) {
                  const fieldName = fieldNode.name.value;
                  if (fieldName !== "__typename") {
                    const parentType = typeInfo.getParentType();
                    if (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 = 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: 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 = extractUnavailableFieldsFromSelectionSet(
              candidate.transformedSubschema.transformedSchema,
              candidate.type,
              originalSelectionSet,
              () => true,
              info.fragments
            );
            const score = calculateSelectionScore(
              unavailableFields,
              info.fragments
            );
            if (score < currentScore) {
              currentScore = score;
              currentSubschema = candidate.transformedSubschema;
              currentFriendSubschemas = /* @__PURE__ */ new Map();
              currentUnavailableSelectionSet = {
                kind: Kind.SELECTION_SET,
                selections: unavailableFields
              };
              currentAvailableSelectionSet = subtractSelectionSets(
                originalSelectionSet,
                currentUnavailableSelectionSet
              );
              for (const friendCandidate of candidates) {
                if (friendCandidate === candidate || !friendCandidate.transformedSubschema || !currentUnavailableSelectionSet.selections.length) {
                  continue;
                }
                const unavailableFieldsInFriend = extractUnavailableFieldsFromSelectionSet(
                  friendCandidate.transformedSubschema.transformedSchema,
                  friendCandidate.type,
                  currentUnavailableSelectionSet,
                  () => true,
                  info.fragments
                );
                const friendScore = calculateSelectionScore(
                  unavailableFieldsInFriend,
                  info.fragments
                );
                if (friendScore < score) {
                  const unavailableInFriendSelectionSet = {
                    kind: Kind.SELECTION_SET,
                    selections: unavailableFieldsInFriend
                  };
                  const subschemaSelectionSet = subtractSelectionSets(
                    currentUnavailableSelectionSet,
                    unavailableInFriendSelectionSet
                  );
                  if (subschemaSelectionSet.selections.length) {
                    currentFriendSubschemas.set(
                      friendCandidate.transformedSubschema,
                      subschemaSelectionSet
                    );
                    currentUnavailableSelectionSet = unavailableInFriendSelectionSet;
                  }
                }
              }
            }
          }
        }
        if (!currentSubschema) {
          throw new Error("Could not determine subschema");
        }
        const jobs = [];
        let hasPromise = false;
        const mainJob = 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 (isPromise(mainJob)) {
          hasPromise = true;
        }
        jobs.push(mainJob);
        if (currentFriendSubschemas?.size) {
          for (const [
            friendSubschema,
            friendSelectionSet
          ] of currentFriendSubschemas) {
            const friendJob = delegateToSchema({
              schema: friendSubschema,
              operation: rootTypeMap.get(info.parentType.name) || "query",
              context,
              info: {
                ...info,
                fieldNodes: friendSelectionSet.selections
              },
              skipTypeMerging: true
            });
            if (isPromise(friendJob)) {
              hasPromise = true;
            }
            jobs.push(friendJob);
          }
        }
        if (jobs.length === 1) {
          return jobs[0];
        }
        function getFieldNames() {
          const fieldNames = /* @__PURE__ */ new Set();
          originalSelectionSet?.selections.forEach((selection) => {
            if (selection.kind === Kind.FIELD && selection.name.value === info.fieldName) {
              selection.selectionSet?.selections.forEach((selection2) => {
                if (selection2.kind === Kind.FIELD) {
                  fieldNames.add(selection2.name.value);
                }
              });
            }
          });
          return fieldNames;
        }
        if (hasPromise) {
          return Promise.all(jobs).then(
            (results) => mergeResults(results, getFieldNames)
          );
        }
        return mergeResults(jobs, getFieldNames);
      };
      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 getTypeInSupergraph(typeName) {
    for (const subschemaConfig of subschemas) {
      const type = subschemaConfig.schema.getType(typeName);
      if (type) {
        return type;
      }
    }
    return void 0;
  }
  const extraDefinitions = [];
  for (const definition of supergraphAst.definitions) {
    if ("name" in definition && definition.name && definition.kind !== Kind.DIRECTIVE_DEFINITION) {
      const typeName = definition.name.value;
      const typeInSchema = getTypeInSupergraph(typeName);
      if (!typeInSchema) {
        extraDefinitions.push(definition);
      } else if ("fields" in definition && definition.fields) {
        const extraFields = [];
        for (const field of definition.fields) {
          if (!doesFieldExistInSupergraph(typeName, field.name.value)) {
            extraFields.push(field);
          }
        }
        if (extraFields.length) {
          let definitionKind;
          if (isObjectType(typeInSchema)) {
            definitionKind = Kind.OBJECT_TYPE_DEFINITION;
          } else if (isInterfaceType(typeInSchema)) {
            definitionKind = Kind.INTERFACE_TYPE_DEFINITION;
          } else if (isInputObjectType(typeInSchema)) {
            definitionKind = Kind.INPUT_OBJECT_TYPE_DEFINITION;
          }
          if (definitionKind) {
            extraDefinitions.push({
              kind: definitionKind,
              name: definition.name,
              fields: extraFields
              // `fields` are different in input object types and regular types
            });
          }
        }
      }
    } else if (definition.kind === Kind.DIRECTIVE_DEFINITION && !definition.name.value.startsWith("join__") && !definition.name.value.startsWith("core")) {
      extraDefinitions.push(definition);
    }
  }
  const additionalTypeDefs = {
    kind: Kind.DOCUMENT,
    definitions: extraDefinitions
  };
  if (opts.onSubschemaConfig) {
    for (const subschema of subschemas) {
      opts.onSubschemaConfig(subschema);
    }
  }
  return {
    subschemas,
    typeDefs: additionalTypeDefs,
    assumeValid: true,
    assumeValidSDL: true,
    typeMergingOptions: {
      useNonNullableFieldOnConflict: true,
      validationSettings: {
        validationLevel: ValidationLevel.Off
      },
      fieldConfigMerger
    }
  };
}
function getStitchedSchemaFromSupergraphSdl(opts) {
  const stitchSchemasOpts = getStitchingOptionsFromSupergraphSdl(opts);
  opts.onStitchingOptions?.(stitchSchemasOpts);
  let supergraphSchema = stitchSchemas(stitchSchemasOpts);
  supergraphSchema = filterInternalFieldsAndTypes(supergraphSchema);
  if (opts.onStitchedSchema) {
    supergraphSchema = opts.onStitchedSchema(supergraphSchema) || supergraphSchema;
  }
  return supergraphSchema;
}
const anyTypeDefinitionNode = {
  name: {
    kind: Kind.NAME,
    value: "_Any"
  },
  kind: Kind.SCALAR_TYPE_DEFINITION
};
const entitiesFieldDefinitionNode = {
  kind: Kind.FIELD_DEFINITION,
  name: {
    kind: Kind.NAME,
    value: "_entities"
  },
  type: {
    kind: Kind.NON_NULL_TYPE,
    type: {
      kind: Kind.LIST_TYPE,
      type: {
        kind: Kind.NAMED_TYPE,
        name: {
          kind: Kind.NAME,
          value: "_Entity"
        }
      }
    }
  },
  arguments: [
    {
      kind: Kind.INPUT_VALUE_DEFINITION,
      name: {
        kind: Kind.NAME,
        value: "representations"
      },
      type: {
        kind: Kind.NON_NULL_TYPE,
        type: {
          kind: Kind.LIST_TYPE,
          type: {
            kind: Kind.NON_NULL_TYPE,
            type: {
              kind: Kind.NAMED_TYPE,
              name: {
                kind: Kind.NAME,
                value: "_Any"
              }
            }
          }
        }
      }
    }
  ]
};
const specifiedTypeNames = [
  "ID",
  "String",
  "Float",
  "Int",
  "Boolean",
  "_Any",
  "_Entity"
];
function makeExternalObject(data, errors, getFieldNames) {
  if (!isExternalObject(data) && typeof data === "object" && data != null) {
    data[UNPATHED_ERRORS_SYMBOL] = errors;
  }
  if (errors.length) {
    const errorsToPop = [...errors];
    const fieldNamesToPop = [];
    for (const fieldName of getFieldNames()) {
      if (data?.[fieldName] == null) {
        fieldNamesToPop.push(fieldName);
      }
    }
    while (fieldNamesToPop.length && errorsToPop.length) {
      const fieldName = fieldNamesToPop.pop();
      if (!fieldName) {
        break;
      }
      const error = errorsToPop.pop();
      if (!error) {
        break;
      }
      let errorToSet;
      if (fieldNamesToPop.length || !errorsToPop.length) {
        errorToSet = error;
      } else {
        errorToSet = new AggregateError(
          errorsToPop,
          errorsToPop.map((error2) => error2.message).join(", \n")
        );
      }
      if (errorToSet) {
        data ||= {};
        data[fieldName] = errorToSet;
      }
    }
  }
  return data;
}
function mergeResults(results, getFieldNames) {
  const errors = [];
  const datas = [];
  for (const result of results) {
    if (result instanceof AggregateError) {
      errors.push(...result.errors);
    } else if (result instanceof Error) {
      errors.push(result);
    } else if (result != null) {
      datas.push(result);
    }
  }
  if (datas.length) {
    if (datas.length === 1) {
      return makeExternalObject(datas[0], errors, getFieldNames);
    }
    return makeExternalObject(
      mergeDeep(datas, void 0, true, true),
      errors,
      getFieldNames
    );
  }
  if (errors.length) {
    if (errors.length === 1) {
      throw errors[0];
    }
    return new AggregateError(
      errors,
      errors.map((error) => error.message).join(", \n")
    );
  }
  return null;
}

const DEFAULT_UPLINKS = [
  "https://uplink.api.apollographql.com/",
  "https://aws.uplink.api.apollographql.com/"
];
async function fetchSupergraphSdlFromManagedFederation(options = {}) {
  const userDefinedUplinks = process.env["APOLLO_SCHEMA_CONFIG_DELIVERY_ENDPOINT"]?.split(",") ?? [];
  const {
    upLink = userDefinedUplinks[0] || DEFAULT_UPLINKS[0],
    loggerByMessageLevel = DEFAULT_MESSAGE_LOGGER,
    fetch: fetch$1 = fetch,
    ...variables
  } = options;
  if (!variables.graphRef) {
    variables.graphRef = process.env["APOLLO_GRAPH_REF"];
  }
  if (!variables.apiKey) {
    variables.apiKey = process.env["APOLLO_KEY"];
  }
  if (!upLink) {
    throw new Error("No up link provided");
  }
  const response = await fetch$1(upLink, {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      query: (
        /* GraphQL */
        `
        query ($apiKey: String!, $graphRef: String!, $lastSeenId: ID) {
          routerConfig(
            ref: $graphRef
            apiKey: $apiKey
            ifAfterId: $lastSeenId
          ) {
            __typename
            ... on FetchError {
              code
              message
              minDelaySeconds
            }
            ... on Unchanged {
              id
              minDelaySeconds
            }
            ... on RouterConfigResult {
              id
              supergraphSdl: supergraphSDL
              minDelaySeconds
              messages {
                level
                body
              }
            }
          }
        }
      `
      ),
      variables
    }),
    signal: AbortSignal.timeout(3e4)
  });
  const responseBody = await response.text();
  if (!response.ok) {
    throw new Error(
      `Failed to fetch supergraph SDL from '${upLink}' due to an HTTP error (${response.status}) ${responseBody}`
    );
  }
  let result;
  try {
    result = JSON.parse(responseBody);
  } catch (err) {
    throw new Error(
      `Failed to parse response from '${upLink}': ${err.message}

${responseBody}`
    );
  }
  if (result.errors) {
    throw new AggregateError(
      result.errors,
      `Failed to fetch supergraph SDL from '${upLink}'`
    );
  }
  if (!result.data?.routerConfig) {
    throw new Error(
      `Failed to fetch supergraph SDL from '${upLink}': ${responseBody}`
    );
  }
  const { routerConfig } = result.data;
  if (routerConfig.__typename === "FetchError") {
    return {
      error: { code: routerConfig.code, message: routerConfig.message },
      minDelaySeconds: routerConfig.minDelaySeconds
    };
  }
  if (routerConfig.__typename === "Unchanged") {
    return {
      id: routerConfig.id,
      minDelaySeconds: routerConfig.minDelaySeconds
    };
  }
  for (const message of routerConfig.messages) {
    loggerByMessageLevel[message.level](message.body);
  }
  return {
    supergraphSdl: routerConfig.supergraphSdl,
    id: routerConfig.id,
    minDelaySeconds: routerConfig.minDelaySeconds
  };
}
async function getStitchedSchemaFromManagedFederation(options) {
  const result = await fetchSupergraphSdlFromManagedFederation({
    graphRef: options.graphRef,
    apiKey: options.apiKey,
    upLink: options.upLink,
    lastSeenId: options.lastSeenId,
    fetch: options.fetch,
    loggerByMessageLevel: options.loggerByMessageLevel
  });
  if ("supergraphSdl" in result) {
    return {
      ...result,
      schema: getStitchedSchemaFromSupergraphSdl({
        supergraphSdl: result.supergraphSdl,
        onStitchingOptions: options.onStitchingOptions,
        onStitchedSchema: options.onStitchedSchema,
        httpExecutorOpts: options.httpExecutorOpts,
        onSubschemaConfig: options.onSubschemaConfig,
        batch: options.batch
      })
    };
  }
  return result;
}
const DEFAULT_MESSAGE_LOGGER = {
  ERROR: (message) => console.error("[Managed Federation] Uplink message: [ERROR]", message),
  WARN: (message) => console.warn("[Managed Federation] Uplink message: [WARN]", message),
  INFO: (message) => console.info("[Managed Federation] Uplink message: [INFO]", message)
};
const TypedEventTargetCtor = EventTarget;
class SupergraphSchemaManager extends TypedEventTargetCtor {
  constructor(options = {}) {
    super();
    this.options = options;
  }
  schema = void 0;
  #lastSeenId;
  #retries = 1;
  #timeout;
  load = async (options) => {
    this.options.apiKey ||= options.apollo.key;
    this.options.graphRef ||= options.apollo.graphRef;
    await this.#fetchSchema();
    return {
      executor(requestContext) {
        return createDefaultExecutor(requestContext.schema)({
          document: requestContext.document,
          variables: requestContext.request.variables,
          operationType: requestContext.operation.operation,
          operationName: requestContext.operationName || void 0,
          context: requestContext.context
        });
      }
    };
  };
  onSchemaLoadOrUpdate = (callback) => {
    const onSchemaChange = (event) => {
      callback({
        apiSchema: event.detail.schema,
        coreSupergraphSdl: event.detail.supergraphSdl
      });
    };
    this.addEventListener("schema", onSchemaChange);
    return () => {
      this.removeEventListener("schema", onSchemaChange);
    };
  };
  start = (delayInSeconds = 0) => {
    if (this.#timeout) {
      this.stop();
    }
    this.#timeout = setTimeout(() => {
      this.#log("info", "Polling started");
      this.#retries = 1;
      this.#fetchSchema();
    }, delayInSeconds * 1e3);
  };
  forcePull = () => {
    if (this.#timeout) {
      clearTimeout(this.#timeout);
      this.#timeout = void 0;
    }
    this.#retries = 1;
    this.#fetchSchema();
  };
  stop = () => {
    this.#log("info", "Polling stopped");
    if (this.#timeout) {
      clearTimeout(this.#timeout);
      this.#timeout = void 0;
    }
    return fakePromise();
  };
  #fetchSchema = async () => {
    const { retryDelaySeconds = 0, minDelaySeconds = 0 } = this.options;
    try {
      this.#log("info", "Fetch schema from managed federation");
      const result = await getStitchedSchemaFromManagedFederation({
        ...this.options,
        loggerByMessageLevel: {
          ERROR: (message) => {
            const logEvent = new CustomEvent(
              "log",
              {
                detail: { source: "uplink", level: "error", message }
              }
            );
            this.dispatchEvent(logEvent);
          },
          WARN: (message) => {
            const logEvent = new CustomEvent(
              "log",
              {
                detail: { source: "uplink", level: "warn", message }
              }
            );
            this.dispatchEvent(logEvent);
          },
          INFO: (message) => {
            const logEvent = new CustomEvent(
              "log",
              {
                detail: { source: "uplink", level: "info", message }
              }
            );
            this.dispatchEvent(logEvent);
          }
        },
        lastSeenId: this.#lastSeenId
      });
      if ("error" in result) {
        this.#lastSeenId = void 0;
        const errorEvent = new CustomEvent(
          "error",
          {
            detail: {
              error: result.error,
              minDelaySeconds: result.minDelaySeconds
            }
          }
        );
        this.dispatchEvent(errorEvent);
        this.#retryOnError(
          result.error,
          Math.max(result.minDelaySeconds, minDelaySeconds)
        );
        return;
      }
      if ("schema" in result) {
        this.#lastSeenId = result.id;
        this.schema = result.schema;
        const schemaEvent = new CustomEvent(
          "schema",
          {
            detail: {
              schema: result.schema,
              supergraphSdl: result.supergraphSdl
            }
          }
        );
        this.dispatchEvent(schemaEvent);
        this.#log("info", "Supergraph successfully updated");
      } else {
        this.#log("info", "Supergraph is up to date");
      }
      this.#retries = 1;
      const delay = Math.max(result.minDelaySeconds, minDelaySeconds);
      this.#timeout = setTimeout(this.#fetchSchema, delay * 1e3);
      this.#log("info", `Next pull in ${delay.toFixed(1)} seconds`);
    } catch (e) {
      this.#retryOnError(e, retryDelaySeconds ?? 0);
      const errorEvent = new CustomEvent(
        "error",
        {
          detail: e
        }
      );
      this.dispatchEvent(errorEvent);
    }
  };
  #retryOnError = (error, delayInSeconds) => {
    const { maxRetries = 3 } = this.options;
    const message = error?.message;
    this.#log(
      "error",
      `Failed to pull schema from managed federation: ${message}`
    );
    if (this.#retries >= maxRetries) {
      this.#timeout = void 0;
      this.#log("error", "Max retries reached, giving up");
      const failureEvent = new CustomEvent(
        "failure",
        {
          detail: { error, delayInSeconds }
        }
      );
      this.dispatchEvent(failureEvent);
      return;
    }
    this.#retries++;
    this.#log(
      "info",
      `Retrying (${this.#retries}/${maxRetries})${delayInSeconds ? ` in ${delayInSeconds.toFixed(1)} seconds` : ""}`
    );
    this.#timeout = setTimeout(this.#fetchSchema, delayInSeconds * 1e3);
  };
  #log = (level, message) => {
    const logEvent = new CustomEvent("log", {
      detail: {
        source: "manager",
        level,
        message
      }
    });
    this.dispatchEvent(logEvent);
  };
  [DisposableSymbols.dispose]() {
    return this.stop();
  }
}

export { DEFAULT_UPLINKS, SupergraphSchemaManager, ensureSupergraphSDLAst, fetchSupergraphSdlFromManagedFederation, filterInternalFieldsAndTypes, getArgsFromKeysForFederation, getCacheKeyFnFromKey, getKeyFnForFederation, getNamedTypeNode, getStitchedSchemaFromManagedFederation, getStitchedSchemaFromSupergraphSdl, getStitchingOptionsFromSupergraphSdl, projectDataSelectionSet };