UNPKG

@graphql-tools/federation

Version:

Useful tools to create and manipulate GraphQL schemas.

2,693 lines • 97.3 kB
import { getTypeInfo, handleOverrideByDelegation, extractUnavailableFieldsFromSelectionSet, subtractSelectionSets, delegateToSchema, OBJECT_SUBSCHEMA_SYMBOL, FIELD_SUBSCHEMA_MAP_SYMBOL, UNPATHED_ERRORS_SYMBOL, isExternalObject, createDefaultExecutor } from '@graphql-tools/delegate';
import { mapSchema, MapperKind, memoize1, parseSelectionSet, mergeDeep, 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 { stitchSchemas, getDefaultFieldConfigMerger, ValidationLevel, calculateSelectionScore } from '@graphql-tools/stitch';
import { isPromise, handleMaybePromise } from '@whatwg-node/promise-helpers';
import { Kind, parse, visit, print, buildASTSchema, isObjectType, isInterfaceType, isInputObjectType, parseType, visitWithTypeInfo } from 'graphql';

function getEnvStr(key, opts = {}) {
  const globalThat = opts.globalThis ?? globalThis;
  let variable = globalThat.process?.env?.[key] || // @ts-expect-error can exist in wrangler and maybe other runtimes
  globalThat.env?.[key] || // @ts-expect-error can exist in deno
  globalThat.Deno?.env?.get(key) || // @ts-expect-error could be
  globalThat[key];
  if (variable != null) {
    variable += "";
  } else {
    variable = void 0;
  }
  return variable?.trim();
}

// Regexps involved with splitting words in various case formats.
const SPLIT_LOWER_UPPER_RE = /([\p{Ll}\d])(\p{Lu})/gu;
const SPLIT_UPPER_UPPER_RE = /(\p{Lu})([\p{Lu}][\p{Ll}])/gu;
// Used to iterate over the initial split result and separate numbers.
const SPLIT_SEPARATE_NUMBER_RE = /(\d)\p{Ll}|(\p{L})\d/u;
// Regexp involved with stripping non-word characters from the result.
const DEFAULT_STRIP_REGEXP = /[^\p{L}\d]+/giu;
// The replacement value for splits.
const SPLIT_REPLACE_VALUE = "$1\0$2";
// The default characters to keep after transforming case.
const DEFAULT_PREFIX_SUFFIX_CHARACTERS = "";
/**
 * Split any cased input strings into an array of words.
 */
function split(value) {
    let result = value.trim();
    result = result
        .replace(SPLIT_LOWER_UPPER_RE, SPLIT_REPLACE_VALUE)
        .replace(SPLIT_UPPER_UPPER_RE, SPLIT_REPLACE_VALUE);
    result = result.replace(DEFAULT_STRIP_REGEXP, "\0");
    let start = 0;
    let end = result.length;
    // Trim the delimiter from around the output string.
    while (result.charAt(start) === "\0")
        start++;
    if (start === end)
        return [];
    while (result.charAt(end - 1) === "\0")
        end--;
    return result.slice(start, end).split(/\0/g);
}
/**
 * Split the input string into an array of words, separating numbers.
 */
function splitSeparateNumbers(value) {
    const words = split(value);
    for (let i = 0; i < words.length; i++) {
        const word = words[i];
        const match = SPLIT_SEPARATE_NUMBER_RE.exec(word);
        if (match) {
            const offset = match.index + (match[1] ?? match[2]).length;
            words.splice(i, 1, word.slice(0, offset), word.slice(offset));
        }
    }
    return words;
}
/**
 * Convert a string to constant case (`FOO_BAR`).
 */
function constantCase(input, options) {
    const [prefix, words, suffix] = splitPrefixSuffix(input, options);
    return (prefix +
        words.map(upperFactory(options?.locale)).join("_") +
        suffix);
}
function upperFactory(locale) {
    return locale === false
        ? (input) => input.toUpperCase()
        : (input) => input.toLocaleUpperCase(locale);
}
function splitPrefixSuffix(input, options = {}) {
    const splitFn = options.split ?? (options.separateNumbers ? splitSeparateNumbers : split);
    const prefixCharacters = options.prefixCharacters ?? DEFAULT_PREFIX_SUFFIX_CHARACTERS;
    const suffixCharacters = options.suffixCharacters ?? DEFAULT_PREFIX_SUFFIX_CHARACTERS;
    let prefixIndex = 0;
    let suffixIndex = input.length;
    while (prefixIndex < input.length) {
        const char = input.charAt(prefixIndex);
        if (!prefixCharacters.includes(char))
            break;
        prefixIndex++;
    }
    while (suffixIndex > prefixIndex) {
        const index = suffixIndex - 1;
        const char = input.charAt(index);
        if (!suffixCharacters.includes(char))
            break;
        suffixIndex = index;
    }
    return [
        input.slice(0, prefixIndex),
        splitFn(input.slice(prefixIndex, suffixIndex)),
        input.slice(suffixIndex),
    ];
}

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.trim().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) {
      let cacheKeyStr = "";
      for (const key2 of keys) {
        const keyVal = root[key2];
        if (keyVal == null) {
          continue;
        } else if (typeof keyVal === "object") {
          if (cacheKeyStr) {
            cacheKeyStr += " ";
          }
          cacheKeyStr += JSON.stringify(keyVal);
        } else {
          if (cacheKeyStr) {
            cacheKeyStr += " ";
          }
          cacheKeyStr += keyVal;
        }
      }
      return cacheKeyStr;
    };
  }
  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 getRngFromEnv() {
  const rngEnv = globalThis.process?.env?.["PROGRESSIVE_OVERRIDE_RNG"];
  if (rngEnv) {
    const rngSeed = parseFloat(rngEnv);
    if (!isNaN(rngSeed) && rngSeed >= 0 && rngSeed < 1) {
      return rngSeed;
    }
  }
  return void 0;
}
const progressiveOverridePossibilityHandler = (possibility, getRng) => {
  const rng = getRngFromEnv() || (getRng ? getRng() : Math.random());
  return rng < possibility;
};
function extractPercentageFromLabel(label) {
  if (label.startsWith("percent(") && label.endsWith(")")) {
    const regexp = /^percent\((\d+(?:\.\d+)?)\)$/;
    const match = regexp.exec(label);
    const percentageStr = match?.[1];
    if (!percentageStr) {
      throw new Error(`Expected a number in percent(x), got: ${label}`);
    }
    const parsedFloat = parseFloat(percentageStr);
    if (isNaN(parsedFloat)) {
      throw new Error(`Could not parse percentage value from label: ${label}`);
    }
    if (parsedFloat < 0 || parsedFloat > 100) {
      throw new Error(
        `Expected a percentage value between 0 and 100, got ${parsedFloat}`
      );
    }
    return parsedFloat;
  }
  return void 0;
}
function parseJoinDirective(directiveNode) {
  if (directiveNode.name.value !== "join__directive") {
    return null;
  }
  if (directiveNode.arguments == null) {
    return null;
  }
  let directiveName;
  let directiveArgsAst;
  const graphNames = [];
  for (const argumentNode of directiveNode.arguments) {
    if (argumentNode.name.value === "name" && argumentNode.value.kind === Kind.STRING) {
      directiveName = argumentNode.value.value;
    } else if (argumentNode.name.value === "args" && argumentNode.value.kind === Kind.OBJECT) {
      directiveArgsAst = argumentNode.value;
    } else if (argumentNode.name.value === "graphs" && argumentNode.value.kind === Kind.LIST) {
      for (const graphNameNode of argumentNode.value.values) {
        if (graphNameNode.kind === Kind.ENUM) {
          graphNames.push(graphNameNode.value);
        }
      }
    }
  }
  if (!directiveName || graphNames.length === 0) {
    return null;
  }
  const args = directiveArgsAst ? directiveArgsAst.fields.map((field) => ({
    kind: Kind.ARGUMENT,
    name: field.name,
    value: field.value
  })) : void 0;
  return {
    graphNames,
    directive: {
      kind: Kind.DIRECTIVE,
      name: { kind: Kind.NAME, value: directiveName },
      arguments: args
    }
  };
}
function filterDirectivesByGraph(graphName, directives, filterDirectives) {
  if (!directives) {
    return directives;
  }
  const subgraphSpecificDirectives = [];
  const filteredDirectives = directives.filter((directiveNode) => {
    if (filterDirectives.includes(directiveNode.name.value)) {
      return false;
    }
    if (directiveNode.name.value === "join__directive") {
      const parsed = parseJoinDirective(directiveNode);
      if (parsed?.graphNames.includes(graphName)) {
        subgraphSpecificDirectives.push(parsed.directive);
      }
      return false;
    }
    return true;
  });
  const allDirectives = [
    ...filteredDirectives,
    ...subgraphSpecificDirectives
  ];
  if (allDirectives.length === 0) {
    return void 0;
  }
  return allDirectives;
}

