UNPKG

@graphql-tools/delegate

Version:

A set of utils for faster development of GraphQL tools

2,766 lines • 92.8 kB
'use strict';

var utils = require('@graphql-tools/utils');
var graphql = require('graphql');
var promiseHelpers = require('@whatwg-node/promise-helpers');
var executor = require('@graphql-tools/executor');
var batchExecute = require('@graphql-tools/batch-execute');
var repeater = require('@repeaterjs/repeater');
var merge = require('dset/merge');

const applySchemaTransforms = utils.memoize2(function applySchemaTransforms2(originalWrappingSchema, subschemaConfig) {
  const schemaTransforms = subschemaConfig.transforms;
  if (schemaTransforms == null) {
    return originalWrappingSchema;
  }
  return schemaTransforms.reduce(
    (schema, transform) => transform.transformSchema?.(schema, subschemaConfig) || schema,
    originalWrappingSchema
  );
});

function isSubschema(value) {
  return Boolean(value.transformedSchema);
}
class Subschema {
  name;
  schema;
  executor;
  batch;
  batchingOptions;
  createProxyingResolver;
  transforms;
  _transformedSchema;
  merge;
  constructor(config) {
    this.name = config.name;
    this.schema = config.schema;
    this.executor = config.executor;
    this.batch = config.batch;
    this.batchingOptions = config.batchingOptions;
    this.createProxyingResolver = config.createProxyingResolver;
    this.transforms = config.transforms ?? [];
    this.merge = config.merge;
  }
  get transformedSchema() {
    if (!this._transformedSchema) {
      if (globalThis.process?.env?.["DEBUG"] != null) {
        console.warn(
          "Transformed schema is not set yet. Returning a dummy one."
        );
      }
      this._transformedSchema = applySchemaTransforms(this.schema, this);
    }
    return this._transformedSchema;
  }
  set transformedSchema(value) {
    this._transformedSchema = value;
  }
}

const prototypePollutingKeys = [
  "__proto__",
  "constructor",
  "prototype"
];
function isPrototypePollutingKey(key) {
  return prototypePollutingKeys.includes(key);
}

const leftOverByDelegationPlan = /* @__PURE__ */ new WeakMap();
const PLAN_LEFT_OVER = Symbol("PLAN_LEFT_OVER");
function getPlanLeftOverFromParent(parent) {
  if (parent != null && typeof parent === "object") {
    return parent[PLAN_LEFT_OVER];
  }
  return void 0;
}

const UNPATHED_ERRORS_SYMBOL = Symbol.for("subschemaErrors");
const OBJECT_SUBSCHEMA_SYMBOL = Symbol.for("initialSubschema");
const FIELD_SUBSCHEMA_MAP_SYMBOL = Symbol.for("subschemaMap");

function isExternalObject(data) {
  return data[UNPATHED_ERRORS_SYMBOL] !== void 0;
}
function annotateExternalObject(object, errors, subschema, subschemaMap) {
  Object.defineProperties(object, {
    [OBJECT_SUBSCHEMA_SYMBOL]: { value: subschema, writable: true },
    [FIELD_SUBSCHEMA_MAP_SYMBOL]: { value: subschemaMap, writable: true },
    [UNPATHED_ERRORS_SYMBOL]: { value: errors, writable: true }
  });
  return object;
}
function getSubschema(object, responseKey) {
  return object[FIELD_SUBSCHEMA_MAP_SYMBOL]?.[responseKey] ?? object[OBJECT_SUBSCHEMA_SYMBOL];
}
function getUnpathedErrors(object) {
  return object[UNPATHED_ERRORS_SYMBOL];
}
const EMPTY_ARRAY = [];
const EMPTY_OBJECT = /* @__PURE__ */ Object.create(null);
const getActualFieldNodes = utils.memoize1(function(fieldNode) {
  return [fieldNode];
});
function mergeFields(mergedTypeInfo, object, sourceSubschema, context, info) {
  const delegationMaps = mergedTypeInfo.delegationPlanBuilder(
    info.schema,
    sourceSubschema,
    info.variableValues != null && Object.keys(info.variableValues).length > 0 ? info.variableValues : EMPTY_OBJECT,
    info.fragments != null && Object.keys(info.fragments).length > 0 ? info.fragments : EMPTY_OBJECT,
    info.fieldNodes?.length ? info.fieldNodes.length === 1 && info.fieldNodes[0] ? getActualFieldNodes(info.fieldNodes[0]) : info.fieldNodes : EMPTY_ARRAY,
    context,
    info
  );
  const leftOver = leftOverByDelegationPlan.get(delegationMaps);
  if (leftOver) {
    object[PLAN_LEFT_OVER] = leftOver;
  }
  return promiseHelpers.handleMaybePromise(
    () => utils.promiseReduce(
      delegationMaps,
      (_, delegationMap) => executeDelegationStage(
        mergedTypeInfo,
        delegationMap,
        object,
        context,
        info
      ),
      void 0
    ),
    () => object
  );
}
function handleResolverResult(resolverResult, subschema, selectionSet, object, combinedFieldSubschemaMap, info, path, combinedErrors) {
  if (resolverResult instanceof Error || resolverResult == null) {
    const schema = subschema.transformedSchema || info.schema;
    const type = schema.getType(object.__typename);
    const { fields } = utils.collectFields(
      schema,
      info.fragments,
      info.variableValues,
      type,
      selectionSet
    );
    const nullResult = {};
    for (const [responseKey, fieldNodes] of fields) {
      const combinedPath = [...path, responseKey];
      if (resolverResult instanceof graphql.GraphQLError) {
        if (resolverResult.message.includes(
          "Cannot return null for non-nullable field"
        )) {
          nullResult[responseKey] = null;
        } else {
          nullResult[responseKey] = utils.relocatedError(
            resolverResult,
            combinedPath
          );
        }
      } else if (resolverResult instanceof Error) {
        nullResult[responseKey] = graphql.locatedError(
          resolverResult,
          fieldNodes,
          combinedPath
        );
      } else {
        nullResult[responseKey] = null;
      }
    }
    resolverResult = nullResult;
  } else {
    if (resolverResult[UNPATHED_ERRORS_SYMBOL]) {
      combinedErrors.push(...resolverResult[UNPATHED_ERRORS_SYMBOL]);
    }
  }
  const objectSubschema = resolverResult[OBJECT_SUBSCHEMA_SYMBOL];
  const fieldSubschemaMap = resolverResult[FIELD_SUBSCHEMA_MAP_SYMBOL];
  for (const responseKey in resolverResult) {
    if (isPrototypePollutingKey(responseKey)) {
      continue;
    }
    const existingPropValue = object[responseKey];
    const sourcePropValue = resolverResult[responseKey];
    if (responseKey === "__typename" && existingPropValue !== sourcePropValue && graphql.isAbstractType(subschema.transformedSchema.getType(sourcePropValue))) {
      continue;
    }
    if (sourcePropValue != null || existingPropValue == null) {
      if (existingPropValue != null && typeof existingPropValue === "object" && !(existingPropValue instanceof Error) && Object.keys(existingPropValue).length > 0) {
        if (Array.isArray(existingPropValue) && Array.isArray(sourcePropValue) && existingPropValue.length === sourcePropValue.length) {
          object[responseKey] = existingPropValue.map(
            (existingElement, index) => sourcePropValue instanceof Error ? existingElement : utils.mergeDeep(
              [existingElement, sourcePropValue[index]],
              void 0,
              true,
              true
            )
          );
        } else if (!(sourcePropValue instanceof Error)) {
          object[responseKey] = utils.mergeDeep(
            [existingPropValue, sourcePropValue],
            void 0,
            true,
            true
          );
        }
      } else {
        object[responseKey] = sourcePropValue;
      }
    }
    combinedFieldSubschemaMap[responseKey] = fieldSubschemaMap?.[responseKey] ?? objectSubschema ?? subschema;
  }
}
function executeDelegationStage(mergedTypeInfo, delegationMap, object, context, info) {
  const combinedErrors = object[UNPATHED_ERRORS_SYMBOL];
  const path = utils.pathToArray(info.path);
  const combinedFieldSubschemaMap = object[FIELD_SUBSCHEMA_MAP_SYMBOL];
  const jobs = [];
  for (const [subschema, selectionSet] of delegationMap) {
    const schema = subschema.transformedSchema || info.schema;
    const type = schema.getType(object.__typename);
    const resolver = mergedTypeInfo.resolvers.get(subschema);
    if (resolver) {
      try {
        const resolverResult$ = resolver(
          object,
          context,
          info,
          subschema,
          selectionSet,
          void 0,
          type
        );
        if (promiseHelpers.isPromise(resolverResult$)) {
          jobs.push(
            resolverResult$.then(
              (resolverResult) => handleResolverResult(
                resolverResult,
                subschema,
                selectionSet,
                object,
                combinedFieldSubschemaMap,
                info,
                path,
                combinedErrors
              ),
              (error) => handleResolverResult(
                error,
                subschema,
                selectionSet,
                object,
                combinedFieldSubschemaMap,
                info,
                path,
                combinedErrors
              )
            )
          );
        } else {
          handleResolverResult(
            resolverResult$,
            subschema,
            selectionSet,
            object,
            combinedFieldSubschemaMap,
            info,
            path,
            combinedErrors
          );
        }
      } catch (error) {
        handleResolverResult(
          error,
          subschema,
          selectionSet,
          object,
          combinedFieldSubschemaMap,
          info,
          path,
          combinedErrors
        );
      }
    }
  }
  if (jobs.length) {
    if (jobs.length === 1) {
      return jobs[0];
    }
    return Promise.all(jobs);
  }
}

function resolveExternalValue(result, unpathedErrors, subschema, context, info, returnType = getReturnType$1(info), skipTypeMerging) {
  const type = graphql.getNullableType(returnType);
  if (result instanceof Error) {
    return result;
  }
  if (result == null) {
    return reportUnpathedErrorsViaNull(unpathedErrors);
  }
  if (graphql.isLeafType(type)) {
    try {
      return type.parseValue(result);
    } catch {
      return null;
    }
  } else if (graphql.isCompositeType(type)) {
    return promiseHelpers.handleMaybePromise(
      () => resolveExternalObject(
        type,
        result,
        unpathedErrors,
        subschema,
        context,
        info,
        skipTypeMerging
      ),
      (result2) => {
        if (info && graphql.isAbstractType(type)) {
          if (result2.__typename != null) {
            const resolvedType = info.schema.getType(result2.__typename);
            if (!resolvedType) {
              return null;
            }
          }
          return result2;
        }
        return result2;
      }
    );
  } else if (graphql.isListType(type)) {
    if (Array.isArray(result)) {
      return resolveExternalList(
        type,
        result,
        unpathedErrors,
        subschema,
        context,
        info,
        skipTypeMerging
      );
    }
    return resolveExternalValue(
      result,
      unpathedErrors,
      subschema,
      context,
      info,
      type.ofType,
      skipTypeMerging
    );
  }
}
function resolveExternalObject(type, object, unpathedErrors, subschema, context, info, skipTypeMerging) {
  if (!isExternalObject(object)) {
    annotateExternalObject(
      object,
      unpathedErrors,
      subschema,
      /* @__PURE__ */ Object.create(null)
    );
  }
  if (skipTypeMerging || info == null) {
    return object;
  }
  const stitchingInfo = info.schema.extensions?.["stitchingInfo"];
  if (stitchingInfo == null) {
    return object;
  }
  let mergedTypeInfo;
  const possibleTypeNames = [object.__typename, type.name];
  for (const possibleTypeName of possibleTypeNames) {
    if (possibleTypeName != null && stitchingInfo.mergedTypes[possibleTypeName]?.targetSubschemas?.get(
      subschema
    )?.length) {
      mergedTypeInfo = stitchingInfo.mergedTypes[possibleTypeName];
      break;
    }
  }
  if (!mergedTypeInfo) {
    return object;
  }
  return mergeFields(
    mergedTypeInfo,
    object,
    subschema,
    context,
    info
  );
}
function resolveExternalList(type, list, unpathedErrors, subschema, context, info, skipTypeMerging) {
  return list.map(
    (listMember) => resolveExternalValue(
      listMember,
      unpathedErrors,
      subschema,
      context,
      info,
      type.ofType,
      skipTypeMerging
    )
  );
}
const reportedErrors = /* @__PURE__ */ new WeakMap();
function reportUnpathedErrorsViaNull(unpathedErrors) {
  if (unpathedErrors.length) {
    const unreportedErrors = [];
    for (const error of unpathedErrors) {
      if (!reportedErrors.has(error)) {
        unreportedErrors.push(error);
        reportedErrors.set(error, true);
      }
    }
    if (unreportedErrors.length) {
      const unreportedError = unreportedErrors[0];
      if (unreportedErrors.length === 1 && unreportedError) {
        return graphql.locatedError(
          unreportedError,
          void 0,
          unreportedError.path
        );
      }
      return new AggregateError(
        unreportedErrors.map(
          (e) => (
            // We cast path as any for GraphQL.js 14 compat
            // locatedError path argument must be defined, but it is just forwarded to a constructor that allows a undefined value
            // https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/locatedError.js#L25
            // https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/GraphQLError.js#L19
            graphql.locatedError(e, void 0, unreportedError?.path)
          )
        ),
        unreportedErrors.map((error) => error.message).join(", \n")
      );
    }
  }
  return null;
}
function getReturnType$1(info) {
  if (info == null) {
    throw new Error(`Return type cannot be inferred without a source schema.`);
  }
  return info.returnType;
}

function checkResultAndHandleErrors(result = {
  data: null,
  errors: []
}, delegationContext) {
  const {
    context,
    info,
    fieldName: responseKey = getResponseKey(info),
    subschema,
    returnType = getReturnType(info),
    skipTypeMerging,
    onLocatedError
  } = delegationContext;
  const { data, unpathedErrors } = mergeDataAndErrors(
    result.data == null ? void 0 : result.data[responseKey],
    result.errors == null ? [] : result.errors,
    info != null && info.path ? graphql.responsePathAsArray(info.path) : void 0,
    onLocatedError
  );
  return resolveExternalValue(
    data,
    unpathedErrors,
    subschema,
    context,
    info,
    returnType,
    skipTypeMerging
  );
}
function mergeDataAndErrors(data, errors, path, onLocatedError, index = 1) {
  if (data == null) {
    if (!errors.length) {
      return { data: null, unpathedErrors: [] };
    }
    if (errors.length === 1 && errors[0]) {
      const error = onLocatedError ? onLocatedError(errors[0]) : errors[0];
      const newPath = path === void 0 ? error.path : !error.path ? path : path.concat(error.path.slice(1));
      return { data: utils.relocatedError(errors[0], newPath), unpathedErrors: [] };
    }
    const combinedError = new AggregateError(
      errors.map(
        (e) => (
          // We cast path as any for GraphQL.js 14 compat
          // locatedError path argument must be defined, but it is just forwarded to a constructor that allows a undefined value
          // https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/locatedError.js#L25
          // https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/GraphQLError.js#L19
          graphql.locatedError(e, void 0, path)
        )
      ),
      errors.map((error) => error.message).join(", \n")
    );
    return { data: combinedError, unpathedErrors: [] };
  }
  if (!errors.length) {
    return { data, unpathedErrors: [] };
  }
  const unpathedErrors = [];
  const errorMap = /* @__PURE__ */ new Map();
  for (const error of errors) {
    const pathSegment = error.path?.[index];
    if (pathSegment != null) {
      let pathSegmentErrors = errorMap.get(pathSegment);
      if (pathSegmentErrors === void 0) {
        pathSegmentErrors = [error];
        errorMap.set(pathSegment, pathSegmentErrors);
      } else {
        pathSegmentErrors.push(error);
      }
    } else {
      unpathedErrors.push(error);
    }
  }
  for (const [pathSegment, pathSegmentErrors] of errorMap) {
    if (data[pathSegment] !== void 0) {
      const { data: newData, unpathedErrors: newErrors } = mergeDataAndErrors(
        data[pathSegment],
        pathSegmentErrors,
        path,
        onLocatedError,
        index + 1
      );
      data[pathSegment] = newData;
      unpathedErrors.push(...newErrors);
    } else {
      unpathedErrors.push(...pathSegmentErrors);
    }
  }
  return { data, unpathedErrors };
}
function getResponseKey(info) {
  if (info == null) {
    throw new Error(
      `Data cannot be extracted from result without an explicit key or source schema.`
    );
  }
  return utils.getResponseKeyFromInfo(info);
}
function getReturnType(info) {
  if (info == null) {
    throw new Error(`Return type cannot be inferred without a source schema.`);
  }
  return info.returnType;
}

function getDocumentMetadata(document) {
  const operations = [];
  const fragments = [];
  const fragmentNames = /* @__PURE__ */ new Set();
  for (let i = 0; i < document.definitions.length; i++) {
    const def = document.definitions[i];
    if (def?.kind === graphql.Kind.FRAGMENT_DEFINITION) {
      fragments.push(def);
      fragmentNames.add(def.name.value);
    } else if (def?.kind === graphql.Kind.OPERATION_DEFINITION) {
      operations.push(def);
    }
  }
  return {
    operations,
    fragments,
    fragmentNames
  };
}

const getTypeInfo = utils.memoize1(function getTypeInfo2(schema) {
  return new graphql.TypeInfo(schema);
});
const getTypeInfoWithType = utils.memoize2(function getTypeInfoWithType2(schema, type) {
  return graphql.versionInfo.major < 16 ? new graphql.TypeInfo(schema, void 0, type) : new graphql.TypeInfo(schema, type);
});

function updateArgument(argumentNodes, variableDefinitionsMap, variableValues, argName, varName, type, value) {
  argumentNodes[argName] = {
    kind: graphql.Kind.ARGUMENT,
    name: {
      kind: graphql.Kind.NAME,
      value: argName
    },
    value: {
      kind: graphql.Kind.VARIABLE,
      name: {
        kind: graphql.Kind.NAME,
        value: varName
      }
    }
  };
  variableDefinitionsMap[varName] = {
    kind: graphql.Kind.VARIABLE_DEFINITION,
    variable: {
      kind: graphql.Kind.VARIABLE,
      name: {
        kind: graphql.Kind.NAME,
        value: varName
      }
    },
    type: utils.astFromType(type)
  };
  if (value !== void 0) {
    variableValues[varName] = value;
    return;
  }
  if (varName in variableValues) {
    delete variableValues[varName];
  }
}
function createVariableNameGenerator(variableDefinitionMap) {
  let varCounter = 0;
  return (argName) => {
    let varName;
    do {
      varName = varCounter === 0 ? argName : `_v${varCounter.toString()}_${argName}`;
      varCounter++;
    } while (varName in variableDefinitionMap);
    return varName;
  };
}