function keySelectionIncludesAllFields(keyFieldSet, fieldDefinitionNodesOfSubgraph) {
  let selectionSet;
  try {
    selectionSet = parseSelectionSet(`{ ${keyFieldSet} }`);
  } catch {
    return false;
  }
  const topLevelFieldNames = /* @__PURE__ */ new Set();
  for (const selection of selectionSet.selections) {
    if (selection.kind === Kind.FIELD) {
      topLevelFieldNames.add(selection.name.value);
    }
  }
  return fieldDefinitionNodesOfSubgraph.every(
    (fieldDefNode) => topLevelFieldNames.has(fieldDefNode.name.value)
  );
}
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();
  const progressiveOverrideInfos = /* @__PURE__ */ new Map();
  const progressiveOverrideInfosOpposite = /* @__PURE__ */ new Map();
  const overrideLabels = /* @__PURE__ */ new Set();
  const subgraphSchemaDefinitionDirectives = /* @__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 directiveImports = /* @__PURE__ */ new Map();
  const directiveDefinitions = /* @__PURE__ */ new Map();
  const inputDefinitions = /* @__PURE__ */ new Map();
  const directiveExtraDefinitions = /* @__PURE__ */ new Map();
  const subgraphNames = [];
  visit(supergraphAst, {
    EnumTypeDefinition(node) {
      if (node.name.value === "join__Graph") {
        node.values?.forEach((valueNode) => {
          subgraphNames.push(valueNode.name.value);
        });
      }
      inputDefinitions.set(node.name.value, node);
    },
    DirectiveDefinition(node) {
      directiveDefinitions.set(node.name.value, node);
      if (node.arguments?.length) {
        const extraDefinitions2 = /* @__PURE__ */ new Set();
        for (const arg of node.arguments) {
          const argTypeNode = getNamedTypeNode(arg.type);
          if (!specifiedTypeNames.includes(argTypeNode.name.value)) {
            extraDefinitions2.add(argTypeNode.name.value);
          }
        }
        if (extraDefinitions2.size > 0) {
          directiveExtraDefinitions.set(node.name.value, extraDefinitions2);
        }
      }
    },
    ScalarTypeDefinition(node) {
      inputDefinitions.set(node.name.value, node);
    },
    InputObjectTypeDefinition(node) {
      inputDefinitions.set(node.name.value, node);
    },
    Directive(node) {
      if (node.name.value === "link") {
        const importedDirectives = node.arguments?.find(
          (arg) => arg.name.value === "import"
        );
        const urlArg = node.arguments?.find((arg) => arg.name.value === "url");
        const urlStr = urlArg?.value?.kind === Kind.STRING ? urlArg.value.value : void 0;
        if (urlStr && importedDirectives?.value?.kind === Kind.LIST) {
          for (const importedDirective of importedDirectives.value.values) {
            if (importedDirective.kind === Kind.STRING) {
              directiveImports.set(importedDirective.value, { url: urlStr });
            } else if (importedDirective.kind === Kind.OBJECT) {
              const nameField = importedDirective.fields.find(
                (field) => field.name.value === "name"
              );
              const asField = importedDirective.fields.find(
                (field) => field.name.value === "as"
              );
              if (nameField?.value?.kind === Kind.STRING && urlStr) {
                const originalName = nameField.value.value;
                const localName = asField?.value?.kind === Kind.STRING ? asField.value.value : originalName;
                directiveImports.set(localName, {
                  url: urlStr,
                  originalName: localName !== originalName ? originalName : void 0
                });
              }
            }
          }
        }
      }
    }
  });
  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;
          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: filterDirectivesByGraph(
                      graphName,
                      fieldNode.directives,
                      ["join__field"]
                    )
                  });
                }
                const overrideFromArg = joinFieldDirectiveNode.arguments?.find(
                  (argumentNode) => argumentNode.name.value === "override"
                );
                let overrideFromSubgraph = void 0;
                if (overrideFromArg?.value?.kind === Kind.STRING) {
                  overrideFromSubgraph = overrideFromArg.value.value;
                }
                const overrideLabelArg = joinFieldDirectiveNode.arguments?.find(
                  (argumentNode) => argumentNode.name.value === "overrideLabel"
                );
                let overrideLabel = void 0;
                if (overrideLabelArg?.value?.kind === Kind.STRING) {
                  overrideLabel = overrideLabelArg.value.value;
                }
                if (overrideFromSubgraph && overrideLabel != null) {
                  let subgraphPossibilities = progressiveOverrideInfos.get(graphName);
                  if (!subgraphPossibilities) {
                    subgraphPossibilities = /* @__PURE__ */ new Map();
                    progressiveOverrideInfos.set(
                      graphName,
                      subgraphPossibilities
                    );
                  }
                  let existingInfos = subgraphPossibilities.get(
                    typeNode.name.value
                  );
                  if (!existingInfos) {
                    existingInfos = [];
                    subgraphPossibilities.set(
                      typeNode.name.value,
                      existingInfos
                    );
                  }
                  existingInfos.push({
                    field: fieldNode.name.value,
                    from: overrideFromSubgraph,
                    label: overrideLabel
                  });
                  if (!overrideLabel.startsWith("percent(")) {
                    overrideLabels.add(overrideLabel);
                  }
                  const oppositeKey = constantCase(overrideFromSubgraph);
                  let oppositeInfos = progressiveOverrideInfosOpposite.get(oppositeKey);
                  if (!oppositeInfos) {
                    oppositeInfos = /* @__PURE__ */ new Map();
                    progressiveOverrideInfosOpposite.set(
                      oppositeKey,
                      oppositeInfos
                    );
                  }
                  let existingOppositeInfos = oppositeInfos.get(
                    typeNode.name.value
                  );
                  if (!existingOppositeInfos) {
                    existingOppositeInfos = [];
                    oppositeInfos.set(
                      typeNode.name.value,
                      existingOppositeInfos
                    );
                  }
                  existingOppositeInfos.push({
                    field: fieldNode.name.value,
                    to: graphName,
                    label: overrideLabel
                  });
                }
                const providedExtraField = joinFieldDirectiveNode.arguments?.find(
                  (argumentNode) => argumentNode.name.value === "provides"
                );
                if (providedExtraField?.value?.kind === Kind.STRING) {
                  let registerProvidedSelectionForField2 = function(parentTypeName, fieldName, selectionSet) {
                    let fieldMap = typeNameFieldProvidedSelectionMap.get(parentTypeName);
                    if (!fieldMap) {
                      fieldMap = /* @__PURE__ */ new Map();
                      typeNameFieldProvidedSelectionMap.set(
                        parentTypeName,
                        fieldMap
                      );
                    }
                    const existing = fieldMap.get(fieldName);
                    if (existing) {
                      fieldMap.set(fieldName, {
                        kind: Kind.SELECTION_SET,
                        selections: [
                          ...existing.selections,
                          ...selectionSet.selections
                        ]
                      });
                    } else {
                      fieldMap.set(fieldName, selectionSet);
                    }
                  }, 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) {
                              registerProvidedSelectionForField2(
                                fieldNodeTypeName2,
                                selection.name.value,
                                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
                    );
                  }
                  registerProvidedSelectionForField2(
                    typeNode.name.value,
                    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
                  );
                }
              }
            });
            const keys = typeNameKeysBySubgraphMap.get(graphName)?.get(typeNode.name.value);
            const keysArr = keys && Array.from(keys);
            if (!joinFieldDirectives?.length) {
              fieldDefinitionNodesOfSubgraph.push({
                ...fieldNode,
                directives: filterDirectivesByGraph(
                  graphName,
                  fieldNode.directives,
                  ["join__field"]
                )
              });
            } else if (notInSubgraph && keysArr?.some(
              (key) => key.split(" ").includes(fieldNode.name.value)
            )) {
              fieldDefinitionNodesOfSubgraph.push({
                ...fieldNode,
                directives: filterDirectivesByGraph(
                  graphName,
                  fieldNode.directives,
                  ["join__field"]
                )
              });
            }
          });
          fieldDefinitionNodesByGraphName.set(
            graphName,
            fieldDefinitionNodesOfSubgraph
          );
          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 (keyArgumentNode?.value?.kind === Kind.STRING) {
              const keyArgVal = keyArgumentNode.value.value;
              if (isResolvable) {
                if (typeNode.kind !== Kind.OBJECT_TYPE_DEFINITION || !keySelectionIncludesAllFields(
                  keyArgVal,
                  fieldDefinitionNodesOfSubgraph
                )) {
                  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 = /* @__PURE__ */ new Set();
                    typeNameKeysMap.set(typeNode.name.value, keys);
                  }
                  keys.add(keyArgVal);
                }
              }
            }
          }
        }
      }
    });
    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: filterDirectivesByGraph(graphName, typeNode.directives, [
            "join__type",
            "join__owner",
            "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: filterDirectivesByGraph(
                  graphName,
                  node.directives,
                  ["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: filterDirectivesByGraph(
                  graphName,
                  node.directives,
                  ["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: filterDirectivesByGraph(
                    graphName,
                    node.directives,
                    ["join__type", "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: filterDirectivesByGraph(
                  graphName,
                  node.directives,
                  ["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
  });
  for (const definition of supergraphAst.definitions) {
    if (definition.kind === Kind.SCHEMA_DEFINITION) {
      if (definition.directives) {
        for (const directiveNode of definition.directives) {
          const parsed = parseJoinDirective(directiveNode);
          if (parsed) {
            for (const graphName of parsed.graphNames) {
              let subgraphSchemaLevelDefs = subgraphSchemaDefinitionDirectives.get(graphName);
              if (!subgraphSchemaLevelDefs) {
                subgraphSchemaLevelDefs = [];
                subgraphSchemaDefinitionDirectives.set(
                  graphName,
                  subgraphSchemaLevelDefs
                );
              }
              subgraphSchemaLevelDefs.push(parsed.directive);
            }
          }
        }
      }
    } else {
      continue;
    }
  }
  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
          };
        }
      });
    }, collectTransitiveDeps2 = function(typeNames, into) {
      const queue = [...typeNames];
      while (queue.length > 0) {
        const typeName = queue.shift();
        const def = inputDefinitions.get(typeName);
        if (!def || into.has(def)) continue;
        into.add(def);
        if (def.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION && def.fields) {
          for (const field of def.fields) {
            const fieldTypeName = getNamedTypeNode(field.type).name.value;
            if (!specifiedTypeNames.includes(fieldTypeName)) {
              queue.push(fieldTypeName);
            }
          }
        }
      }
    };
    const mergeConfig = {};
    const typeNameKeyMap = typeNameKeysBySubgraphMap.get(subgraphName);
    const unionTypeNodes = [];
    const pendingConflictSubschemaConfigs = [];
    if (typeNameKeyMap) {
      const typeNameFieldsKeyMap = typeNameFieldsKeyBySubgraphMap.get(subgraphName);
      for (const [typeName, keys] of typeNameKeyMap) {
        let getMergedTypeConfigFromKey2 = function(key, keysExtraKeys = extraKeys) {
          return {
            selectionSet: `{ ${key} }`,
            argsFromKeys: getArgsFromKeysForFederation,
            key: getKeyFnForFederation(typeName, [key, ...keysExtraKeys]),
            fieldName: `_entities`,
            dataLoaderOptions: {
              cacheKeyFn: getCacheKeyFnFromKey(key),
              ...opts.batchDelegateOptions || {}
            }
          };
        };
        const mergedTypeConfig = mergeConfig[typeName] = {};
        const fieldsKeyMap = typeNameFieldsKeyMap?.get(typeName);
        const extraKeys = /* @__PURE__ */ new Set();
        if (fieldsKeyMap) {
          let hashStringToAlphanumeric2 = function(str) {
            let hash = 5381;
            for (let index = 0; index < str.length; index++) {
              hash = Math.imul(hash, 33) ^ str.charCodeAt(index) | 0;
            }
            return (hash >>> 0).toString(36);
          }, aliasFieldsWithArgs2 = function(selectionSetNode) {
            for (const selection of selectionSetNode.selections) {
              if (selection.kind === Kind.FIELD && selection.arguments?.length) {
                const normalizedArgs = [...selection.arguments].sort((a, b) => a.name.value.localeCompare(b.name.value)).map(
                  (arg) => `${arg.name.value}:${memoizedASTPrint(arg.value)}`
                ).join(",");
                const argsHash = hashStringToAlphanumeric2(normalizedArgs);
                selection.alias = {
                  kind: Kind.NAME,
                  value: "_" + selection.name.value + "_" + argsHash
                };
              }
              if ("selectionSet" in selection && selection.selectionSet) {
                aliasFieldsWithArgs2(selection.selectionSet);
              }
            }
          };
          const mainFieldsConfig = mergedTypeConfig.fields = {};
          const groups = [
            {
              extraKeys,
              fieldsConfig: mainFieldsConfig,
              aliasedFields: /* @__PURE__ */ new Map()
            }
          ];
          for (const [fieldName, fieldNameKey] of fieldsKeyMap) {
            const selectionSetNode = parseSelectionSet(`{${fieldNameKey}}`);
            aliasFieldsWithArgs2(selectionSetNode);
            const selectionSet = print(selectionSetNode).replaceAll(/\n/g, " ").replaceAll(/\s+/g, " ");
            const extraKey = (
              // remove first and last characters (curly braces)
              selectionSet.slice(1, -1)
            );
            const fieldAliasedNames = /* @__PURE__ */ new Map();
            for (const sel of selectionSetNode.selections) {
              if (sel.kind === Kind.FIELD && sel.alias) {
                fieldAliasedNames.set(sel.name.value, sel.alias.value);
              }
            }
            let targetGroup;
            for (const group of groups) {
              let hasConflict = false;
              for (const [origName, aliasName] of fieldAliasedNames) {
                const existingAlias = group.aliasedFields.get(origName);
                if (existingAlias !== void 0 && existingAlias !== aliasName) {
                  hasConflict = true;
                  break;
                }
              }
              if (!hasConflict) {
                targetGroup = group;
                break;
              }
            }
            if (!targetGroup) {
              const newExtraKeys = /* @__PURE__ */ new Set();
              const newFieldsConfig = {};
              targetGroup = {
                extraKeys: newExtraKeys,
                fieldsConfig: newFieldsConfig,
                aliasedFields: /* @__PURE__ */ new Map()
              };
              groups.push(targetGroup);
            }
            targetGroup.extraKeys.add(extraKey);
            targetGroup.fieldsConfig[fieldName] = {
              selectionSet,
              computed: true
            };
            for (const [origName, aliasName] of fieldAliasedNames) {
              targetGroup.aliasedFields.set(origName, aliasName);
            }
          }
          for (const group of groups.slice(1)) {
            const additionalMergeTypeConfig = {
              fields: group.fieldsConfig
            };
            if (typeNameCanonicalMap.get(typeName) === subgraphName) {
              additionalMergeTypeConfig.canonical = true;
            }
            pendingConflictSubschemaConfigs.push({
              typeName,
              // Store closure-captured values for later SubschemaConfig creation
              // by borrowing getMergedTypeConfigFromKey with the group's extraKeys.
              mergeTypeConfig: additionalMergeTypeConfig,
              groupExtraKeys: group.extraKeys
            });
          }
        }
        if (typeNameCanonicalMap.get(typeName) === subgraphName) {
          mergedTypeConfig.canonical = true;
        }
        const keysArr = Array.from(keys);
        if (keysArr.length === 1 && keysArr[0]) {
          Object.assign(
            mergedTypeConfig,
            getMergedTypeConfigFromKey2(keysArr[0])
          );
        }
        if (keysArr.length > 1) {
          const entryPoints = keysArr.map(
            (key) => getMergedTypeConfigFromKey2(key)
          );
          mergedTypeConfig.entryPoints = entryPoints;
        }
        for (const pending of pendingConflictSubschemaConfigs) {
          if (pending.typeName === typeName && !("selectionSet" in pending.mergeTypeConfig) && !("entryPoints" in pending.mergeTypeConfig)) {
            const groupExtraKeys = pending.groupExtraKeys;
            if (keysArr.length === 1 && keysArr[0]) {
              Object.assign(
                pending.mergeTypeConfig,
                getMergedTypeConfigFromKey2(keysArr[0], groupExtraKeys)
              );
            } else if (keysArr.length > 1) {
              pending.mergeTypeConfig.entryPoints = keysArr.map(
                (key) => getMergedTypeConfigFromKey2(key, groupExtraKeys)
              );
            }
            opts.onMergedTypeConfig?.(
              pending.typeName,
              pending.mergeTypeConfig
            );
          }
        }
        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
      ]
    };
    const linkImports = /* @__PURE__ */ new Map();
    const extraDefinitions2 = /* @__PURE__ */ new Set();
    visit(schemaAst, {
      Directive(node) {
        const directiveName = node.name.value;
        const directiveDefinition = directiveDefinitions.get(directiveName);
        if (directiveDefinition && !extraDefinitions2.has(directiveDefinition)) {
          extraDefinitions2.add(directiveDefinition);
          const extraDefinitionsForDirective = directiveExtraDefinitions.get(directiveName);
          if (extraDefinitionsForDirective) {
            collectTransitiveDeps2(
              extraDefinitionsForDirective,
              extraDefinitions2
            );
          }
          const directiveNameInImport = `@${directiveName}`;
          const directiveImport = directiveImports.get(directiveNameInImport);
          if (directiveImport) {
            let urlImports = linkImports.get(directiveImport.url);
            if (!urlImports) {
              urlImports = [];
              linkImports.set(directiveImport.url, urlImports);
            }
            urlImports.push({
              name: directiveImport.originalName || directiveNameInImport,
              as: directiveNameInImport
            });
          }
        }
      }
    });
    const linkDirectiveNodes = [];
    for (const [url, linkImportsForUrl] of linkImports) {
      const urlArg = {
        kind: Kind.ARGUMENT,
        name: {
          kind: Kind.NAME,
          value: "url"
        },
        value: {
          kind: Kind.STRING,
          value: url
        }
      };
      const importArg = {
        kind: Kind.ARGUMENT,
        name: {
          kind: Kind.NAME,
          value: "import"
        },
        value: {
          kind: Kind.LIST,
          values: linkImportsForUrl.map((linkImport) => {
            if (linkImport.name === linkImport.as) {
              return {
                kind: Kind.STRING,
                value: linkImport.name
              };
            } else {
              return {
                kind: Kind.OBJECT,
                fields: [
                  {
                    kind: Kind.OBJECT_FIELD,
                    name: {
                      kind: Kind.NAME,
                      value: "name"
                    },
                    value: {
                      kind: Kind.STRING,
                      value: linkImport.name
                    }
                  },
                  {
                    kind: Kind.OBJECT_FIELD,
                    name: {
                      kind: Kind.NAME,
                      value: "as"
                    },
                    value: {
                      kind: Kind.STRING,
                      value: linkImport.as
                    }
                  }
                ]
              };
            }
          })
        }
      };
      linkDirectiveNodes.push({
        kind: Kind.DIRECTIVE,
        name: {
          kind: Kind.NAME,
          value: "link"
        },
        arguments: [urlArg, importArg]
      });
    }
    if (linkDirectiveNodes.length > 0) {
      const linkDirectiveDef = directiveDefinitions.get("link");
      if (linkDirectiveDef) {
        extraDefinitions2.add(linkDirectiveDef);
      }
      const linkDirectiveExtraDefs = directiveExtraDefinitions.get("link");
      if (linkDirectiveExtraDefs) {
        collectTransitiveDeps2(linkDirectiveExtraDefs, extraDefinitions2);
      }
      extraDefinitions2.add({
        kind: Kind.SCHEMA_EXTENSION,
        directives: [...linkDirectiveNodes]
      });
    }
    const schemaDefDirectives = subgraphSchemaDefinitionDirectives.get(subgraphName);
    if (schemaDefDirectives) {
      extraDefinitions2.add({
        kind: Kind.SCHEMA_EXTENSION,
        directives: schemaDefDirectives
      });
    }
    schemaAst = {
      ...schemaAst,
      definitions: [...extraDefinitions2, ...schemaAst.definitions]
    };
    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 progressiveOverrideInfosForSubgraph = progressiveOverrideInfos.get(subgraphName);
    if (progressiveOverrideInfosForSubgraph != null) {
      for (const [
        typeName,
        fieldInfos
      ] of progressiveOverrideInfosForSubgraph) {
        let mergedConfig = mergeConfig[typeName];
        if (!mergedConfig) {
          mergedConfig = mergeConfig[typeName] = {};
        }
        for (const fieldInfo of fieldInfos) {
          let fieldsConfig = mergedConfig.fields;
          if (!fieldsConfig) {
            fieldsConfig = mergedConfig.fields = {};
          }
          let fieldConfig = fieldsConfig[fieldInfo.field];
          if (!fieldConfig) {
            fieldConfig = fieldsConfig[fieldInfo.field] = {};
          }
          const label = fieldInfo.label;
          const percent = extractPercentageFromLabel(label);
          if (percent != null) {
            const possibility = percent / 100;
            fieldConfig.override = () => progressiveOverridePossibilityHandler(possibility, opts.getRng);
          } else if (opts.handleProgressiveOverride) {
            const progressiveOverrideHandler = opts.handleProgressiveOverride;
            fieldConfig.override = (context, info) => progressiveOverrideHandler(label, context, info);
          }
        }
      }
    }
    const progressiveOverrideOppositeInfosForSubgraph = progressiveOverrideInfosOpposite.get(constantCase(subgraphName));
    if (progressiveOverrideOppositeInfosForSubgraph != null) {
      for (const [
        typeName,
        fieldInfos
      ] of progressiveOverrideOppositeInfosForSubgraph) {
        let mergedConfig = mergeConfig[typeName];
        if (!mergedConfig) {
          mergedConfig = mergeConfig[typeName] = {};
        }
        for (const fieldInfo of fieldInfos) {
          let fieldsConfig = mergedConfig.fields;
          if (!fieldsConfig) {
            fieldsConfig = mergedConfig.fields = {};
          }
          let fieldConfig = fieldsConfig[fieldInfo.field];
          if (!fieldConfig) {
            fieldConfig = fieldsConfig[fieldInfo.field] = {};
          }
          const label = fieldInfo.label;
          const percent = extractPercentageFromLabel(label);
          if (percent != null) {
            const possibility = percent / 100;
            fieldConfig.override = () => !progressiveOverridePossibilityHandler(possibility, opts.getRng);
          } else if (opts.handleProgressiveOverride) {
            const progressiveOverrideHandler = opts.handleProgressiveOverride;
            fieldConfig.override = (context, info) => !progressiveOverrideHandler(label, context, info);
          }
        }
      }
    }
    let mainSchema = schema;
    const additionalGroupFieldsByType = /* @__PURE__ */ new Map();
    for (const {
      typeName,
      mergeTypeConfig
    } of pendingConflictSubschemaConfigs) {
      for (const [fieldName, fieldConfig] of Object.entries(
        mergeTypeConfig.fields ?? {}
      )) {
        if (!fieldConfig?.computed) continue;
        let set = additionalGroupFieldsByType.get(typeName);
        if (!set) {
          set = /* @__PURE__ */ new Set();
          additionalGroupFieldsByType.set(typeName, set);
        }
        set.add(fieldName);
      }
    }
    if (additionalGroupFieldsByType.size > 0) {
      mainSchema = mapSchema(schema, {
        [MapperKind.OBJECT_FIELD]: (fieldConfig, fieldName, typeName) => {
          if (additionalGroupFieldsByType.get(typeName)?.has(fieldName)) {
            return null;
          }
          return fieldConfig;
        }
      });
    }
    const allComputedFieldsByType = new Map(
      Array.from(additionalGroupFieldsByType, ([t, s]) => [t, new Set(s)])
    );
    for (const [typeName, typeConfig] of Object.entries(mergeConfig)) {
      if (!typeConfig?.fields) continue;
      for (const [fieldName, fieldConfig] of Object.entries(
        typeConfig.fields
      )) {
        if (!fieldConfig?.computed) continue;
        let set = allComputedFieldsByType.get(typeName);
        if (!set) {
          set = /* @__PURE__ */ new Set();
          allComputedFieldsByType.set(typeName, set);
        }
        set.add(fieldName);
      }
    }
    const subschemaConfig = {
      name: subgraphName,
      endpoint,
      schema: mainSchema,
      executor,
      merge: mergeConfig,
      transforms,
      batch: opts.batch,
      batchingOptions: opts.batchingOptions
    };
    subschemas.push(subschemaConfig);
    for (const {
      typeName,
      mergeTypeConfig
    } of pendingConflictSubschemaConfigs) {
      const groupOwnFields = new Set(
        Object.entries(mergeTypeConfig.fields ?? {}).filter(([, fc]) => fc?.computed).map(([fn]) => fn)
      );
      const allComputedForType = allComputedFieldsByType.get(typeName) ?? /* @__PURE__ */ new Set();
      const fieldsToRemove = new Set(
        [...allComputedForType].filter((f) => !groupOwnFields.has(f))
      );
      const groupSchema = fieldsToRemove.size > 0 || allComputedFieldsByType.size > 0 ? mapSchema(schema, {
        [MapperKind.OBJECT_FIELD]: (fieldConfig, fieldName, type) => {
          if (type === typeName && fieldsToRemove.has(fieldName)) {
            return null;
          }
          if (type !== typeName && allComputedFieldsByType.get(type)?.has(fieldName)) {
            return null;
          }
          return fieldConfig;
        }
      }) : schema;
      subschemas.push({
        name: subgraphName,
        endpoint,
        schema: groupSchema,
        executor,
        merge: { [typeName]: mergeTypeConfig },
        transforms,
        batch: opts.batch,
        batchingOptions: opts.batchingOptions
      });
    }
  }
  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 filteredCandidates2 = candidates.filter((candidate) => {
          const subschemaConfig = candidate.subschema;
          const overrideHandler = subschemaConfig?.merge?.[candidate.type.name]?.fields?.[candidate.fieldName]?.override;
          if (overrideHandler) {
            return handleOverrideByDelegation(info, context, overrideHandler);
          }
          return true;
        });
        const originalSelectionSet = {
          kind: Kind.SELECTION_SET,
          selections: info.fieldNodes
        };
        const candidatesReversed = filteredCandidates2.toReversed ? filteredCandidates2.toReversed() : [...filteredCandidates2].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 filteredCandidates2) {
                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,
          args,
          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,
              args,
              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);
    }
  }
  let schemaExtensions;
  if (overrideLabels.size) {
    schemaExtensions = {
      schemaExtensions: {
        overrideLabels
      },
      types: {}
    };
  }
  return {
    subschemas,
    typeDefs: additionalTypeDefs,
    assumeValid: true,
    assumeValidSDL: true,
    typeMergingOptions: {
      useNonNullableFieldOnConflict: true,
      validationSettings: {
        validationLevel: ValidationLevel.Off
      },
      fieldConfigMerger
    },
    schemaExtensions
  };
}
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;
      }
      const errorToSet = fieldNamesToPop.length || !errorsToPop.length ? error : new AggregateError(
        [error, ...errorsToPop],
        [error, ...errorsToPop].map((e) => e.message).join(", \n")
      );
      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);
    }
    const mergedData = mergeDeep(datas, void 0, true, true);
    const symbols = [
      OBJECT_SUBSCHEMA_SYMBOL,
      FIELD_SUBSCHEMA_MAP_SYMBOL,
      UNPATHED_ERRORS_SYMBOL
    ];
    for (const symbol of symbols) {
      if (mergedData?.[symbol] == null) {
        for (const data of datas) {
          const symbolValue = data?.[symbol];
          if (symbolValue != null) {
            mergedData[symbol] = symbolValue;
            break;
          }
        }
      }
    }
    return makeExternalObject(mergedData, 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 = getEnvStr("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 = getEnvStr("APOLLO_GRAPH_REF");
  }
  if (!variables.apiKey) {
    variables.apiKey = getEnvStr("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, extractPercentageFromLabel, fetchSupergraphSdlFromManagedFederation, filterDirectivesByGraph, filterInternalFieldsAndTypes, getArgsFromKeysForFederation, getCacheKeyFnFromKey, getKeyFnForFederation, getNamedTypeNode, getRngFromEnv, getStitchedSchemaFromManagedFederation, getStitchedSchemaFromSupergraphSdl, getStitchingOptionsFromSupergraphSdl, parseJoinDirective, progressiveOverridePossibilityHandler, projectDataSelectionSet };