function finalizeGatewayDocument(targetSchema, fragments, operations, onOverlappingAliases, delegationContext) {
  let usedVariables = [];
  let usedFragments = [];
  const newOperations = [];
  let newFragments = [];
  const validFragments = [];
  const validFragmentsWithType = /* @__PURE__ */ Object.create(null);
  for (const fragment of fragments) {
    const typeName = fragment.typeCondition.name.value;
    const type = targetSchema.getType(typeName);
    if (type != null) {
      validFragments.push(fragment);
      validFragmentsWithType[fragment.name.value] = type;
    }
  }
  let fragmentSet = /* @__PURE__ */ Object.create(null);
  for (const operation of operations) {
    const type = utils.getDefinedRootType(targetSchema, operation.operation);
    const {
      selectionSet,
      usedFragments: operationUsedFragments,
      usedVariables: operationUsedVariables
    } = finalizeSelectionSet(
      targetSchema,
      type,
      validFragmentsWithType,
      operation.selectionSet,
      onOverlappingAliases
    );
    usedFragments = union(usedFragments, operationUsedFragments);
    const {
      usedVariables: collectedUsedVariables,
      newFragments: collectedNewFragments,
      fragmentSet: collectedFragmentSet
    } = collectFragmentVariables(
      targetSchema,
      fragmentSet,
      validFragments,
      validFragmentsWithType,
      usedFragments,
      onOverlappingAliases
    );
    const operationOrFragmentVariables = union(
      operationUsedVariables,
      collectedUsedVariables
    );
    usedVariables = union(usedVariables, operationOrFragmentVariables);
    newFragments = collectedNewFragments;
    fragmentSet = collectedFragmentSet;
    const variableDefinitions = (operation.variableDefinitions ?? []).filter(
      (variable) => operationOrFragmentVariables.indexOf(variable.variable.name.value) !== -1
    );
    if (operation.operation === "subscription") {
      selectionSet.selections = selectionSet.selections.filter(
        (selection) => selection.kind !== graphql.Kind.FIELD || selection.name.value !== "__typename"
      );
    }
    if (selectionSet.selections.length === 1 && selectionSet.selections[0] && selectionSet.selections[0].kind === graphql.Kind.FIELD && selectionSet.selections[0].name.value === "__typename") {
      continue;
    }
    newOperations.push({
      kind: graphql.Kind.OPERATION_DEFINITION,
      operation: operation.operation,
      name: operation.name,
      directives: operation.directives,
      variableDefinitions,
      selectionSet
    });
  }
  if (!newOperations.length) {
    throw utils.createGraphQLError(
      "Failed to create a gateway request. The request must contain at least one operation.",
      {
        extensions: {
          [executor.CRITICAL_ERROR]: true
        }
      }
    );
  }
  let newDocument = {
    kind: graphql.Kind.DOCUMENT,
    definitions: [...newOperations, ...newFragments]
  };
  const stitchingInfo = delegationContext.info?.schema?.extensions?.["stitchingInfo"];
  if (stitchingInfo != null) {
    const typeInfo = getTypeInfo(targetSchema);
    newDocument = graphql.visit(
      newDocument,
      graphql.visitWithTypeInfo(typeInfo, {
        [graphql.Kind.FIELD](fieldNode) {
          const parentType = typeInfo.getParentType();
          if (parentType) {
            const parentTypeName = parentType.name;
            const typeConfig = stitchingInfo?.mergedTypes?.[parentTypeName];
            if (typeConfig) {
              const providedSelectionsByField = typeConfig?.providedSelectionsByField?.get(
                delegationContext.subschema
              );
              if (providedSelectionsByField) {
                const providedSelection = providedSelectionsByField[fieldNode.name.value];
                if (providedSelection) {
                  return {
                    ...fieldNode,
                    selectionSet: {
                      kind: graphql.Kind.SELECTION_SET,
                      selections: [
                        ...providedSelection.selections,
                        ...fieldNode.selectionSet?.selections ?? []
                      ]
                    }
                  };
                }
              }
            }
          }
          return fieldNode;
        }
      })
    );
  }
  return {
    usedVariables,
    newDocument
  };
}
function finalizeGatewayRequest(originalRequest, delegationContext, onOverlappingAliases) {
  let { document, variables } = originalRequest;
  let { operations, fragments } = getDocumentMetadata(document);
  const { targetSchema, args } = delegationContext;
  if (args) {
    const requestWithNewVariables = addVariablesToRootFields(
      targetSchema,
      operations,
      args
    );
    operations = requestWithNewVariables.newOperations;
    variables = Object.assign(
      {},
      variables ?? {},
      requestWithNewVariables.newVariables
    );
  }
  const { usedVariables, newDocument } = finalizeGatewayDocument(
    targetSchema,
    fragments,
    operations,
    onOverlappingAliases,
    delegationContext
  );
  const newVariables = {};
  if (variables != null) {
    for (const variableName of usedVariables) {
      const variableValue = variables[variableName];
      if (variableValue !== void 0) {
        newVariables[variableName] = variableValue;
      }
    }
  }
  return {
    ...originalRequest,
    document: newDocument,
    variables: newVariables
  };
}
function isTypeNameField(selection) {
  return selection.kind === graphql.Kind.FIELD && !selection.alias && selection.name.value === "__typename";
}
function filterTypenameFields(selections) {
  let hasTypeNameField = false;
  const filteredSelections = selections.filter((selection) => {
    if (isTypeNameField(selection)) {
      hasTypeNameField = true;
      return false;
    }
    return true;
  });
  return {
    hasTypeNameField,
    selections: filteredSelections
  };
}
function addVariablesToRootFields(targetSchema, operations, args) {
  const newVariables = /* @__PURE__ */ Object.create(null);
  const newOperations = operations.map((operation) => {
    const variableDefinitionMap = (operation.variableDefinitions ?? []).reduce(
      (prev, def) => ({
        ...prev,
        [def.variable.name.value]: def
      }),
      {}
    );
    const type = utils.getDefinedRootType(targetSchema, operation.operation);
    const newSelections = [];
    for (const selection of operation.selectionSet.selections) {
      if (selection.kind === graphql.Kind.FIELD) {
        const argumentNodes = selection.arguments ?? [];
        const argumentNodeMap = argumentNodes.reduce(
          (prev, argument) => ({
            ...prev,
            [argument.name.value]: argument
          }),
          {}
        );
        const targetField = type.getFields()[selection.name.value];
        if (targetField != null) {
          updateArguments(
            targetField,
            argumentNodeMap,
            variableDefinitionMap,
            newVariables,
            args
          );
        }
        newSelections.push({
          ...selection,
          arguments: Object.values(argumentNodeMap)
        });
      } else {
        newSelections.push(selection);
      }
    }
    const newSelectionSet = {
      kind: graphql.Kind.SELECTION_SET,
      selections: newSelections
    };
    return {
      ...operation,
      variableDefinitions: Object.values(variableDefinitionMap),
      selectionSet: newSelectionSet
    };
  });
  return {
    newOperations,
    newVariables
  };
}
function updateArguments(targetField, argumentNodeMap, variableDefinitionMap, variableValues, newArgs) {
  const generateVariableName = createVariableNameGenerator(
    variableDefinitionMap
  );
  for (const argument of targetField.args) {
    const argName = argument.name;
    const argType = argument.type;
    if (argName in newArgs) {
      updateArgument(
        argumentNodeMap,
        variableDefinitionMap,
        variableValues,
        argName,
        generateVariableName(argName),
        argType,
        utils.serializeInputValue(argType, newArgs[argName])
      );
    }
  }
}
function collectFragmentVariables(targetSchema, fragmentSet, validFragments, validFragmentsWithType, usedFragments, onOverlappingAliases) {
  let remainingFragments = usedFragments.slice();
  let usedVariables = [];
  const newFragments = [];
  while (remainingFragments.length !== 0) {
    const nextFragmentName = remainingFragments.pop();
    const fragment = validFragments.find(
      (fr) => fr.name.value === nextFragmentName
    );
    if (fragment != null) {
      const name = nextFragmentName;
      const typeName = fragment.typeCondition.name.value;
      const type = targetSchema.getType(typeName);
      if (type == null) {
        throw new Error(
          `Fragment reference type "${typeName}", but the type is not contained within the target schema.`
        );
      }
      const {
        selectionSet,
        usedFragments: fragmentUsedFragments,
        usedVariables: fragmentUsedVariables
      } = finalizeSelectionSet(
        targetSchema,
        type,
        validFragmentsWithType,
        fragment.selectionSet,
        onOverlappingAliases
      );
      remainingFragments = union(remainingFragments, fragmentUsedFragments);
      usedVariables = union(usedVariables, fragmentUsedVariables);
      if (name && !(name in fragmentSet)) {
        fragmentSet[name] = true;
        newFragments.push({
          kind: graphql.Kind.FRAGMENT_DEFINITION,
          name: {
            kind: graphql.Kind.NAME,
            value: name
          },
          typeCondition: fragment.typeCondition,
          selectionSet
        });
      }
    }
  }
  return {
    usedVariables,
    newFragments,
    fragmentSet
  };
}
const filteredSelectionSetVisitorKeys = {
  SelectionSet: ["selections"],
  Field: ["selectionSet"],
  InlineFragment: ["selectionSet"],
  FragmentDefinition: ["selectionSet"]
};
const variablesVisitorKeys = {
  SelectionSet: ["selections"],
  Field: ["arguments", "directives", "selectionSet"],
  Argument: ["value"],
  InlineFragment: ["directives", "selectionSet"],
  FragmentSpread: ["directives"],
  FragmentDefinition: ["selectionSet"],
  ObjectValue: ["fields"],
  ObjectField: ["name", "value"],
  Directive: ["arguments"],
  ListValue: ["values"]
};
function finalizeSelectionSet(schema, type, validFragments, selectionSet, onOverlappingAliases) {
  const usedFragments = [];
  const usedVariables = [];
  const typeInfo = getTypeInfoWithType(schema, type);
  const seenNonNullableMap = /* @__PURE__ */ new WeakMap();
  const seenNullableMap = /* @__PURE__ */ new WeakMap();
  const filteredSelectionSet = graphql.visit(
    selectionSet,
    graphql.visitWithTypeInfo(typeInfo, {
      [graphql.Kind.FIELD]: {
        enter: (node) => {
          const parentType = typeInfo.getParentType();
          if (graphql.isObjectType(parentType) || graphql.isInterfaceType(parentType)) {
            const field = typeInfo.getFieldDef();
            if (!field) {
              return null;
            }
            const args = field.args != null ? field.args : [];
            const argsMap = /* @__PURE__ */ Object.create(null);
            for (const arg of args) {
              argsMap[arg.name] = arg;
            }
            if (node.arguments != null) {
              const newArgs = [];
              for (const arg of node.arguments) {
                if (arg.name.value in argsMap) {
                  newArgs.push(arg);
                }
              }
              if (newArgs.length !== node.arguments.length) {
                return {
                  ...node,
                  arguments: newArgs
                };
              }
            }
          }
          if (graphql.isUnionType(parentType) && typeInfo.getType() == null) {
            const possibleTypeNames = [];
            const fieldName = node.name.value;
            for (const memberType of parentType.getTypes()) {
              const memberFields = memberType.getFields();
              const possibleField = memberFields[fieldName];
              if (possibleField != null) {
                const namedType = graphql.getNamedType(possibleField.type);
                if (node.selectionSet?.selections?.length && graphql.isLeafType(namedType)) {
                  continue;
                }
                if (!node.selectionSet?.selections?.length && graphql.isCompositeType(namedType)) {
                  continue;
                }
                possibleTypeNames.push(memberType.name);
              }
            }
            if (possibleTypeNames.length > 0) {
              return possibleTypeNames.map((possibleTypeName) => ({
                kind: graphql.Kind.INLINE_FRAGMENT,
                typeCondition: {
                  kind: graphql.Kind.NAMED_TYPE,
                  name: {
                    kind: graphql.Kind.NAME,
                    value: possibleTypeName
                  }
                },
                selectionSet: {
                  kind: graphql.Kind.SELECTION_SET,
                  selections: [node]
                }
              }));
            }
          }
          return void 0;
        },
        leave: (node) => {
          const type2 = typeInfo.getType();
          if (type2 == null) {
            return null;
          }
          const namedType = graphql.getNamedType(type2);
          if (schema.getType(namedType.name) == null) {
            return null;
          }
          if (graphql.isObjectType(namedType) || graphql.isInterfaceType(namedType)) {
            const selections = node.selectionSet != null ? node.selectionSet.selections : null;
            if (selections == null || selections.length === 0) {
              return null;
            }
          }
          return void 0;
        }
      },
      [graphql.Kind.FRAGMENT_SPREAD]: {
        enter: (node) => {
          if (!(node.name.value in validFragments)) {
            return null;
          }
          const parentType = typeInfo.getParentType();
          const innerType = validFragments[node.name.value];
          if (!utils.implementsAbstractType(schema, parentType, innerType)) {
            return null;
          }
          usedFragments.push(node.name.value);
          return void 0;
        }
      },
      [graphql.Kind.SELECTION_SET]: {
        enter: (node, _key, _parent, _path) => {
          const parentType = typeInfo.getParentType();
          const { hasTypeNameField, selections } = filterTypenameFields(
            node.selections
          );
          if (hasTypeNameField || parentType != null && graphql.isAbstractType(parentType)) {
            selections.unshift({
              kind: graphql.Kind.FIELD,
              name: {
                kind: graphql.Kind.NAME,
                value: "__typename"
              }
            });
          }
          return {
            ...node,
            selections
          };
        }
      },
      [graphql.Kind.INLINE_FRAGMENT]: {
        enter: (node) => {
          if (node.typeCondition != null) {
            const parentType = typeInfo.getParentType();
            const innerType = schema.getType(node.typeCondition.name.value);
            if (graphql.isUnionType(parentType) && parentType.getTypes().some((t) => t.name === innerType?.name)) {
              return node;
            }
            if (!utils.implementsAbstractType(schema, parentType, innerType)) {
              return null;
            }
          }
          return void 0;
        },
        leave: (selection, _key, parent) => {
          if (!selection.selectionSet?.selections?.length) {
            return null;
          }
          if (Array.isArray(parent)) {
            const selectionTypeName = selection.typeCondition?.name.value;
            if (selectionTypeName) {
              const selectionType = schema.getType(selectionTypeName);
              if (selectionType && "getFields" in selectionType) {
                const selectionTypeFields = selectionType.getFields();
                let seenNonNullable = seenNonNullableMap.get(parent);
                if (!seenNonNullable) {
                  seenNonNullable = /* @__PURE__ */ new Set();
                  seenNonNullableMap.set(parent, seenNonNullable);
                }
                let seenNullable = seenNullableMap.get(parent);
                if (!seenNullable) {
                  seenNullable = /* @__PURE__ */ new Set();
                  seenNullableMap.set(parent, seenNullable);
                }
                selection = {
                  ...selection,
                  selectionSet: {
                    ...selection.selectionSet,
                    selections: selection.selectionSet.selections.map(
                      (subSelection) => {
                        if (subSelection.kind === graphql.Kind.FIELD) {
                          const fieldName = subSelection.name.value;
                          if (!subSelection.alias) {
                            const field = selectionTypeFields[fieldName];
                            if (field) {
                              let currentNullable;
                              if (graphql.isNullableType(field.type)) {
                                seenNullable.add(fieldName);
                                currentNullable = true;
                              } else {
                                seenNonNullable.add(fieldName);
                                currentNullable = false;
                              }
                              if (seenNullable.has(fieldName) && seenNonNullable.has(fieldName)) {
                                onOverlappingAliases();
                                return {
                                  ...subSelection,
                                  alias: {
                                    kind: graphql.Kind.NAME,
                                    value: currentNullable ? `_nullable_${fieldName}` : `_nonNullable_${fieldName}`
                                  }
                                };
                              }
                            }
                          }
                        }
                        return subSelection;
                      }
                    )
                  }
                };
              }
            }
          }
          const { selections } = filterTypenameFields(
            selection.selectionSet.selections
          );
          if (selections.length === 0) {
            return null;
          }
          return {
            ...selection,
            selectionSet: {
              ...selection.selectionSet,
              selections
            },
            // @defer is not available for the communication between the gw and subgraph
            directives: selection.directives?.filter?.(
              (directive) => directive.name.value !== "defer"
            )
          };
        }
      }
    }),
    // visitorKeys argument usage a la https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
    // empty keys cannot be removed only because of typescript errors
    // will hopefully be fixed in future version of graphql-js to be optional
    filteredSelectionSetVisitorKeys
  );
  graphql.visit(
    filteredSelectionSet,
    {
      [graphql.Kind.VARIABLE]: (variableNode) => {
        usedVariables.push(variableNode.name.value);
      }
    },
    // visitorKeys argument usage a la https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
    // empty keys cannot be removed only because of typescript errors
    // will hopefully be fixed in future version of graphql-js to be optional
    variablesVisitorKeys
  );
  return {
    selectionSet: filteredSelectionSet,
    usedFragments,
    usedVariables
  };
}
function union(...arrays) {
  const cache = /* @__PURE__ */ Object.create(null);
  const result = [];
  for (const array of arrays) {
    for (const item of array) {
      if (!(item in cache)) {
        cache[item] = true;
        result.push(item);
      }
    }
  }
  return result;
}

function prepareGatewayDocument(originalDocument, transformedSchema, returnType, infoSchema) {
  const wrappedConcreteTypesDocument = wrapConcreteTypes(
    returnType,
    transformedSchema,
    originalDocument
  );
  if (infoSchema == null) {
    return wrappedConcreteTypesDocument;
  }
  const visitedSelections = /* @__PURE__ */ new WeakSet();
  const {
    possibleTypesMap,
    reversePossibleTypesMap: reversePossibleTypesMap2,
    interfaceExtensionsMap,
    fieldNodesByType,
    fieldNodesByField,
    dynamicSelectionSetsByField
  } = getSchemaMetaData(infoSchema, transformedSchema);
  const { operations, fragments, fragmentNames } = getDocumentMetadata(
    wrappedConcreteTypesDocument
  );
  const { expandedFragments, fragmentReplacements } = getExpandedFragments(
    fragments,
    fragmentNames,
    possibleTypesMap
  );
  const typeInfo = getTypeInfo(transformedSchema);
  const expandedDocument = {
    kind: graphql.Kind.DOCUMENT,
    definitions: [...operations, ...fragments, ...expandedFragments]
  };
  const visitorKeyMap = {
    Document: ["definitions"],
    OperationDefinition: ["selectionSet"],
    SelectionSet: ["selections"],
    Field: ["selectionSet"],
    InlineFragment: ["selectionSet"],
    FragmentDefinition: ["selectionSet"]
  };
  return graphql.visit(
    expandedDocument,
    graphql.visitWithTypeInfo(typeInfo, {
      [graphql.Kind.SELECTION_SET]: (node) => visitSelectionSet(
        node,
        fragmentReplacements,
        transformedSchema,
        typeInfo,
        possibleTypesMap,
        reversePossibleTypesMap2,
        interfaceExtensionsMap,
        fieldNodesByType,
        fieldNodesByField,
        dynamicSelectionSetsByField,
        infoSchema,
        visitedSelections
      )
    }),
    // visitorKeys argument usage a la https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
    // empty keys cannot be removed only because of typescript errors
    // will hopefully be fixed in future version of graphql-js to be optional
    visitorKeyMap
  );
}
const getExtraPossibleTypesFn = utils.memoize2(function getExtraPossibleTypes(transformedSchema, infoSchema) {
  const extraPossiblesTypesMap = /* @__PURE__ */ new Map();
  return function getExtraPossibleTypes2(typeName) {
    let extraTypesForSubschema = extraPossiblesTypesMap.get(typeName);
    if (!extraTypesForSubschema) {
      extraTypesForSubschema = /* @__PURE__ */ new Set();
      const gatewayType = infoSchema.getType(typeName);
      const subschemaType = transformedSchema.getType(typeName);
      if (graphql.isAbstractType(gatewayType) && graphql.isAbstractType(subschemaType)) {
        const possibleTypes = infoSchema.getPossibleTypes(gatewayType);
        const possibleTypesInSubschema = transformedSchema.getPossibleTypes(subschemaType);
        for (const possibleType of possibleTypes) {
          const possibleTypeInSubschema = transformedSchema.getType(
            possibleType.name
          );
          if (!possibleTypeInSubschema) {
            continue;
          }
          if (possibleTypeInSubschema && possibleTypesInSubschema.some((t) => t.name === possibleType.name)) {
            continue;
          }
          extraTypesForSubschema.add(possibleType.name);
        }
      }
      extraPossiblesTypesMap.set(typeName, extraTypesForSubschema);
    }
    return extraTypesForSubschema;
  };
});
function visitSelectionSet(node, fragmentReplacements, transformedSchema, typeInfo, possibleTypesMap, reversePossibleTypesMap2, interfaceExtensionsMap, fieldNodesByType, fieldNodesByField, dynamicSelectionSetsByField, infoSchema, visitedSelections) {
  const newSelections = /* @__PURE__ */ new Set();
  const maybeType = typeInfo.getParentType();
  if (maybeType != null) {
    const parentType = graphql.getNamedType(maybeType);
    const parentTypeName = parentType.name;
    const fieldNodes = fieldNodesByType[parentTypeName];
    if (fieldNodes) {
      for (const fieldNode of fieldNodes) {
        newSelections.add(fieldNode);
      }
    }
    const interfaceExtensions = interfaceExtensionsMap[parentType.name];
    const interfaceExtensionFields = [];
    for (const selection of node.selections) {
      if (selection.kind === graphql.Kind.INLINE_FRAGMENT) {
        if (selection.typeCondition != null) {
          if (!visitedSelections.has(selection)) {
            visitedSelections.add(selection);
            const typeName = selection.typeCondition.name.value;
            const getExtraPossibleTypes2 = getExtraPossibleTypesFn(
              transformedSchema,
              infoSchema
            );
            const extraPossibleTypes = getExtraPossibleTypes2(typeName);
            for (const extraPossibleTypeName of extraPossibleTypes) {
              newSelections.add({
                ...selection,
                typeCondition: {
                  kind: graphql.Kind.NAMED_TYPE,
                  name: {
                    kind: graphql.Kind.NAME,
                    value: extraPossibleTypeName
                  }
                }
              });
            }
            const typeInSubschema = transformedSchema.getType(typeName);
            if (graphql.isObjectType(typeInSubschema) || graphql.isInterfaceType(typeInSubschema)) {
              const fieldMap = typeInSubschema.getFields();
              for (const subSelection of selection.selectionSet.selections) {
                if (subSelection.kind === graphql.Kind.FIELD) {
                  const fieldName = subSelection.name.value;
                  const field = fieldMap[fieldName];
                  if (!field) {
                    newSelections.add(subSelection);
                  }
                }
              }
            } else if (!typeInSubschema) {
              for (const subSelection of selection.selectionSet.selections) {
                newSelections.add(subSelection);
              }
            }
          }
          const possibleTypes = possibleTypesMap[selection.typeCondition.name.value];
          if (possibleTypes == null) {
            const fieldNodesForTypeName = fieldNodesByField[parentTypeName]?.["__typename"];
            if (fieldNodesForTypeName) {
              for (const fieldNode of fieldNodesForTypeName) {
                newSelections.add(fieldNode);
              }
            }
            newSelections.add(selection);
            continue;
          }
          for (const possibleTypeName of possibleTypes) {
            const maybePossibleType = transformedSchema.getType(possibleTypeName);
            if (maybePossibleType != null && utils.implementsAbstractType(
              transformedSchema,
              parentType,
              maybePossibleType
            )) {
              newSelections.add(
                generateInlineFragment(
                  possibleTypeName,
                  selection.selectionSet
                )
              );
            }
          }
          if (possibleTypes.length === 0) {
            newSelections.add(selection);
          }
        } else {
          newSelections.add(selection);
        }
      } else if (selection.kind === graphql.Kind.FRAGMENT_SPREAD) {
        const fragmentName = selection.name.value;
        if (!fragmentReplacements[fragmentName]) {
          newSelections.add(selection);
          continue;
        }
        for (const replacement of fragmentReplacements[fragmentName]) {
          const typeName = replacement.typeName;
          const maybeReplacementType = transformedSchema.getType(typeName);
          if (maybeReplacementType != null && utils.implementsAbstractType(transformedSchema, parentType, maybeType)) {
            newSelections.add({
              kind: graphql.Kind.FRAGMENT_SPREAD,
              name: {
                kind: graphql.Kind.NAME,
                value: replacement.fragmentName
              }
            });
          }
        }
      } else {
        const fieldName = selection.name.value;
        if (graphql.isAbstractType(parentType)) {
          const fieldNodesForTypeName = fieldNodesByField[parentTypeName]?.["__typename"];
          if (fieldNodesForTypeName) {
            for (const fieldNode of fieldNodesForTypeName) {
              newSelections.add(fieldNode);
            }
          }
        }
        const fieldNodesMapForType = fieldNodesByField[parentTypeName];
        if (fieldNodesMapForType) {
          addDependenciesNestedly(
            selection,
            /* @__PURE__ */ new Set(),
            fieldNodesMapForType,
            newSelections
          );
        }
        const dynamicSelectionSets = dynamicSelectionSetsByField[parentTypeName]?.[fieldName];
        if (dynamicSelectionSets != null) {
          for (const selectionSetFn of dynamicSelectionSets) {
            const selectionSet = selectionSetFn(selection);
            if (selectionSet != null) {
              for (const selection2 of selectionSet.selections) {
                newSelections.add(selection2);
              }
            }
          }
        }
        if (interfaceExtensions?.[fieldName]) {
          interfaceExtensionFields.push(selection);
        } else {
          newSelections.add(selection);
        }
      }
    }
    if (reversePossibleTypesMap2[parentType.name]) {
      newSelections.add({
        kind: graphql.Kind.FIELD,
        name: {
          kind: graphql.Kind.NAME,
          value: "__typename"
        }
      });
    }
    if (interfaceExtensionFields.length) {
      const possibleTypes = possibleTypesMap[parentType.name];
      if (possibleTypes != null) {
        for (const possibleType of possibleTypes) {
          newSelections.add(
            generateInlineFragment(possibleType, {
              kind: graphql.Kind.SELECTION_SET,
              selections: interfaceExtensionFields
            })
          );
        }
      }
    }
    return {
      ...node,
      selections: Array.from(newSelections)
    };
  }
  return node;
}
function addDependenciesNestedly(fieldNode, seenFieldNames, fieldNodesByField, newSelections) {
  if (seenFieldNames.has(fieldNode.name.value)) {
    return;
  }
  seenFieldNames.add(fieldNode.name.value);
  const fieldNodes = fieldNodesByField[fieldNode.name.value];
  if (fieldNodes != null) {
    for (const nestedFieldNode of fieldNodes) {
      newSelections.add(nestedFieldNode);
      addDependenciesNestedly(
        nestedFieldNode,
        seenFieldNames,
        fieldNodesByField,
        newSelections
      );
    }
  }
}
function generateInlineFragment(typeName, selectionSet) {
  return {
    kind: graphql.Kind.INLINE_FRAGMENT,
    typeCondition: {
      kind: graphql.Kind.NAMED_TYPE,
      name: {
        kind: graphql.Kind.NAME,
        value: typeName
      }
    },
    selectionSet
  };
}
const getSchemaMetaData = utils.memoize2(
  (sourceSchema, targetSchema) => {
    const typeMap = sourceSchema.getTypeMap();
    const targetTypeMap = targetSchema.getTypeMap();
    const possibleTypesMap = /* @__PURE__ */ Object.create(null);
    const interfaceExtensionsMap = /* @__PURE__ */ Object.create(null);
    for (const typeName in typeMap) {
      const type = typeMap[typeName];
      if (graphql.isAbstractType(type)) {
        const targetType = targetTypeMap[typeName];
        if (graphql.isInterfaceType(type) && graphql.isInterfaceType(targetType)) {
          const targetTypeFields = targetType.getFields();
          const sourceTypeFields = type.getFields();
          const extensionFields = /* @__PURE__ */ Object.create(null);
          let isExtensionFieldsEmpty = true;
          for (const fieldName in sourceTypeFields) {
            if (!targetTypeFields[fieldName]) {
              extensionFields[fieldName] = true;
              isExtensionFieldsEmpty = false;
            }
          }
          if (!isExtensionFieldsEmpty) {
            interfaceExtensionsMap[typeName] = extensionFields;
          }
        }
        if (interfaceExtensionsMap[typeName] || !graphql.isAbstractType(targetType)) {
          const implementations = sourceSchema.getPossibleTypes(type);
          possibleTypesMap[typeName] = [];
          for (const impl of implementations) {
            if (targetTypeMap[impl.name]) {
              possibleTypesMap[typeName].push(impl.name);
            }
          }
        }
      }
    }
    const stitchingInfo = sourceSchema.extensions?.["stitchingInfo"];
    return {
      possibleTypesMap,
      reversePossibleTypesMap: reversePossibleTypesMap(possibleTypesMap),
      interfaceExtensionsMap,
      fieldNodesByType: stitchingInfo?.fieldNodesByType ?? {},
      fieldNodesByField: stitchingInfo?.fieldNodesByField ?? {},
      dynamicSelectionSetsByField: stitchingInfo?.dynamicSelectionSetsByField ?? {}
    };
  }
);
function reversePossibleTypesMap(possibleTypesMap) {
  const result = /* @__PURE__ */ Object.create(null);
  for (const typeName in possibleTypesMap) {
    const toTypeNames = possibleTypesMap[typeName];
    if (toTypeNames) {
      for (const toTypeName of toTypeNames) {
        if (!result[toTypeName]) {
          result[toTypeName] = [];
        }
        result[toTypeName].push(typeName);
      }
    }
  }
  return result;
}
function getExpandedFragments(fragments, fragmentNames, possibleTypesMap) {
  let fragmentCounter = 0;
  function generateFragmentName(typeName) {
    let fragmentName;
    do {
      fragmentName = `_${typeName}_Fragment${fragmentCounter.toString()}`;
      fragmentCounter++;
    } while (fragmentNames.has(fragmentName));
    return fragmentName;
  }
  const expandedFragments = [];
  const fragmentReplacements = /* @__PURE__ */ Object.create(null);
  for (const fragment of fragments) {
    const possibleTypes = possibleTypesMap[fragment.typeCondition.name.value];
    if (possibleTypes != null) {
      const fragmentName = fragment.name.value;
      fragmentReplacements[fragmentName] = [];
      for (const possibleTypeName of possibleTypes) {
        const name = generateFragmentName(possibleTypeName);
        fragmentNames.add(name);
        expandedFragments.push({
          kind: graphql.Kind.FRAGMENT_DEFINITION,
          name: {
            kind: graphql.Kind.NAME,
            value: name
          },
          typeCondition: {
            kind: graphql.Kind.NAMED_TYPE,
            name: {
              kind: graphql.Kind.NAME,
              value: possibleTypeName
            }
          },
          selectionSet: fragment.selectionSet
        });
        fragmentReplacements[fragmentName].push({
          fragmentName: name,
          typeName: possibleTypeName
        });
      }
    }
  }
  return {
    expandedFragments,
    fragmentReplacements
  };
}
function wrapConcreteTypes(returnType, targetSchema, document) {
  const namedType = graphql.getNamedType(returnType);
  if (graphql.isLeafType(namedType)) {
    return document;
  }
  let possibleTypes = graphql.isAbstractType(
    namedType
  ) ? targetSchema.getPossibleTypes(namedType) : [namedType];
  if (possibleTypes.length === 0) {
    possibleTypes = [namedType];
  }
  const rootTypeNames = utils.getRootTypeNames(targetSchema);
  const typeInfo = getTypeInfo(targetSchema);
  const visitorKeys = {
    Document: ["definitions"],
    OperationDefinition: ["selectionSet"],
    SelectionSet: ["selections"],
    InlineFragment: ["selectionSet"],
    FragmentDefinition: ["selectionSet"]
  };
  return graphql.visit(
    document,
    graphql.visitWithTypeInfo(typeInfo, {
      [graphql.Kind.FRAGMENT_DEFINITION]: (node) => {
        const typeName = node.typeCondition.name.value;
        if (!rootTypeNames.has(typeName)) {
          return false;
        }
        return void 0;
      },
      [graphql.Kind.FIELD]: (node) => {
        const fieldType = typeInfo.getType();
        if (fieldType) {
          const fieldNamedType = graphql.getNamedType(fieldType);
          if (graphql.isAbstractType(fieldNamedType) && fieldNamedType.name !== namedType.name && possibleTypes.length > 0) {
            return {
              ...node,
              selectionSet: {
                kind: graphql.Kind.SELECTION_SET,
                selections: possibleTypes.map((possibleType) => ({
                  kind: graphql.Kind.INLINE_FRAGMENT,
                  typeCondition: {
                    kind: graphql.Kind.NAMED_TYPE,
                    name: {
                      kind: graphql.Kind.NAME,
                      value: possibleType.name
                    }
                  },
                  selectionSet: node.selectionSet
                }))
              }
            };
          }
        }
        return void 0;
      }
    }),
    // visitorKeys argument usage a la https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
    // empty keys cannot be removed only because of typescript errors
    // will hopefully be fixed in future version of graphql-js to be optional
    visitorKeys
  );
}

class Transformer {
  transformations = [];
  delegationContext;
  hasOverlappingAliases = false;
  constructor(context) {
    this.delegationContext = context;
    const transforms = context.transforms;
    const delegationTransforms = transforms.slice().reverse();
    for (const transform of delegationTransforms) {
      this.addTransform(transform);
    }
  }
  addTransform(transform, context = {}) {
    this.transformations.push({ transform, context });
  }
  transformRequest(originalRequest) {
    let request = {
      ...originalRequest,
      document: prepareGatewayDocument(
        originalRequest.document,
        this.delegationContext.transformedSchema,
        this.delegationContext.returnType,
        this.delegationContext.info?.schema
      )
    };
    for (const transformation of this.transformations) {
      if (transformation.transform.transformRequest) {
        request = transformation.transform.transformRequest(
          request,
          this.delegationContext,
          transformation.context
        );
      }
    }
    return finalizeGatewayRequest(request, this.delegationContext, () => {
      this.hasOverlappingAliases = true;
    });
  }
  transformResult(originalResult) {
    let result = originalResult;
    for (let i = this.transformations.length - 1; i >= 0; i--) {
      const transformation = this.transformations[i];
      if (transformation?.transform.transformResult) {
        result = transformation.transform.transformResult(
          result,
          this.delegationContext,
          transformation.context
        );
      }
    }
    if (this.hasOverlappingAliases) {
      result = removeOverlappingAliases(result);
    }
    return checkResultAndHandleErrors(result, this.delegationContext);
  }
}
function removeOverlappingAliases(result) {
  if (result != null) {
    if (Array.isArray(result)) {
      return result.map(removeOverlappingAliases);
    } else if (typeof result === "object") {
      const newResult = {};
      for (const key in result) {
        if (key.startsWith("_nullable_") || key.startsWith("_nonNullable_")) {
          const newKey = key.replace(/^_nullable_/, "").replace(/^_nonNullable_/, "");
          newResult[newKey] = removeOverlappingAliases(result[key]);
        } else {
          newResult[key] = removeOverlappingAliases(result[key]);
        }
      }
      return newResult;
    }
  }
  return result;
}

function getDelegatingOperation(parentType, schema) {
  if (parentType === schema.getMutationType()) {
    return "mutation";
  } else if (parentType === schema.getSubscriptionType()) {
    return "subscription";
  }
  return "query";
}
function createRequest({
  sourceSchema,
  sourceParentType,
  sourceFieldName,
  fragments,
  variableDefinitions,
  variableValues,
  targetRootValue,
  targetOperationName,
  targetOperation,
  targetFieldName,
  selectionSet,
  fieldNodes,
  context,
  info
}) {
  let newSelectionSet;
  const argumentNodeMap = /* @__PURE__ */ Object.create(null);
  if (selectionSet != null) {
    newSelectionSet = selectionSet;
  } else {
    const selections = [];
    for (const fieldNode2 of fieldNodes || []) {
      if (fieldNode2.selectionSet) {
        for (const selection of fieldNode2.selectionSet.selections) {
          selections.push(selection);
        }
      }
    }
    newSelectionSet = selections.length ? {
      kind: graphql.Kind.SELECTION_SET,
      selections
    } : void 0;
    const args = fieldNodes?.[0]?.arguments;
    if (args) {
      for (const argNode of args) {
        argumentNodeMap[argNode.name.value] = argNode;
      }
    }
  }
  const newVariables = /* @__PURE__ */ Object.create(null);
  const variableDefinitionMap = /* @__PURE__ */ Object.create(null);
  if (sourceSchema != null && variableDefinitions != null) {
    for (const def of variableDefinitions) {
      const varName = def.variable.name.value;
      variableDefinitionMap[varName] = def;
      const varType = graphql.typeFromAST(
        sourceSchema,
        def.type
      );
      const serializedValue = utils.serializeInputValue(
        varType,
        variableValues?.[varName]
      );
      if (serializedValue !== void 0) {
        newVariables[varName] = serializedValue;
      }
    }
  }
  if (sourceParentType != null && sourceFieldName != null) {
    updateArgumentsWithDefaults(
      sourceParentType,
      sourceFieldName,
      argumentNodeMap,
      variableDefinitionMap,
      newVariables
    );
  }
  const fieldNode = fieldNodes?.[0];
  const rootFieldName = targetFieldName ?? fieldNode?.name.value;
  if (rootFieldName === void 0) {
    throw new Error(
      `Either "targetFieldName" or a non empty "fieldNodes" array must be provided.`
    );
  }
  const rootfieldNode = {
    kind: graphql.Kind.FIELD,
    arguments: Object.values(argumentNodeMap),
    name: {
      kind: graphql.Kind.NAME,
      value: rootFieldName
    },
    selectionSet: newSelectionSet,
    directives: fieldNode?.directives
  };
  const operationName = targetOperationName ? {
    kind: graphql.Kind.NAME,
    value: targetOperationName
  } : void 0;
  const operationDefinition = {
    kind: graphql.Kind.OPERATION_DEFINITION,
    name: operationName,
    operation: targetOperation,
    variableDefinitions: Object.values(variableDefinitionMap),
    selectionSet: {
      kind: graphql.Kind.SELECTION_SET,
      selections: [rootfieldNode]
    }
  };
  const definitions = [operationDefinition];
  if (fragments != null) {
    for (const fragmentName in fragments) {
      const fragment = fragments[fragmentName];
      if (fragment) {
        definitions.push(fragment);
      }
    }
  }
  const document = {
    kind: graphql.Kind.DOCUMENT,
    definitions
  };
  return {
    document,
    variables: newVariables,
    rootValue: targetRootValue,
    operationName: targetOperationName,
    context,
    info,
    operationType: targetOperation
  };
}
function updateArgumentsWithDefaults(sourceParentType, sourceFieldName, argumentNodeMap, variableDefinitionMap, variableValues) {
  const generateVariableName = createVariableNameGenerator(
    variableDefinitionMap
  );
  const sourceField = sourceParentType.getFields()[sourceFieldName];
  if (!sourceField) {
    throw new Error(
      `Field "${sourceFieldName}" was not found in type "${sourceParentType}".`
    );
  }
  for (const argument of sourceField.args) {
    const argName = argument.name;
    const sourceArgType = argument.type;
    if (argumentNodeMap[argName] === void 0) {
      const defaultValue = argument.defaultValue;
      if (defaultValue !== void 0) {
        updateArgument(
          argumentNodeMap,
          variableDefinitionMap,
          variableValues,
          argName,
          generateVariableName(argName),
          sourceArgType,
          utils.serializeInputValue(sourceArgType, defaultValue)
        );
      }
    }
  }
}

function defaultMergedResolver(parent, args, context, info) {
  if (!parent) {
    return null;
  }
  const responseKey = utils.getResponseKeyFromInfo(info);
  if (!isExternalObject(parent)) {
    return graphql.defaultFieldResolver(parent, args, context, info);
  }
  if (!Object.prototype.hasOwnProperty.call(parent, responseKey)) {
    const leftOver = getPlanLeftOverFromParent(parent);
    if (leftOver) {
      let missingFieldNodes = leftOver.missingFieldsParentMap.get(parent);
      if (!missingFieldNodes) {
        missingFieldNodes = [];
        leftOver.missingFieldsParentMap.set(parent, missingFieldNodes);
      }
      missingFieldNodes.push(
        ...info.fieldNodes.filter(
          (fieldNode) => leftOver.unproxiableFieldNodes.some(
            (unproxiableFieldNode) => unproxiableFieldNode === fieldNode
          )
        )
      );
      let missingDeferredFields = leftOver.missingFieldsParentDeferredMap.get(parent);
      if (!missingDeferredFields) {
        missingDeferredFields = /* @__PURE__ */ new Map();
        leftOver.missingFieldsParentDeferredMap.set(
          parent,
          missingDeferredFields
        );
      }
      const deferred = promiseHelpers.createDeferredPromise();
      missingDeferredFields.set(responseKey, deferred);
      const stitchingInfo = info.schema.extensions?.["stitchingInfo"];
      const parentTypeName = parent?.__typename || info.parentType.name;
      const fieldNodesByType = stitchingInfo?.fieldNodesByField?.[parentTypeName]?.[info.fieldName];
      if (fieldNodesByType?.every((fieldNode) => {
        const responseKey2 = fieldNode.alias?.value ?? fieldNode.name.value;
        if (Object.prototype.hasOwnProperty.call(parent, responseKey2)) {
          return true;
        }
        return false;
      })) {
        handleResult(parent, responseKey, context, info);
      }
      return deferred.promise;
    }
    return void 0;
  }
  return handleResult(parent, responseKey, context, info);
}
function handleResult(parent, responseKey, context, info) {
  const subschema = getSubschema(parent, responseKey);
  const data = parent[responseKey];
  const unpathedErrors = getUnpathedErrors(parent);
  const resolvedData$ = resolveExternalValue(
    data,
    unpathedErrors,
    subschema,
    context,
    info
  );
  const leftOver = getPlanLeftOverFromParent(parent);
  if (leftOver) {
    return promiseHelpers.handleMaybePromise(
      () => resolvedData$,
      (resolvedData) => {
        parent[responseKey] = resolvedData;
        handleLeftOver(parent, context, info, leftOver);
        return resolvedData;
      }
    );
  }
  return resolvedData$;
}
function handleLeftOver(parent, context, info, leftOver) {
  const stitchingInfo = info.schema.extensions?.["stitchingInfo"];
  if (stitchingInfo) {
    for (const possibleSubschema of leftOver.nonProxiableSubschemas) {
      const parentTypeName = info.parentType.name;
      const selectionSets = /* @__PURE__ */ new Set();
      const mainSelectionSet = stitchingInfo.mergedTypes[parentTypeName]?.selectionSets.get(
        possibleSubschema
      );
      if (mainSelectionSet) {
        selectionSets.add(mainSelectionSet);
      }
      for (const fieldNode of leftOver.unproxiableFieldNodes) {
        const fieldName = fieldNode.name.value;
        const fieldSelectionSet = stitchingInfo.mergedTypes[parentTypeName]?.fieldSelectionSets.get(
          possibleSubschema
        )?.[fieldName];
        if (fieldSelectionSet) {
          selectionSets.add(fieldSelectionSet);
        }
      }
      if (selectionSets.size) {
        const selectionSet = {
          kind: graphql.Kind.SELECTION_SET,
          selections: Array.from(selectionSets).flatMap(
            (selectionSet2) => selectionSet2.selections
          )
        };
        promiseHelpers.handleMaybePromise(
          () => flattenPromise(parent),
          (flattenedParent) => {
            handleFlattenedParent(
              flattenedParent,
              parent,
              possibleSubschema,
              selectionSet,
              leftOver,
              stitchingInfo,
              parentTypeName,
              context,
              info
            );
          }
        );
      }
    }
  }
}
function handleFlattenedParent(flattenedParent, leftOverParent, possibleSubschema, selectionSet, leftOver, stitchingInfo, parentTypeName, context, info) {
  if (parentSatisfiedSelectionSet(flattenedParent, selectionSet)) {
    const missingFieldNodes = leftOver.missingFieldsParentMap.get(leftOverParent);
    if (missingFieldNodes) {
      const resolver = stitchingInfo.mergedTypes[parentTypeName]?.resolvers.get(
        possibleSubschema
      );
      if (resolver) {
        Object.assign(leftOverParent, flattenedParent);
        const selectionSet2 = {
          kind: graphql.Kind.SELECTION_SET,
          selections: missingFieldNodes
        };
        promiseHelpers.handleMaybePromise(
          () => resolver(
            leftOverParent,
            context,
            info,
            possibleSubschema,
            selectionSet2,
            info.parentType,
            info.parentType
          ),
          (resolverResult) => {
            handleDeferredResolverResult(
              resolverResult,
              possibleSubschema,
              selectionSet2,
              leftOverParent,
              leftOver,
              context,
              info
            );
          },
          (error) => handleDeferredResolverFailure(leftOver, leftOverParent, error)
        );
      }
    }
  } else {
    for (const selectionNode of selectionSet.selections) {
      if (selectionNode.kind === graphql.Kind.FIELD && selectionNode.selectionSet?.selections?.length) {
        const responseKey = selectionNode.alias?.value ?? selectionNode.name.value;
        const nestedParent = flattenedParent[responseKey];
        const nestedSelectionSet = selectionNode.selectionSet;
        if (nestedParent != null) {
          if (!parentSatisfiedSelectionSet(nestedParent, nestedSelectionSet)) {
            async function handleNestedParentItem(nestedParentItem, fieldNode) {
              const nestedTypeName = nestedParentItem["__typename"];
              const sourceSubschema = getSubschema(
                flattenedParent,
                responseKey
              );
              if (sourceSubschema && nestedTypeName) {
                const delegationPlan = stitchingInfo.mergedTypes[nestedTypeName]?.delegationPlanBuilder(
                  info.schema,
                  sourceSubschema,
                  info.variableValues != null && Object.keys(info.variableValues).length > 0 ? info.variableValues : EMPTY_OBJECT,
                  info.fragments != null && Object.keys(info.fragments).length > 0 ? info.fragments : EMPTY_OBJECT,
                  getActualFieldNodes(fieldNode),
                  context,
                  info
                );
                if (delegationPlan?.length) {
                  for (const delegationMap of delegationPlan) {
                    for (const [subschema, selectionSet2] of delegationMap) {
                      const resolver = stitchingInfo.mergedTypes[nestedTypeName]?.resolvers.get(subschema);
                      if (resolver) {
                        const res = await resolver(
                          nestedParentItem,
                          context,
                          info,
                          subschema,
                          selectionSet2,
                          info.parentType,
                          info.parentType
                        );
                        if (res) {
                          handleResolverResult(
                            res,
                            subschema,
                            selectionSet2,
                            nestedParentItem,
                            nestedParentItem[FIELD_SUBSCHEMA_MAP_SYMBOL] ||= /* @__PURE__ */ new Map(),
                            info,
                            graphql.responsePathAsArray(info.path),
                            nestedParentItem[UNPATHED_ERRORS_SYMBOL] ||= []
                          );
                        }
                      }
                    }
                  }
                }
                if (parentSatisfiedSelectionSet(nestedParent, nestedSelectionSet)) {
                  handleFlattenedParent(
                    flattenedParent,
                    leftOverParent,
                    possibleSubschema,
                    selectionSet,
                    leftOver,
                    stitchingInfo,
                    parentTypeName,
                    context,
                    info
                  );
                }
              }
            }
            if (Array.isArray(nestedParent)) {
              nestedParent.forEach(
                (nestedParentItem) => handleNestedParentItem(nestedParentItem, selectionNode)
              );
            } else {
              handleNestedParentItem(nestedParent, selectionNode);
            }
          }
        }
      }
    }
  }
}
function handleDeferredResolverResult(resolverResult, possibleSubschema, selectionSet, leftOverParent, leftOver, context, info) {
  handleResolverResult(
    resolverResult,
    possibleSubschema,
    selectionSet,
    leftOverParent,
    leftOverParent[FIELD_SUBSCHEMA_MAP_SYMBOL],
    info,
    graphql.responsePathAsArray(info.path),
    leftOverParent[UNPATHED_ERRORS_SYMBOL]
  );
  const deferredFields = leftOver.missingFieldsParentDeferredMap.get(leftOverParent);
  if (deferredFields) {
    for (const [responseKey, deferred] of deferredFields) {
      if (Object.prototype.hasOwnProperty.call(resolverResult, responseKey)) {
        deferred.resolve(
          handleResult(leftOverParent, responseKey, context, info)
        );
      }
    }
    leftOver.missingFieldsParentDeferredMap.delete(leftOverParent);
  }
}
function handleDeferredResolverFailure(leftOver, leftOverParent, error) {
  const deferredFields = leftOver.missingFieldsParentDeferredMap.get(leftOverParent);
  if (deferredFields) {
    for (const [_responseKey, deferred] of deferredFields) {
      deferred.reject(error);
    }
    leftOver.missingFieldsParentDeferredMap.delete(leftOverParent);
  }
}
function parentSatisfiedSelectionSet(parent, selectionSet) {
  if (Array.isArray(parent)) {
    const subschemas2 = /* @__PURE__ */ new Set();
    for (const item of parent) {
      const satisfied = parentSatisfiedSelectionSet(item, selectionSet);
      if (satisfied === void 0) {
        return void 0;
      }
      for (const subschema of satisfied) {
        subschemas2.add(subschema);
      }
    }
    return subschemas2;
  }
  if (parent === null) {
    return /* @__PURE__ */ new Set();
  }
  if (parent === void 0) {
    return void 0;
  }
  const subschemas = /* @__PURE__ */ new Set();
  for (const selection of selectionSet.selections) {
    if (selection.kind === graphql.Kind.FIELD) {
      const responseKey = selection.alias?.value ?? selection.name.value;
      if (parent[responseKey] === void 0) {
        return void 0;
      }
      if (isExternalObject(parent)) {
        const subschema = getSubschema(parent, responseKey);
        if (subschema) {
          subschemas.add(subschema);
        }
      }
      if (parent[responseKey] === null) {
        continue;
      }
      if (selection.selectionSet != null) {
        const satisfied = parentSatisfiedSelectionSet(
          parent[responseKey],
          selection.selectionSet
        );
        if (satisfied === void 0) {
          return void 0;
        }
        for (const subschema of satisfied) {
          subschemas.add(subschema);
        }
      }
    } else if (selection.kind === graphql.Kind.INLINE_FRAGMENT) {
      const inlineSatisfied = parentSatisfiedSelectionSet(
        parent,
        selection.selectionSet
      );
      if (inlineSatisfied === void 0) {
        return void 0;
      }
      for (const subschema of inlineSatisfied) {
        subschemas.add(subschema);
      }
    }
  }
  return subschemas;
}
function flattenPromise(data) {
  if (promiseHelpers.isPromise(data)) {
    return data.then(flattenPromise);
  }
  if (Array.isArray(data)) {
    return Promise.all(data.map(flattenPromise));
  }
  if (data != null && typeof data === "object") {
    const jobs = [];
    const newData = {};
    for (const key in data) {
      const keyResult = flattenPromise(data[key]);
      if (promiseHelpers.isPromise(keyResult)) {
        jobs.push(
          keyResult.then((resolvedKeyResult) => {
            newData[key] = resolvedKeyResult;
          })
        );
      } else {
        newData[key] = keyResult;
      }
    }
    if (OBJECT_SUBSCHEMA_SYMBOL in data) {
      newData[OBJECT_SUBSCHEMA_SYMBOL] = data[OBJECT_SUBSCHEMA_SYMBOL];
    }
    if (FIELD_SUBSCHEMA_MAP_SYMBOL in data) {
      newData[FIELD_SUBSCHEMA_MAP_SYMBOL] = data[FIELD_SUBSCHEMA_MAP_SYMBOL];
    }
    if (UNPATHED_ERRORS_SYMBOL in data) {
      newData[UNPATHED_ERRORS_SYMBOL] = data[UNPATHED_ERRORS_SYMBOL];
    }
    if (jobs.length) {
      return Promise.all(jobs).then(() => newData);
    }
    return newData;
  }
  return data;
}

function isSubschemaConfig(value) {
  return Boolean(value?.schema);
}
function cloneSubschemaConfig(subschemaConfig) {
  const newSubschemaConfig = {
    ...subschemaConfig,
    transforms: subschemaConfig.transforms != null ? [...subschemaConfig.transforms] : void 0
  };
  if (newSubschemaConfig.merge != null) {
    newSubschemaConfig.merge = { ...subschemaConfig.merge };
    for (const typeName in newSubschemaConfig.merge) {
      const mergedTypeConfig = newSubschemaConfig.merge[typeName] = {
        ...subschemaConfig.merge?.[typeName] ?? {}
      };
      if (mergedTypeConfig.entryPoints != null) {
        mergedTypeConfig.entryPoints = mergedTypeConfig.entryPoints.map(
          (entryPoint) => ({
            ...entryPoint
          })
        );
      }
      if (mergedTypeConfig.fields != null) {
        const fields = mergedTypeConfig.fields = {
          ...mergedTypeConfig.fields
        };
        for (const fieldName in fields) {
          fields[fieldName] = { ...fields[fieldName] };
        }
      }
    }
  }
  return newSubschemaConfig;
}

function delegateToSchema(options) {
  const {
    info,
    schema,
    rootValue = schema.rootValue ?? info.rootValue,
    operationName = info.operation.name?.value,
    operation = getDelegatingOperation(info.parentType, info.schema),
    fieldName = info.fieldName,
    selectionSet,
    fieldNodes = info.fieldNodes,
    context
  } = options;
  const request = createRequest({
    sourceSchema: info.schema,
    sourceParentType: info.parentType,
    sourceFieldName: info.fieldName,
    fragments: info.fragments,
    variableDefinitions: info.operation.variableDefinitions,
    variableValues: info.variableValues,
    targetRootValue: rootValue,
    targetOperationName: operationName,
    targetOperation: operation,
    targetFieldName: fieldName,
    selectionSet,
    fieldNodes,
    context,
    info
  });
  return delegateRequest({
    ...options,
    request
  });
}
function getDelegationReturnType(targetSchema, operation, fieldName) {
  const rootType = utils.getDefinedRootType(targetSchema, operation);
  const rootFieldType = rootType.getFields()[fieldName];
  if (!rootFieldType) {
    throw new Error(
      `Unable to find field '${fieldName}' in type '${rootType}'.`
    );
  }
  return rootFieldType.type;
}
function delegateRequest(options) {
  const delegationContext = getDelegationContext(options);
  const transformer = new Transformer(delegationContext);
  const processedRequest = transformer.transformRequest(options.request);
  if (options.validateRequest) {
    validateRequest(delegationContext, processedRequest.document);
  }
  return promiseHelpers.handleMaybePromise(
    () => getExecutor(delegationContext)(processedRequest),
    function handleExecutorResult(executorResult) {
      if (utils.isAsyncIterable(executorResult)) {
        if (delegationContext.operation === "query" && graphql.isListType(delegationContext.returnType)) {
          return new repeater.Repeater(async (push, stop) => {
            const pushed = /* @__PURE__ */ new WeakSet();
            let stopped = false;
            stop.finally(() => {
              stopped = true;
            });
            try {
              for await (const result of executorResult) {
                if (stopped) {
                  break;
                }
                if (result.incremental) {
                  const data = {};
                  for (const incrementalRes of result.incremental) {
                    if (incrementalRes.items?.length) {
                      for (const item of incrementalRes.items) {
                        merge.dset(
                          data,
                          (incrementalRes.path || []).slice(0, -1),
                          item
                        );
                      }
                      await push(await transformer.transformResult({ data }));
                    }
                  }
                  if (result.hasNext === false) {
                    break;
                  } else {
                    continue;
                  }
                }
                const transformedResult = await transformer.transformResult(result);
                if (Array.isArray(transformedResult)) {
                  for (const individualResult$ of transformedResult) {
                    if (stopped) {
                      break;
                    }
                    const individualResult = await individualResult$;
                    if (!pushed.has(individualResult)) {
                      pushed.add(individualResult);
                      await push(individualResult);
                    }
                  }
                } else {
                  await push(await transformedResult);
                }
              }
              stop();
            } catch (error) {
              stop(error);
            }
          });
        }
        return promiseHelpers.mapAsyncIterator(
          executorResult,
          (result) => transformer.transformResult(result)
        );
      }
      return transformer.transformResult(executorResult);
    }
  );
}
function getDelegationContext({
  request,
  schema,
  fieldName,
  returnType,
  args,
  info,
  transforms = [],
  transformedSchema,
  skipTypeMerging = false,
  onLocatedError
}) {
  const operationDefinition = utils.getOperationASTFromRequest(request);
  let targetFieldName;
  if (fieldName == null) {
    targetFieldName = operationDefinition.selectionSet.selections[0].name.value;
  } else {
    targetFieldName = fieldName;
  }
  const stitchingInfo = info?.schema.extensions?.["stitchingInfo"];
  const subschemaOrSubschemaConfig = stitchingInfo?.subschemaMap.get(schema) ?? schema;
  const operation = operationDefinition.operation;
  if (isSubschemaConfig(subschemaOrSubschemaConfig)) {
    const targetSchema = subschemaOrSubschemaConfig.schema;
    return {
      subschema: schema,
      subschemaConfig: subschemaOrSubschemaConfig,
      targetSchema,
      operation,
      fieldName: targetFieldName,
      args,
      context: request.context,
      info,
      returnType: returnType ?? info?.returnType ?? getDelegationReturnType(targetSchema, operation, targetFieldName),
      transforms: subschemaOrSubschemaConfig.transforms != null ? subschemaOrSubschemaConfig.transforms.concat(transforms) : transforms,
      transformedSchema: transformedSchema ?? (subschemaOrSubschemaConfig instanceof Subschema ? subschemaOrSubschemaConfig.transformedSchema : applySchemaTransforms(targetSchema, subschemaOrSubschemaConfig)),
      skipTypeMerging,
      onLocatedError
    };
  }
  return {
    subschema: schema,
    subschemaConfig: void 0,
    targetSchema: subschemaOrSubschemaConfig,
    operation,
    fieldName: targetFieldName,
    args,
    context: request.context,
    info,
    returnType: returnType ?? info?.returnType ?? getDelegationReturnType(
      subschemaOrSubschemaConfig,
      operation,
      targetFieldName
    ),
    transforms,
    transformedSchema: transformedSchema ?? subschemaOrSubschemaConfig,
    skipTypeMerging
  };
}
function validateRequest(delegationContext, document) {
  const errors = graphql.validate(delegationContext.targetSchema, document);
  if (errors.length > 0) {
    if (errors.length > 1) {
      const combinedError = new AggregateError(
        errors,
        errors.map((error2) => error2.message).join(", \n")
      );
      throw combinedError;
    }
    const error = errors[0];
    if (error) {
      throw error.originalError || error;
    }
  }
}
const GLOBAL_CONTEXT = {};
function getExecutor(delegationContext) {
  const { subschemaConfig, targetSchema, context } = delegationContext;
  let executor$1 = subschemaConfig?.executor || executor.executorFromSchema(targetSchema);
  if (subschemaConfig?.batch) {
    const batchingOptions = subschemaConfig?.batchingOptions;
    executor$1 = batchExecute.getBatchingExecutor(
      context ?? GLOBAL_CONTEXT,
      executor$1,
      batchingOptions?.dataLoaderOptions,
      batchingOptions?.extensionsReducer
    );
  }
  return executor$1;
}

function extractUnavailableFieldsFromSelectionSet(schema, fieldType, fieldSelectionSet, shouldAdd, fragments = {}) {
  if (graphql.isLeafType(fieldType)) {
    return [];
  }
  if (graphql.isUnionType(fieldType)) {
    const unavailableSelections2 = [];
    for (const type of fieldType.getTypes()) {
      const fieldSelectionExcluded = {
        ...fieldSelectionSet,
        selections: fieldSelectionSet.selections.filter(
          (selection) => selection.kind === graphql.Kind.INLINE_FRAGMENT ? selection.typeCondition ? selection.typeCondition.name.value === type.name : false : true
        )
      };
      unavailableSelections2.push(
        ...extractUnavailableFieldsFromSelectionSet(
          schema,
          type,
          fieldSelectionExcluded,
          shouldAdd,
          fragments
        )
      );
    }
    return unavailableSelections2;
  }
  const subFields = fieldType.getFields();
  const unavailableSelections = [];
  for (const selection of fieldSelectionSet.selections) {
    if (selection.kind === graphql.Kind.FIELD) {
      if (selection.name.value === "__typename") {
        continue;
      }
      const fieldName = selection.name.value;
      const selectionField = subFields[fieldName];
      if (!selectionField) {
        if (shouldAdd(fieldType, selection)) {
          unavailableSelections.push(selection);
        }
      } else {
        const unavailableSubFields = extractUnavailableFields(
          schema,
          selectionField,
          selection,
          shouldAdd,
          fragments
        );
        if (unavailableSubFields.length) {
          unavailableSelections.push({
            ...selection,
            selectionSet: {
              kind: graphql.Kind.SELECTION_SET,
              selections: unavailableSubFields
            }
          });
        }
      }
    } else if (selection.kind === graphql.Kind.INLINE_FRAGMENT) {
      const subFieldName = selection.typeCondition?.name.value || fieldType.name;
      const subFieldType = selection.typeCondition && schema.getType(subFieldName) || fieldType;
      if (subFieldName === fieldType.name || (graphql.isObjectType(subFieldType) || graphql.isInterfaceType(subFieldType)) && graphql.isAbstractType(fieldType) && schema.isSubType(fieldType, subFieldType)) {
        const unavailableFields = extractUnavailableFieldsFromSelectionSet(
          schema,
          subFieldType,
          selection.selectionSet,
          shouldAdd,
          fragments
        );
        if (unavailableFields.length) {
          unavailableSelections.push({
            ...selection,
            selectionSet: {
              kind: graphql.Kind.SELECTION_SET,
              selections: unavailableFields
            }
          });
        }
      } else if (graphql.isObjectType(subFieldType) || graphql.isInterfaceType(subFieldType)) {
        for (const subSelection of selection.selectionSet.selections) {
          if (subSelection.kind === graphql.Kind.FIELD && subSelection.name.value === "__typename") {
            continue;
          }
          if (shouldAdd(subFieldType, subSelection)) {
            unavailableSelections.push(subSelection);
          }
        }
      }
    } else if (selection.kind === graphql.Kind.FRAGMENT_SPREAD) {
      const fragment = fragments[selection.name.value];
      if (fragment) {
        const fragmentUnavailableFields = extractUnavailableFieldsFromSelectionSet(
          schema,
          fieldType,
          {
            kind: graphql.Kind.SELECTION_SET,
            selections: [
              {
                kind: graphql.Kind.INLINE_FRAGMENT,
                typeCondition: {
                  kind: graphql.Kind.NAMED_TYPE,
                  name: {
                    kind: graphql.Kind.NAME,
                    value: fragment.typeCondition.name.value
                  }
                },
                selectionSet: fragment.selectionSet
              }
            ]
          },
          shouldAdd,
          fragments
        );
        if (fragmentUnavailableFields.length) {
          unavailableSelections.push(...fragmentUnavailableFields);
        }
      }
    }
  }
  return unavailableSelections;
}
function extractUnavailableFields(schema, field, fieldNode, shouldAdd, fragments = {}) {
  if (fieldNode.selectionSet) {
    const fieldType = graphql.getNamedType(field.type);
    return extractUnavailableFieldsFromSelectionSet(
      schema,
      fieldType,
      fieldNode.selectionSet,
      shouldAdd,
      fragments
    );
  }
  return [];
}
function fieldExistsInSelectionSet(node, path) {
  let currentNode = node;
  const isArrayOfSelectionNodes = (node2) => Array.isArray(node2);
  for (const [segment, fieldName] of path) {
    if (!currentNode) {
      return false;
    }
    if (isArrayOfSelectionNodes(currentNode) && fieldName) {
      currentNode = currentNode.find((selectionNode) => {
        return selectionNode.name?.value === fieldName;
      });
    } else {
      currentNode = currentNode[segment];
    }
  }
  return !!currentNode;
}
function getPathWithFieldNames(node, path) {
  const pathWithFieldNames = [];
  let currentNode = node;
  const isArrayOfSelectionNodes = (node2) => Array.isArray(node2);
  for (const segment of path) {
    currentNode = currentNode[segment];
    if (!isArrayOfSelectionNodes(currentNode) && currentNode.kind === graphql.Kind.FIELD) {
      pathWithFieldNames.push([segment, currentNode.name.value]);
    } else {
      pathWithFieldNames.push([segment]);
    }
  }
  return pathWithFieldNames;
}
function subtractSelectionSets(selectionSetA, selectionSetB) {
  return graphql.visit(selectionSetA, {
    [graphql.Kind.FIELD]: {
      enter(node, _key, _parent, path) {
        if (!node.selectionSet) {
          const pathWithFieldNames = getPathWithFieldNames(selectionSetA, path);
          const fieldExists = fieldExistsInSelectionSet(
            selectionSetB,
            pathWithFieldNames
          );
          if (fieldExists) {
            return null;
          }
        }
        return void 0;
      }
    },
    [graphql.Kind.SELECTION_SET]: {
      leave(node) {
        if (node.selections.length === 0) {
          return null;
        }
        return void 0;
      }
    },
    [graphql.Kind.INLINE_FRAGMENT]: {
      leave(node) {
        if (node.selectionSet?.selections.length === 0) {
          return null;
        }
        return void 0;
      }
    }
  });
}

Object.defineProperty(exports, "createDeferred", {
  enumerable: true,
  get: function () { return utils.createDeferred; }
});
Object.defineProperty(exports, "createDefaultExecutor", {
  enumerable: true,
  get: function () { return executor.executorFromSchema; }
});
exports.EMPTY_ARRAY = EMPTY_ARRAY;
exports.EMPTY_OBJECT = EMPTY_OBJECT;
exports.FIELD_SUBSCHEMA_MAP_SYMBOL = FIELD_SUBSCHEMA_MAP_SYMBOL;
exports.OBJECT_SUBSCHEMA_SYMBOL = OBJECT_SUBSCHEMA_SYMBOL;
exports.PLAN_LEFT_OVER = PLAN_LEFT_OVER;
exports.Subschema = Subschema;
exports.Transformer = Transformer;
exports.UNPATHED_ERRORS_SYMBOL = UNPATHED_ERRORS_SYMBOL;
exports.annotateExternalObject = annotateExternalObject;
exports.applySchemaTransforms = applySchemaTransforms;
exports.cloneSubschemaConfig = cloneSubschemaConfig;
exports.createRequest = createRequest;
exports.defaultMergedResolver = defaultMergedResolver;
exports.delegateRequest = delegateRequest;
exports.delegateToSchema = delegateToSchema;
exports.extractUnavailableFields = extractUnavailableFields;
exports.extractUnavailableFieldsFromSelectionSet = extractUnavailableFieldsFromSelectionSet;
exports.getActualFieldNodes = getActualFieldNodes;
exports.getDelegatingOperation = getDelegatingOperation;
exports.getPlanLeftOverFromParent = getPlanLeftOverFromParent;
exports.getSubschema = getSubschema;
exports.getTypeInfo = getTypeInfo;
exports.getTypeInfoWithType = getTypeInfoWithType;
exports.getUnpathedErrors = getUnpathedErrors;
exports.handleResolverResult = handleResolverResult;
exports.isExternalObject = isExternalObject;
exports.isPrototypePollutingKey = isPrototypePollutingKey;
exports.isSubschema = isSubschema;
exports.isSubschemaConfig = isSubschemaConfig;
exports.leftOverByDelegationPlan = leftOverByDelegationPlan;
exports.mergeFields = mergeFields;
exports.resolveExternalValue = resolveExternalValue;
exports.subtractSelectionSets = subtractSelectionSets;